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