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