/src/libreoffice/sc/source/ui/view/viewfun2.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 eCode Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #include <scitems.hxx> |
21 | | |
22 | | #include <sfx2/app.hxx> |
23 | | #include <sfx2/request.hxx> |
24 | | #include <editeng/borderline.hxx> |
25 | | #include <editeng/boxitem.hxx> |
26 | | #include <editeng/fontitem.hxx> |
27 | | #include <editeng/lineitem.hxx> |
28 | | #include <editeng/scriptsetitem.hxx> |
29 | | #include <svl/srchitem.hxx> |
30 | | #include <sfx2/linkmgr.hxx> |
31 | | #include <sfx2/dispatch.hxx> |
32 | | #include <sfx2/docfilt.hxx> |
33 | | #include <sfx2/docfile.hxx> |
34 | | #include <sfx2/objitem.hxx> |
35 | | #include <sfx2/viewfrm.hxx> |
36 | | #include <svl/numformat.hxx> |
37 | | #include <svl/stritem.hxx> |
38 | | #include <svl/zforlist.hxx> |
39 | | #include <svx/srchdlg.hxx> |
40 | | #include <svx/svdview.hxx> |
41 | | #include <vcl/svapp.hxx> |
42 | | #include <vcl/weld/MessageDialog.hxx> |
43 | | #include <vcl/weld/weld.hxx> |
44 | | #include <osl/diagnose.h> |
45 | | |
46 | | #include <viewfunc.hxx> |
47 | | #include <vcl/uitest/logger.hxx> |
48 | | #include <vcl/uitest/eventdescription.hxx> |
49 | | |
50 | | #include <sc.hrc> |
51 | | #include <globstr.hrc> |
52 | | #include <scresid.hxx> |
53 | | |
54 | | #include <attrib.hxx> |
55 | | #include <autoform.hxx> |
56 | | #include <formulacell.hxx> |
57 | | #include <cellmergeoption.hxx> |
58 | | #include <compiler.hxx> |
59 | | #include <docfunc.hxx> |
60 | | #include <docpool.hxx> |
61 | | #include <docsh.hxx> |
62 | | #include <global.hxx> |
63 | | #include <patattr.hxx> |
64 | | #include <printfun.hxx> |
65 | | #include <refundo.hxx> |
66 | | #include <table.hxx> |
67 | | #include <tablink.hxx> |
68 | | #include <tabvwsh.hxx> |
69 | | #include <uiitems.hxx> |
70 | | #include <undoblk.hxx> |
71 | | #include <undotab.hxx> |
72 | | #include <sizedev.hxx> |
73 | | #include <editable.hxx> |
74 | | #include <docuno.hxx> |
75 | | #include <charthelper.hxx> |
76 | | #include <tabbgcolor.hxx> |
77 | | #include <clipparam.hxx> |
78 | | #include <prnsave.hxx> |
79 | | #include <searchresults.hxx> |
80 | | #include <tokenarray.hxx> |
81 | | #include <rowheightcontext.hxx> |
82 | | #include <LibreOfficeKit/LibreOfficeKitEnums.h> |
83 | | #include <comphelper/lok.hxx> |
84 | | #include <mergecellsdialog.hxx> |
85 | | #include <sheetevents.hxx> |
86 | | #include <columnspanset.hxx> |
87 | | #include <SheetViewManager.hxx> |
88 | | |
89 | | #include <vector> |
90 | | #include <memory> |
91 | | #include <boost/property_tree/json_parser.hpp> |
92 | | #include <tools/json_writer.hxx> |
93 | | |
94 | | #include <officecfg/Office/Calc.hxx> |
95 | | #include <sfx2/lokhelper.hxx> |
96 | | |
97 | | using namespace com::sun::star; |
98 | | using ::editeng::SvxBorderLine; |
99 | | |
100 | | namespace { |
101 | | |
102 | | void collectUIInformation(std::map<OUString, OUString>&& aParameters, const OUString& rAction) |
103 | 0 | { |
104 | 0 | EventDescription aDescription; |
105 | 0 | aDescription.aID = "grid_window"; |
106 | 0 | aDescription.aAction = rAction; |
107 | 0 | aDescription.aParameters = std::move(aParameters); |
108 | 0 | aDescription.aParent = "MainWindow"; |
109 | 0 | aDescription.aKeyWord = "ScGridWinUIObject"; |
110 | |
|
111 | 0 | UITestLogger::getInstance().logEvent(aDescription); |
112 | 0 | } |
113 | | } |
114 | | |
115 | | bool ScViewFunc::AdjustBlockHeight( bool bPaint, ScMarkData* pMarkData, bool bRangeWidthChanged ) |
116 | 0 | { |
117 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
118 | 0 | if (!pMarkData) |
119 | 0 | pMarkData = &GetViewData().GetMarkData(); |
120 | |
|
121 | 0 | ScDocument& rDoc = pDocSh->GetDocument(); |
122 | 0 | std::vector<sc::ColRowSpan> aMarkedRows = pMarkData->GetMarkedRowSpans(); |
123 | |
|
124 | 0 | if (aMarkedRows.empty()) |
125 | 0 | { |
126 | 0 | SCROW nCurRow = GetViewData().GetCurY(); |
127 | 0 | aMarkedRows.emplace_back(nCurRow, nCurRow); |
128 | 0 | } |
129 | |
|
130 | 0 | if (comphelper::LibreOfficeKit::isActive()) |
131 | 0 | { |
132 | 0 | SCCOLROW nStart = aMarkedRows[0].mnStart; |
133 | 0 | OnLOKSetWidthOrHeight(nStart, /*width: */ false); |
134 | 0 | } |
135 | |
|
136 | 0 | double nPPTX = GetViewData().GetPPTX(); |
137 | 0 | double nPPTY = GetViewData().GetPPTY(); |
138 | 0 | double fZoomX = GetViewData().GetZoomX(); |
139 | 0 | double fZoomY = GetViewData().GetZoomY(); |
140 | |
|
141 | 0 | ScSizeDeviceProvider aProv(*pDocSh); |
142 | 0 | if (aProv.IsPrinter()) |
143 | 0 | { |
144 | 0 | nPPTX = aProv.GetPPTX(); |
145 | 0 | nPPTY = aProv.GetPPTY(); |
146 | 0 | fZoomX = fZoomY = 1.0; |
147 | 0 | } |
148 | |
|
149 | 0 | sc::RowHeightContext aCxt(rDoc.MaxRow(), nPPTX, nPPTY, fZoomX, fZoomY, aProv.GetDevice()); |
150 | 0 | bool bAnyChanged = false; |
151 | 0 | for (const SCTAB& nTab : *pMarkData) |
152 | 0 | { |
153 | 0 | bool bChanged = false; |
154 | 0 | SCROW nPaintY = 0; |
155 | 0 | for (const auto& rRow : aMarkedRows) |
156 | 0 | { |
157 | 0 | SCROW nStartNo = rRow.mnStart; |
158 | 0 | SCROW nEndNo = rRow.mnEnd; |
159 | 0 | ScAddress aTopLeft(0, nStartNo, nTab); |
160 | 0 | rDoc.UpdateScriptTypes(aTopLeft, rDoc.GetSheetLimits().GetMaxColCount(), nEndNo-nStartNo+1); |
161 | 0 | if (rDoc.SetOptimalHeight(aCxt, nStartNo, nEndNo, nTab, true)) |
162 | 0 | { |
163 | 0 | if (!bChanged) |
164 | 0 | nPaintY = nStartNo; |
165 | 0 | bAnyChanged = bChanged = true; |
166 | 0 | } |
167 | 0 | } |
168 | | // tdf#76183: recalculate objects' positions |
169 | 0 | if (bChanged) |
170 | 0 | rDoc.SetDrawPageSize(nTab); |
171 | 0 | if ( bPaint && bChanged ) |
172 | 0 | pDocSh->PostPaint( 0, nPaintY, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, |
173 | 0 | PaintPartFlags::Grid | PaintPartFlags::Left ); |
174 | 0 | } |
175 | |
|
176 | 0 | if ( bPaint && bAnyChanged ) |
177 | 0 | pDocSh->UpdateOle(GetViewData()); |
178 | |
|
179 | 0 | if (comphelper::LibreOfficeKit::isActive()) |
180 | 0 | { |
181 | 0 | ScTabViewShell::notifyAllViewsSheetGeomInvalidation( |
182 | 0 | GetViewData().GetViewShell(), |
183 | 0 | bRangeWidthChanged /* bColumns */, true /* bRows */, |
184 | 0 | true /* bSizes*/, false /* bHidden */, false /* bFiltered */, |
185 | 0 | false /* bGroups */, GetViewData().GetTabNumber()); |
186 | 0 | ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), ROW_HEADER, GetViewData().GetTabNumber()); |
187 | 0 | } |
188 | |
|
189 | 0 | return bAnyChanged; |
190 | 0 | } |
191 | | |
192 | | bool ScViewFunc::AdjustRowHeight( SCROW nStartRow, SCROW nEndRow, bool bApi ) |
193 | 0 | { |
194 | 0 | if (comphelper::LibreOfficeKit::isActive()) |
195 | 0 | { |
196 | 0 | OnLOKSetWidthOrHeight(nStartRow, /*width: */ false); |
197 | 0 | } |
198 | |
|
199 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
200 | 0 | ScDocument& rDoc = pDocSh->GetDocument(); |
201 | 0 | SCTAB nTab = GetViewData().CurrentTabForData(); |
202 | 0 | double nPPTX = GetViewData().GetPPTX(); |
203 | 0 | double nPPTY = GetViewData().GetPPTY(); |
204 | 0 | double fZoomX = GetViewData().GetZoomX(); |
205 | 0 | double fZoomY = GetViewData().GetZoomY(); |
206 | 0 | sal_uInt16 nOldPixel = 0; |
207 | 0 | if (nStartRow == nEndRow) |
208 | 0 | nOldPixel = static_cast<sal_uInt16>(rDoc.GetRowHeight(nStartRow,nTab) * nPPTY); |
209 | |
|
210 | 0 | ScSizeDeviceProvider aProv(*pDocSh); |
211 | 0 | if (aProv.IsPrinter()) |
212 | 0 | { |
213 | 0 | nPPTX = aProv.GetPPTX(); |
214 | 0 | nPPTY = aProv.GetPPTY(); |
215 | 0 | fZoomX = fZoomY = 1.0; |
216 | 0 | } |
217 | 0 | sc::RowHeightContext aCxt(rDoc.MaxRow(), nPPTX, nPPTY, fZoomX, fZoomY, aProv.GetDevice()); |
218 | 0 | bool bChanged = rDoc.SetOptimalHeight(aCxt, nStartRow, nEndRow, nTab, bApi); |
219 | | |
220 | | // tdf#76183: recalculate objects' positions |
221 | 0 | if (bChanged) |
222 | 0 | rDoc.SetDrawPageSize(nTab); |
223 | |
|
224 | 0 | if (bChanged && ( nStartRow == nEndRow )) |
225 | 0 | { |
226 | 0 | sal_uInt16 nNewPixel = static_cast<sal_uInt16>(rDoc.GetRowHeight(nStartRow,nTab) * nPPTY); |
227 | 0 | if ( nNewPixel == nOldPixel ) |
228 | 0 | bChanged = false; |
229 | 0 | } |
230 | |
|
231 | 0 | if ( bChanged ) |
232 | 0 | pDocSh->PostPaint( 0, nStartRow, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, |
233 | 0 | PaintPartFlags::Grid | PaintPartFlags::Left ); |
234 | |
|
235 | 0 | if (comphelper::LibreOfficeKit::isActive()) |
236 | 0 | { |
237 | 0 | ScTabViewShell::notifyAllViewsSheetGeomInvalidation( |
238 | 0 | GetViewData().GetViewShell(), |
239 | 0 | false /* bColumns */, true /* bRows */, |
240 | 0 | true /* bSizes*/, false /* bHidden */, false /* bFiltered */, |
241 | 0 | false /* bGroups */, GetViewData().GetTabNumber()); |
242 | 0 | ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), ROW_HEADER, GetViewData().GetTabNumber()); |
243 | 0 | } |
244 | |
|
245 | 0 | return bChanged; |
246 | 0 | } |
247 | | |
248 | | namespace { |
249 | | |
250 | | enum ScAutoSum |
251 | | { |
252 | | ScAutoSumNone = 0, |
253 | | ScAutoSumData, |
254 | | ScAutoSumSum, |
255 | | ScAutoSumAverage, |
256 | | ScAutoSumMax, |
257 | | ScAutoSumMin, |
258 | | ScAutoSumCount, |
259 | | ScAutoSumCountA, |
260 | | ScAutoSumProduct, |
261 | | ScAutoSumStDev, |
262 | | ScAutoSumStDevP, |
263 | | ScAutoSumVar, |
264 | | ScAutoSumVarP, |
265 | | ScAutoSumEnd |
266 | | }; |
267 | | |
268 | | } |
269 | | |
270 | | static ScAutoSum lcl_IsAutoSumData( ScDocument& rDoc, SCCOL nCol, SCROW nRow, |
271 | | SCTAB nTab, ScDirection eDir, SCCOLROW& nExtend ) |
272 | 0 | { |
273 | 0 | ScRefCellValue aCell(rDoc, ScAddress(nCol, nRow, nTab)); |
274 | 0 | if (aCell.hasNumeric()) |
275 | 0 | { |
276 | 0 | if (aCell.getType() == CELLTYPE_FORMULA) |
277 | 0 | { |
278 | 0 | ScAutoSum val = ScAutoSumNone; |
279 | 0 | ScTokenArray* pCode = aCell.getFormula()->GetCode(); |
280 | 0 | if ( pCode ) |
281 | 0 | { |
282 | 0 | switch( pCode->GetOuterFuncOpCode() ) |
283 | 0 | { |
284 | 0 | case ocSum : val = ScAutoSumSum; |
285 | 0 | break; |
286 | 0 | case ocAverage : val = ScAutoSumAverage; |
287 | 0 | break; |
288 | 0 | case ocMax : val = ScAutoSumMax; |
289 | 0 | break; |
290 | 0 | case ocMin : val = ScAutoSumMin; |
291 | 0 | break; |
292 | 0 | case ocCount : val = ScAutoSumCount; |
293 | 0 | break; |
294 | 0 | case ocCount2 : val = ScAutoSumCountA; |
295 | 0 | break; |
296 | 0 | case ocProduct : val = ScAutoSumProduct; |
297 | 0 | break; |
298 | 0 | case ocStDev : val = ScAutoSumStDev; |
299 | 0 | break; |
300 | 0 | case ocStDevP : val = ScAutoSumStDevP; |
301 | 0 | break; |
302 | 0 | case ocVar : val = ScAutoSumVar; |
303 | 0 | break; |
304 | 0 | case ocVarP : val = ScAutoSumVarP; |
305 | 0 | break; |
306 | 0 | default : |
307 | 0 | break; |
308 | 0 | } |
309 | 0 | if ( pCode->GetAdjacentExtendOfOuterFuncRefs( nExtend, |
310 | 0 | ScAddress( nCol, nRow, nTab ), eDir ) ) |
311 | 0 | return val; |
312 | 0 | } |
313 | 0 | } |
314 | 0 | return ScAutoSumData; |
315 | 0 | } |
316 | 0 | return ScAutoSumNone; |
317 | 0 | } |
318 | | |
319 | 0 | #define SC_AUTOSUM_MAXCOUNT 20 |
320 | | |
321 | | static ScAutoSum lcl_SeekAutoSumData( ScDocument& rDoc, SCCOL& nCol, SCROW& nRow, |
322 | | SCTAB nTab, ScDirection eDir, SCCOLROW& nExtend ) |
323 | 0 | { |
324 | 0 | sal_uInt16 nCount = 0; |
325 | 0 | while (nCount < SC_AUTOSUM_MAXCOUNT) |
326 | 0 | { |
327 | 0 | if ( eDir == DIR_TOP ) |
328 | 0 | { |
329 | 0 | if (nRow > 0) |
330 | 0 | --nRow; |
331 | 0 | else |
332 | 0 | return ScAutoSumNone; |
333 | 0 | } |
334 | 0 | else |
335 | 0 | { |
336 | 0 | if (nCol > 0) |
337 | 0 | --nCol; |
338 | 0 | else |
339 | 0 | return ScAutoSumNone; |
340 | 0 | } |
341 | 0 | ScAutoSum eSum; |
342 | 0 | if ( (eSum = lcl_IsAutoSumData( |
343 | 0 | rDoc, nCol, nRow, nTab, eDir, nExtend )) != ScAutoSumNone ) |
344 | 0 | return eSum; |
345 | 0 | ++nCount; |
346 | 0 | } |
347 | 0 | return ScAutoSumNone; |
348 | 0 | } |
349 | | |
350 | | #undef SC_AUTOSUM_MAXCOUNT |
351 | | |
352 | | static bool lcl_FindNextSumEntryInColumn( ScDocument& rDoc, SCCOL nCol, SCROW& nRow, |
353 | | SCTAB nTab, SCCOLROW& nExtend, SCROW nMinRow ) |
354 | 0 | { |
355 | 0 | const SCROW nTmp = nRow; |
356 | 0 | ScAutoSum eSkip = ScAutoSumNone; |
357 | 0 | for (;;) |
358 | 0 | { |
359 | 0 | eSkip = lcl_IsAutoSumData( rDoc, nCol, nRow, nTab, DIR_TOP, nExtend ); |
360 | 0 | if (eSkip != ScAutoSumData || nRow <= nMinRow ) |
361 | 0 | break; |
362 | 0 | --nRow; |
363 | 0 | } |
364 | 0 | return eSkip >= ScAutoSumSum && nRow < nTmp; |
365 | 0 | } |
366 | | |
367 | | static bool lcl_FindNextSumEntryInRow( ScDocument& rDoc, SCCOL& nCol, SCROW nRow, |
368 | | SCTAB nTab, SCCOLROW& nExtend, SCCOL nMinCol ) |
369 | 0 | { |
370 | 0 | const SCCOL nTmp = nCol; |
371 | 0 | ScAutoSum eSkip = ScAutoSumNone; |
372 | 0 | for (;;) |
373 | 0 | { |
374 | 0 | eSkip = lcl_IsAutoSumData( rDoc, nCol, nRow, nTab, DIR_LEFT, nExtend ); |
375 | 0 | if (eSkip != ScAutoSumData || nCol <= nMinCol ) |
376 | 0 | break; |
377 | 0 | --nCol; |
378 | 0 | } |
379 | 0 | return eSkip >= ScAutoSumSum && nCol < nTmp; |
380 | 0 | } |
381 | | |
382 | | static ScAutoSum lcl_GetAutoSumForColumnRange( ScDocument& rDoc, ScRangeList& rRangeList, const ScRange& rRange ) |
383 | 0 | { |
384 | 0 | const ScAddress aStart = rRange.aStart; |
385 | 0 | const ScAddress aEnd = rRange.aEnd; |
386 | 0 | if ( aStart.Col() != aEnd.Col() ) |
387 | 0 | { |
388 | 0 | return ScAutoSumNone; |
389 | 0 | } |
390 | | |
391 | 0 | const SCTAB nTab = aEnd.Tab(); |
392 | 0 | const SCCOL nCol = aEnd.Col(); |
393 | 0 | SCROW nEndRow = aEnd.Row(); |
394 | 0 | SCROW nStartRow = nEndRow; |
395 | 0 | SCCOLROW nExtend = 0; |
396 | 0 | ScAutoSum eSum = lcl_IsAutoSumData( rDoc, nCol, nEndRow, nTab, DIR_TOP, nExtend /*out*/ ); |
397 | |
|
398 | 0 | if ( eSum >= ScAutoSumSum ) |
399 | 0 | { |
400 | 0 | bool bContinue = false; |
401 | 0 | do |
402 | 0 | { |
403 | 0 | rRangeList.push_back( ScRange( nCol, nStartRow, nTab, nCol, nEndRow, nTab ) ); |
404 | 0 | nEndRow = static_cast< SCROW >( nExtend ); |
405 | 0 | bContinue = lcl_FindNextSumEntryInColumn( rDoc, nCol, nEndRow /*inout*/, nTab, nExtend /*out*/, aStart.Row() ); |
406 | 0 | if ( bContinue ) |
407 | 0 | { |
408 | 0 | nStartRow = nEndRow; |
409 | 0 | } |
410 | 0 | } while ( bContinue ); |
411 | 0 | } |
412 | 0 | else |
413 | 0 | { |
414 | 0 | while ( nStartRow > aStart.Row() ) |
415 | 0 | { |
416 | 0 | eSum = lcl_IsAutoSumData( rDoc, nCol, nStartRow-1, nTab, DIR_TOP, nExtend /*out*/ ); |
417 | 0 | if (eSum >= ScAutoSumSum ) |
418 | 0 | break; |
419 | 0 | --nStartRow; |
420 | 0 | } |
421 | 0 | rRangeList.push_back( ScRange( nCol, nStartRow, nTab, nCol, nEndRow, nTab ) ); |
422 | 0 | if (eSum == ScAutoSumNone) |
423 | 0 | eSum = ScAutoSumData; |
424 | 0 | } |
425 | |
|
426 | 0 | return eSum; |
427 | 0 | } |
428 | | |
429 | | static ScAutoSum lcl_GetAutoSumForRowRange( ScDocument& rDoc, ScRangeList& rRangeList, const ScRange& rRange ) |
430 | 0 | { |
431 | 0 | const ScAddress aStart = rRange.aStart; |
432 | 0 | const ScAddress aEnd = rRange.aEnd; |
433 | 0 | if ( aStart.Row() != aEnd.Row() ) |
434 | 0 | { |
435 | 0 | return ScAutoSumNone; |
436 | 0 | } |
437 | | |
438 | 0 | const SCTAB nTab = aEnd.Tab(); |
439 | 0 | const SCROW nRow = aEnd.Row(); |
440 | 0 | SCCOL nEndCol = aEnd.Col(); |
441 | 0 | SCCOL nStartCol = nEndCol; |
442 | 0 | SCCOLROW nExtend = 0; |
443 | 0 | ScAutoSum eSum = lcl_IsAutoSumData( rDoc, nEndCol, nRow, nTab, DIR_LEFT, nExtend /*out*/ ); |
444 | |
|
445 | 0 | if ( eSum >= ScAutoSumSum ) |
446 | 0 | { |
447 | 0 | bool bContinue = false; |
448 | 0 | do |
449 | 0 | { |
450 | 0 | rRangeList.push_back( ScRange( nStartCol, nRow, nTab, nEndCol, nRow, nTab ) ); |
451 | 0 | nEndCol = static_cast< SCCOL >( nExtend ); |
452 | 0 | bContinue = lcl_FindNextSumEntryInRow( rDoc, nEndCol /*inout*/, nRow, nTab, nExtend /*out*/, aStart.Col() ); |
453 | 0 | if ( bContinue ) |
454 | 0 | { |
455 | 0 | nStartCol = nEndCol; |
456 | 0 | } |
457 | 0 | } while ( bContinue ); |
458 | 0 | } |
459 | 0 | else |
460 | 0 | { |
461 | 0 | while ( nStartCol > aStart.Col() ) |
462 | 0 | { |
463 | 0 | eSum = lcl_IsAutoSumData( rDoc, nStartCol-1, nRow, nTab, DIR_LEFT, nExtend /*out*/ ); |
464 | 0 | if (eSum >= ScAutoSumSum ) |
465 | 0 | break; |
466 | 0 | --nStartCol; |
467 | 0 | } |
468 | 0 | rRangeList.push_back( ScRange( nStartCol, nRow, nTab, nEndCol, nRow, nTab ) ); |
469 | 0 | if (eSum == ScAutoSumNone) |
470 | 0 | eSum = ScAutoSumData; |
471 | 0 | } |
472 | |
|
473 | 0 | return eSum; |
474 | 0 | } |
475 | | |
476 | | static sal_Int8 GetSubTotal( const OpCode eCode ) |
477 | 0 | { |
478 | 0 | sal_Int8 val; |
479 | 0 | switch ( eCode ) |
480 | 0 | { |
481 | 0 | case ocSum : val = 9; |
482 | 0 | break; |
483 | 0 | case ocAverage : val = 1; |
484 | 0 | break; |
485 | 0 | case ocMax : val = 4; |
486 | 0 | break; |
487 | 0 | case ocMin : val = 5; |
488 | 0 | break; |
489 | 0 | case ocCount : val = 2; |
490 | 0 | break; |
491 | 0 | case ocCount2 : val = 3; |
492 | 0 | break; |
493 | 0 | case ocProduct : val = 6; |
494 | 0 | break; |
495 | 0 | case ocStDev : val = 7; |
496 | 0 | break; |
497 | 0 | case ocStDevP : val = 8; |
498 | 0 | break; |
499 | 0 | case ocVar : val = 10; |
500 | 0 | break; |
501 | 0 | case ocVarP : val = 11; |
502 | 0 | break; |
503 | 0 | default : val = 9; |
504 | 0 | } |
505 | | |
506 | 0 | return val; |
507 | 0 | } |
508 | | |
509 | | bool ScViewFunc::GetAutoSumArea( ScRangeList& rRangeList ) |
510 | 0 | { |
511 | 0 | ScDocument& rDoc = GetViewData().GetDocument(); |
512 | 0 | SCTAB nTab = GetViewData().CurrentTabForData(); |
513 | |
|
514 | 0 | SCCOL nCol = GetViewData().GetCurX(); |
515 | 0 | SCROW nRow = GetViewData().GetCurY(); |
516 | |
|
517 | 0 | SCCOL nStartCol = nCol; |
518 | 0 | SCROW nStartRow = nRow; |
519 | 0 | SCCOL nEndCol = nCol; |
520 | 0 | SCROW nEndRow = nRow; |
521 | 0 | SCCOL nSeekCol = nCol; |
522 | 0 | SCROW nSeekRow = nRow; |
523 | 0 | SCCOLROW nExtend; // will become valid via reference for ScAutoSumSum |
524 | |
|
525 | 0 | bool bCol = false; |
526 | 0 | bool bRow = false; |
527 | |
|
528 | 0 | ScAutoSum eSum; |
529 | 0 | if ( nRow != 0 |
530 | 0 | && ((eSum = lcl_IsAutoSumData( rDoc, nCol, nRow-1, nTab, |
531 | 0 | DIR_TOP, nExtend /*out*/ )) == ScAutoSumData ) |
532 | 0 | && ((eSum = lcl_IsAutoSumData( rDoc, nCol, nRow-1, nTab, |
533 | 0 | DIR_LEFT, nExtend /*out*/ )) == ScAutoSumData ) |
534 | 0 | ) |
535 | 0 | { |
536 | 0 | bRow = true; |
537 | 0 | nSeekRow = nRow - 1; |
538 | 0 | } |
539 | 0 | else if ( nCol != 0 && (eSum = lcl_IsAutoSumData( rDoc, nCol-1, nRow, nTab, |
540 | 0 | DIR_LEFT, nExtend /*out*/ )) == ScAutoSumData ) |
541 | 0 | { |
542 | 0 | bCol = true; |
543 | 0 | nSeekCol = nCol - 1; |
544 | 0 | } |
545 | 0 | else if ( (eSum = lcl_SeekAutoSumData( rDoc, nCol, nSeekRow, nTab, DIR_TOP, nExtend /*out*/ )) != ScAutoSumNone ) |
546 | 0 | bRow = true; |
547 | 0 | else if (( eSum = lcl_SeekAutoSumData( rDoc, nSeekCol, nRow, nTab, DIR_LEFT, nExtend /*out*/ )) != ScAutoSumNone ) |
548 | 0 | bCol = true; |
549 | |
|
550 | 0 | if ( bCol || bRow ) |
551 | 0 | { |
552 | 0 | if ( bRow ) |
553 | 0 | { |
554 | 0 | nStartRow = nSeekRow; // nSeekRow might be adjusted via reference |
555 | 0 | if ( eSum >= ScAutoSumSum && eSum < ScAutoSumEnd ) |
556 | 0 | nEndRow = nStartRow; // only sum sums |
557 | 0 | else |
558 | 0 | nEndRow = nRow - 1; // maybe extend data area at bottom |
559 | 0 | } |
560 | 0 | else |
561 | 0 | { |
562 | 0 | nStartCol = nSeekCol; // nSeekCol might be adjusted via reference |
563 | 0 | if ( eSum >= ScAutoSumSum ) |
564 | 0 | nEndCol = nStartCol; // only sum sums |
565 | 0 | else |
566 | 0 | nEndCol = nCol - 1; // maybe extend data area to the right |
567 | 0 | } |
568 | 0 | bool bContinue = false; |
569 | 0 | do |
570 | 0 | { |
571 | 0 | if ( eSum == ScAutoSumData ) |
572 | 0 | { |
573 | 0 | if ( bRow ) |
574 | 0 | { |
575 | 0 | while ( nStartRow != 0 && lcl_IsAutoSumData( rDoc, nCol, |
576 | 0 | nStartRow-1, nTab, DIR_TOP, nExtend /*out*/ ) == eSum ) |
577 | 0 | --nStartRow; |
578 | 0 | } |
579 | 0 | else |
580 | 0 | { |
581 | 0 | while ( nStartCol != 0 && lcl_IsAutoSumData( rDoc, nStartCol-1, |
582 | 0 | nRow, nTab, DIR_LEFT, nExtend /*out*/ ) == eSum ) |
583 | 0 | --nStartCol; |
584 | 0 | } |
585 | 0 | } |
586 | 0 | rRangeList.push_back( |
587 | 0 | ScRange( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab ) ); |
588 | 0 | if ( eSum >= ScAutoSumSum ) |
589 | 0 | { |
590 | 0 | if ( bRow ) |
591 | 0 | { |
592 | 0 | nEndRow = static_cast< SCROW >( nExtend ); |
593 | 0 | bContinue = lcl_FindNextSumEntryInColumn( rDoc, nCol, nEndRow /*inout*/, nTab, nExtend /*out*/, 0 ); |
594 | 0 | if ( bContinue ) |
595 | 0 | { |
596 | 0 | nStartRow = nEndRow; |
597 | 0 | } |
598 | 0 | } |
599 | 0 | else |
600 | 0 | { |
601 | 0 | nEndCol = static_cast< SCCOL >( nExtend ); |
602 | 0 | bContinue = lcl_FindNextSumEntryInRow( rDoc, nEndCol /*inout*/, nRow, nTab, nExtend /*out*/, 0 ); |
603 | 0 | if ( bContinue ) |
604 | 0 | { |
605 | 0 | nStartCol = nEndCol; |
606 | 0 | } |
607 | 0 | } |
608 | 0 | } |
609 | 0 | } while ( bContinue ); |
610 | 0 | return true; |
611 | 0 | } |
612 | 0 | return false; |
613 | 0 | } |
614 | | |
615 | | void ScViewFunc::EnterAutoSum(const ScRangeList& rRangeList, bool bSubTotal, const ScAddress& rAddr, const OpCode eCode) |
616 | 0 | { |
617 | 0 | OUString aFormula = GetAutoSumFormula( rRangeList, bSubTotal, rAddr , eCode); |
618 | 0 | EnterBlock( aFormula, nullptr ); |
619 | 0 | } |
620 | | |
621 | | bool ScViewFunc::AutoSum( const ScRange& rRange, bool bSubTotal, bool bSetCursor, bool bContinue , const OpCode eCode) |
622 | 0 | { |
623 | 0 | ScDocument& rDoc = GetViewData().GetDocument(); |
624 | 0 | const SCTAB nTab = rRange.aStart.Tab(); |
625 | 0 | SCCOL nStartCol = rRange.aStart.Col(); |
626 | 0 | SCROW nStartRow = rRange.aStart.Row(); |
627 | 0 | const SCCOL nEndCol = rRange.aEnd.Col(); |
628 | 0 | const SCROW nEndRow = rRange.aEnd.Row(); |
629 | 0 | SCCOLROW nExtend = 0; // out parameter for lcl_IsAutoSumData |
630 | | |
631 | | // ignore rows at the top of the given range which don't contain autosum data |
632 | 0 | bool bRowData = false; |
633 | 0 | for ( SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow ) |
634 | 0 | { |
635 | 0 | for ( SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol ) |
636 | 0 | { |
637 | 0 | if ( lcl_IsAutoSumData( rDoc, nCol, nRow, nTab, DIR_TOP, nExtend ) != ScAutoSumNone ) |
638 | 0 | { |
639 | 0 | bRowData = true; |
640 | 0 | break; |
641 | 0 | } |
642 | 0 | } |
643 | 0 | if ( bRowData ) |
644 | 0 | { |
645 | 0 | nStartRow = nRow; |
646 | 0 | break; |
647 | 0 | } |
648 | 0 | } |
649 | 0 | if ( !bRowData ) |
650 | 0 | { |
651 | 0 | return false; |
652 | 0 | } |
653 | | |
654 | | // ignore columns at the left of the given range which don't contain autosum data |
655 | 0 | bool bColData = false; |
656 | 0 | for ( SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol ) |
657 | 0 | { |
658 | 0 | for ( SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow ) |
659 | 0 | { |
660 | 0 | if ( lcl_IsAutoSumData( rDoc, nCol, nRow, nTab, DIR_LEFT, nExtend ) != ScAutoSumNone ) |
661 | 0 | { |
662 | 0 | bColData = true; |
663 | 0 | break; |
664 | 0 | } |
665 | 0 | } |
666 | 0 | if ( bColData ) |
667 | 0 | { |
668 | 0 | nStartCol = nCol; |
669 | 0 | break; |
670 | 0 | } |
671 | 0 | } |
672 | 0 | if ( !bColData ) |
673 | 0 | { |
674 | 0 | return false; |
675 | 0 | } |
676 | | |
677 | 0 | const bool bEndRowEmpty = rDoc.IsBlockEmpty( nStartCol, nEndRow, nEndCol, nEndRow, nTab ); |
678 | 0 | const bool bEndColEmpty = rDoc.IsBlockEmpty( nEndCol, nStartRow, nEndCol, nEndRow, nTab ); |
679 | 0 | bool bRow = ( nStartRow != nEndRow ) && ( bEndRowEmpty || !bEndColEmpty ); |
680 | 0 | bool bCol = ( nStartCol != nEndCol ) && ( bEndColEmpty || nStartRow == nEndRow ); |
681 | | |
682 | | // find an empty row for entering the result |
683 | 0 | SCROW nInsRow = nEndRow; |
684 | 0 | if ( bRow && !bEndRowEmpty ) |
685 | 0 | { |
686 | 0 | if ( nInsRow < rDoc.MaxRow() ) |
687 | 0 | { |
688 | 0 | ++nInsRow; |
689 | 0 | while ( !rDoc.IsBlockEmpty( nStartCol, nInsRow, nEndCol, nInsRow, nTab ) ) |
690 | 0 | { |
691 | 0 | if ( nInsRow < rDoc.MaxRow() ) |
692 | 0 | { |
693 | 0 | ++nInsRow; |
694 | 0 | } |
695 | 0 | else |
696 | 0 | { |
697 | 0 | bRow = false; |
698 | 0 | break; |
699 | 0 | } |
700 | 0 | } |
701 | 0 | } |
702 | 0 | else |
703 | 0 | { |
704 | 0 | bRow = false; |
705 | 0 | } |
706 | 0 | } |
707 | | |
708 | | // find an empty column for entering the result |
709 | 0 | SCCOL nInsCol = nEndCol; |
710 | 0 | if ( bCol && !bEndColEmpty ) |
711 | 0 | { |
712 | 0 | if ( nInsCol < rDoc.MaxCol() ) |
713 | 0 | { |
714 | 0 | ++nInsCol; |
715 | 0 | while ( !rDoc.IsBlockEmpty( nInsCol, nStartRow, nInsCol, nEndRow, nTab ) ) |
716 | 0 | { |
717 | 0 | if ( nInsCol < rDoc.MaxCol() ) |
718 | 0 | { |
719 | 0 | ++nInsCol; |
720 | 0 | } |
721 | 0 | else |
722 | 0 | { |
723 | 0 | bCol = false; |
724 | 0 | break; |
725 | 0 | } |
726 | 0 | } |
727 | 0 | } |
728 | 0 | else |
729 | 0 | { |
730 | 0 | bCol = false; |
731 | 0 | } |
732 | 0 | } |
733 | |
|
734 | 0 | if ( !bRow && !bCol ) |
735 | 0 | { |
736 | 0 | return false; |
737 | 0 | } |
738 | | |
739 | 0 | SCCOL nMarkEndCol = nEndCol; |
740 | 0 | SCROW nMarkEndRow = nEndRow; |
741 | 0 | ScAutoSum eSum = ScAutoSumNone; |
742 | 0 | SCROW nColSums = 0; |
743 | 0 | SCCOL nRowSums = 0; |
744 | 0 | SCROW nColSumsStartRow = 0; |
745 | 0 | SCCOL nRowSumsStartCol = 0; |
746 | |
|
747 | 0 | if ( bRow ) |
748 | 0 | { |
749 | | // calculate the row sums for all columns of the given range |
750 | |
|
751 | 0 | SCROW nSumEndRow = nEndRow; |
752 | |
|
753 | 0 | if ( bEndRowEmpty ) |
754 | 0 | { |
755 | | // the last row of the given range is empty; |
756 | | // don't take into account for calculating the autosum |
757 | 0 | --nSumEndRow; |
758 | 0 | } |
759 | 0 | else |
760 | 0 | { |
761 | | // increase mark range |
762 | 0 | ++nMarkEndRow; |
763 | 0 | } |
764 | |
|
765 | 0 | for ( SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol ) |
766 | 0 | { |
767 | 0 | if ( !rDoc.IsBlockEmpty( nCol, nStartRow, nCol, nSumEndRow, nTab ) ) |
768 | 0 | { |
769 | 0 | ScRangeList aRangeList; |
770 | | // Include the originally selected start row. |
771 | 0 | const ScRange aRange( nCol, rRange.aStart.Row(), nTab, nCol, nSumEndRow, nTab ); |
772 | 0 | if ( (eSum = lcl_GetAutoSumForColumnRange( rDoc, aRangeList, aRange )) != ScAutoSumNone ) |
773 | 0 | { |
774 | 0 | if (++nRowSums == 1) |
775 | 0 | nRowSumsStartCol = aRangeList[0].aStart.Col(); |
776 | 0 | const OUString aFormula = GetAutoSumFormula( |
777 | 0 | aRangeList, bSubTotal, ScAddress(nCol, nInsRow, nTab), eCode); |
778 | 0 | EnterData( nCol, nInsRow, nTab, aFormula ); |
779 | 0 | } |
780 | 0 | } |
781 | 0 | } |
782 | 0 | } |
783 | |
|
784 | 0 | if ( bCol ) |
785 | 0 | { |
786 | | // calculate the column sums for all rows of the given range |
787 | |
|
788 | 0 | SCCOL nSumEndCol = nEndCol; |
789 | |
|
790 | 0 | if ( bEndColEmpty ) |
791 | 0 | { |
792 | | // the last column of the given range is empty; |
793 | | // don't take into account for calculating the autosum |
794 | 0 | --nSumEndCol; |
795 | 0 | } |
796 | 0 | else |
797 | 0 | { |
798 | | // increase mark range |
799 | 0 | ++nMarkEndCol; |
800 | 0 | } |
801 | |
|
802 | 0 | for ( SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow ) |
803 | 0 | { |
804 | 0 | if ( !rDoc.IsBlockEmpty( nStartCol, nRow, nSumEndCol, nRow, nTab ) ) |
805 | 0 | { |
806 | 0 | ScRangeList aRangeList; |
807 | | // Include the originally selected start column. |
808 | 0 | const ScRange aRange( rRange.aStart.Col(), nRow, nTab, nSumEndCol, nRow, nTab ); |
809 | 0 | if ( (eSum = lcl_GetAutoSumForRowRange( rDoc, aRangeList, aRange )) != ScAutoSumNone ) |
810 | 0 | { |
811 | 0 | if (++nColSums == 1) |
812 | 0 | nColSumsStartRow = aRangeList[0].aStart.Row(); |
813 | 0 | const OUString aFormula = GetAutoSumFormula( aRangeList, bSubTotal, ScAddress(nInsCol, nRow, nTab), eCode ); |
814 | 0 | EnterData( nInsCol, nRow, nTab, aFormula ); |
815 | 0 | } |
816 | 0 | } |
817 | 0 | } |
818 | 0 | } |
819 | | |
820 | | // Set new mark range and cursor position. |
821 | | // For sum of sums (and data until sum) mark the actual resulting range if |
822 | | // there is only one, or the data range if more than one. Otherwise use the |
823 | | // original selection. All extended by end column/row where the sum is put. |
824 | 0 | const ScRange aMarkRange( |
825 | 0 | (eSum >= ScAutoSumSum ? |
826 | 0 | (nRowSums == 1 ? nRowSumsStartCol : nStartCol) : |
827 | 0 | rRange.aStart.Col()), |
828 | 0 | (eSum >= ScAutoSumSum ? |
829 | 0 | (nColSums == 1 ? nColSumsStartRow : nStartRow) : |
830 | 0 | rRange.aStart.Row()), |
831 | 0 | nTab, nMarkEndCol, nMarkEndRow, nTab ); |
832 | 0 | MarkRange( aMarkRange, false, bContinue ); |
833 | 0 | if ( bSetCursor ) |
834 | 0 | { |
835 | 0 | SetCursor( nMarkEndCol, nMarkEndRow ); |
836 | 0 | } |
837 | |
|
838 | 0 | return true; |
839 | 0 | } |
840 | | |
841 | | OUString ScViewFunc::GetAutoSumFormula( const ScRangeList& rRangeList, bool bSubTotal, const ScAddress& rAddr , const OpCode eCode) |
842 | 0 | { |
843 | 0 | ScViewData& rViewData = GetViewData(); |
844 | 0 | ScDocument& rDoc = rViewData.GetDocument(); |
845 | 0 | ScTokenArray aArray(rDoc); |
846 | |
|
847 | 0 | aArray.AddOpCode(bSubTotal ? ocSubTotal : eCode); |
848 | 0 | aArray.AddOpCode(ocOpen); |
849 | |
|
850 | 0 | if (bSubTotal) |
851 | 0 | { |
852 | 0 | aArray.AddDouble( GetSubTotal( eCode ) ); |
853 | 0 | aArray.AddOpCode(ocSep); |
854 | 0 | } |
855 | |
|
856 | 0 | if(!rRangeList.empty()) |
857 | 0 | { |
858 | 0 | size_t ListSize = rRangeList.size(); |
859 | 0 | for ( size_t i = 0; i < ListSize; ++i ) |
860 | 0 | { |
861 | 0 | const ScRange & r = rRangeList[i]; |
862 | 0 | if (i != 0) |
863 | 0 | aArray.AddOpCode(ocSep); |
864 | 0 | ScComplexRefData aRef; |
865 | 0 | aRef.InitRangeRel(rDoc, r, rAddr); |
866 | 0 | aArray.AddDoubleReference(aRef); |
867 | 0 | } |
868 | 0 | } |
869 | |
|
870 | 0 | aArray.AddOpCode(ocClose); |
871 | |
|
872 | 0 | ScCompiler aComp(rDoc, rAddr, aArray, rDoc.GetGrammar()); |
873 | 0 | OUStringBuffer aBuf; |
874 | 0 | aComp.CreateStringFromTokenArray(aBuf); |
875 | 0 | aBuf.insert(0, "="); |
876 | 0 | return aBuf.makeStringAndClear(); |
877 | 0 | } |
878 | | |
879 | | void ScViewFunc::EnterBlock( const OUString& rString, const EditTextObject* pData ) |
880 | 0 | { |
881 | | // test for multi selection |
882 | |
|
883 | 0 | SCCOL nCol = GetViewData().GetCurX(); |
884 | 0 | SCROW nRow = GetViewData().GetCurY(); |
885 | 0 | SCTAB nTab = GetViewData().CurrentTabForData(); |
886 | 0 | ScMarkData& rMark = GetViewData().GetMarkData(); |
887 | 0 | if ( rMark.IsMultiMarked() ) |
888 | 0 | { |
889 | 0 | rMark.MarkToSimple(); |
890 | 0 | if ( rMark.IsMultiMarked() ) |
891 | 0 | { // "Insert into multi selection not possible" |
892 | 0 | ErrorMessage(STR_MSSG_PASTEFROMCLIP_0); |
893 | | |
894 | | // insert into single cell |
895 | 0 | if ( pData ) |
896 | 0 | EnterData(nCol, nRow, nTab, *pData); |
897 | 0 | else |
898 | 0 | EnterData( nCol, nRow, nTab, rString ); |
899 | 0 | return; |
900 | 0 | } |
901 | 0 | } |
902 | | |
903 | 0 | if (GetViewData().SelectionForbidsCellFill()) |
904 | 0 | { |
905 | 0 | PaintArea(nCol, nRow, nCol, nRow); // possibly the edit-engine is still painted there |
906 | 0 | return; |
907 | 0 | } |
908 | | |
909 | 0 | ScDocument& rDoc = GetViewData().GetDocument(); |
910 | 0 | OUString aNewStr = rString; |
911 | 0 | if ( pData ) |
912 | 0 | { |
913 | 0 | const ScPatternAttr* pOldPattern = rDoc.GetPattern( nCol, nRow, nTab ); |
914 | 0 | ScTabEditEngine aEngine( *pOldPattern, rDoc.GetEditEnginePool(), rDoc ); |
915 | 0 | aEngine.SetTextCurrentDefaults(*pData); |
916 | |
|
917 | 0 | ScEditAttrTester aTester( &aEngine ); |
918 | 0 | if (!aTester.NeedsObject()) |
919 | 0 | { |
920 | 0 | aNewStr = aEngine.GetText(); |
921 | 0 | pData = nullptr; |
922 | 0 | } |
923 | 0 | } |
924 | | |
925 | | // Insert via PasteFromClip |
926 | 0 | weld::WaitObject aWait(GetViewData().GetDialogParent()); |
927 | |
|
928 | 0 | ScAddress aPos( nCol, nRow, nTab ); |
929 | |
|
930 | 0 | ScDocumentUniquePtr pInsDoc(new ScDocument( SCDOCMODE_CLIP )); |
931 | 0 | pInsDoc->ResetClip( &rDoc, nTab ); |
932 | |
|
933 | 0 | if (aNewStr[0] == '=') // Formula ? |
934 | 0 | { |
935 | | // SetString not possible, because in Clipboard-Documents nothing will be compiled! |
936 | 0 | pInsDoc->SetFormulaCell(aPos, new ScFormulaCell(rDoc, aPos, aNewStr)); |
937 | 0 | } |
938 | 0 | else if ( pData ) |
939 | 0 | { |
940 | | // A copy of pData will be stored. |
941 | 0 | pInsDoc->SetEditText(aPos, *pData, rDoc.GetEditEnginePool()); |
942 | 0 | } |
943 | 0 | else |
944 | 0 | pInsDoc->SetString( nCol, nRow, nTab, aNewStr ); |
945 | |
|
946 | 0 | pInsDoc->SetClipArea( ScRange(aPos) ); |
947 | | // insert Block, with Undo etc. |
948 | 0 | if ( !PasteFromClip( InsertDeleteFlags::CONTENTS, pInsDoc.get(), ScPasteFunc::NONE, false, false, |
949 | 0 | false, INS_NONE, InsertDeleteFlags::ATTRIB ) ) |
950 | 0 | return; |
951 | | |
952 | 0 | const SfxUInt32Item& rItem = pInsDoc->GetAttr(nCol, nRow, nTab, ATTR_VALUE_FORMAT); |
953 | | // set number format if incompatible |
954 | | // MarkData was already MarkToSimple'ed in PasteFromClip |
955 | 0 | const ScRange& aRange = rMark.GetMarkArea(); |
956 | 0 | ScPatternAttr aPattern(rDoc.getCellAttributeHelper()); |
957 | 0 | aPattern.ItemSetPut(rItem); |
958 | 0 | SvNumFormatType nNewType = rDoc.GetFormatTable()->GetType(rItem.GetValue()); |
959 | 0 | rDoc.ApplyPatternIfNumberformatIncompatible( aRange, rMark, |
960 | 0 | aPattern, nNewType ); |
961 | 0 | } |
962 | | |
963 | | // manual page break |
964 | | |
965 | | void ScViewFunc::InsertPageBreak( bool bColumn, bool bRecord, const ScAddress* pPos, |
966 | | bool bSetModified ) |
967 | 0 | { |
968 | 0 | SCTAB nTab = GetViewData().CurrentTabForData(); |
969 | 0 | ScAddress aCursor; |
970 | 0 | if (pPos) |
971 | 0 | aCursor = *pPos; |
972 | 0 | else |
973 | 0 | aCursor = ScAddress( GetViewData().GetCurX(), GetViewData().GetCurY(), nTab ); |
974 | |
|
975 | 0 | bool bSuccess = GetViewData().GetDocShell()->GetDocFunc(). |
976 | 0 | InsertPageBreak( bColumn, aCursor, bRecord, bSetModified ); |
977 | |
|
978 | 0 | if ( bSuccess && bSetModified ) |
979 | 0 | UpdatePageBreakData( true ); // for PageBreak-Mode |
980 | 0 | } |
981 | | |
982 | | void ScViewFunc::DeletePageBreak( bool bColumn, bool bRecord, const ScAddress* pPos, |
983 | | bool bSetModified ) |
984 | 0 | { |
985 | 0 | SCTAB nTab = GetViewData().CurrentTabForData(); |
986 | 0 | ScAddress aCursor; |
987 | 0 | if (pPos) |
988 | 0 | aCursor = *pPos; |
989 | 0 | else |
990 | 0 | aCursor = ScAddress( GetViewData().GetCurX(), GetViewData().GetCurY(), nTab ); |
991 | |
|
992 | 0 | bool bSuccess = GetViewData().GetDocShell()->GetDocFunc(). |
993 | 0 | RemovePageBreak( bColumn, aCursor, bRecord, bSetModified ); |
994 | |
|
995 | 0 | if ( bSuccess && bSetModified ) |
996 | 0 | UpdatePageBreakData( true ); // for PageBreak-Mode |
997 | 0 | } |
998 | | |
999 | | void ScViewFunc::RemoveManualBreaks() |
1000 | 0 | { |
1001 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
1002 | 0 | ScDocument& rDoc = pDocSh->GetDocument(); |
1003 | 0 | SCTAB nTab = GetViewData().CurrentTabForData(); |
1004 | 0 | bool bUndo(rDoc.IsUndoEnabled()); |
1005 | |
|
1006 | 0 | if (bUndo) |
1007 | 0 | { |
1008 | 0 | ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO )); |
1009 | 0 | pUndoDoc->InitUndo( rDoc, nTab, nTab, true, true ); |
1010 | 0 | rDoc.CopyToDocument( 0,0,nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, *pUndoDoc ); |
1011 | 0 | pDocSh->GetUndoManager()->AddUndoAction( |
1012 | 0 | std::make_unique<ScUndoRemoveBreaks>( *pDocSh, nTab, std::move(pUndoDoc) ) ); |
1013 | 0 | } |
1014 | |
|
1015 | 0 | rDoc.RemoveManualBreaks(nTab); |
1016 | 0 | rDoc.UpdatePageBreaks(nTab); |
1017 | |
|
1018 | 0 | UpdatePageBreakData( true ); |
1019 | 0 | pDocSh->SetDocumentModified(); |
1020 | 0 | pDocSh->PostPaint( 0,0,nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, PaintPartFlags::Grid ); |
1021 | 0 | } |
1022 | | |
1023 | | void ScViewFunc::SetPrintZoom(sal_uInt16 nScale) |
1024 | 0 | { |
1025 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
1026 | 0 | SCTAB nTab = GetViewData().CurrentTabForData(); |
1027 | 0 | pDocSh->SetPrintZoom( nTab, nScale, 0/*nPages*/ ); |
1028 | 0 | } |
1029 | | |
1030 | | void ScViewFunc::AdjustPrintZoom() |
1031 | 0 | { |
1032 | 0 | ScRange aRange; |
1033 | 0 | if ( GetViewData().GetSimpleArea( aRange ) != SC_MARK_SIMPLE ) |
1034 | 0 | aRange = GetViewData().GetMarkData().GetMultiMarkArea(); |
1035 | 0 | GetViewData().GetDocShell()->AdjustPrintZoom( aRange ); |
1036 | 0 | } |
1037 | | |
1038 | | void ScViewFunc::SetPrintRanges( bool bEntireSheet, const OUString* pPrint, |
1039 | | const OUString* pRepCol, const OUString* pRepRow, |
1040 | | bool bAddPrint ) |
1041 | 0 | { |
1042 | | // on all selected tables |
1043 | |
|
1044 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
1045 | 0 | ScDocument& rDoc = pDocSh->GetDocument(); |
1046 | 0 | ScMarkData& rMark = GetViewData().GetMarkData(); |
1047 | 0 | bool bUndo (rDoc.IsUndoEnabled()); |
1048 | |
|
1049 | 0 | std::unique_ptr<ScPrintRangeSaver> pOldRanges = rDoc.CreatePrintRangeSaver(); |
1050 | |
|
1051 | 0 | ScAddress::Details aDetails(rDoc.GetAddressConvention(), 0, 0); |
1052 | |
|
1053 | 0 | for (const SCTAB& nTab : rMark) |
1054 | 0 | { |
1055 | 0 | ScRange aRange( 0,0,nTab ); |
1056 | | |
1057 | | // print ranges |
1058 | |
|
1059 | 0 | if( !bAddPrint ) |
1060 | 0 | { |
1061 | 0 | rDoc.ClearPrintRanges( nTab ); |
1062 | 0 | rDoc.ClearPrintNamedRanges(nTab); |
1063 | 0 | } |
1064 | |
|
1065 | 0 | if( bEntireSheet ) |
1066 | 0 | { |
1067 | 0 | rDoc.SetPrintEntireSheet( nTab ); |
1068 | 0 | } |
1069 | 0 | else if ( pPrint ) |
1070 | 0 | { |
1071 | 0 | if ( !pPrint->isEmpty() ) |
1072 | 0 | { |
1073 | 0 | const sal_Unicode sep = ScCompiler::GetNativeSymbolChar(ocSep); |
1074 | 0 | sal_Int32 nPos = 0; |
1075 | 0 | do |
1076 | 0 | { |
1077 | 0 | const OUString aToken = pPrint->getToken(0, sep, nPos); |
1078 | 0 | if ( aRange.ParseAny( aToken, rDoc, aDetails ) & ScRefFlags::VALID ) |
1079 | 0 | rDoc.AddPrintRange( nTab, aRange ); |
1080 | 0 | } |
1081 | 0 | while (nPos >= 0); |
1082 | 0 | } |
1083 | 0 | } |
1084 | 0 | else // NULL = use selection (print range is always set), use empty string to delete all ranges |
1085 | 0 | { |
1086 | 0 | if ( GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE ) |
1087 | 0 | { |
1088 | 0 | rDoc.AddPrintRange( nTab, aRange ); |
1089 | 0 | } |
1090 | 0 | else if ( rMark.IsMultiMarked() ) |
1091 | 0 | { |
1092 | 0 | rMark.MarkToMulti(); |
1093 | 0 | ScRangeListRef pList( new ScRangeList ); |
1094 | 0 | rMark.FillRangeListWithMarks( pList.get(), false ); |
1095 | 0 | for (size_t i = 0, n = pList->size(); i < n; ++i) |
1096 | 0 | { |
1097 | 0 | const ScRange & rR = (*pList)[i]; |
1098 | 0 | rDoc.AddPrintRange(nTab, rR); |
1099 | 0 | } |
1100 | 0 | } |
1101 | 0 | } |
1102 | | |
1103 | | // repeat columns |
1104 | |
|
1105 | 0 | if ( pRepCol ) |
1106 | 0 | { |
1107 | 0 | if ( pRepCol->isEmpty() ) |
1108 | 0 | rDoc.SetRepeatColRange( nTab, std::nullopt ); |
1109 | 0 | else |
1110 | 0 | if ( aRange.ParseAny( *pRepCol, rDoc, aDetails ) & ScRefFlags::VALID ) |
1111 | 0 | rDoc.SetRepeatColRange( nTab, std::move(aRange) ); |
1112 | 0 | } |
1113 | | |
1114 | | // repeat rows |
1115 | |
|
1116 | 0 | if ( pRepRow ) |
1117 | 0 | { |
1118 | 0 | if ( pRepRow->isEmpty() ) |
1119 | 0 | rDoc.SetRepeatRowRange( nTab, std::nullopt ); |
1120 | 0 | else |
1121 | 0 | if ( aRange.ParseAny( *pRepRow, rDoc, aDetails ) & ScRefFlags::VALID ) |
1122 | 0 | rDoc.SetRepeatRowRange( nTab, std::move(aRange) ); |
1123 | 0 | } |
1124 | 0 | } |
1125 | | |
1126 | | // undo (for all tables) |
1127 | 0 | if (bUndo) |
1128 | 0 | { |
1129 | 0 | SCTAB nCurTab = GetViewData().CurrentTabForData(); |
1130 | 0 | std::unique_ptr<ScPrintRangeSaver> pNewRanges = rDoc.CreatePrintRangeSaver(); |
1131 | 0 | if (comphelper::LibreOfficeKit::isActive()) |
1132 | 0 | { |
1133 | 0 | tools::JsonWriter aJsonWriter; |
1134 | 0 | pNewRanges->GetPrintRangesInfo(aJsonWriter); |
1135 | |
|
1136 | 0 | SfxViewShell* pViewShell = GetViewData().GetViewShell(); |
1137 | 0 | const OString message = aJsonWriter.finishAndGetAsOString(); |
1138 | 0 | pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_PRINT_RANGES, message); |
1139 | 0 | } |
1140 | |
|
1141 | 0 | pDocSh->GetUndoManager()->AddUndoAction( |
1142 | 0 | std::make_unique<ScUndoPrintRange>( *pDocSh, nCurTab, std::move(pOldRanges), std::move(pNewRanges) ) ); |
1143 | 0 | } |
1144 | 0 | else |
1145 | 0 | pOldRanges.reset(); |
1146 | | |
1147 | | // update page breaks |
1148 | |
|
1149 | 0 | for (const auto& rTab : rMark) |
1150 | 0 | ScPrintFunc( *pDocSh, pDocSh->GetPrinter(), rTab ).UpdatePages(); |
1151 | |
|
1152 | 0 | SfxBindings& rBindings = GetViewData().GetBindings(); |
1153 | 0 | rBindings.Invalidate( SID_DELETE_PRINTAREA ); |
1154 | |
|
1155 | 0 | pDocSh->SetDocumentModified(); |
1156 | 0 | } |
1157 | | |
1158 | | // Merge cells |
1159 | | |
1160 | | bool ScViewFunc::TestMergeCells() // pre-test (for menu) |
1161 | 0 | { |
1162 | | // simple test: true if there's a selection but no multi selection and not filtered |
1163 | |
|
1164 | 0 | const ScMarkData& rMark = GetViewData().GetMarkData(); |
1165 | 0 | if ( rMark.IsMarked() || rMark.IsMultiMarked() ) |
1166 | 0 | { |
1167 | 0 | ScRange aRange; |
1168 | 0 | bool bMergeable = ( GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE ); |
1169 | 0 | bMergeable = bMergeable && ( aRange.aStart.Col() != aRange.aEnd.Col() || |
1170 | 0 | aRange.aStart.Row() != aRange.aEnd.Row() ); |
1171 | 0 | return bMergeable; |
1172 | 0 | } |
1173 | 0 | else |
1174 | 0 | return false; |
1175 | 0 | } |
1176 | | |
1177 | | void ScViewFunc::MergeCells( bool bApi, bool bDoContents, bool bCenter, |
1178 | | const sal_uInt16 nSlot ) |
1179 | 0 | { |
1180 | | // Editable- and Being-Nested- test must be at the beginning (in DocFunc too), |
1181 | | // so that the Contents-QueryBox won't appear |
1182 | 0 | ScEditableTester aTester = ScEditableTester::CreateAndTestView(this); |
1183 | 0 | if (!aTester.IsEditable()) |
1184 | 0 | { |
1185 | 0 | ErrorMessage(aTester.GetMessageId()); |
1186 | 0 | return; |
1187 | 0 | } |
1188 | | |
1189 | 0 | ScMarkData& rMark = GetViewData().GetMarkData(); |
1190 | 0 | rMark.MarkToSimple(); |
1191 | 0 | if (!rMark.IsMarked()) |
1192 | 0 | { |
1193 | 0 | ErrorMessage(STR_NOMULTISELECT); |
1194 | 0 | return; |
1195 | 0 | } |
1196 | | |
1197 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
1198 | 0 | ScDocument& rDoc = pDocSh->GetDocument(); |
1199 | |
|
1200 | 0 | const ScRange& aMarkRange = rMark.GetMarkArea(); |
1201 | 0 | SCCOL nStartCol = aMarkRange.aStart.Col(); |
1202 | 0 | SCROW nStartRow = aMarkRange.aStart.Row(); |
1203 | 0 | SCTAB nStartTab = aMarkRange.aStart.Tab(); |
1204 | 0 | SCCOL nEndCol = aMarkRange.aEnd.Col(); |
1205 | 0 | SCROW nEndRow = aMarkRange.aEnd.Row(); |
1206 | 0 | SCTAB nEndTab = aMarkRange.aEnd.Tab(); |
1207 | 0 | if ( nStartCol == nEndCol && nStartRow == nEndRow ) |
1208 | 0 | { |
1209 | | // nothing to do |
1210 | 0 | return; |
1211 | 0 | } |
1212 | | |
1213 | 0 | if ( rDoc.HasAttrib( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab, |
1214 | 0 | HasAttrFlags::Merged | HasAttrFlags::Overlapped ) ) |
1215 | 0 | { // "Don't nest merging !" |
1216 | 0 | ErrorMessage(STR_MSSG_MERGECELLS_0); |
1217 | 0 | return; |
1218 | 0 | } |
1219 | | |
1220 | | // Check for the contents of all selected tables. |
1221 | 0 | bool bAskDialog = false; |
1222 | 0 | ScCellMergeOption aMergeOption(nStartCol, nStartRow, nEndCol, nEndRow, bCenter); |
1223 | 0 | for (const SCTAB& i : rMark) |
1224 | 0 | { |
1225 | 0 | aMergeOption.maTabs.insert(i); |
1226 | |
|
1227 | 0 | sc::MultiDataCellState aState = rDoc.HasMultipleDataCells(aMergeOption.getSingleRange(i)); |
1228 | 0 | switch (aState.meState) |
1229 | 0 | { |
1230 | 0 | case sc::MultiDataCellState::HasMultipleCells: |
1231 | 0 | { |
1232 | | // this range contains multiple data cells. |
1233 | 0 | bAskDialog = true; |
1234 | 0 | break; |
1235 | 0 | } |
1236 | 0 | case sc::MultiDataCellState::HasOneCell: |
1237 | 0 | { |
1238 | | // this range contains only one data cell. |
1239 | 0 | if (nStartCol != aState.mnCol1 || nStartRow != aState.mnRow1) |
1240 | 0 | bDoContents = true; // move the value to the top-left. |
1241 | 0 | break; |
1242 | 0 | } |
1243 | 0 | default: |
1244 | 0 | ; |
1245 | 0 | } |
1246 | 0 | } |
1247 | | |
1248 | 0 | bool bEmptyMergedCells = officecfg::Office::Calc::Compatibility::MergeCells::EmptyMergedCells::get(); |
1249 | |
|
1250 | 0 | auto doMerge = [this, pDocSh, aMergeOption=std::move(aMergeOption), |
1251 | 0 | bApi, nStartCol, nStartRow, aMarkRange] |
1252 | 0 | (bool bNowDoContents, bool bNowEmptyMergedCells) |
1253 | 0 | { |
1254 | 0 | if (pDocSh->GetDocFunc().MergeCells(aMergeOption, bNowDoContents, true/*bRecord*/, |
1255 | 0 | bApi, bNowEmptyMergedCells)) |
1256 | 0 | { |
1257 | 0 | SetCursor( nStartCol, nStartRow ); |
1258 | | // DoneBlockMode( sal_False); |
1259 | 0 | Unmark(); |
1260 | |
|
1261 | 0 | pDocSh->UpdateOle(GetViewData()); |
1262 | 0 | UpdateInputLine(); |
1263 | |
|
1264 | 0 | OUString aStartAddress = aMarkRange.aStart.GetColRowString(); |
1265 | 0 | OUString aEndAddress = aMarkRange.aEnd.GetColRowString(); |
1266 | |
|
1267 | 0 | collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}, u"MERGE_CELLS"_ustr); |
1268 | 0 | } |
1269 | 0 | }; |
1270 | |
|
1271 | 0 | if (bAskDialog) |
1272 | 0 | { |
1273 | 0 | bool bShowDialog = officecfg::Office::Calc::Compatibility::MergeCells::ShowDialog::get(); |
1274 | 0 | if (!bApi && bShowDialog) |
1275 | 0 | { |
1276 | 0 | auto pBox = std::make_shared<ScMergeCellsDialog>(GetViewData().GetDialogParent()); |
1277 | |
|
1278 | 0 | SfxViewShell* pViewShell = GetViewData().GetViewShell(); |
1279 | |
|
1280 | 0 | weld::DialogController::runAsync(pBox, [pBox, bDoContents, bEmptyMergedCells, pViewShell, |
1281 | 0 | nSlot, bApi, doMerge=std::move(doMerge)](sal_Int32 nRetVal) { |
1282 | 0 | if (nRetVal == RET_OK) |
1283 | 0 | { |
1284 | 0 | bool bRealDoContents = bDoContents; |
1285 | 0 | bool bRealEmptyMergedCells = bEmptyMergedCells; |
1286 | 0 | switch (pBox->GetMergeCellsOption()) |
1287 | 0 | { |
1288 | 0 | case MoveContentHiddenCells: |
1289 | 0 | bRealDoContents = true; |
1290 | 0 | break; |
1291 | 0 | case KeepContentHiddenCells: |
1292 | 0 | bRealEmptyMergedCells = false; |
1293 | 0 | break; |
1294 | 0 | case EmptyContentHiddenCells: |
1295 | 0 | bRealEmptyMergedCells = true; |
1296 | 0 | break; |
1297 | 0 | default: |
1298 | 0 | assert(!"Unknown option for merge cells."); |
1299 | 0 | break; |
1300 | 0 | } |
1301 | | |
1302 | 0 | doMerge(bRealDoContents, bRealEmptyMergedCells); |
1303 | |
|
1304 | 0 | if (nSlot != 0) |
1305 | 0 | { |
1306 | 0 | SfxRequest aReq(pViewShell->GetViewFrame(), nSlot); |
1307 | 0 | if (!bApi && bRealDoContents) |
1308 | 0 | aReq.AppendItem(SfxBoolItem(nSlot, bDoContents)); |
1309 | 0 | SfxBindings& rBindings = pViewShell->GetViewFrame().GetBindings(); |
1310 | 0 | rBindings.Invalidate(nSlot); |
1311 | 0 | aReq.Done(); |
1312 | 0 | } |
1313 | 0 | } |
1314 | | // else cancelled |
1315 | 0 | }); |
1316 | 0 | } |
1317 | 0 | } else |
1318 | 0 | doMerge(bDoContents, bEmptyMergedCells); |
1319 | 0 | } |
1320 | | |
1321 | | bool ScViewFunc::TestRemoveMerge() |
1322 | 0 | { |
1323 | 0 | bool bMerged = false; |
1324 | 0 | ScRange aRange; |
1325 | 0 | if (GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE) |
1326 | 0 | { |
1327 | 0 | ScDocument& rDoc = GetViewData().GetDocument(); |
1328 | 0 | if ( rDoc.HasAttrib( aRange, HasAttrFlags::Merged ) ) |
1329 | 0 | bMerged = true; |
1330 | 0 | } |
1331 | 0 | return bMerged; |
1332 | 0 | } |
1333 | | |
1334 | | static bool lcl_extendMergeRange(ScCellMergeOption& rOption, const ScRange& rRange) |
1335 | 0 | { |
1336 | 0 | bool bExtended = false; |
1337 | 0 | if (rOption.mnStartCol > rRange.aStart.Col()) |
1338 | 0 | { |
1339 | 0 | rOption.mnStartCol = rRange.aStart.Col(); |
1340 | 0 | bExtended = true; |
1341 | 0 | } |
1342 | 0 | if (rOption.mnStartRow > rRange.aStart.Row()) |
1343 | 0 | { |
1344 | 0 | rOption.mnStartRow = rRange.aStart.Row(); |
1345 | 0 | bExtended = true; |
1346 | 0 | } |
1347 | 0 | if (rOption.mnEndCol < rRange.aEnd.Col()) |
1348 | 0 | { |
1349 | 0 | rOption.mnEndCol = rRange.aEnd.Col(); |
1350 | 0 | bExtended = true; |
1351 | 0 | } |
1352 | 0 | if (rOption.mnEndRow < rRange.aEnd.Row()) |
1353 | 0 | { |
1354 | 0 | rOption.mnEndRow = rRange.aEnd.Row(); |
1355 | 0 | bExtended = true; |
1356 | 0 | } |
1357 | 0 | return bExtended; |
1358 | 0 | } |
1359 | | |
1360 | | bool ScViewFunc::RemoveMerge() |
1361 | 0 | { |
1362 | 0 | ScRange aRange; |
1363 | 0 | ScEditableTester aTester = ScEditableTester::CreateAndTestView(this); |
1364 | 0 | if (!aTester.IsEditable()) |
1365 | 0 | { |
1366 | 0 | ErrorMessage(aTester.GetMessageId()); |
1367 | 0 | return false; |
1368 | 0 | } |
1369 | 0 | else if (GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE) |
1370 | 0 | { |
1371 | 0 | ScDocument& rDoc = GetViewData().GetDocument(); |
1372 | 0 | ScRange aExtended( aRange ); |
1373 | 0 | rDoc.ExtendMerge( aExtended ); |
1374 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
1375 | 0 | const ScMarkData& rMark = GetViewData().GetMarkData(); |
1376 | 0 | ScCellMergeOption aOption(aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row()); |
1377 | 0 | bool bExtended = false; |
1378 | 0 | do |
1379 | 0 | { |
1380 | 0 | bExtended = false; |
1381 | 0 | for (const SCTAB& i : rMark) |
1382 | 0 | { |
1383 | 0 | aOption.maTabs.insert(i); |
1384 | 0 | aExtended.aStart.SetTab(i); |
1385 | 0 | aExtended.aEnd.SetTab(i); |
1386 | 0 | rDoc.ExtendMerge(aExtended); |
1387 | 0 | rDoc.ExtendOverlapped(aExtended); |
1388 | | |
1389 | | // Expand the current range to be inclusive of all merged |
1390 | | // areas on all sheets. |
1391 | 0 | bExtended = lcl_extendMergeRange(aOption, aExtended); |
1392 | 0 | } |
1393 | 0 | } |
1394 | 0 | while (bExtended); |
1395 | |
|
1396 | 0 | bool bOk = pDocSh->GetDocFunc().UnmergeCells(aOption, true/*bRecord*/, nullptr); |
1397 | 0 | aExtended = aOption.getFirstSingleRange(); |
1398 | 0 | MarkRange( aExtended ); |
1399 | |
|
1400 | 0 | if (bOk) |
1401 | 0 | pDocSh->UpdateOle(GetViewData()); |
1402 | 0 | } |
1403 | | |
1404 | 0 | OUString aCellLocation = aRange.aStart.GetColRowString(); |
1405 | 0 | collectUIInformation({{"CELL", aCellLocation}}, u"UNMERGE_CELL"_ustr); |
1406 | |
|
1407 | 0 | return true; //! bOk ?? |
1408 | 0 | } |
1409 | | |
1410 | | void ScViewFunc::FillSimple( FillDir eDir ) |
1411 | 0 | { |
1412 | 0 | ScRange aRange; |
1413 | 0 | if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE) |
1414 | 0 | { |
1415 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
1416 | 0 | const ScMarkData& rMark = GetViewData().GetMarkData(); |
1417 | 0 | bool bSuccess = pDocSh->GetDocFunc().FillSimple( aRange, &rMark, eDir, false ); |
1418 | 0 | if (bSuccess) |
1419 | 0 | { |
1420 | 0 | pDocSh->UpdateOle(GetViewData()); |
1421 | 0 | UpdateScrollBars(); |
1422 | |
|
1423 | 0 | auto& rDoc = pDocSh->GetDocument(); |
1424 | 0 | const ScTabViewShell* pTabViewShell = GetViewData().GetViewShell(); |
1425 | 0 | const bool bDoAutoSpell = pTabViewShell && pTabViewShell->IsAutoSpell(); |
1426 | 0 | if ( bDoAutoSpell ) |
1427 | 0 | { |
1428 | | // Copy AutoSpellData from above(left/right/below) if no selection. |
1429 | 0 | switch (eDir) |
1430 | 0 | { |
1431 | 0 | case FILL_TO_BOTTOM: |
1432 | 0 | if (aRange.aStart.Row() > 0 && aRange.aStart.Row() == aRange.aEnd.Row()) |
1433 | 0 | aRange.aStart.IncRow(-1); |
1434 | 0 | break; |
1435 | 0 | case FILL_TO_TOP: |
1436 | 0 | if (aRange.aEnd.Row() < rDoc.MaxRow() && aRange.aStart.Row() == aRange.aEnd.Row()) |
1437 | 0 | aRange.aEnd.IncRow(1); |
1438 | 0 | break; |
1439 | 0 | case FILL_TO_RIGHT: |
1440 | 0 | if (aRange.aStart.Col() > 0 && aRange.aStart.Col() == aRange.aEnd.Col()) |
1441 | 0 | aRange.aStart.IncCol(-1); |
1442 | 0 | break; |
1443 | 0 | case FILL_TO_LEFT: |
1444 | 0 | if (aRange.aEnd.Col() < rDoc.MaxCol() && aRange.aStart.Col() == aRange.aEnd.Col()) |
1445 | 0 | aRange.aEnd.IncCol(1); |
1446 | 0 | break; |
1447 | 0 | } |
1448 | 0 | CopyAutoSpellData(eDir, aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row(), |
1449 | 0 | ::std::numeric_limits<sal_uLong>::max()); |
1450 | 0 | } |
1451 | | |
1452 | | // Invalidate cell slots and update input line with new content. |
1453 | 0 | CellContentChanged(); |
1454 | 0 | } |
1455 | 0 | } |
1456 | 0 | else |
1457 | 0 | ErrorMessage(STR_NOMULTISELECT); |
1458 | 0 | } |
1459 | | |
1460 | | void ScViewFunc::FillSeries( FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd, |
1461 | | double fStart, double fStep, double fMax ) |
1462 | 0 | { |
1463 | 0 | ScRange aRange; |
1464 | 0 | if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE) |
1465 | 0 | { |
1466 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
1467 | 0 | const ScMarkData& rMark = GetViewData().GetMarkData(); |
1468 | 0 | bool bSuccess = pDocSh->GetDocFunc(). |
1469 | 0 | FillSeries( aRange, &rMark, eDir, eCmd, eDateCmd, |
1470 | 0 | fStart, fStep, fMax, false ); |
1471 | 0 | if (bSuccess) |
1472 | 0 | { |
1473 | 0 | pDocSh->UpdateOle(GetViewData()); |
1474 | 0 | UpdateScrollBars(); |
1475 | |
|
1476 | 0 | HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh, aRange); |
1477 | 0 | } |
1478 | 0 | } |
1479 | 0 | else |
1480 | 0 | ErrorMessage(STR_NOMULTISELECT); |
1481 | 0 | } |
1482 | | |
1483 | | void ScViewFunc::FillAuto( FillDir eDir, SCCOL nStartCol, SCROW nStartRow, |
1484 | | SCCOL nEndCol, SCROW nEndRow, sal_uLong nCount ) |
1485 | 0 | { |
1486 | 0 | SCTAB nTab = GetViewData().CurrentTabForData(); |
1487 | 0 | ScRange aRange( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab ); |
1488 | 0 | ScRange aSourceRange( aRange ); |
1489 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
1490 | 0 | const ScMarkData& rMark = GetViewData().GetMarkData(); |
1491 | 0 | bool bSuccess = pDocSh->GetDocFunc(). |
1492 | 0 | FillAuto( aRange, &rMark, eDir, nCount, false ); |
1493 | 0 | if (!bSuccess) |
1494 | 0 | return; |
1495 | | |
1496 | 0 | MarkRange( aRange, false ); // aRange was modified in FillAuto |
1497 | 0 | pDocSh->UpdateOle(GetViewData()); |
1498 | 0 | UpdateScrollBars(); |
1499 | |
|
1500 | 0 | const ScTabViewShell* pTabViewShell = GetViewData().GetViewShell(); |
1501 | 0 | const bool bDoAutoSpell = pTabViewShell && pTabViewShell->IsAutoSpell(); |
1502 | 0 | if ( bDoAutoSpell ) |
1503 | 0 | CopyAutoSpellData(eDir, nStartCol, nStartRow, nEndCol, nEndRow, nCount); |
1504 | |
|
1505 | 0 | ScModelObj* pModelObj = pDocSh->GetModel(); |
1506 | |
|
1507 | 0 | ScRangeList aChangeRanges; |
1508 | 0 | ScRange aChangeRange( aRange ); |
1509 | 0 | switch (eDir) |
1510 | 0 | { |
1511 | 0 | case FILL_TO_BOTTOM: |
1512 | 0 | aChangeRange.aStart.SetRow( aSourceRange.aEnd.Row() + 1 ); |
1513 | 0 | break; |
1514 | 0 | case FILL_TO_TOP: |
1515 | 0 | aChangeRange.aEnd.SetRow( aSourceRange.aStart.Row() - 1 ); |
1516 | 0 | break; |
1517 | 0 | case FILL_TO_RIGHT: |
1518 | 0 | aChangeRange.aStart.SetCol( aSourceRange.aEnd.Col() + 1 ); |
1519 | 0 | break; |
1520 | 0 | case FILL_TO_LEFT: |
1521 | 0 | aChangeRange.aEnd.SetCol( aSourceRange.aStart.Col() - 1 ); |
1522 | 0 | break; |
1523 | 0 | default: |
1524 | 0 | break; |
1525 | 0 | } |
1526 | 0 | aChangeRanges.push_back( aChangeRange ); |
1527 | |
|
1528 | 0 | if (HelperNotifyChanges::getMustPropagateChangesModel(pModelObj)) |
1529 | 0 | HelperNotifyChanges::Notify(*pModelObj, aChangeRanges); |
1530 | 0 | else if (pModelObj) |
1531 | 0 | HelperNotifyChanges::Notify(*pModelObj, aChangeRanges, u"data-area-invalidate"_ustr); |
1532 | 0 | } |
1533 | | |
1534 | | void ScViewFunc::CopyAutoSpellData( FillDir eDir, SCCOL nStartCol, SCROW nStartRow, |
1535 | | SCCOL nEndCol, SCROW nEndRow, sal_uLong nCount ) |
1536 | 0 | { |
1537 | 0 | const ScDocument* pDoc = &GetViewData().GetDocument(); |
1538 | 0 | SCTAB nTab = GetViewData().CurrentTabForData(); |
1539 | 0 | CellType eCellType; |
1540 | |
|
1541 | 0 | ScGridWindow* pWin = GetActiveWin(); |
1542 | 0 | if ( pWin->InsideVisibleRange(nStartCol, nStartRow) && pWin->InsideVisibleRange(nEndCol, nEndRow) ) |
1543 | 0 | { |
1544 | 0 | if ( nCount == ::std::numeric_limits<sal_uLong>::max() ) |
1545 | 0 | { |
1546 | 0 | switch( eDir ) |
1547 | 0 | { |
1548 | 0 | case FILL_TO_BOTTOM: |
1549 | 0 | for ( SCCOL nColItr = nStartCol; nColItr <= nEndCol; ++nColItr ) |
1550 | 0 | { |
1551 | 0 | eCellType = pDoc->GetCellType(nColItr, nStartRow, nTab); // We need this optimization only for EditTextObject source cells |
1552 | 0 | if (eCellType != CELLTYPE_EDIT) |
1553 | 0 | continue; |
1554 | | |
1555 | 0 | sc::MisspellRangeResult aRangeResult = pWin->GetAutoSpellData(nColItr, nStartRow); |
1556 | 0 | if (!aRangeResult.HasRanges()) |
1557 | 0 | continue; |
1558 | 0 | for ( SCROW nRowItr = nStartRow + 1; nRowItr <= nEndRow; ++nRowItr ) |
1559 | 0 | pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult); |
1560 | 0 | } |
1561 | 0 | break; |
1562 | 0 | case FILL_TO_TOP: |
1563 | 0 | for ( SCCOL nColItr = nStartCol; nColItr <= nEndCol; ++nColItr ) |
1564 | 0 | { |
1565 | 0 | eCellType = pDoc->GetCellType(nColItr, nEndRow, nTab); // We need this optimization only for EditTextObject source cells |
1566 | 0 | if (eCellType != CELLTYPE_EDIT) |
1567 | 0 | continue; |
1568 | | |
1569 | 0 | sc::MisspellRangeResult aRangeResult = pWin->GetAutoSpellData(nColItr, nEndRow); |
1570 | 0 | if (!aRangeResult.HasRanges()) |
1571 | 0 | continue; |
1572 | 0 | for ( SCROW nRowItr = nEndRow - 1; nRowItr >= nStartRow; --nRowItr ) |
1573 | 0 | pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult); |
1574 | 0 | } |
1575 | 0 | break; |
1576 | 0 | case FILL_TO_RIGHT: |
1577 | 0 | for ( SCROW nRowItr = nStartRow; nRowItr <= nEndRow; ++nRowItr ) |
1578 | 0 | { |
1579 | 0 | eCellType = pDoc->GetCellType(nStartCol, nRowItr, nTab); // We need this optimization only for EditTextObject source cells |
1580 | 0 | if (eCellType != CELLTYPE_EDIT) |
1581 | 0 | continue; |
1582 | | |
1583 | 0 | sc::MisspellRangeResult aRangeResult = pWin->GetAutoSpellData(nStartCol, nRowItr); |
1584 | 0 | if (!aRangeResult.HasRanges()) |
1585 | 0 | continue; |
1586 | 0 | for ( SCCOL nColItr = nStartCol + 1; nColItr <= nEndCol; ++nColItr ) |
1587 | 0 | pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult); |
1588 | 0 | } |
1589 | 0 | break; |
1590 | 0 | case FILL_TO_LEFT: |
1591 | 0 | for ( SCROW nRowItr = nStartRow; nRowItr <= nEndRow; ++nRowItr ) |
1592 | 0 | { |
1593 | 0 | eCellType = pDoc->GetCellType(nEndCol, nRowItr, nTab); // We need this optimization only for EditTextObject source cells |
1594 | 0 | if (eCellType != CELLTYPE_EDIT) |
1595 | 0 | continue; |
1596 | | |
1597 | 0 | sc::MisspellRangeResult aRangeResult = pWin->GetAutoSpellData(nEndCol, nRowItr); |
1598 | 0 | if (!aRangeResult.HasRanges()) |
1599 | 0 | continue; |
1600 | 0 | for ( SCCOL nColItr = nEndCol - 1; nColItr >= nStartCol; --nColItr ) |
1601 | 0 | pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult); |
1602 | 0 | } |
1603 | 0 | break; |
1604 | 0 | } |
1605 | 0 | return; |
1606 | 0 | } |
1607 | | |
1608 | 0 | SCROW nRowRepeatSize = nEndRow - nStartRow + 1; |
1609 | 0 | SCCOL nColRepeatSize = nEndCol - nStartCol + 1; |
1610 | 0 | SCROW nTillRow = 0; |
1611 | 0 | SCCOL nTillCol = 0; |
1612 | 0 | std::vector<std::vector<sc::MisspellRangeResult>> aSourceSpellRanges(nRowRepeatSize, std::vector<sc::MisspellRangeResult>(nColRepeatSize)); |
1613 | |
|
1614 | 0 | for ( SCROW nRowIdx = 0; nRowIdx < nRowRepeatSize; ++nRowIdx ) |
1615 | 0 | { |
1616 | 0 | for ( SCCOL nColIdx = 0; nColIdx < nColRepeatSize; ++nColIdx ) |
1617 | 0 | { |
1618 | 0 | eCellType = pDoc->GetCellType(nStartCol + nColIdx, nStartRow + nRowIdx, nTab); // We need this optimization only for EditTextObject source cells |
1619 | 0 | if (eCellType != CELLTYPE_EDIT) |
1620 | 0 | continue; |
1621 | | |
1622 | 0 | aSourceSpellRanges[nRowIdx][nColIdx] = pWin->GetAutoSpellData( nStartCol + nColIdx, nStartRow + nRowIdx ); |
1623 | 0 | } |
1624 | 0 | } |
1625 | |
|
1626 | 0 | switch( eDir ) |
1627 | 0 | { |
1628 | 0 | case FILL_TO_BOTTOM: |
1629 | 0 | nTillRow = nEndRow + nCount; |
1630 | 0 | for ( SCCOL nColItr = nStartCol; nColItr <= nEndCol; ++nColItr ) |
1631 | 0 | { |
1632 | 0 | for ( SCROW nRowItr = nEndRow + 1; nRowItr <= nTillRow; ++nRowItr ) |
1633 | 0 | { |
1634 | 0 | size_t nSourceRowIdx = ( nRowItr - nEndRow - 1 ) % nRowRepeatSize; |
1635 | 0 | sc::MisspellRangeResult aRangeResult = aSourceSpellRanges[nSourceRowIdx][nColItr - nStartCol]; |
1636 | 0 | if (!aRangeResult.HasRanges()) |
1637 | 0 | continue; |
1638 | 0 | pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult); |
1639 | 0 | } |
1640 | 0 | } |
1641 | 0 | break; |
1642 | | |
1643 | 0 | case FILL_TO_TOP: |
1644 | 0 | nTillRow = nStartRow - nCount; |
1645 | 0 | for ( SCCOL nColItr = nStartCol; nColItr <= nEndCol; ++nColItr ) |
1646 | 0 | { |
1647 | 0 | for ( SCROW nRowItr = nStartRow - 1; nRowItr >= nTillRow; --nRowItr ) |
1648 | 0 | { |
1649 | 0 | size_t nSourceRowIdx = nRowRepeatSize - 1 - ( ( nStartRow - 1 - nRowItr ) % nRowRepeatSize ); |
1650 | 0 | sc::MisspellRangeResult aRangeResult = aSourceSpellRanges[nSourceRowIdx][nColItr - nStartCol]; |
1651 | 0 | if (!aRangeResult.HasRanges()) |
1652 | 0 | continue; |
1653 | 0 | pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult); |
1654 | 0 | } |
1655 | 0 | } |
1656 | 0 | break; |
1657 | | |
1658 | 0 | case FILL_TO_RIGHT: |
1659 | 0 | nTillCol = nEndCol + nCount; |
1660 | 0 | for ( SCCOL nColItr = nEndCol + 1; nColItr <= nTillCol; ++nColItr ) |
1661 | 0 | { |
1662 | 0 | size_t nSourceColIdx = ( nColItr - nEndCol - 1 ) % nColRepeatSize; |
1663 | 0 | for ( SCROW nRowItr = nStartRow; nRowItr <= nEndRow; ++nRowItr ) |
1664 | 0 | { |
1665 | 0 | sc::MisspellRangeResult aRangeResult = aSourceSpellRanges[nRowItr - nStartRow][nSourceColIdx]; |
1666 | 0 | if (!aRangeResult.HasRanges()) |
1667 | 0 | continue; |
1668 | 0 | pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult); |
1669 | 0 | } |
1670 | 0 | } |
1671 | 0 | break; |
1672 | | |
1673 | 0 | case FILL_TO_LEFT: |
1674 | 0 | nTillCol = nStartCol - nCount; |
1675 | 0 | for ( SCCOL nColItr = nStartCol - 1; nColItr >= nTillCol; --nColItr ) |
1676 | 0 | { |
1677 | 0 | size_t nSourceColIdx = nColRepeatSize - 1 - ( ( nStartCol - 1 - nColItr ) % nColRepeatSize ); |
1678 | 0 | for ( SCROW nRowItr = nStartRow; nRowItr <= nEndRow; ++nRowItr ) |
1679 | 0 | { |
1680 | 0 | sc::MisspellRangeResult aRangeResult = aSourceSpellRanges[nRowItr - nStartRow][nSourceColIdx]; |
1681 | 0 | if (!aRangeResult.HasRanges()) |
1682 | 0 | continue; |
1683 | 0 | pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult); |
1684 | 0 | } |
1685 | 0 | } |
1686 | 0 | break; |
1687 | 0 | } |
1688 | 0 | } |
1689 | 0 | else |
1690 | 0 | pWin->ResetAutoSpellForContentChange(); |
1691 | |
|
1692 | 0 | } |
1693 | | |
1694 | | void ScViewFunc::FillTab( InsertDeleteFlags nFlags, ScPasteFunc nFunction, bool bSkipEmpty, bool bAsLink ) |
1695 | 0 | { |
1696 | | //! allow source sheet to be protected |
1697 | 0 | ScEditableTester aTester = ScEditableTester::CreateAndTestView(this); |
1698 | 0 | if (!aTester.IsEditable()) |
1699 | 0 | { |
1700 | 0 | ErrorMessage(aTester.GetMessageId()); |
1701 | 0 | return; |
1702 | 0 | } |
1703 | | |
1704 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
1705 | 0 | ScDocument& rDoc = pDocSh->GetDocument(); |
1706 | 0 | ScMarkData& rMark = GetViewData().GetMarkData(); |
1707 | 0 | SCTAB nTab = GetViewData().CurrentTabForData(); |
1708 | 0 | bool bUndo(rDoc.IsUndoEnabled()); |
1709 | |
|
1710 | 0 | ScRange aMarkRange; |
1711 | 0 | rMark.MarkToSimple(); |
1712 | 0 | bool bMulti = rMark.IsMultiMarked(); |
1713 | 0 | if (bMulti) |
1714 | 0 | aMarkRange = rMark.GetMultiMarkArea(); |
1715 | 0 | else if (rMark.IsMarked()) |
1716 | 0 | aMarkRange = rMark.GetMarkArea(); |
1717 | 0 | else |
1718 | 0 | aMarkRange = ScRange( GetViewData().GetCurX(), GetViewData().GetCurY(), nTab ); |
1719 | |
|
1720 | 0 | ScDocumentUniquePtr pUndoDoc; |
1721 | |
|
1722 | 0 | if (bUndo) |
1723 | 0 | { |
1724 | 0 | pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO )); |
1725 | 0 | pUndoDoc->InitUndo( rDoc, nTab, nTab ); |
1726 | |
|
1727 | 0 | for (const SCTAB& i : rMark) |
1728 | 0 | if (i != nTab ) |
1729 | 0 | { |
1730 | 0 | pUndoDoc->AddUndoTab( i, i ); |
1731 | 0 | aMarkRange.aStart.SetTab( i ); |
1732 | 0 | aMarkRange.aEnd.SetTab( i ); |
1733 | 0 | rDoc.CopyToDocument( aMarkRange, InsertDeleteFlags::ALL, bMulti, *pUndoDoc ); |
1734 | 0 | } |
1735 | 0 | } |
1736 | |
|
1737 | 0 | if (bMulti) |
1738 | 0 | rDoc.FillTabMarked( nTab, rMark, nFlags, nFunction, bSkipEmpty, bAsLink ); |
1739 | 0 | else |
1740 | 0 | { |
1741 | 0 | aMarkRange.aStart.SetTab( nTab ); |
1742 | 0 | aMarkRange.aEnd.SetTab( nTab ); |
1743 | 0 | rDoc.FillTab( aMarkRange, rMark, nFlags, nFunction, bSkipEmpty, bAsLink ); |
1744 | 0 | } |
1745 | |
|
1746 | 0 | if (bUndo) |
1747 | 0 | { //! for ChangeTrack not until the end |
1748 | 0 | pDocSh->GetUndoManager()->AddUndoAction( |
1749 | 0 | std::make_unique<ScUndoFillTable>( *pDocSh, rMark, |
1750 | 0 | aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), nTab, |
1751 | 0 | aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), nTab, |
1752 | 0 | std::move(pUndoDoc), bMulti, nTab, nFlags, nFunction, bSkipEmpty, bAsLink ) ); |
1753 | 0 | } |
1754 | |
|
1755 | 0 | pDocSh->PostPaintGridAll(); |
1756 | 0 | pDocSh->PostDataChanged(); |
1757 | 0 | } |
1758 | | |
1759 | | /** Downward fill of selected cell(s) by double-clicking cross-hair cursor |
1760 | | |
1761 | | Either, extends a current selection if non-empty cells exist immediately |
1762 | | below the selection, overwriting cells below the selection up to the |
1763 | | minimum row of already filled cells. |
1764 | | |
1765 | | Or, extends a current selection down to the last non-empty cell of an |
1766 | | adjacent column when the lower-right corner of the selection is |
1767 | | double-clicked. It uses a left-adjoining non-empty column as a guide if |
1768 | | such is available, otherwise a right-adjoining non-empty column is used. |
1769 | | |
1770 | | @return No return value |
1771 | | |
1772 | | @see #i12313# |
1773 | | */ |
1774 | | void ScViewFunc::FillCrossDblClick() |
1775 | 0 | { |
1776 | 0 | ScRange aRange; |
1777 | 0 | GetViewData().GetSimpleArea( aRange ); |
1778 | 0 | aRange.PutInOrder(); |
1779 | |
|
1780 | 0 | SCTAB nTab = GetViewData().GetCurPos().Tab(); |
1781 | 0 | SCCOL nStartX = aRange.aStart.Col(); |
1782 | 0 | SCROW nStartY = aRange.aStart.Row(); |
1783 | 0 | SCCOL nEndX = aRange.aEnd.Col(); |
1784 | 0 | SCROW nEndY = aRange.aEnd.Row(); |
1785 | |
|
1786 | 0 | ScDocument& rDoc = GetViewData().GetDocument(); |
1787 | |
|
1788 | 0 | if (nEndY >= rDoc.MaxRow()) |
1789 | | // Nothing to fill. |
1790 | 0 | return; |
1791 | | |
1792 | | // Make sure the selection is not empty |
1793 | 0 | if ( rDoc.IsBlockEmpty( nStartX, nStartY, nEndX, nEndY, nTab ) ) |
1794 | 0 | return; |
1795 | | |
1796 | | // If there is data in all columns immediately below the selection then |
1797 | | // switch to overwriting fill. |
1798 | 0 | SCROW nOverWriteEndRow = rDoc.MaxRow(); |
1799 | 0 | for (SCCOL nCol = nStartX; nCol <= nEndX; ++nCol) |
1800 | 0 | { |
1801 | 0 | if (rDoc.HasData( nCol, nEndY + 1, nTab)) |
1802 | 0 | { |
1803 | | // Determine the shortest data column to end the fill. |
1804 | 0 | SCROW nY = nEndY + 1; |
1805 | | // FindAreaPos() returns the start row of the next data block if |
1806 | | // the current row is the last row of a data block and an empty |
1807 | | // cell follows. Somewhat unexpected behaviour... |
1808 | | // So check beforehand if there is one non-empty cell following. |
1809 | 0 | if (rDoc.HasData( nCol, nY + 1, nTab)) |
1810 | 0 | { |
1811 | 0 | rDoc.FindAreaPos( nCol, nY, nTab, SC_MOVE_DOWN); |
1812 | 0 | if (nOverWriteEndRow > nY) |
1813 | 0 | nOverWriteEndRow = nY; |
1814 | 0 | } |
1815 | 0 | else |
1816 | 0 | { |
1817 | 0 | nOverWriteEndRow = nY; |
1818 | 0 | } |
1819 | 0 | } |
1820 | 0 | else |
1821 | 0 | { |
1822 | 0 | nOverWriteEndRow = 0; |
1823 | 0 | break; // for |
1824 | 0 | } |
1825 | 0 | } |
1826 | |
|
1827 | 0 | if (nOverWriteEndRow > nEndY) |
1828 | 0 | { |
1829 | 0 | FillAuto( FILL_TO_BOTTOM, nStartX, nStartY, nEndX, nEndY, nOverWriteEndRow - nEndY); |
1830 | 0 | return; |
1831 | 0 | } |
1832 | | |
1833 | | // Non-overwriting fill follows. |
1834 | | |
1835 | 0 | const bool bDataLeft = (nStartX > 0); |
1836 | 0 | if (!bDataLeft && nEndX >= rDoc.MaxCol()) |
1837 | | // Absolutely no data left or right of selection. |
1838 | 0 | return; |
1839 | | |
1840 | | // Check that there is |
1841 | | // 1) data immediately left (preferred) or right of start (row) of selection |
1842 | | // 2) data there below |
1843 | | // 3) no data immediately below selection |
1844 | | |
1845 | 0 | SCCOL nMovX = (bDataLeft ? nStartX - 1 : nEndX + 1); |
1846 | 0 | SCROW nMovY = nStartY; |
1847 | 0 | bool bDataFound = (rDoc.HasData( nMovX, nStartY, nTab) && rDoc.HasData( nMovX, nStartY + 1, nTab)); |
1848 | 0 | if (!bDataFound && bDataLeft && nEndX < rDoc.MaxCol()) |
1849 | 0 | { |
1850 | 0 | nMovX = nEndX + 1; // check right |
1851 | 0 | bDataFound = (rDoc.HasData( nMovX, nStartY, nTab) && rDoc.HasData( nMovX, nStartY + 1, nTab)); |
1852 | 0 | } |
1853 | |
|
1854 | 0 | if (!(bDataFound && rDoc.IsEmptyData( nStartX, nEndY + 1, nEndX, nEndY + 1, nTab ))) |
1855 | 0 | return; |
1856 | | |
1857 | | // Get end of data left or right. |
1858 | 0 | rDoc.FindAreaPos( nMovX, nMovY, nTab, SC_MOVE_DOWN); |
1859 | | // Find minimum end row of below empty area and data right. |
1860 | 0 | for (SCCOL nX = nStartX; nX <= nEndX; ++nX) |
1861 | 0 | { |
1862 | 0 | SCROW nY = nEndY + 1; |
1863 | | // Get next row with data in this column. |
1864 | 0 | rDoc.FindAreaPos( nX, nY, nTab, SC_MOVE_DOWN); |
1865 | 0 | if (nMovY == rDoc.MaxRow() && nY == rDoc.MaxRow()) |
1866 | 0 | { |
1867 | | // FindAreaPos() returns MAXROW also if there is no data at all |
1868 | | // from the start, so check if that contains data if the nearby |
1869 | | // (left or right) data ends there and increment if no data |
1870 | | // here, pretending the next data would be thereafter so nMovY |
1871 | | // will not be decremented. |
1872 | 0 | if (!rDoc.HasData( nX, nY, nTab)) |
1873 | 0 | ++nY; |
1874 | 0 | } |
1875 | 0 | if (nMovY > nY - 1) |
1876 | 0 | nMovY = nY - 1; |
1877 | 0 | } |
1878 | |
|
1879 | 0 | if (nMovY > nEndY) |
1880 | 0 | { |
1881 | 0 | FillAuto( FILL_TO_BOTTOM, nStartX, nStartY, nEndX, nEndY, nMovY - nEndY); |
1882 | 0 | } |
1883 | 0 | } |
1884 | | |
1885 | | void ScViewFunc::ConvertFormulaToValue() |
1886 | 0 | { |
1887 | 0 | ScRange aRange; |
1888 | 0 | GetViewData().GetSimpleArea(aRange); |
1889 | 0 | aRange.PutInOrder(); |
1890 | |
|
1891 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
1892 | 0 | pDocSh->GetDocFunc().ConvertFormulaToValue(aRange, true); |
1893 | | // tdf#131326 - invalidate cell slots and update input line with new content |
1894 | 0 | CellContentChanged(); |
1895 | 0 | pDocSh->PostPaint(aRange, PaintPartFlags::Grid); |
1896 | 0 | } |
1897 | | |
1898 | | void ScViewFunc::TransliterateText( TransliterationFlags nType ) |
1899 | 0 | { |
1900 | 0 | ScMarkData aFuncMark = GetViewData().GetMarkData(); |
1901 | 0 | if ( !aFuncMark.IsMarked() && !aFuncMark.IsMultiMarked() ) |
1902 | 0 | { |
1903 | | // no selection -> use cursor position |
1904 | |
|
1905 | 0 | ScAddress aCursor( GetViewData().GetCurX(), GetViewData().GetCurY(), GetViewData().CurrentTabForData() ); |
1906 | 0 | aFuncMark.SetMarkArea( ScRange( aCursor ) ); |
1907 | 0 | } |
1908 | |
|
1909 | 0 | bool bSuccess = GetViewData().GetDocShell()->GetDocFunc(). |
1910 | 0 | TransliterateText( aFuncMark, nType, false ); |
1911 | 0 | if (bSuccess) |
1912 | 0 | { |
1913 | 0 | GetViewData().GetViewShell()->UpdateInputHandler(); |
1914 | 0 | } |
1915 | 0 | } |
1916 | | |
1917 | | // AutoFormat |
1918 | | |
1919 | | void ScViewFunc::AutoFormat( sal_uInt16 nFormatNo ) |
1920 | 0 | { |
1921 | 0 | ScRange aRange; |
1922 | 0 | if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE) |
1923 | 0 | { |
1924 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
1925 | 0 | ScMarkData& rMark = GetViewData().GetMarkData(); |
1926 | |
|
1927 | 0 | bool bSuccess = pDocSh->GetDocFunc().AutoFormat( aRange, &rMark, nFormatNo, false ); |
1928 | 0 | if (bSuccess) |
1929 | 0 | pDocSh->UpdateOle(GetViewData()); |
1930 | 0 | } |
1931 | 0 | else |
1932 | 0 | ErrorMessage(STR_NOMULTISELECT); |
1933 | 0 | } |
1934 | | |
1935 | | // Search & Replace |
1936 | | |
1937 | | bool ScViewFunc::SearchAndReplace( const SvxSearchItem* pSearchItem, |
1938 | | bool bAddUndo, bool bIsApi ) |
1939 | 0 | { |
1940 | 0 | SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Empty); |
1941 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
1942 | 0 | ScDocument& rDoc = pDocSh->GetDocument(); |
1943 | 0 | ScMarkData& rMark = GetViewData().GetMarkData(); |
1944 | 0 | if (bAddUndo && !rDoc.IsUndoEnabled()) |
1945 | 0 | bAddUndo = false; |
1946 | |
|
1947 | 0 | bool bCursorMoved = false; |
1948 | 0 | SCCOL nOrigPosX = GetViewData().GetCurX(); |
1949 | 0 | SCROW nOrigPosY = GetViewData().GetCurY(); |
1950 | 0 | if ( !rMark.IsMarked() && !rMark.IsMultiMarked() && (pSearchItem->HasStartPoint()) ) |
1951 | 0 | { |
1952 | | // No selection -> but we have a start point (top left corner of the |
1953 | | // current view), start searching from there, not from the current |
1954 | | // cursor position. |
1955 | 0 | SCCOL nPosX; |
1956 | 0 | SCROW nPosY; |
1957 | |
|
1958 | 0 | int nPixelX = pSearchItem->GetStartPointX() * GetViewData().GetPPTX(); |
1959 | 0 | int nPixelY = pSearchItem->GetStartPointY() * GetViewData().GetPPTY(); |
1960 | |
|
1961 | 0 | GetViewData().GetPosFromPixel(nPixelX, nPixelY, GetViewData().GetActivePart(), nPosX, nPosY); |
1962 | |
|
1963 | 0 | AlignToCursor( nPosX, nPosY, SC_FOLLOW_JUMP ); |
1964 | 0 | SetCursor( nPosX, nPosY, true ); |
1965 | 0 | bCursorMoved = true; |
1966 | 0 | } |
1967 | |
|
1968 | 0 | SCCOL nCol, nOldCol; |
1969 | 0 | SCROW nRow, nOldRow; |
1970 | 0 | SCTAB nTab, nOldTab; |
1971 | 0 | nCol = nOldCol = GetViewData().GetCurX(); |
1972 | 0 | nRow = nOldRow = GetViewData().GetCurY(); |
1973 | 0 | nTab = nOldTab = GetViewData().CurrentTabForData(); |
1974 | |
|
1975 | 0 | SvxSearchCmd nCommand = pSearchItem->GetCommand(); |
1976 | 0 | bool bAllTables = pSearchItem->IsAllTables(); |
1977 | 0 | std::set<SCTAB> aOldSelectedTables; |
1978 | 0 | SCTAB nLastTab = rDoc.GetTableCount() - 1; |
1979 | 0 | SCTAB nStartTab, nEndTab; |
1980 | 0 | if ( bAllTables ) |
1981 | 0 | { |
1982 | 0 | nStartTab = 0; |
1983 | 0 | nEndTab = nLastTab; |
1984 | 0 | std::set<SCTAB> aTmp(rMark.begin(), rMark.end()); |
1985 | 0 | aOldSelectedTables.swap(aTmp); |
1986 | 0 | } |
1987 | 0 | else |
1988 | 0 | { //! at least one is always selected |
1989 | 0 | nStartTab = rMark.GetFirstSelected(); |
1990 | 0 | nEndTab = rMark.GetLastSelected(); |
1991 | 0 | } |
1992 | |
|
1993 | 0 | if ( nCommand == SvxSearchCmd::FIND |
1994 | 0 | || nCommand == SvxSearchCmd::FIND_ALL) |
1995 | 0 | bAddUndo = false; |
1996 | | |
1997 | | //! account for bAttrib during Undo !!! |
1998 | |
|
1999 | 0 | ScDocumentUniquePtr pUndoDoc; |
2000 | 0 | std::unique_ptr<ScMarkData> pUndoMark; |
2001 | 0 | OUString aUndoStr; |
2002 | 0 | if (bAddUndo) |
2003 | 0 | { |
2004 | 0 | pUndoMark.reset(new ScMarkData(rMark)); // Mark is being modified |
2005 | 0 | if ( nCommand == SvxSearchCmd::REPLACE_ALL ) |
2006 | 0 | { |
2007 | 0 | pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO)); |
2008 | 0 | pUndoDoc->InitUndo( rDoc, nStartTab, nEndTab ); |
2009 | 0 | } |
2010 | 0 | } |
2011 | |
|
2012 | 0 | if ( bAllTables ) |
2013 | 0 | { //! select all, after pUndoMark has been created |
2014 | 0 | for ( SCTAB j = nStartTab; j <= nEndTab; j++ ) |
2015 | 0 | { |
2016 | 0 | rMark.SelectTable( j, true ); |
2017 | 0 | } |
2018 | 0 | } |
2019 | |
|
2020 | 0 | DoneBlockMode(true); // don't delete mark |
2021 | 0 | InitOwnBlockMode( ScRange( nCol, nRow, nStartTab, nCol, nRow, nEndTab)); |
2022 | | |
2023 | | // If search starts at the beginning don't ask again whether it shall start at the beginning |
2024 | 0 | bool bFirst = true; |
2025 | 0 | if ( nCol == 0 && nRow == 0 && nTab == nStartTab && !pSearchItem->GetBackward() ) |
2026 | 0 | bFirst = false; |
2027 | |
|
2028 | 0 | bool bFound = false; |
2029 | 0 | while (true) |
2030 | 0 | { |
2031 | 0 | GetFrameWin()->EnterWait(); |
2032 | 0 | ScRangeList aMatchedRanges; |
2033 | 0 | bool bMatchedRangesWereClamped = false; |
2034 | 0 | if (rDoc.SearchAndReplace(*pSearchItem, nCol, nRow, nTab, rMark, aMatchedRanges, aUndoStr, pUndoDoc.get(), bMatchedRangesWereClamped)) |
2035 | 0 | { |
2036 | 0 | bFound = true; |
2037 | 0 | if (bAddUndo) |
2038 | 0 | { |
2039 | 0 | GetViewData().GetDocShell()->GetUndoManager()->AddUndoAction( |
2040 | 0 | std::make_unique<ScUndoReplace>( *GetViewData().GetDocShell(), *pUndoMark, |
2041 | 0 | nCol, nRow, nTab, |
2042 | 0 | aUndoStr, std::move(pUndoDoc), pSearchItem ) ); |
2043 | 0 | } |
2044 | |
|
2045 | 0 | if (nCommand == SvxSearchCmd::FIND_ALL || nCommand == SvxSearchCmd::REPLACE_ALL) |
2046 | 0 | { |
2047 | 0 | SfxViewFrame* pViewFrm = SfxViewFrame::Current(); |
2048 | 0 | bool bShow = GetViewData().GetViewShell()->GetViewData().GetOptions().GetOption(sc::ViewOption::SUMMARY); |
2049 | |
|
2050 | 0 | if (bShow && pViewFrm && !comphelper::LibreOfficeKit::isActive()) |
2051 | 0 | { |
2052 | 0 | pViewFrm->ShowChildWindow(sc::SearchResultsDlgWrapper::GetChildWindowId()); |
2053 | 0 | SfxChildWindow* pWnd = pViewFrm->GetChildWindow(sc::SearchResultsDlgWrapper::GetChildWindowId()); |
2054 | 0 | if (pWnd) |
2055 | 0 | { |
2056 | 0 | sc::SearchResultsDlg* pDlg = static_cast<sc::SearchResultsDlg*>(pWnd->GetController().get()); |
2057 | 0 | if (pDlg) |
2058 | 0 | { |
2059 | 0 | const bool bCellNotes = (pSearchItem->GetCellType() == SvxSearchCellType::NOTE); |
2060 | | // ScCellIterator iterates over cells with content, |
2061 | | // for empty cells iterate over match positions. |
2062 | 0 | const bool bEmptyCells = (!bCellNotes |
2063 | 0 | && ((nCommand == SvxSearchCmd::FIND_ALL |
2064 | 0 | && ScDocument::IsEmptyCellSearch(*pSearchItem)) |
2065 | 0 | || (nCommand == SvxSearchCmd::REPLACE_ALL |
2066 | 0 | && pSearchItem->GetReplaceString().isEmpty()))); |
2067 | 0 | pDlg->FillResults(rDoc, aMatchedRanges, bCellNotes, bEmptyCells, bMatchedRangesWereClamped); |
2068 | 0 | } |
2069 | 0 | } |
2070 | 0 | } |
2071 | |
|
2072 | 0 | rMark.ResetMark(); |
2073 | 0 | for (size_t i = 0, n = aMatchedRanges.size(); i < n; ++i) |
2074 | 0 | { |
2075 | 0 | const ScRange& r = aMatchedRanges[i]; |
2076 | 0 | if (r.aStart.Tab() == nTab) |
2077 | 0 | rMark.SetMultiMarkArea(r); |
2078 | 0 | } |
2079 | 0 | } |
2080 | |
|
2081 | 0 | break; // break 'while (TRUE)' |
2082 | 0 | } |
2083 | 0 | else if ( bFirst && (nCommand == SvxSearchCmd::FIND || |
2084 | 0 | nCommand == SvxSearchCmd::REPLACE) ) |
2085 | 0 | { |
2086 | 0 | bFirst = false; |
2087 | 0 | GetFrameWin()->LeaveWait(); |
2088 | 0 | if (!bIsApi) |
2089 | 0 | { |
2090 | 0 | if ( nStartTab == nEndTab ) |
2091 | 0 | SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::EndSheet); |
2092 | 0 | else |
2093 | 0 | SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::End); |
2094 | |
|
2095 | 0 | rDoc.GetSearchAndReplaceStart( *pSearchItem, nCol, nRow ); |
2096 | 0 | if (pSearchItem->GetBackward()) |
2097 | 0 | nTab = nEndTab; |
2098 | 0 | else |
2099 | 0 | nTab = nStartTab; |
2100 | 0 | } |
2101 | 0 | else |
2102 | 0 | { |
2103 | 0 | break; // break 'while (TRUE)' |
2104 | 0 | } |
2105 | 0 | } |
2106 | 0 | else // nothing found |
2107 | 0 | { |
2108 | 0 | if ( nCommand == SvxSearchCmd::FIND_ALL || nCommand == SvxSearchCmd::REPLACE_ALL ) |
2109 | 0 | { |
2110 | 0 | pDocSh->PostPaintGridAll(); // Mark |
2111 | 0 | } |
2112 | |
|
2113 | 0 | GetFrameWin()->LeaveWait(); |
2114 | 0 | if (!bIsApi) |
2115 | 0 | { |
2116 | 0 | GetViewData().GetViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, pSearchItem->GetSearchString().toUtf8()); |
2117 | 0 | SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound); |
2118 | 0 | } |
2119 | |
|
2120 | 0 | break; // break 'while (TRUE)' |
2121 | 0 | } |
2122 | 0 | } // of while true |
2123 | |
|
2124 | 0 | if (!aOldSelectedTables.empty()) |
2125 | 0 | { |
2126 | | // restore originally selected table |
2127 | 0 | for (SCTAB i = 0; i <= nEndTab; ++i) |
2128 | 0 | rMark.SelectTable(i, false); |
2129 | |
|
2130 | 0 | for (const auto& rTab : aOldSelectedTables) |
2131 | 0 | rMark.SelectTable(rTab, true); |
2132 | |
|
2133 | 0 | if ( bFound ) |
2134 | 0 | { // if a table is selected as a "match" it remains selected. |
2135 | 0 | rMark.SelectTable( nTab, true ); |
2136 | | // It's a swap if only one table was selected before |
2137 | | //! otherwise now one table more might be selected |
2138 | 0 | if ( aOldSelectedTables.size() == 1 && nTab != nOldTab ) |
2139 | 0 | rMark.SelectTable( nOldTab, false ); |
2140 | 0 | } |
2141 | 0 | } |
2142 | | |
2143 | | // Avoid LOK selection notifications before we have all the results. |
2144 | 0 | GetViewData().GetViewShell()->setTiledSearching(true); |
2145 | 0 | MarkDataChanged(); |
2146 | 0 | GetViewData().GetViewShell()->setTiledSearching(false); |
2147 | |
|
2148 | 0 | if ( bFound ) |
2149 | 0 | { |
2150 | 0 | if ( nTab != GetViewData().CurrentTabForData() ) |
2151 | 0 | SetTabNo( nTab ); |
2152 | | |
2153 | | // if nothing is marked, DoneBlockMode, then marking can start |
2154 | | // directly from this place via Shift-Cursor |
2155 | 0 | if (!rMark.IsMarked() && !rMark.IsMultiMarked()) |
2156 | 0 | DoneBlockMode(true); |
2157 | |
|
2158 | 0 | AlignToCursor( nCol, nRow, SC_FOLLOW_JUMP ); |
2159 | 0 | SetCursor( nCol, nRow, true ); |
2160 | |
|
2161 | 0 | if (comphelper::LibreOfficeKit::isActive()) |
2162 | 0 | { |
2163 | 0 | Point aCurPos = GetViewData().GetScrPos(nCol, nRow, GetViewData().GetActivePart()); |
2164 | | |
2165 | | // just update the cell selection |
2166 | 0 | ScGridWindow* pGridWindow = GetViewData().GetActiveWin(); |
2167 | | // Don't move cell selection handles for find-all: selection of all but the first result would be lost. |
2168 | 0 | if (pGridWindow && nCommand == SvxSearchCmd::FIND) |
2169 | 0 | { |
2170 | | // move the cell selection handles |
2171 | 0 | pGridWindow->SetCellSelectionPixel(LOK_SETTEXTSELECTION_RESET, aCurPos.X(), aCurPos.Y()); |
2172 | 0 | pGridWindow->SetCellSelectionPixel(LOK_SETTEXTSELECTION_START, aCurPos.X(), aCurPos.Y()); |
2173 | 0 | pGridWindow->SetCellSelectionPixel(LOK_SETTEXTSELECTION_END, aCurPos.X(), aCurPos.Y()); |
2174 | 0 | } |
2175 | |
|
2176 | 0 | if (pGridWindow) |
2177 | 0 | { |
2178 | 0 | std::vector<tools::Rectangle> aLogicRects; |
2179 | 0 | pGridWindow->GetCellSelection(aLogicRects); |
2180 | |
|
2181 | 0 | boost::property_tree::ptree aTree; |
2182 | 0 | aTree.put("searchString", pSearchItem->GetSearchString().toUtf8().getStr()); |
2183 | 0 | aTree.put("highlightAll", nCommand == SvxSearchCmd::FIND_ALL); |
2184 | |
|
2185 | 0 | boost::property_tree::ptree aSelections; |
2186 | 0 | for (const tools::Rectangle& rLogicRect : aLogicRects) |
2187 | 0 | { |
2188 | 0 | boost::property_tree::ptree aSelection; |
2189 | 0 | aSelection.put("part", OString::number(nTab).getStr()); |
2190 | 0 | aSelection.put("rectangles", rLogicRect.toString().getStr()); |
2191 | 0 | aSelections.push_back(std::make_pair("", aSelection)); |
2192 | 0 | } |
2193 | 0 | aTree.add_child("searchResultSelection", aSelections); |
2194 | |
|
2195 | 0 | std::stringstream aStream; |
2196 | 0 | boost::property_tree::write_json(aStream, aTree); |
2197 | 0 | OString aPayload( aStream.str() ); |
2198 | 0 | SfxViewShell* pViewShell = GetViewData().GetViewShell(); |
2199 | 0 | pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_RESULT_SELECTION, aPayload); |
2200 | | |
2201 | | // Trigger LOK_CALLBACK_TEXT_SELECTION now. |
2202 | 0 | MarkDataChanged(); |
2203 | 0 | } |
2204 | 0 | } |
2205 | |
|
2206 | 0 | if ( nCommand == SvxSearchCmd::REPLACE |
2207 | 0 | || nCommand == SvxSearchCmd::REPLACE_ALL ) |
2208 | 0 | { |
2209 | 0 | if ( nCommand == SvxSearchCmd::REPLACE ) |
2210 | 0 | { |
2211 | 0 | pDocSh->PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PaintPartFlags::Grid ); |
2212 | | |
2213 | | // jump to next cell if we replaced everything in the cell |
2214 | | // where the cursor was positioned (but avoid switching tabs) |
2215 | 0 | if ( nCol == nOldCol && nRow == nOldRow && nTab == nOldTab ) |
2216 | 0 | { |
2217 | 0 | SvxSearchItem aSearchItem = ScGlobal::GetSearchItem(); |
2218 | 0 | aSearchItem.SetCommand(SvxSearchCmd::FIND); |
2219 | 0 | aSearchItem.SetWhich(SID_SEARCH_ITEM); |
2220 | |
|
2221 | 0 | ScRangeList aMatchedRanges; |
2222 | 0 | bool bMatchedRangesWereClamped; |
2223 | 0 | ScTable::UpdateSearchItemAddressForReplace( aSearchItem, nCol, nRow ); |
2224 | 0 | if ( rDoc.SearchAndReplace( aSearchItem, nCol, nRow, nTab, rMark, aMatchedRanges, aUndoStr, nullptr, bMatchedRangesWereClamped ) && |
2225 | 0 | ( nTab == nOldTab ) && |
2226 | 0 | ( nCol != nOldCol || nRow != nOldRow ) ) |
2227 | 0 | { |
2228 | 0 | AlignToCursor(nCol, nRow, SC_FOLLOW_JUMP); |
2229 | 0 | SetCursor( nCol, nRow, true ); |
2230 | 0 | } |
2231 | 0 | } |
2232 | 0 | } |
2233 | 0 | else |
2234 | 0 | pDocSh->PostPaintGridAll(); |
2235 | 0 | pDocSh->SetDocumentModified(); |
2236 | 0 | } |
2237 | 0 | else if ( nCommand == SvxSearchCmd::FIND_ALL ) |
2238 | 0 | pDocSh->PostPaintGridAll(); // mark |
2239 | 0 | GetFrameWin()->LeaveWait(); |
2240 | 0 | } |
2241 | 0 | else if (bCursorMoved) |
2242 | 0 | { |
2243 | 0 | SetCursor(nOrigPosX, nOrigPosY, true); |
2244 | 0 | } |
2245 | 0 | return bFound; |
2246 | 0 | } |
2247 | | |
2248 | | // Goal Seek |
2249 | | |
2250 | | void ScViewFunc::Solve( const ScSolveParam& rParam ) |
2251 | 0 | { |
2252 | 0 | ScDocument& rDoc = GetViewData().GetDocument(); |
2253 | |
|
2254 | 0 | SCCOL nDestCol = rParam.aRefVariableCell.Col(); |
2255 | 0 | SCROW nDestRow = rParam.aRefVariableCell.Row(); |
2256 | 0 | SCTAB nDestTab = rParam.aRefVariableCell.Tab(); |
2257 | |
|
2258 | 0 | ScEditableTester aTester = ScEditableTester::CreateAndTestBlock(rDoc, nDestTab, nDestCol, nDestRow, nDestCol, nDestRow); |
2259 | 0 | if (!aTester.IsEditable()) |
2260 | 0 | { |
2261 | 0 | ErrorMessage(aTester.GetMessageId()); |
2262 | 0 | return; |
2263 | 0 | } |
2264 | | |
2265 | 0 | OUString aTargetValStr; |
2266 | 0 | if ( rParam.pStrTargetVal ) |
2267 | 0 | aTargetValStr = *rParam.pStrTargetVal; |
2268 | |
|
2269 | 0 | OUString aMsgStr; |
2270 | 0 | OUString aResStr; |
2271 | 0 | double nSolveResult; |
2272 | 0 | GetFrameWin()->EnterWait(); |
2273 | |
|
2274 | 0 | bool bExact = |
2275 | 0 | rDoc.Solver( |
2276 | 0 | rParam.aRefFormulaCell.Col(), |
2277 | 0 | rParam.aRefFormulaCell.Row(), |
2278 | 0 | rParam.aRefFormulaCell.Tab(), |
2279 | 0 | nDestCol, nDestRow, nDestTab, |
2280 | 0 | aTargetValStr, |
2281 | 0 | nSolveResult); |
2282 | |
|
2283 | 0 | GetFrameWin()->LeaveWait(); |
2284 | |
|
2285 | 0 | SvNumberFormatter* pFormatter = rDoc.GetFormatTable(); |
2286 | 0 | sal_uLong nFormat = 0; |
2287 | 0 | const ScPatternAttr* pPattern = rDoc.GetPattern( nDestCol, nDestRow, nDestTab ); |
2288 | 0 | if ( pPattern ) |
2289 | 0 | nFormat = pPattern->GetNumberFormat( pFormatter ); |
2290 | 0 | const Color* p; |
2291 | 0 | pFormatter->GetOutputString( nSolveResult, nFormat, aResStr, &p ); |
2292 | |
|
2293 | 0 | if ( bExact ) |
2294 | 0 | { |
2295 | 0 | aMsgStr += ScResId( STR_MSSG_SOLVE_0 ) + |
2296 | 0 | aResStr + |
2297 | 0 | ScResId( STR_MSSG_SOLVE_1 ); |
2298 | 0 | } |
2299 | 0 | else |
2300 | 0 | { |
2301 | 0 | aMsgStr = ScResId( STR_MSSG_SOLVE_2 ) + |
2302 | 0 | ScResId( STR_MSSG_SOLVE_3 ) + |
2303 | 0 | aResStr + |
2304 | 0 | ScResId( STR_MSSG_SOLVE_4 ); |
2305 | 0 | } |
2306 | |
|
2307 | 0 | std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetViewData().GetDialogParent(), |
2308 | 0 | VclMessageType::Question, VclButtonsType::YesNo, aMsgStr)); |
2309 | 0 | xBox->set_title(ScResId(STR_MSSG_DOSUBTOTALS_0)); |
2310 | 0 | xBox->set_default_response(RET_NO); |
2311 | 0 | int nResponse = xBox->run(); |
2312 | 0 | if (nResponse == RET_YES) |
2313 | 0 | EnterValue( nDestCol, nDestRow, nDestTab, nSolveResult ); |
2314 | |
|
2315 | 0 | GetViewData().GetViewShell()->UpdateInputHandler( true ); |
2316 | 0 | } |
2317 | | |
2318 | | // multi operation |
2319 | | |
2320 | | void ScViewFunc::TabOp( const ScTabOpParam& rParam, bool bRecord ) |
2321 | 0 | { |
2322 | 0 | ScRange aRange; |
2323 | 0 | if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE) |
2324 | 0 | { |
2325 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
2326 | 0 | ScMarkData& rMark = GetViewData().GetMarkData(); |
2327 | 0 | pDocSh->GetDocFunc().TabOp( aRange, &rMark, rParam, bRecord, false ); |
2328 | 0 | } |
2329 | 0 | else |
2330 | 0 | ErrorMessage(STR_NOMULTISELECT); |
2331 | 0 | } |
2332 | | |
2333 | | void ScViewFunc::MakeScenario( const OUString& rName, const OUString& rComment, |
2334 | | const Color& rColor, ScScenarioFlags nFlags ) |
2335 | 0 | { |
2336 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
2337 | 0 | ScMarkData& rMark = GetViewData().GetMarkData(); |
2338 | 0 | SCTAB nTab = GetViewData().CurrentTabForData(); |
2339 | |
|
2340 | 0 | SCTAB nNewTab = pDocSh->MakeScenario( nTab, rName, rComment, rColor, nFlags, rMark ); |
2341 | 0 | if (nFlags & ScScenarioFlags::CopyAll) |
2342 | 0 | SetTabNo( nNewTab, true ); // ScScenarioFlags::CopyAll -> visible |
2343 | 0 | else |
2344 | 0 | { |
2345 | 0 | SfxBindings& rBindings = GetViewData().GetBindings(); |
2346 | 0 | rBindings.Invalidate( SID_STATUS_DOCPOS ); // Statusbar |
2347 | 0 | rBindings.Invalidate( SID_ROWCOL_SELCOUNT ); // Statusbar |
2348 | 0 | rBindings.Invalidate( SID_TABLES_COUNT ); |
2349 | 0 | rBindings.Invalidate( SID_SELECT_SCENARIO ); |
2350 | 0 | rBindings.Invalidate( FID_TABLE_SHOW ); |
2351 | 0 | } |
2352 | 0 | } |
2353 | | |
2354 | | void ScViewFunc::ExtendScenario() |
2355 | 0 | { |
2356 | 0 | ScEditableTester aTester = ScEditableTester::CreateAndTestView(this); |
2357 | 0 | if (!aTester.IsEditable()) |
2358 | 0 | { |
2359 | 0 | ErrorMessage(aTester.GetMessageId()); |
2360 | 0 | return; |
2361 | 0 | } |
2362 | | |
2363 | | // Undo: apply attributes |
2364 | | |
2365 | 0 | ScDocument& rDoc = GetViewData().GetDocument(); |
2366 | 0 | ScPatternAttr aPattern(rDoc.getCellAttributeHelper()); |
2367 | 0 | aPattern.ItemSetPut(ScMergeFlagAttr(ScMF::Scenario)); |
2368 | 0 | aPattern.ItemSetPut(ScProtectionAttr(true)); |
2369 | 0 | ApplySelectionPattern(aPattern); |
2370 | 0 | } |
2371 | | |
2372 | | void ScViewFunc::UseScenario( const OUString& rName ) |
2373 | 0 | { |
2374 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
2375 | 0 | SCTAB nTab = GetViewData().CurrentTabForData(); |
2376 | |
|
2377 | 0 | DoneBlockMode(); |
2378 | 0 | InitOwnBlockMode( ScRange( GetViewData().GetCurX(), GetViewData().GetCurY(), nTab)); |
2379 | 0 | pDocSh->UseScenario( nTab, rName ); |
2380 | 0 | } |
2381 | | |
2382 | | // Insert table |
2383 | | |
2384 | | bool ScViewFunc::InsertTable( const OUString& rName, SCTAB nTab, bool bRecord ) |
2385 | 0 | { |
2386 | | // Order Table/Name is inverted for DocFunc |
2387 | 0 | bool bSuccess = GetViewData().GetDocShell()->GetDocFunc(). |
2388 | 0 | InsertTable( nTab, rName, bRecord, false ); |
2389 | 0 | if (bSuccess) |
2390 | 0 | SetTabNo( nTab, true ); |
2391 | |
|
2392 | 0 | return bSuccess; |
2393 | 0 | } |
2394 | | |
2395 | | // Insert tables |
2396 | | |
2397 | | void ScViewFunc::InsertTables(std::vector<OUString>& aNames, SCTAB nTab, |
2398 | | SCTAB nCount, bool bRecord ) |
2399 | 0 | { |
2400 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
2401 | 0 | ScDocument& rDoc = pDocSh->GetDocument(); |
2402 | 0 | if (bRecord && !rDoc.IsUndoEnabled()) |
2403 | 0 | bRecord = false; |
2404 | |
|
2405 | 0 | weld::WaitObject aWait(GetViewData().GetDialogParent()); |
2406 | |
|
2407 | 0 | if (bRecord) |
2408 | 0 | { |
2409 | 0 | rDoc.BeginDrawUndo(); // InsertTab creates a SdrUndoNewPage |
2410 | 0 | } |
2411 | |
|
2412 | 0 | bool bFlag=false; |
2413 | |
|
2414 | 0 | if(aNames.empty()) |
2415 | 0 | { |
2416 | 0 | rDoc.CreateValidTabNames(aNames, nCount); |
2417 | 0 | } |
2418 | 0 | if (rDoc.InsertTabs(nTab, aNames)) |
2419 | 0 | { |
2420 | 0 | pDocSh->Broadcast( ScTablesHint( SC_TABS_INSERTED, nTab, nCount ) ); |
2421 | 0 | bFlag = true; |
2422 | 0 | } |
2423 | |
|
2424 | 0 | if (!bFlag) |
2425 | 0 | return; |
2426 | | |
2427 | 0 | if (bRecord) |
2428 | 0 | pDocSh->GetUndoManager()->AddUndoAction( |
2429 | 0 | std::make_unique<ScUndoInsertTables>( *pDocSh, nTab, std::move(aNames))); |
2430 | | |
2431 | | // Update views |
2432 | |
|
2433 | 0 | SetTabNo( nTab, true ); |
2434 | 0 | pDocSh->PostPaintExtras(); |
2435 | 0 | pDocSh->SetDocumentModified(); |
2436 | 0 | SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) ); |
2437 | 0 | } |
2438 | | |
2439 | | bool ScViewFunc::AppendTable( const OUString& rName, bool bRecord ) |
2440 | 0 | { |
2441 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
2442 | 0 | ScDocument& rDoc = pDocSh->GetDocument(); |
2443 | 0 | if (bRecord && !rDoc.IsUndoEnabled()) |
2444 | 0 | bRecord = false; |
2445 | |
|
2446 | 0 | weld::WaitObject aWait(GetViewData().GetDialogParent()); |
2447 | |
|
2448 | 0 | if (bRecord) |
2449 | 0 | rDoc.BeginDrawUndo(); // InsertTab creates a SdrUndoNewPage |
2450 | |
|
2451 | 0 | if (rDoc.InsertTab( SC_TAB_APPEND, rName )) |
2452 | 0 | { |
2453 | 0 | SCTAB nTab = rDoc.GetTableCount()-1; |
2454 | 0 | if (bRecord) |
2455 | 0 | pDocSh->GetUndoManager()->AddUndoAction( |
2456 | 0 | std::make_unique<ScUndoInsertTab>( *pDocSh, nTab, true, rName)); |
2457 | 0 | GetViewData().InsertTab( nTab ); |
2458 | 0 | SetTabNo( nTab, true ); |
2459 | 0 | pDocSh->PostPaintExtras(); |
2460 | 0 | pDocSh->SetDocumentModified(); |
2461 | 0 | SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) ); |
2462 | 0 | return true; |
2463 | 0 | } |
2464 | 0 | else |
2465 | 0 | { |
2466 | 0 | return false; |
2467 | 0 | } |
2468 | 0 | } |
2469 | | |
2470 | | void ScViewFunc::DeleteTable( SCTAB nTab, bool bRecord ) |
2471 | 0 | { |
2472 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
2473 | 0 | ScDocument& rDoc = pDocSh->GetDocument(); |
2474 | |
|
2475 | 0 | bool bSuccess = pDocSh->GetDocFunc().DeleteTable( nTab, bRecord ); |
2476 | 0 | if (bSuccess) |
2477 | 0 | { |
2478 | 0 | SCTAB nNewTab = nTab; |
2479 | 0 | if ( nNewTab >= rDoc.GetTableCount() ) |
2480 | 0 | --nNewTab; |
2481 | 0 | SetTabNo( nNewTab, true ); |
2482 | 0 | } |
2483 | 0 | } |
2484 | | |
2485 | | //only use this method for undo for now, all sheets must be connected |
2486 | | //this method doesn't support undo for now, merge it when it with the other method later |
2487 | | void ScViewFunc::DeleteTables( const SCTAB nTab, SCTAB nSheets ) |
2488 | 0 | { |
2489 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
2490 | 0 | ScDocument& rDoc = pDocSh->GetDocument(); |
2491 | 0 | bool bVbaEnabled = rDoc.IsInVBAMode(); |
2492 | 0 | SCTAB nNewTab = nTab; |
2493 | 0 | weld::WaitObject aWait(GetViewData().GetDialogParent()); |
2494 | |
|
2495 | 0 | while ( nNewTab > 0 && !rDoc.IsVisible( nNewTab ) ) |
2496 | 0 | --nNewTab; |
2497 | |
|
2498 | 0 | if (!rDoc.DeleteTabs(nTab, nSheets)) |
2499 | 0 | return; |
2500 | | |
2501 | 0 | if( bVbaEnabled ) |
2502 | 0 | { |
2503 | 0 | for (SCTAB aTab = 0; aTab < nSheets; ++aTab) |
2504 | 0 | { |
2505 | 0 | OUString sCodeName; |
2506 | 0 | bool bHasCodeName = rDoc.GetCodeName( nTab + aTab, sCodeName ); |
2507 | 0 | if ( bHasCodeName ) |
2508 | 0 | VBA_DeleteModule( *pDocSh, sCodeName ); |
2509 | 0 | } |
2510 | 0 | } |
2511 | |
|
2512 | 0 | pDocSh->Broadcast( ScTablesHint( SC_TABS_DELETED, nTab, nSheets ) ); |
2513 | 0 | if ( nNewTab >= rDoc.GetTableCount() ) |
2514 | 0 | nNewTab = rDoc.GetTableCount() - 1; |
2515 | 0 | SetTabNo( nNewTab, true ); |
2516 | |
|
2517 | 0 | pDocSh->PostPaintExtras(); |
2518 | 0 | pDocSh->SetDocumentModified(); |
2519 | |
|
2520 | 0 | SfxApplication* pSfxApp = SfxGetpApp(); // Navigator |
2521 | 0 | pSfxApp->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) ); |
2522 | 0 | pSfxApp->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) ); |
2523 | 0 | pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); |
2524 | 0 | } |
2525 | | |
2526 | | bool ScViewFunc::DeleteTables(const std::vector<SCTAB>& rTabs, bool bRecord) |
2527 | 0 | { |
2528 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
2529 | 0 | ScDocument& rDoc = pDocSh->GetDocument(); |
2530 | 0 | bool bVbaEnabled = rDoc.IsInVBAMode(); |
2531 | 0 | SCTAB nNewTab = rTabs.front(); |
2532 | 0 | weld::WaitObject aWait(GetViewData().GetDialogParent()); |
2533 | 0 | if (bRecord && !rDoc.IsUndoEnabled()) |
2534 | 0 | bRecord = false; |
2535 | 0 | if ( bVbaEnabled ) |
2536 | 0 | bRecord = false; |
2537 | |
|
2538 | 0 | while ( nNewTab > 0 && !rDoc.IsVisible( nNewTab ) ) |
2539 | 0 | --nNewTab; |
2540 | |
|
2541 | 0 | bool bWasLinked = false; |
2542 | 0 | ScDocumentUniquePtr pUndoDoc; |
2543 | 0 | std::unique_ptr<ScRefUndoData> pUndoData; |
2544 | 0 | if (bRecord) |
2545 | 0 | { |
2546 | 0 | pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO )); |
2547 | 0 | SCTAB nCount = rDoc.GetTableCount(); |
2548 | |
|
2549 | 0 | OUString aOldName; |
2550 | 0 | bool isFirstTab = true; |
2551 | 0 | for (SCTAB nTab : rTabs) |
2552 | 0 | { |
2553 | 0 | if (isFirstTab) |
2554 | 0 | { |
2555 | 0 | pUndoDoc->InitUndo( rDoc, nTab,nTab, true,true ); // incl. column/fow flags |
2556 | 0 | isFirstTab = false; |
2557 | 0 | } |
2558 | 0 | else |
2559 | 0 | pUndoDoc->AddUndoTab( nTab,nTab, true,true ); // incl. column/fow flags |
2560 | |
|
2561 | 0 | rDoc.CopyToDocument(0,0,nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, InsertDeleteFlags::ALL,false, *pUndoDoc ); |
2562 | 0 | rDoc.GetName( nTab, aOldName ); |
2563 | 0 | pUndoDoc->RenameTab( nTab, aOldName ); |
2564 | 0 | if (rDoc.IsLinked(nTab)) |
2565 | 0 | { |
2566 | 0 | bWasLinked = true; |
2567 | 0 | pUndoDoc->SetLink( nTab, rDoc.GetLinkMode(nTab), rDoc.GetLinkDoc(nTab), |
2568 | 0 | rDoc.GetLinkFlt(nTab), rDoc.GetLinkOpt(nTab), |
2569 | 0 | rDoc.GetLinkTab(nTab), |
2570 | 0 | rDoc.GetLinkRefreshDelay(nTab) ); |
2571 | 0 | } |
2572 | 0 | if ( rDoc.IsScenario(nTab) ) |
2573 | 0 | { |
2574 | 0 | pUndoDoc->SetScenario( nTab, true ); |
2575 | 0 | OUString aComment; |
2576 | 0 | Color aColor; |
2577 | 0 | ScScenarioFlags nScenFlags; |
2578 | 0 | rDoc.GetScenarioData( nTab, aComment, aColor, nScenFlags ); |
2579 | 0 | pUndoDoc->SetScenarioData( nTab, aComment, aColor, nScenFlags ); |
2580 | 0 | bool bActive = rDoc.IsActiveScenario( nTab ); |
2581 | 0 | pUndoDoc->SetActiveScenario( nTab, bActive ); |
2582 | 0 | } |
2583 | 0 | pUndoDoc->SetVisible( nTab, rDoc.IsVisible( nTab ) ); |
2584 | 0 | pUndoDoc->SetTabBgColor( nTab, rDoc.GetTabBgColor(nTab) ); |
2585 | 0 | auto pSheetEvents = rDoc.GetSheetEvents( nTab ); |
2586 | 0 | pUndoDoc->SetSheetEvents( nTab, std::unique_ptr<ScSheetEvents>(pSheetEvents ? new ScSheetEvents(*pSheetEvents) : nullptr) ); |
2587 | 0 | pUndoDoc->SetLayoutRTL( nTab, rDoc.IsLayoutRTL( nTab ) ); |
2588 | |
|
2589 | 0 | if ( rDoc.IsTabProtected( nTab ) ) |
2590 | 0 | pUndoDoc->SetTabProtection(nTab, rDoc.GetTabProtection(nTab)); |
2591 | | |
2592 | | // Drawing-Layer is responsible for its Undo !!! |
2593 | | // pUndoDoc->TransferDrawPage(rDoc, nTab,nTab); |
2594 | 0 | } |
2595 | |
|
2596 | 0 | pUndoDoc->AddUndoTab( 0, nCount-1 ); // all Tabs for references |
2597 | |
|
2598 | 0 | rDoc.BeginDrawUndo(); // DeleteTab creates a SdrUndoDelPage |
2599 | |
|
2600 | 0 | pUndoData.reset(new ScRefUndoData( rDoc )); |
2601 | 0 | } |
2602 | |
|
2603 | 0 | bool bDelDone = false; |
2604 | |
|
2605 | 0 | std::vector<ScTable*> aSheetViewHolderTablesToDelete; |
2606 | |
|
2607 | 0 | for (sal_Int32 i = rTabs.size() - 1; i >= 0; --i) |
2608 | 0 | { |
2609 | 0 | SCTAB nTab = rTabs[i]; |
2610 | 0 | OUString sCodeName; |
2611 | 0 | bool bHasCodeName = rDoc.GetCodeName(nTab, sCodeName); |
2612 | | |
2613 | | // If we delete the current viewed table, make sure that we exit any sheet views |
2614 | 0 | if (GetViewData().GetTabNumber() == nTab && GetViewData().GetSheetViewID() != sc::DefaultSheetViewID) |
2615 | 0 | GetViewData().SetSheetViewID(sc::DefaultSheetViewID); |
2616 | |
|
2617 | 0 | if (auto pManager = rDoc.GetSheetViewManager(nTab)) |
2618 | 0 | { |
2619 | 0 | for (auto const& pSheetView : pManager->getSheetViews()) |
2620 | 0 | { |
2621 | 0 | aSheetViewHolderTablesToDelete.push_back(pSheetView->getTablePointer()); |
2622 | 0 | } |
2623 | 0 | } |
2624 | |
|
2625 | 0 | if (rDoc.DeleteTab(nTab)) |
2626 | 0 | { |
2627 | 0 | bDelDone = true; |
2628 | 0 | if( bVbaEnabled && bHasCodeName ) |
2629 | 0 | { |
2630 | 0 | VBA_DeleteModule( *pDocSh, sCodeName ); |
2631 | 0 | } |
2632 | 0 | pDocSh->Broadcast( ScTablesHint(SC_TAB_DELETED, nTab) ); |
2633 | 0 | } |
2634 | 0 | } |
2635 | | |
2636 | | // Delete sheet view holder tables if it's table has been deleted |
2637 | 0 | for (auto* pTable : aSheetViewHolderTablesToDelete) |
2638 | 0 | { |
2639 | 0 | SCTAB nTab = pTable->GetTab(); |
2640 | 0 | if (rDoc.DeleteTab(nTab)) |
2641 | 0 | { |
2642 | 0 | pDocSh->Broadcast(ScTablesHint(SC_TAB_DELETED, nTab)); |
2643 | 0 | } |
2644 | 0 | } |
2645 | |
|
2646 | 0 | if (bRecord) |
2647 | 0 | { |
2648 | 0 | pDocSh->GetUndoManager()->AddUndoAction( |
2649 | 0 | std::make_unique<ScUndoDeleteTab>( *GetViewData().GetDocShell(), rTabs, |
2650 | 0 | std::move(pUndoDoc), std::move(pUndoData) )); |
2651 | 0 | } |
2652 | |
|
2653 | 0 | if (bDelDone) |
2654 | 0 | { |
2655 | 0 | if ( nNewTab >= rDoc.GetTableCount() ) |
2656 | 0 | nNewTab = rDoc.GetTableCount() - 1; |
2657 | |
|
2658 | 0 | SetTabNo( nNewTab, true ); |
2659 | |
|
2660 | 0 | if (bWasLinked) |
2661 | 0 | { |
2662 | 0 | pDocSh->UpdateLinks(); // update Link-Manager |
2663 | 0 | GetViewData().GetBindings().Invalidate(SID_LINKS); |
2664 | 0 | } |
2665 | |
|
2666 | 0 | pDocSh->PostPaintExtras(); |
2667 | 0 | pDocSh->SetDocumentModified(); |
2668 | |
|
2669 | 0 | SfxApplication* pSfxApp = SfxGetpApp(); // Navigator |
2670 | 0 | pSfxApp->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) ); |
2671 | 0 | pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) ); |
2672 | 0 | pSfxApp->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) ); |
2673 | 0 | pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); |
2674 | 0 | } |
2675 | 0 | return bDelDone; |
2676 | 0 | } |
2677 | | |
2678 | | bool ScViewFunc::RenameTable( const OUString& rName, SCTAB nTab ) |
2679 | 0 | { |
2680 | | // order Table/Name is inverted for DocFunc |
2681 | 0 | bool bSuccess = GetViewData().GetDocShell()->GetDocFunc(). |
2682 | 0 | RenameTable( nTab, rName, true, false ); |
2683 | 0 | if (bSuccess) |
2684 | 0 | { |
2685 | | // the table name might be part of a formula |
2686 | 0 | GetViewData().GetViewShell()->UpdateInputHandler(); |
2687 | 0 | } |
2688 | 0 | return bSuccess; |
2689 | 0 | } |
2690 | | |
2691 | | bool ScViewFunc::SetTabBgColor( const Color& rColor, SCTAB nTab ) |
2692 | 0 | { |
2693 | 0 | bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().SetTabBgColor( nTab, rColor, true, false ); |
2694 | 0 | if (bSuccess) |
2695 | 0 | { |
2696 | 0 | GetViewData().GetViewShell()->UpdateInputHandler(); |
2697 | 0 | } |
2698 | 0 | return bSuccess; |
2699 | 0 | } |
2700 | | |
2701 | | bool ScViewFunc::SetTabBgColor( ScUndoTabColorInfo::List& rUndoSetTabBgColorInfoList ) |
2702 | 0 | { |
2703 | 0 | bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().SetTabBgColor( rUndoSetTabBgColorInfoList, false ); |
2704 | 0 | if (bSuccess) |
2705 | 0 | { |
2706 | 0 | GetViewData().GetViewShell()->UpdateInputHandler(); |
2707 | 0 | } |
2708 | 0 | return bSuccess; |
2709 | 0 | } |
2710 | | |
2711 | | void ScViewFunc::InsertAreaLink( const OUString& rFile, |
2712 | | const OUString& rFilter, const OUString& rOptions, |
2713 | | const OUString& rSource ) |
2714 | 0 | { |
2715 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
2716 | 0 | SCCOL nPosX = GetViewData().GetCurX(); |
2717 | 0 | SCROW nPosY = GetViewData().GetCurY(); |
2718 | 0 | SCTAB nTab = GetViewData().CurrentTabForData(); |
2719 | 0 | ScAddress aPos( nPosX, nPosY, nTab ); |
2720 | |
|
2721 | 0 | pDocSh->GetDocFunc().InsertAreaLink( rFile, rFilter, rOptions, rSource, ScRange(aPos), 0/*nRefresh*/, false, false ); |
2722 | 0 | } |
2723 | | |
2724 | | void ScViewFunc::InsertTableLink( const OUString& rFile, |
2725 | | const OUString& rFilter, const OUString& rOptions, |
2726 | | std::u16string_view rTabName ) |
2727 | 0 | { |
2728 | 0 | OUString aFilterName = rFilter; |
2729 | 0 | OUString aOpt = rOptions; |
2730 | 0 | ScDocumentLoader aLoader( rFile, aFilterName, aOpt ); |
2731 | 0 | if (aLoader.IsError()) |
2732 | 0 | return; |
2733 | | |
2734 | 0 | ScDocShell* pSrcSh = aLoader.GetDocShell(); |
2735 | 0 | ScDocument& rSrcDoc = pSrcSh->GetDocument(); |
2736 | 0 | SCTAB nTab = MAXTAB+1; |
2737 | 0 | if (rTabName.empty()) // no name given -> first table |
2738 | 0 | nTab = 0; |
2739 | 0 | else |
2740 | 0 | { |
2741 | 0 | OUString aTemp; |
2742 | 0 | SCTAB nCount = rSrcDoc.GetTableCount(); |
2743 | 0 | for (SCTAB i=0; i<nCount; i++) |
2744 | 0 | { |
2745 | 0 | rSrcDoc.GetName( i, aTemp ); |
2746 | 0 | if ( aTemp == rTabName ) |
2747 | 0 | nTab = i; |
2748 | 0 | } |
2749 | 0 | } |
2750 | |
|
2751 | 0 | if ( nTab <= MAXTAB ) |
2752 | 0 | ImportTables( pSrcSh, 1, &nTab, true, |
2753 | 0 | GetViewData().CurrentTabForData() ); |
2754 | 0 | } |
2755 | | |
2756 | | // Copy/link tables from another document |
2757 | | |
2758 | | void ScViewFunc::ImportTables( ScDocShell* pSrcShell, |
2759 | | SCTAB nCount, const SCTAB* pSrcTabs, bool bLink,SCTAB nTab ) |
2760 | 0 | { |
2761 | 0 | ScDocument& rSrcDoc = pSrcShell->GetDocument(); |
2762 | |
|
2763 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
2764 | 0 | ScDocument& rDoc = pDocSh->GetDocument(); |
2765 | 0 | bool bUndo(rDoc.IsUndoEnabled()); |
2766 | |
|
2767 | 0 | bool bError = false; |
2768 | |
|
2769 | 0 | if (rSrcDoc.GetDrawLayer()) |
2770 | 0 | pDocSh->MakeDrawLayer(); |
2771 | |
|
2772 | 0 | if (bUndo) |
2773 | 0 | rDoc.BeginDrawUndo(); // drawing layer must do its own undo actions |
2774 | |
|
2775 | 0 | SCTAB nInsCount = 0; |
2776 | 0 | SCTAB i; |
2777 | 0 | for( i=0; i<nCount; i++ ) |
2778 | 0 | { // insert sheets first and update all references |
2779 | 0 | OUString aName; |
2780 | 0 | rSrcDoc.GetName( pSrcTabs[i], aName ); |
2781 | 0 | rDoc.CreateValidTabName( aName ); |
2782 | 0 | if ( !rDoc.InsertTab( nTab+i, aName ) ) |
2783 | 0 | { |
2784 | 0 | bError = true; // total error |
2785 | 0 | break; // for |
2786 | 0 | } |
2787 | 0 | ++nInsCount; |
2788 | 0 | } |
2789 | 0 | for (i=0; i<nCount && !bError; i++) |
2790 | 0 | { |
2791 | 0 | SCTAB nSrcTab = pSrcTabs[i]; |
2792 | 0 | SCTAB nDestTab1=nTab+i; |
2793 | 0 | bool bValid = pDocSh->TransferTab( *pSrcShell, nSrcTab, nDestTab1, |
2794 | 0 | false, false ); // no insert |
2795 | |
|
2796 | 0 | if (!bValid) |
2797 | 0 | { |
2798 | 0 | bError = true; |
2799 | 0 | } |
2800 | |
|
2801 | 0 | } |
2802 | |
|
2803 | 0 | if (bLink) |
2804 | 0 | { |
2805 | 0 | sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager(); |
2806 | |
|
2807 | 0 | SfxMedium* pMed = pSrcShell->GetMedium(); |
2808 | 0 | OUString aFileName = pMed->GetName(); |
2809 | 0 | OUString aFilterName; |
2810 | 0 | if (pMed->GetFilter()) |
2811 | 0 | aFilterName = pMed->GetFilter()->GetFilterName(); |
2812 | 0 | OUString aOptions = ScDocumentLoader::GetOptions(*pMed); |
2813 | |
|
2814 | 0 | bool bWasThere = rDoc.HasLink( aFileName, aFilterName, aOptions ); |
2815 | |
|
2816 | 0 | sal_uLong nRefresh = 0; |
2817 | 0 | OUString aTabStr; |
2818 | 0 | for (i=0; i<nInsCount; i++) |
2819 | 0 | { |
2820 | 0 | rSrcDoc.GetName( pSrcTabs[i], aTabStr ); |
2821 | 0 | rDoc.SetLink( nTab+i, ScLinkMode::NORMAL, |
2822 | 0 | aFileName, aFilterName, aOptions, aTabStr, nRefresh ); |
2823 | 0 | } |
2824 | |
|
2825 | 0 | if (!bWasThere) // Insert link only once per source document |
2826 | 0 | { |
2827 | 0 | ScTableLink* pLink = new ScTableLink( *pDocSh, aFileName, aFilterName, aOptions, nRefresh ); |
2828 | 0 | pLink->SetInCreate( true ); |
2829 | 0 | pLinkManager->InsertFileLink( *pLink, sfx2::SvBaseLinkObjectType::ClientFile, aFileName, &aFilterName ); |
2830 | 0 | pLink->Update(); |
2831 | 0 | pLink->SetInCreate( false ); |
2832 | |
|
2833 | 0 | SfxBindings& rBindings = GetViewData().GetBindings(); |
2834 | 0 | rBindings.Invalidate( SID_LINKS ); |
2835 | 0 | } |
2836 | 0 | } |
2837 | |
|
2838 | 0 | if (bUndo) |
2839 | 0 | { |
2840 | 0 | pDocSh->GetUndoManager()->AddUndoAction( |
2841 | 0 | std::make_unique<ScUndoImportTab>( *pDocSh, nTab, nCount ) ); |
2842 | 0 | } |
2843 | |
|
2844 | 0 | for (i=0; i<nInsCount; i++) |
2845 | 0 | GetViewData().InsertTab(nTab); |
2846 | 0 | SetTabNo(nTab,true); |
2847 | 0 | pDocSh->PostPaint( 0,0,0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB, |
2848 | 0 | PaintPartFlags::Grid | PaintPartFlags::Top | PaintPartFlags::Left | PaintPartFlags::Extras ); |
2849 | |
|
2850 | 0 | SfxApplication* pSfxApp = SfxGetpApp(); |
2851 | 0 | pSfxApp->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) ); |
2852 | 0 | pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) ); |
2853 | |
|
2854 | 0 | pDocSh->PostPaintExtras(); |
2855 | 0 | pDocSh->PostPaintGridAll(); |
2856 | 0 | pDocSh->SetDocumentModified(); |
2857 | 0 | } |
2858 | | |
2859 | | // Move/Copy table to another document |
2860 | | |
2861 | | void ScViewFunc::MoveTable(sal_uInt16 nDestDocNo, SCTAB nDestTab, bool bCopy, |
2862 | | const OUString* pNewTabName, bool bContextMenu, |
2863 | | SCTAB nContextMenuSourceTab) |
2864 | 0 | { |
2865 | 0 | ScDocument& rDoc = GetViewData().GetDocument(); |
2866 | 0 | ScDocShell* pDocShell = GetViewData().GetDocShell(); |
2867 | 0 | ScDocShell* pDestShell = nullptr; |
2868 | 0 | ScTabViewShell* pDestViewSh = nullptr; |
2869 | 0 | bool bUndo (rDoc.IsUndoEnabled()); |
2870 | 0 | bool bRename = pNewTabName && !pNewTabName->isEmpty(); |
2871 | |
|
2872 | 0 | bool bNewDoc = (nDestDocNo == SC_DOC_NEW); |
2873 | 0 | if ( bNewDoc ) |
2874 | 0 | { |
2875 | 0 | nDestTab = 0; // firstly insert |
2876 | | |
2877 | | // execute without SfxCallMode::RECORD, because already contained in move command |
2878 | |
|
2879 | 0 | SfxStringItem aItem( SID_FILE_NAME, "private:factory/" + STRING_SCAPP ); |
2880 | 0 | SfxStringItem aTarget( SID_TARGETNAME, u"_blank"_ustr ); |
2881 | |
|
2882 | 0 | const SfxPoolItemHolder aResult(GetViewData().GetDispatcher().ExecuteList( |
2883 | 0 | SID_OPENDOC, SfxCallMode::API|SfxCallMode::SYNCHRON, |
2884 | 0 | { &aItem, &aTarget })); |
2885 | |
|
2886 | 0 | if (aResult) |
2887 | 0 | { |
2888 | 0 | if ( auto pObjectItem = dynamic_cast<const SfxObjectItem*>(aResult.getItem()) ) |
2889 | 0 | pDestShell = dynamic_cast<ScDocShell*>( pObjectItem->GetShell() ); |
2890 | 0 | else if ( auto pViewFrameItem = dynamic_cast<const SfxViewFrameItem*>(aResult.getItem())) |
2891 | 0 | { |
2892 | 0 | SfxViewFrame* pFrm = pViewFrameItem->GetFrame(); |
2893 | 0 | if (pFrm) |
2894 | 0 | pDestShell = dynamic_cast<ScDocShell*>( pFrm->GetObjectShell() ); |
2895 | 0 | } |
2896 | 0 | if (pDestShell) |
2897 | 0 | pDestViewSh = pDestShell->GetBestViewShell(); |
2898 | 0 | } |
2899 | 0 | } |
2900 | 0 | else |
2901 | 0 | pDestShell = ScDocShell::GetShellByNum( nDestDocNo ); |
2902 | |
|
2903 | 0 | if (!pDestShell) |
2904 | 0 | { |
2905 | 0 | OSL_FAIL("Destination document not found !!!"); |
2906 | 0 | return; |
2907 | 0 | } |
2908 | | |
2909 | 0 | ScMarkData& rMark = GetViewData().GetMarkData(); |
2910 | 0 | if (bRename && rMark.GetSelectCount() != 1) |
2911 | 0 | { |
2912 | | // Custom sheet name is provided, but more than one sheet is selected. |
2913 | | // We don't support this scenario at the moment. |
2914 | 0 | return; |
2915 | 0 | } |
2916 | | |
2917 | 0 | ScDocument& rDestDoc = pDestShell->GetDocument(); |
2918 | |
|
2919 | 0 | if (&rDestDoc != &rDoc) |
2920 | 0 | { |
2921 | 0 | if (bNewDoc) |
2922 | 0 | { |
2923 | 0 | while (rDestDoc.GetTableCount() > 1) |
2924 | 0 | rDestDoc.DeleteTab(0); |
2925 | 0 | rDestDoc.RenameTab( 0, u"______42_____"_ustr ); |
2926 | 0 | } |
2927 | |
|
2928 | 0 | SCTAB nTabCount = rDoc.GetTableCount(); |
2929 | 0 | SCTAB nTabSelCount = rMark.GetSelectCount(); |
2930 | |
|
2931 | 0 | std::vector<SCTAB> TheTabs; |
2932 | |
|
2933 | 0 | for(SCTAB i=0; i<nTabCount; ++i) |
2934 | 0 | { |
2935 | 0 | if(rMark.GetTableSelect(i)) |
2936 | 0 | { |
2937 | 0 | OUString aTabName; |
2938 | 0 | rDoc.GetName( i, aTabName); |
2939 | 0 | TheTabs.push_back(i); |
2940 | 0 | for(SCTAB j=i+1;j<nTabCount;j++) |
2941 | 0 | { |
2942 | 0 | if((!rDoc.IsVisible(j)) && rDoc.IsScenario(j)) |
2943 | 0 | { |
2944 | 0 | rDoc.GetName( j, aTabName); |
2945 | 0 | TheTabs.push_back(j); |
2946 | 0 | i=j; |
2947 | 0 | } |
2948 | 0 | else break; |
2949 | 0 | } |
2950 | 0 | } |
2951 | 0 | } |
2952 | |
|
2953 | 0 | GetFrameWin()->EnterWait(); |
2954 | |
|
2955 | 0 | if (rDoc.GetDrawLayer()) |
2956 | 0 | pDestShell->MakeDrawLayer(); |
2957 | |
|
2958 | 0 | if (!bNewDoc && bUndo) |
2959 | 0 | rDestDoc.BeginDrawUndo(); // drawing layer must do its own undo actions |
2960 | |
|
2961 | 0 | bool bValid = true; |
2962 | 0 | if(nDestTab==SC_TAB_APPEND) |
2963 | 0 | nDestTab=rDestDoc.GetTableCount(); |
2964 | 0 | SCTAB nDestTab1=nDestTab; |
2965 | 0 | ScClipParam aParam; |
2966 | 0 | for( size_t j=0; j<TheTabs.size(); ++j, ++nDestTab1 ) |
2967 | 0 | { // insert sheets first and update all references |
2968 | 0 | OUString aName; |
2969 | 0 | if (bRename) |
2970 | 0 | aName = *pNewTabName; |
2971 | 0 | else |
2972 | 0 | rDoc.GetName( TheTabs[j], aName ); |
2973 | |
|
2974 | 0 | rDestDoc.CreateValidTabName( aName ); |
2975 | 0 | if ( !rDestDoc.InsertTab( nDestTab1, aName ) ) |
2976 | 0 | { |
2977 | 0 | bValid = false; // total error |
2978 | 0 | break; // for |
2979 | 0 | } |
2980 | 0 | ScRange aRange( 0, 0, TheTabs[j], rDoc.MaxCol(), rDoc.MaxRow(), TheTabs[j] ); |
2981 | 0 | aParam.maRanges.push_back(aRange); |
2982 | 0 | } |
2983 | 0 | rDoc.SetClipParam(aParam); |
2984 | 0 | if ( bValid ) |
2985 | 0 | { |
2986 | 0 | nDestTab1 = nDestTab; |
2987 | 0 | for(SCTAB nTab : TheTabs) |
2988 | 0 | { |
2989 | 0 | bValid = pDestShell->TransferTab( *pDocShell, nTab, nDestTab1, false, false ); |
2990 | 0 | nDestTab1++; |
2991 | 0 | } |
2992 | 0 | } |
2993 | 0 | if (!bNewDoc && bUndo) |
2994 | 0 | { |
2995 | 0 | OUString sName; |
2996 | 0 | rDestDoc.GetName(nDestTab, sName); |
2997 | 0 | pDestShell->GetUndoManager()->AddUndoAction( |
2998 | 0 | std::make_unique<ScUndoImportTab>( *pDestShell, nDestTab, |
2999 | 0 | static_cast<SCTAB>(TheTabs.size()))); |
3000 | |
|
3001 | 0 | } |
3002 | 0 | else |
3003 | 0 | { |
3004 | 0 | pDestShell->GetUndoManager()->Clear(); |
3005 | 0 | } |
3006 | |
|
3007 | 0 | GetFrameWin()->LeaveWait(); |
3008 | |
|
3009 | 0 | if (!bValid) |
3010 | 0 | { |
3011 | 0 | ErrorMessage(STR_TABINSERT_ERROR); |
3012 | 0 | return; |
3013 | 0 | } |
3014 | | |
3015 | 0 | if (!bCopy) |
3016 | 0 | { |
3017 | 0 | if(nTabCount!=nTabSelCount) |
3018 | 0 | DeleteTables(TheTabs); // incl. Paint & Undo |
3019 | 0 | else |
3020 | 0 | ErrorMessage(STR_TABREMOVE_ERROR); |
3021 | 0 | } |
3022 | |
|
3023 | 0 | if (bNewDoc) |
3024 | 0 | { |
3025 | | // ChartListenerCollection must be updated before DeleteTab |
3026 | 0 | if ( rDestDoc.IsChartListenerCollectionNeedsUpdate() ) |
3027 | 0 | rDestDoc.UpdateChartListenerCollection(); |
3028 | |
|
3029 | 0 | SCTAB nNumTabsInserted = static_cast<SCTAB>(TheTabs.size()); |
3030 | 0 | pDestShell->Broadcast( ScTablesHint( SC_TABS_INSERTED, 0, nNumTabsInserted ) ); |
3031 | |
|
3032 | 0 | rDestDoc.DeleteTab( nNumTabsInserted ); // old first table |
3033 | 0 | pDestShell->Broadcast( ScTablesHint( SC_TAB_DELETED, nNumTabsInserted ) ); |
3034 | |
|
3035 | 0 | if (pDestViewSh) |
3036 | 0 | { |
3037 | | // Make sure to clear the cached page view after sheet |
3038 | | // deletion, which still points to the sdr page belonging to |
3039 | | // the deleted sheet. |
3040 | 0 | SdrView* pSdrView = pDestViewSh->GetScDrawView(); |
3041 | 0 | if (pSdrView) |
3042 | 0 | pSdrView->ClearPageView(); |
3043 | |
|
3044 | 0 | pDestViewSh->TabChanged(); // pages on the drawing layer |
3045 | 0 | } |
3046 | 0 | pDestShell->PostPaint( 0,0,0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB, |
3047 | 0 | PaintPartFlags::Grid | PaintPartFlags::Top | PaintPartFlags::Left | |
3048 | 0 | PaintPartFlags::Extras | PaintPartFlags::Size ); |
3049 | | // PaintPartFlags::Size for outline |
3050 | 0 | } |
3051 | 0 | else |
3052 | 0 | { |
3053 | 0 | pDestShell->Broadcast( ScTablesHint( SC_TAB_INSERTED, nDestTab ) ); |
3054 | 0 | pDestShell->PostPaintExtras(); |
3055 | 0 | pDestShell->PostPaintGridAll(); |
3056 | 0 | } |
3057 | |
|
3058 | 0 | TheTabs.clear(); |
3059 | |
|
3060 | 0 | pDestShell->SetDocumentModified(); |
3061 | 0 | SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) ); |
3062 | 0 | } |
3063 | 0 | else |
3064 | 0 | { |
3065 | | // Move or copy within the same document. |
3066 | 0 | SCTAB nTabCount = rDoc.GetTableCount(); |
3067 | |
|
3068 | 0 | std::unique_ptr<std::vector<SCTAB>> pSrcTabs(new std::vector<SCTAB>); |
3069 | 0 | std::unique_ptr<std::vector<SCTAB>> pDestTabs(new std::vector<SCTAB>); |
3070 | 0 | std::unique_ptr<std::vector<OUString>> pTabNames(new std::vector<OUString>); |
3071 | 0 | std::unique_ptr<std::vector<OUString>> pDestNames; |
3072 | 0 | pSrcTabs->reserve(nTabCount); |
3073 | 0 | pDestTabs->reserve(nTabCount); |
3074 | 0 | pTabNames->reserve(nTabCount); |
3075 | 0 | OUString aDestName; |
3076 | |
|
3077 | 0 | if (bContextMenu) |
3078 | 0 | { |
3079 | 0 | OUString aTabName; |
3080 | 0 | rDoc.GetName(nContextMenuSourceTab, aTabName); |
3081 | 0 | pTabNames->push_back(aTabName); |
3082 | 0 | } |
3083 | 0 | else |
3084 | 0 | { |
3085 | 0 | for(SCTAB i=0;i<nTabCount;i++) |
3086 | 0 | { |
3087 | 0 | if(rMark.GetTableSelect(i)) |
3088 | 0 | { |
3089 | 0 | OUString aTabName; |
3090 | 0 | rDoc.GetName( i, aTabName); |
3091 | 0 | pTabNames->push_back(aTabName); |
3092 | |
|
3093 | 0 | for(SCTAB j=i+1;j<nTabCount;j++) |
3094 | 0 | { |
3095 | 0 | if((!rDoc.IsVisible(j)) && rDoc.IsScenario(j)) |
3096 | 0 | { |
3097 | 0 | rDoc.GetName( j, aTabName); |
3098 | 0 | pTabNames->push_back(aTabName); |
3099 | 0 | i=j; |
3100 | 0 | } |
3101 | 0 | else break; |
3102 | 0 | } |
3103 | 0 | } |
3104 | 0 | } |
3105 | 0 | } |
3106 | |
|
3107 | 0 | if (bCopy && bUndo) |
3108 | 0 | rDoc.BeginDrawUndo(); // drawing layer must do its own undo actions |
3109 | |
|
3110 | 0 | rDoc.GetName( nDestTab, aDestName); |
3111 | 0 | SCTAB nDestTab1=nDestTab; |
3112 | 0 | SCTAB nMovTab=0; |
3113 | 0 | for (size_t j = 0, n = pTabNames->size(); j < n; ++j) |
3114 | 0 | { |
3115 | 0 | nTabCount = rDoc.GetTableCount(); |
3116 | 0 | const OUString& rStr = (*pTabNames)[j]; |
3117 | 0 | if(!rDoc.GetTable(rStr,nMovTab)) |
3118 | 0 | { |
3119 | 0 | nMovTab=nTabCount; |
3120 | 0 | } |
3121 | 0 | if(!rDoc.GetTable(aDestName,nDestTab1)) |
3122 | 0 | { |
3123 | 0 | nDestTab1=nTabCount; |
3124 | 0 | } |
3125 | 0 | pDocShell->MoveTable( nMovTab, nDestTab1, bCopy, false ); // Undo is here |
3126 | | |
3127 | | // tdf#43175 - Adjust chart references on every copied sheet |
3128 | 0 | if (bCopy) |
3129 | 0 | { |
3130 | | // New position of source table after moving |
3131 | 0 | SCTAB nSrcTab = (nDestTab1 <= nMovTab) ? nMovTab + 1 : nMovTab; |
3132 | | //#i29848# adjust references to data on the copied sheet |
3133 | 0 | ScChartHelper::AdjustRangesOfChartsOnDestinationPage(rDoc, rDestDoc, nSrcTab, |
3134 | 0 | nDestTab1); |
3135 | 0 | } |
3136 | |
|
3137 | 0 | if(bCopy && rDoc.IsScenario(nMovTab)) |
3138 | 0 | { |
3139 | 0 | OUString aComment; |
3140 | 0 | Color aColor; |
3141 | 0 | ScScenarioFlags nFlags; |
3142 | |
|
3143 | 0 | rDoc.GetScenarioData(nMovTab, aComment,aColor, nFlags); |
3144 | 0 | rDoc.SetScenario(nDestTab1,true); |
3145 | 0 | rDoc.SetScenarioData(nDestTab1,aComment,aColor,nFlags); |
3146 | 0 | bool bActive = rDoc.IsActiveScenario(nMovTab ); |
3147 | 0 | rDoc.SetActiveScenario( nDestTab1, bActive ); |
3148 | 0 | bool bVisible=rDoc.IsVisible(nMovTab); |
3149 | 0 | rDoc.SetVisible(nDestTab1,bVisible ); |
3150 | 0 | } |
3151 | |
|
3152 | 0 | pSrcTabs->push_back(nMovTab); |
3153 | |
|
3154 | 0 | if(!bCopy) |
3155 | 0 | { |
3156 | 0 | if(!rDoc.GetTable(rStr,nDestTab1)) |
3157 | 0 | { |
3158 | 0 | nDestTab1=nTabCount; |
3159 | 0 | } |
3160 | 0 | } |
3161 | |
|
3162 | 0 | pDestTabs->push_back(nDestTab1); |
3163 | 0 | } |
3164 | | |
3165 | | // Rename must be done after all sheets have been moved. |
3166 | 0 | if (bRename) |
3167 | 0 | { |
3168 | 0 | pDestNames.reset(new std::vector<OUString>); |
3169 | 0 | size_t n = pDestTabs->size(); |
3170 | 0 | pDestNames->reserve(n); |
3171 | 0 | for (size_t j = 0; j < n; ++j) |
3172 | 0 | { |
3173 | 0 | SCTAB nRenameTab = (*pDestTabs)[j]; |
3174 | 0 | OUString aTabName = *pNewTabName; |
3175 | 0 | rDoc.CreateValidTabName( aTabName ); |
3176 | 0 | pDestNames->push_back(aTabName); |
3177 | 0 | rDoc.RenameTab(nRenameTab, aTabName); |
3178 | 0 | } |
3179 | 0 | } |
3180 | 0 | else |
3181 | | // No need to keep this around when we are not renaming. |
3182 | 0 | pTabNames.reset(); |
3183 | |
|
3184 | 0 | SCTAB nTab = GetViewData().CurrentTabForData(); |
3185 | |
|
3186 | 0 | if (comphelper::LibreOfficeKit::isActive() && !pSrcTabs->empty()) |
3187 | 0 | { |
3188 | 0 | ScModelObj* pModel = pDocShell->GetModel(); |
3189 | 0 | SfxLokHelper::notifyDocumentSizeChangedAllViews(pModel); |
3190 | 0 | } |
3191 | |
|
3192 | 0 | if (bUndo) |
3193 | 0 | { |
3194 | 0 | if (bCopy) |
3195 | 0 | { |
3196 | 0 | pDocShell->GetUndoManager()->AddUndoAction( |
3197 | 0 | std::make_unique<ScUndoCopyTab>( |
3198 | 0 | *pDocShell, std::move(pSrcTabs), std::move(pDestTabs), std::move(pDestNames))); |
3199 | 0 | } |
3200 | 0 | else |
3201 | 0 | { |
3202 | 0 | pDocShell->GetUndoManager()->AddUndoAction( |
3203 | 0 | std::make_unique<ScUndoMoveTab>( |
3204 | 0 | *pDocShell, std::move(pSrcTabs), std::move(pDestTabs), std::move(pTabNames), std::move(pDestNames))); |
3205 | 0 | } |
3206 | 0 | } |
3207 | |
|
3208 | 0 | if (bContextMenu) |
3209 | 0 | { |
3210 | 0 | for (SCTAB i = 0; i < nTabCount; i++) |
3211 | 0 | { |
3212 | 0 | if (rMark.GetTableSelect(i)) |
3213 | 0 | SetTabNo(i, true); |
3214 | 0 | } |
3215 | 0 | } |
3216 | 0 | else |
3217 | 0 | { |
3218 | 0 | SCTAB nNewTab = nDestTab; |
3219 | 0 | if (nNewTab == SC_TAB_APPEND) |
3220 | 0 | nNewTab = rDoc.GetTableCount() - 1; |
3221 | 0 | else if (!bCopy && nTab < nDestTab) |
3222 | 0 | nNewTab--; |
3223 | |
|
3224 | 0 | SetTabNo(nNewTab, true); |
3225 | 0 | } |
3226 | 0 | } |
3227 | 0 | } |
3228 | | |
3229 | | void ScViewFunc::ShowTable( const std::vector<OUString>& rNames ) |
3230 | 0 | { |
3231 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
3232 | 0 | ScDocument& rDoc = pDocSh->GetDocument(); |
3233 | 0 | bool bUndo(rDoc.IsUndoEnabled()); |
3234 | |
|
3235 | 0 | std::vector<SCTAB> undoTabs; |
3236 | 0 | SCTAB nPos = 0; |
3237 | |
|
3238 | 0 | bool bFound(false); |
3239 | |
|
3240 | 0 | for (const OUString& aName : rNames) |
3241 | 0 | { |
3242 | 0 | if (rDoc.GetTable(aName, nPos)) |
3243 | 0 | { |
3244 | 0 | rDoc.SetVisible( nPos, true ); |
3245 | 0 | SetTabNo( nPos, true ); |
3246 | 0 | SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) ); |
3247 | 0 | if (!bFound) |
3248 | 0 | bFound = true; |
3249 | 0 | if (bUndo) |
3250 | 0 | undoTabs.push_back(nPos); |
3251 | 0 | } |
3252 | 0 | } |
3253 | 0 | if (bFound) |
3254 | 0 | { |
3255 | 0 | if (bUndo) |
3256 | 0 | { |
3257 | 0 | pDocSh->GetUndoManager()->AddUndoAction( std::make_unique<ScUndoShowHideTab>( *pDocSh, std::move(undoTabs), true ) ); |
3258 | 0 | } |
3259 | 0 | pDocSh->PostPaint(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Extras); |
3260 | 0 | pDocSh->SetDocumentModified(); |
3261 | 0 | } |
3262 | 0 | } |
3263 | | |
3264 | | void ScViewFunc::HideTable( const ScMarkData& rMark, SCTAB nTabToSelect ) |
3265 | 0 | { |
3266 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
3267 | 0 | ScDocument& rDoc = pDocSh->GetDocument(); |
3268 | 0 | bool bUndo(rDoc.IsUndoEnabled()); |
3269 | 0 | SCTAB nVisible = 0; |
3270 | 0 | SCTAB nTabCount = rDoc.GetTableCount(); |
3271 | |
|
3272 | 0 | SCTAB nTabSelCount = rMark.GetSelectCount(); |
3273 | | |
3274 | | // check to make sure we won't hide all sheets. we need at least one visible at all times. |
3275 | 0 | for ( SCTAB i=0; i < nTabCount && nVisible <= nTabSelCount ; i++ ) |
3276 | 0 | if (rDoc.IsVisible(i)) |
3277 | 0 | ++nVisible; |
3278 | |
|
3279 | 0 | if (nVisible <= nTabSelCount) |
3280 | 0 | return; |
3281 | | |
3282 | 0 | std::vector<SCTAB> undoTabs; |
3283 | | |
3284 | | // need to take a copy of selectedtabs since it is modified in the loop |
3285 | 0 | const ScMarkData::MarkedTabsType selectedTabs = rMark.GetSelectedTabs(); |
3286 | 0 | for (const SCTAB& nTab : selectedTabs) |
3287 | 0 | { |
3288 | 0 | if (rDoc.IsVisible( nTab )) |
3289 | 0 | { |
3290 | 0 | rDoc.SetVisible( nTab, false ); |
3291 | | // Update views |
3292 | 0 | pDocSh->Broadcast( ScTablesHint( SC_TAB_HIDDEN, nTab ) ); |
3293 | 0 | SetTabNo( nTab, true ); |
3294 | | // Store for undo |
3295 | 0 | if (bUndo) |
3296 | 0 | undoTabs.push_back(nTab); |
3297 | 0 | } |
3298 | 0 | } |
3299 | |
|
3300 | 0 | if (nTabToSelect != -1) |
3301 | 0 | SetTabNo(nTabToSelect); |
3302 | |
|
3303 | 0 | if (bUndo) |
3304 | 0 | { |
3305 | 0 | pDocSh->GetUndoManager()->AddUndoAction( std::make_unique<ScUndoShowHideTab>( *pDocSh, std::move(undoTabs), false ) ); |
3306 | 0 | } |
3307 | | |
3308 | | // Update views |
3309 | 0 | SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) ); |
3310 | 0 | pDocSh->PostPaint(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Extras); |
3311 | 0 | pDocSh->SetDocumentModified(); |
3312 | 0 | } |
3313 | | |
3314 | | void ScViewFunc::InsertSpecialChar( const OUString& rStr, const vcl::Font& rFont ) |
3315 | 0 | { |
3316 | 0 | ScEditableTester aTester = ScEditableTester::CreateAndTestView(this); |
3317 | 0 | if (!aTester.IsEditable()) |
3318 | 0 | { |
3319 | 0 | ErrorMessage(aTester.GetMessageId()); |
3320 | 0 | return; |
3321 | 0 | } |
3322 | | |
3323 | 0 | const sal_Unicode* pChar = rStr.getStr(); |
3324 | 0 | ScTabViewShell* pViewShell = GetViewData().GetViewShell(); |
3325 | 0 | SvxFontItem aFontItem( rFont.GetFamilyType(), |
3326 | 0 | rFont.GetFamilyName(), |
3327 | 0 | rFont.GetStyleName(), |
3328 | 0 | rFont.GetPitch(), |
3329 | 0 | rFont.GetCharSet(), |
3330 | 0 | ATTR_FONT ); |
3331 | | |
3332 | | // if string contains WEAK characters, set all fonts |
3333 | 0 | SvtScriptType nScript; |
3334 | 0 | ScDocument& rDoc = GetViewData().GetDocument(); |
3335 | 0 | if ( rDoc.HasStringWeakCharacters( rStr ) ) |
3336 | 0 | nScript = SvtScriptType::LATIN | SvtScriptType::ASIAN | SvtScriptType::COMPLEX; |
3337 | 0 | else |
3338 | 0 | nScript = rDoc.GetStringScriptType( rStr ); |
3339 | |
|
3340 | 0 | SvxScriptSetItem aSetItem( SID_ATTR_CHAR_FONT, pViewShell->GetPool() ); |
3341 | 0 | aSetItem.PutItemForScriptType( nScript, aFontItem ); |
3342 | 0 | ApplyUserItemSet( aSetItem.GetItemSet() ); |
3343 | |
|
3344 | 0 | while ( *pChar ) |
3345 | 0 | pViewShell->TabKeyInput( KeyEvent( *(pChar++), vcl::KeyCode() ) ); |
3346 | 0 | } |
3347 | | |
3348 | | void ScViewFunc::UpdateLineAttrs( SvxBorderLine& rLine, |
3349 | | const SvxBorderLine* pDestLine, |
3350 | | const SvxBorderLine* pSrcLine, |
3351 | | bool bColor ) |
3352 | 0 | { |
3353 | 0 | if ( !(pSrcLine && pDestLine) ) |
3354 | 0 | return; |
3355 | | |
3356 | 0 | if ( bColor ) |
3357 | 0 | { |
3358 | 0 | rLine.SetColor ( pSrcLine->GetColor() ); |
3359 | 0 | rLine.SetBorderLineStyle(pDestLine->GetBorderLineStyle()); |
3360 | 0 | rLine.SetWidth ( pDestLine->GetWidth() ); |
3361 | 0 | } |
3362 | 0 | else |
3363 | 0 | { |
3364 | 0 | rLine.SetColor ( pDestLine->GetColor() ); |
3365 | 0 | rLine.SetBorderLineStyle(pSrcLine->GetBorderLineStyle()); |
3366 | 0 | rLine.SetWidth ( pSrcLine->GetWidth() ); |
3367 | 0 | } |
3368 | 0 | } |
3369 | | |
3370 | | #define SET_LINE_ATTRIBUTES(LINE,BOXLINE) \ |
3371 | 0 | pBoxLine = aBoxItem.Get##LINE(); \ |
3372 | 0 | if ( pBoxLine ) \ |
3373 | 0 | { \ |
3374 | 0 | if ( pLine ) \ |
3375 | 0 | { \ |
3376 | 0 | UpdateLineAttrs( aLine, pBoxLine, pLine, bColorOnly ); \ |
3377 | 0 | aBoxItem.SetLine( &aLine, BOXLINE ); \ |
3378 | 0 | } \ |
3379 | 0 | else \ |
3380 | 0 | aBoxItem.SetLine( nullptr, BOXLINE ); \ |
3381 | 0 | } |
3382 | | |
3383 | | void ScViewFunc::SetSelectionFrameLines( const SvxBorderLine* pLine, |
3384 | | bool bColorOnly ) |
3385 | 0 | { |
3386 | | // Not editable only due to a matrix? Attribute is ok anyhow. |
3387 | 0 | bool bOnlyNotBecauseOfMatrix; |
3388 | 0 | if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix ) |
3389 | 0 | { |
3390 | 0 | ErrorMessage(STR_PROTECTIONERR); |
3391 | 0 | return; |
3392 | 0 | } |
3393 | | |
3394 | 0 | ScDocument& rDoc = GetViewData().GetDocument(); |
3395 | 0 | ScMarkData aFuncMark( GetViewData().GetMarkData() ); // local copy for UnmarkFiltered |
3396 | 0 | ScViewUtil::UnmarkFiltered( aFuncMark, rDoc ); |
3397 | 0 | ScDocShell* pDocSh = GetViewData().GetDocShell(); |
3398 | 0 | const ScPatternAttr* pSelAttrs = GetSelectionPattern(); |
3399 | 0 | const SfxItemSet& rSelItemSet = pSelAttrs->GetItemSet(); |
3400 | |
|
3401 | 0 | const SfxPoolItem* pBorderAttr = nullptr; |
3402 | 0 | SfxItemState eItemState = rSelItemSet.GetItemState( ATTR_BORDER, true, &pBorderAttr ); |
3403 | |
|
3404 | 0 | const SfxPoolItem* pTLBRItem = nullptr; |
3405 | 0 | SfxItemState eTLBRState = rSelItemSet.GetItemState( ATTR_BORDER_TLBR, true, &pTLBRItem ); |
3406 | |
|
3407 | 0 | const SfxPoolItem* pBLTRItem = nullptr; |
3408 | 0 | SfxItemState eBLTRState = rSelItemSet.GetItemState( ATTR_BORDER_BLTR, true, &pBLTRItem ); |
3409 | | |
3410 | | // any of the lines visible? |
3411 | 0 | if( !((eItemState != SfxItemState::DEFAULT) || (eTLBRState != SfxItemState::DEFAULT) || (eBLTRState != SfxItemState::DEFAULT)) ) |
3412 | 0 | return; |
3413 | | |
3414 | | // none of the lines don't care? |
3415 | 0 | if( (eItemState != SfxItemState::INVALID) && (eTLBRState != SfxItemState::INVALID) && (eBLTRState != SfxItemState::INVALID) ) |
3416 | 0 | { |
3417 | 0 | SfxItemSetFixed<ATTR_PATTERN_START, ATTR_PATTERN_END> aOldSet( *rDoc.GetPool() ); |
3418 | 0 | SfxItemSetFixed<ATTR_PATTERN_START, ATTR_PATTERN_END> aNewSet( *rDoc.GetPool() ); |
3419 | |
|
3420 | 0 | SvxBorderLine aLine; |
3421 | |
|
3422 | 0 | if( pBorderAttr ) |
3423 | 0 | { |
3424 | 0 | const SvxBorderLine* pBoxLine = nullptr; |
3425 | 0 | SvxBoxItem aBoxItem( *static_cast<const SvxBoxItem*>(pBorderAttr) ); |
3426 | 0 | SvxBoxInfoItem aBoxInfoItem( ATTR_BORDER_INNER ); |
3427 | | |
3428 | | // here pBoxLine is used |
3429 | 0 | SET_LINE_ATTRIBUTES(Top,SvxBoxItemLine::TOP) |
3430 | 0 | SET_LINE_ATTRIBUTES(Bottom,SvxBoxItemLine::BOTTOM) |
3431 | 0 | SET_LINE_ATTRIBUTES(Left,SvxBoxItemLine::LEFT) |
3432 | 0 | SET_LINE_ATTRIBUTES(Right,SvxBoxItemLine::RIGHT) |
3433 | |
|
3434 | 0 | aBoxInfoItem.SetLine( aBoxItem.GetTop(), SvxBoxInfoItemLine::HORI ); |
3435 | 0 | aBoxInfoItem.SetLine( aBoxItem.GetLeft(), SvxBoxInfoItemLine::VERT ); |
3436 | 0 | aBoxInfoItem.ResetFlags(); // set Lines to Valid |
3437 | |
|
3438 | 0 | aOldSet.Put( *pBorderAttr ); |
3439 | 0 | aNewSet.Put( aBoxItem ); |
3440 | 0 | aNewSet.Put( aBoxInfoItem ); |
3441 | 0 | } |
3442 | |
|
3443 | 0 | if( pTLBRItem && static_cast<const SvxLineItem*>(pTLBRItem)->GetLine() ) |
3444 | 0 | { |
3445 | 0 | SvxLineItem aTLBRItem( *static_cast<const SvxLineItem*>(pTLBRItem) ); |
3446 | 0 | UpdateLineAttrs( aLine, aTLBRItem.GetLine(), pLine, bColorOnly ); |
3447 | 0 | aTLBRItem.SetLine( &aLine ); |
3448 | 0 | aOldSet.Put( *pTLBRItem ); |
3449 | 0 | aNewSet.Put( aTLBRItem ); |
3450 | 0 | } |
3451 | |
|
3452 | 0 | if( pBLTRItem && static_cast<const SvxLineItem*>(pBLTRItem)->GetLine() ) |
3453 | 0 | { |
3454 | 0 | SvxLineItem aBLTRItem( *static_cast<const SvxLineItem*>(pBLTRItem) ); |
3455 | 0 | UpdateLineAttrs( aLine, aBLTRItem.GetLine(), pLine, bColorOnly ); |
3456 | 0 | aBLTRItem.SetLine( &aLine ); |
3457 | 0 | aOldSet.Put( *pBLTRItem ); |
3458 | 0 | aNewSet.Put( aBLTRItem ); |
3459 | 0 | } |
3460 | |
|
3461 | 0 | ApplyAttributes( aNewSet, aOldSet ); |
3462 | 0 | } |
3463 | 0 | else // if ( eItemState == SfxItemState::INVALID ) |
3464 | 0 | { |
3465 | 0 | aFuncMark.MarkToMulti(); |
3466 | 0 | rDoc.ApplySelectionLineStyle( aFuncMark, pLine, bColorOnly ); |
3467 | 0 | } |
3468 | |
|
3469 | 0 | const ScRange& aMarkRange = aFuncMark.GetMultiMarkArea(); |
3470 | 0 | SCCOL nStartCol = aMarkRange.aStart.Col(); |
3471 | 0 | SCROW nStartRow = aMarkRange.aStart.Row(); |
3472 | 0 | SCTAB nStartTab = aMarkRange.aStart.Tab(); |
3473 | 0 | SCCOL nEndCol = aMarkRange.aEnd.Col(); |
3474 | 0 | SCROW nEndRow = aMarkRange.aEnd.Row(); |
3475 | 0 | SCTAB nEndTab = aMarkRange.aEnd.Tab(); |
3476 | 0 | pDocSh->PostPaint( nStartCol, nStartRow, nStartTab, |
3477 | 0 | nEndCol, nEndRow, nEndTab, |
3478 | 0 | PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE ); |
3479 | |
|
3480 | 0 | pDocSh->UpdateOle(GetViewData()); |
3481 | 0 | pDocSh->SetDocumentModified(); |
3482 | 0 | } |
3483 | | |
3484 | | #undef SET_LINE_ATTRIBUTES |
3485 | | |
3486 | | void ScViewFunc::SetValidation( const ScValidationData& rNew ) |
3487 | 0 | { |
3488 | 0 | ScDocument& rDoc = GetViewData().GetDocument(); |
3489 | 0 | sal_uInt32 nIndex = rDoc.AddValidationEntry(rNew); // for it there is no Undo |
3490 | 0 | SfxUInt32Item aItem( ATTR_VALIDDATA, nIndex ); |
3491 | |
|
3492 | 0 | ApplyAttr( aItem ); // with Paint and Undo... |
3493 | 0 | } |
3494 | | |
3495 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |