/src/libreoffice/sc/source/ui/undo/undoblk.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #include <scitems.hxx> |
21 | | #include <utility> |
22 | | #include <vcl/virdev.hxx> |
23 | | #include <vcl/weld/WaitObject.hxx> |
24 | | #include <vcl/weld/Window.hxx> |
25 | | #include <editeng/boxitem.hxx> |
26 | | #include <sfx2/app.hxx> |
27 | | #include <comphelper/lok.hxx> |
28 | | #include <osl/diagnose.h> |
29 | | |
30 | | #include <undoblk.hxx> |
31 | | #include <undoutil.hxx> |
32 | | #include <document.hxx> |
33 | | #include <patattr.hxx> |
34 | | #include <docsh.hxx> |
35 | | #include <tabvwsh.hxx> |
36 | | #include <rangenam.hxx> |
37 | | #include <rangeutl.hxx> |
38 | | #include <stlpool.hxx> |
39 | | #include <stlsheet.hxx> |
40 | | #include <globstr.hrc> |
41 | | #include <scresid.hxx> |
42 | | #include <global.hxx> |
43 | | #include <target.hxx> |
44 | | #include <docpool.hxx> |
45 | | #include <docfunc.hxx> |
46 | | #include <attrib.hxx> |
47 | | #include <chgtrack.hxx> |
48 | | #include <transobj.hxx> |
49 | | #include <refundo.hxx> |
50 | | #include <undoolk.hxx> |
51 | | #include <clipparam.hxx> |
52 | | #include <tokenarray.hxx> |
53 | | #include <rowheightcontext.hxx> |
54 | | #include <refupdatecontext.hxx> |
55 | | #include <validat.hxx> |
56 | | #include <gridwin.hxx> |
57 | | #include <columnspanset.hxx> |
58 | | |
59 | | #include <memory> |
60 | | #include <set> |
61 | | |
62 | | // TODO: |
63 | | /*A*/ // SetOptimalHeight on Document, if no View |
64 | | /*B*/ // linked sheets |
65 | | /*C*/ // ScArea |
66 | | //? // check later |
67 | | |
68 | | namespace |
69 | | { |
70 | | /** Refresh the header row to update ScMF::Auto flags. */ |
71 | | void refreshAutoFilterForColumnChange(ScDocument& rDocument, SCTAB nTab) |
72 | 0 | { |
73 | 0 | ScDBData* pDBData = rDocument.GetAnonymousDBData(nTab); |
74 | 0 | if (!pDBData || !pDBData->HasAutoFilter()) |
75 | 0 | return; |
76 | | |
77 | 0 | ScRange aRange; |
78 | 0 | pDBData->GetArea(aRange); |
79 | | // Scan the full header row as stale flags may be outside the range. |
80 | 0 | rDocument.RefreshAutoFilter(0, aRange.aStart.Row(), rDocument.MaxCol(), aRange.aStart.Row(), nTab); |
81 | 0 | } |
82 | | } // end anonymous namespace |
83 | | |
84 | | ScUndoInsertCells::ScUndoInsertCells( ScDocShell& rNewDocShell, |
85 | | const ScRange& rRange, |
86 | | SCTAB nNewCount, std::unique_ptr<SCTAB[]> pNewTabs, std::unique_ptr<SCTAB[]> pNewScenarios, |
87 | | InsCellCmd eNewCmd, ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData, |
88 | | bool bNewPartOfPaste ) : |
89 | 0 | ScMoveUndo( rNewDocShell, std::move(pUndoDocument), std::move(pRefData) ), |
90 | 0 | aEffRange( rRange ), |
91 | 0 | nCount( nNewCount ), |
92 | 0 | pTabs( std::move(pNewTabs) ), |
93 | 0 | pScenarios( std::move(pNewScenarios) ), |
94 | 0 | eCmd( eNewCmd ), |
95 | 0 | bPartOfPaste( bNewPartOfPaste ) |
96 | 0 | { |
97 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
98 | 0 | if (eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER) // whole row? |
99 | 0 | { |
100 | 0 | aEffRange.aStart.SetCol(0); |
101 | 0 | aEffRange.aEnd.SetCol(rDoc.MaxCol()); |
102 | 0 | } |
103 | |
|
104 | 0 | if (eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER) // whole column? |
105 | 0 | { |
106 | 0 | aEffRange.aStart.SetRow(0); |
107 | 0 | aEffRange.aEnd.SetRow(rDoc.MaxRow()); |
108 | 0 | } |
109 | |
|
110 | 0 | SetChangeTrack(); |
111 | 0 | } |
112 | | |
113 | | ScUndoInsertCells::~ScUndoInsertCells() |
114 | 0 | { |
115 | 0 | } |
116 | | |
117 | | OUString ScUndoInsertCells::GetComment() const |
118 | 0 | { |
119 | 0 | return ScResId( pPasteUndo ? STR_UNDO_PASTE : STR_UNDO_INSERTCELLS ); |
120 | 0 | } |
121 | | |
122 | | bool ScUndoInsertCells::Merge( SfxUndoAction* pNextAction ) |
123 | 0 | { |
124 | | // If a paste undo action has already been added, append (detective) action there. |
125 | 0 | if ( pPasteUndo ) |
126 | 0 | return pPasteUndo->Merge( pNextAction ); |
127 | | |
128 | 0 | if ( bPartOfPaste ) |
129 | 0 | if ( auto pWrapper = dynamic_cast<ScUndoWrapper*>( pNextAction) ) |
130 | 0 | { |
131 | 0 | if (dynamic_cast<const ScUndoPaste*>(pWrapper->GetWrappedUndo())) |
132 | 0 | { |
133 | | // Store paste action if this is part of paste with inserting cells. |
134 | | // A list action isn't used because Repeat wouldn't work (insert wrong cells). |
135 | | |
136 | | // Pass ownership of the wrapped SfxUndoAction* to pPasteUndo |
137 | 0 | pPasteUndo = pWrapper->ReleaseWrappedUndo(); |
138 | 0 | return true; |
139 | 0 | } |
140 | 0 | } |
141 | | |
142 | | // Call base class for detective handling |
143 | 0 | return ScMoveUndo::Merge( pNextAction ); |
144 | 0 | } |
145 | | |
146 | | void ScUndoInsertCells::SetChangeTrack() |
147 | 0 | { |
148 | 0 | ScChangeTrack* pChangeTrack = rDocShell.GetDocument().GetChangeTrack(); |
149 | 0 | if ( pChangeTrack ) |
150 | 0 | { |
151 | 0 | pChangeTrack->AppendInsert( aEffRange ); |
152 | 0 | nEndChangeAction = pChangeTrack->GetActionMax(); |
153 | 0 | } |
154 | 0 | else |
155 | 0 | nEndChangeAction = 0; |
156 | 0 | } |
157 | | |
158 | | void ScUndoInsertCells::DoChange( const bool bUndo ) |
159 | 0 | { |
160 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
161 | 0 | SCTAB i; |
162 | |
|
163 | 0 | if ( bUndo ) |
164 | 0 | { |
165 | 0 | ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack(); |
166 | 0 | if ( pChangeTrack ) |
167 | 0 | pChangeTrack->Undo( nEndChangeAction, nEndChangeAction ); |
168 | 0 | } |
169 | 0 | else |
170 | 0 | SetChangeTrack(); |
171 | | |
172 | | // refresh of merged cells has to be after inserting/deleting |
173 | |
|
174 | 0 | ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); |
175 | 0 | switch (eCmd) |
176 | 0 | { |
177 | 0 | case INS_INSROWS_BEFORE: |
178 | 0 | case INS_INSROWS_AFTER: |
179 | 0 | case INS_CELLSDOWN: |
180 | 0 | for( i=0; i<nCount; i++ ) |
181 | 0 | { |
182 | |
|
183 | 0 | if (bUndo) |
184 | 0 | rDoc.DeleteRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i], |
185 | 0 | aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1)); |
186 | 0 | else |
187 | 0 | rDoc.InsertRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i], |
188 | 0 | aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1)); |
189 | |
|
190 | 0 | if (pViewShell) |
191 | 0 | { |
192 | 0 | const tools::Long nSign = bUndo ? -1 : 1; |
193 | 0 | pViewShell->OnLOKInsertDeleteRow(aEffRange.aStart.Row(), nSign * (aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1)); |
194 | 0 | } |
195 | 0 | } |
196 | 0 | break; |
197 | 0 | case INS_INSCOLS_BEFORE: |
198 | 0 | case INS_INSCOLS_AFTER: |
199 | 0 | case INS_CELLSRIGHT: |
200 | 0 | for( i=0; i<nCount; i++ ) |
201 | 0 | { |
202 | 0 | if (bUndo) |
203 | 0 | rDoc.DeleteCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i], |
204 | 0 | aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1)); |
205 | 0 | else |
206 | 0 | rDoc.InsertCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i], |
207 | 0 | aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1)); |
208 | |
|
209 | 0 | refreshAutoFilterForColumnChange(rDoc, pTabs[i]); |
210 | |
|
211 | 0 | if (pViewShell) |
212 | 0 | { |
213 | 0 | const tools::Long nSign = bUndo ? -1 : 1; |
214 | 0 | pViewShell->OnLOKInsertDeleteColumn(aEffRange.aStart.Col(), nSign * (aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1)); |
215 | 0 | } |
216 | 0 | } |
217 | 0 | break; |
218 | 0 | default: |
219 | 0 | { |
220 | | // added to avoid warnings |
221 | 0 | } |
222 | 0 | } |
223 | | |
224 | 0 | ScRange aWorkRange( aEffRange ); |
225 | 0 | if ( eCmd == INS_CELLSRIGHT ) // only "shift right" requires refresh of the moved area |
226 | 0 | aWorkRange.aEnd.SetCol(rDoc.MaxCol()); |
227 | 0 | for( i=0; i<nCount; i++ ) |
228 | 0 | { |
229 | 0 | if ( rDoc.HasAttrib( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i], |
230 | 0 | aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i], HasAttrFlags::Merged ) ) |
231 | 0 | { |
232 | 0 | SCCOL nEndCol = aWorkRange.aEnd.Col(); |
233 | 0 | SCROW nEndRow = aWorkRange.aEnd.Row(); |
234 | 0 | rDoc.ExtendMerge( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), nEndCol, nEndRow, pTabs[i], true ); |
235 | 0 | } |
236 | 0 | } |
237 | | |
238 | | // Undo for displaced attributes? |
239 | |
|
240 | 0 | PaintPartFlags nPaint = PaintPartFlags::Grid; |
241 | |
|
242 | 0 | switch (eCmd) |
243 | 0 | { |
244 | 0 | case INS_INSROWS_BEFORE: |
245 | 0 | case INS_INSROWS_AFTER: |
246 | 0 | nPaint |= PaintPartFlags::Left; |
247 | 0 | aWorkRange.aEnd.SetRow(rDoc.MaxRow()); |
248 | 0 | break; |
249 | 0 | case INS_CELLSDOWN: |
250 | 0 | for( i=0; i<nCount; i++ ) |
251 | 0 | { |
252 | 0 | aWorkRange.aEnd.SetRow(rDoc.MaxRow()); |
253 | 0 | if ( rDocShell.AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i] )) |
254 | 0 | { |
255 | 0 | aWorkRange.aStart.SetCol(0); |
256 | 0 | aWorkRange.aEnd.SetCol(rDoc.MaxCol()); |
257 | 0 | nPaint |= PaintPartFlags::Left; |
258 | 0 | } |
259 | 0 | } |
260 | 0 | break; |
261 | 0 | case INS_INSCOLS_BEFORE: |
262 | 0 | case INS_INSCOLS_AFTER: |
263 | 0 | nPaint |= PaintPartFlags::Top; // top bar |
264 | 0 | [[fallthrough]]; |
265 | 0 | case INS_CELLSRIGHT: |
266 | 0 | for( i=0; i<nCount; i++ ) |
267 | 0 | { |
268 | 0 | aWorkRange.aEnd.SetCol(rDoc.MaxCol()); // to the far right |
269 | 0 | if ( rDocShell.AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i]) ) |
270 | 0 | { // AdjustDraw does not paint PaintPartFlags::Top, |
271 | 0 | aWorkRange.aStart.SetCol(0); // thus solved like this |
272 | 0 | aWorkRange.aEnd.SetRow(rDoc.MaxRow()); |
273 | 0 | nPaint |= PaintPartFlags::Left; |
274 | 0 | } |
275 | 0 | } |
276 | 0 | break; |
277 | 0 | default: |
278 | 0 | { |
279 | | // added to avoid warnings |
280 | 0 | } |
281 | 0 | } |
282 | | |
283 | 0 | for( i=0; i<nCount; i++ ) |
284 | 0 | { |
285 | 0 | rDocShell.PostPaint( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i], |
286 | 0 | aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i]+pScenarios[i], nPaint ); |
287 | 0 | } |
288 | 0 | rDocShell.PostDataChanged(); |
289 | 0 | if (!pViewShell) |
290 | 0 | return; |
291 | | |
292 | 0 | pViewShell->CellContentChanged(); |
293 | |
|
294 | 0 | if (!comphelper::LibreOfficeKit::isActive()) |
295 | 0 | return; |
296 | | |
297 | 0 | SCTAB nTab = pViewShell->GetViewData().GetTabNumber(); |
298 | 0 | bool bColsAffected = (eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER || eCmd == INS_CELLSRIGHT); |
299 | 0 | bool bRowsAffected = (eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER || eCmd == INS_CELLSDOWN); |
300 | |
|
301 | 0 | if (bColsAffected) |
302 | 0 | ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, COLUMN_HEADER, nTab); |
303 | |
|
304 | 0 | if (bRowsAffected) |
305 | 0 | ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, ROW_HEADER, nTab); |
306 | |
|
307 | 0 | ScTabViewShell::notifyAllViewsSheetGeomInvalidation( |
308 | 0 | pViewShell, |
309 | 0 | bColsAffected, bRowsAffected, |
310 | 0 | true /* bSizes*/, true /* bHidden */, true /* bFiltered */, |
311 | 0 | true /* bGroups */, nTab); |
312 | 0 | } |
313 | | |
314 | | void ScUndoInsertCells::Undo() |
315 | 0 | { |
316 | 0 | if ( pPasteUndo ) |
317 | 0 | pPasteUndo->Undo(); // undo paste first |
318 | |
|
319 | 0 | weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important due to TrackFormulas in UpdateReference |
320 | 0 | BeginUndo(); |
321 | 0 | DoChange( true ); |
322 | |
|
323 | 0 | sc::UndoSheetViewSortData::restore(rDocShell, true); |
324 | |
|
325 | 0 | EndUndo(); |
326 | |
|
327 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
328 | 0 | for (SCTAB i = 0; i < nCount; ++i) |
329 | 0 | rDoc.SetDrawPageSize(pTabs[i]); |
330 | 0 | } |
331 | | |
332 | | void ScUndoInsertCells::Redo() |
333 | 0 | { |
334 | 0 | weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important due to TrackFormulas in UpdateReference |
335 | 0 | BeginRedo(); |
336 | 0 | DoChange( false ); |
337 | |
|
338 | 0 | sc::UndoSheetViewSortData::restore(rDocShell, false); |
339 | |
|
340 | 0 | EndRedo(); |
341 | |
|
342 | 0 | if ( pPasteUndo ) |
343 | 0 | pPasteUndo->Redo(); // redo paste last |
344 | |
|
345 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
346 | 0 | for (SCTAB i = 0; i < nCount; ++i) |
347 | 0 | rDoc.SetDrawPageSize(pTabs[i]); |
348 | 0 | } |
349 | | |
350 | | void ScUndoInsertCells::Repeat(SfxRepeatTarget& rTarget) |
351 | 0 | { |
352 | 0 | if (dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr) |
353 | 0 | { |
354 | 0 | if ( pPasteUndo ) |
355 | 0 | { |
356 | | // Repeat for paste with inserting cells is handled completely |
357 | | // by the Paste undo action |
358 | |
|
359 | 0 | pPasteUndo->Repeat( rTarget ); |
360 | 0 | } |
361 | 0 | else |
362 | 0 | static_cast<ScTabViewTarget&>(rTarget).GetViewShell().InsertCells( eCmd ); |
363 | 0 | } |
364 | 0 | } |
365 | | |
366 | | bool ScUndoInsertCells::CanRepeat(SfxRepeatTarget& rTarget) const |
367 | 0 | { |
368 | 0 | return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr; |
369 | 0 | } |
370 | | |
371 | | ScUndoDeleteCells::ScUndoDeleteCells( ScDocShell& rNewDocShell, |
372 | | const ScRange& rRange, |
373 | | SCTAB nNewCount, std::unique_ptr<SCTAB[]> pNewTabs, std::unique_ptr<SCTAB[]> pNewScenarios, |
374 | | DelCellCmd eNewCmd, ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData ) : |
375 | 0 | ScMoveUndo( rNewDocShell, std::move(pUndoDocument), std::move(pRefData) ), |
376 | 0 | aEffRange( rRange ), |
377 | 0 | nCount( nNewCount ), |
378 | 0 | pTabs( std::move(pNewTabs) ), |
379 | 0 | pScenarios( std::move(pNewScenarios) ), |
380 | 0 | eCmd( eNewCmd ) |
381 | 0 | { |
382 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
383 | 0 | if (eCmd == DelCellCmd::Rows) // whole row? |
384 | 0 | { |
385 | 0 | aEffRange.aStart.SetCol(0); |
386 | 0 | aEffRange.aEnd.SetCol(rDoc.MaxCol()); |
387 | 0 | } |
388 | |
|
389 | 0 | if (eCmd == DelCellCmd::Cols) // whole column? |
390 | 0 | { |
391 | 0 | aEffRange.aStart.SetRow(0); |
392 | 0 | aEffRange.aEnd.SetRow(rDoc.MaxRow()); |
393 | 0 | } |
394 | |
|
395 | 0 | SetChangeTrack(); |
396 | 0 | } |
397 | | |
398 | | ScUndoDeleteCells::~ScUndoDeleteCells() |
399 | 0 | { |
400 | 0 | } |
401 | | |
402 | | OUString ScUndoDeleteCells::GetComment() const |
403 | 0 | { |
404 | 0 | return ScResId( STR_UNDO_DELETECELLS ); // "Delete" |
405 | 0 | } |
406 | | |
407 | | void ScUndoDeleteCells::SetChangeTrack() |
408 | 0 | { |
409 | 0 | ScChangeTrack* pChangeTrack = rDocShell.GetDocument().GetChangeTrack(); |
410 | 0 | if ( pChangeTrack ) |
411 | 0 | pChangeTrack->AppendDeleteRange( aEffRange, pRefUndoDoc.get(), |
412 | 0 | nStartChangeAction, nEndChangeAction ); |
413 | 0 | else |
414 | 0 | nStartChangeAction = nEndChangeAction = 0; |
415 | 0 | } |
416 | | |
417 | | void ScUndoDeleteCells::DoChange( const bool bUndo ) |
418 | 0 | { |
419 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
420 | 0 | SCTAB i; |
421 | |
|
422 | 0 | if ( bUndo ) |
423 | 0 | { |
424 | 0 | ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack(); |
425 | 0 | if ( pChangeTrack ) |
426 | 0 | pChangeTrack->Undo( nStartChangeAction, nEndChangeAction ); |
427 | 0 | } |
428 | 0 | else |
429 | 0 | SetChangeTrack(); |
430 | |
|
431 | 0 | ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); |
432 | |
|
433 | 0 | switch (eCmd) |
434 | 0 | { |
435 | 0 | case DelCellCmd::Rows: |
436 | 0 | case DelCellCmd::CellsUp: |
437 | 0 | for( i=0; i<nCount; i++ ) |
438 | 0 | { |
439 | 0 | if (bUndo) |
440 | 0 | rDoc.InsertRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i], |
441 | 0 | aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1)); |
442 | 0 | else |
443 | 0 | rDoc.DeleteRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i], |
444 | 0 | aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1)); |
445 | |
|
446 | 0 | if (pViewShell) |
447 | 0 | { |
448 | 0 | const tools::Long nSign = bUndo ? 1 : -1; |
449 | 0 | pViewShell->OnLOKInsertDeleteRow(aEffRange.aStart.Row(), nSign * (aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1)); |
450 | 0 | } |
451 | 0 | } |
452 | 0 | break; |
453 | 0 | case DelCellCmd::Cols: |
454 | 0 | case DelCellCmd::CellsLeft: |
455 | 0 | for( i=0; i<nCount; i++ ) |
456 | 0 | { |
457 | 0 | if (bUndo) |
458 | 0 | rDoc.InsertCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i], |
459 | 0 | aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1)); |
460 | 0 | else |
461 | 0 | rDoc.DeleteCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i], |
462 | 0 | aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1)); |
463 | |
|
464 | 0 | if (pViewShell) |
465 | 0 | { |
466 | 0 | const tools::Long nSign = bUndo ? 1 : -1; |
467 | 0 | pViewShell->OnLOKInsertDeleteColumn(aEffRange.aStart.Col(), nSign * (aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1)); |
468 | 0 | } |
469 | 0 | } |
470 | 0 | break; |
471 | 0 | default: |
472 | 0 | { |
473 | | // added to avoid warnings |
474 | 0 | } |
475 | 0 | } |
476 | | |
477 | | // if Undo, restore references |
478 | 0 | for( i=0; i<nCount && bUndo; i++ ) |
479 | 0 | { |
480 | 0 | pRefUndoDoc->CopyToDocument(aEffRange.aStart.Col(), aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Col(), aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i], |
481 | 0 | InsertDeleteFlags::ALL | InsertDeleteFlags::NOCAPTIONS, false, rDoc); |
482 | 0 | } |
483 | | |
484 | | // Refresh after all cell operations are done. |
485 | 0 | if (eCmd == DelCellCmd::Cols || eCmd == DelCellCmd::CellsLeft) |
486 | 0 | { |
487 | 0 | for (i = 0; i < nCount; i++) |
488 | 0 | refreshAutoFilterForColumnChange(rDoc, pTabs[i]); |
489 | 0 | } |
490 | |
|
491 | 0 | ScRange aWorkRange( aEffRange ); |
492 | 0 | if ( eCmd == DelCellCmd::CellsLeft ) // only "shift left" requires refresh of the moved area |
493 | 0 | aWorkRange.aEnd.SetCol(rDoc.MaxCol()); |
494 | |
|
495 | 0 | for( i=0; i<nCount; i++ ) |
496 | 0 | { |
497 | 0 | if ( rDoc.HasAttrib( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i], |
498 | 0 | aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i], HasAttrFlags::Merged | HasAttrFlags::Overlapped ) ) |
499 | 0 | { |
500 | | // #i51445# old merge flag attributes must be deleted also for single cells, |
501 | | // not only for whole columns/rows |
502 | |
|
503 | 0 | if ( !bUndo ) |
504 | 0 | { |
505 | 0 | if ( eCmd==DelCellCmd::Cols || eCmd==DelCellCmd::CellsLeft ) |
506 | 0 | aWorkRange.aEnd.SetCol(rDoc.MaxCol()); |
507 | 0 | if ( eCmd==DelCellCmd::Rows || eCmd==DelCellCmd::CellsUp ) |
508 | 0 | aWorkRange.aEnd.SetRow(rDoc.MaxRow()); |
509 | 0 | ScMarkData aMarkData(rDoc.GetSheetLimits()); |
510 | 0 | aMarkData.SelectOneTable( aWorkRange.aStart.Tab() ); |
511 | 0 | ScPatternAttr aPattern(rDoc.getCellAttributeHelper()); |
512 | 0 | aPattern.ItemSetPut(ScMergeFlagAttr()); |
513 | 0 | rDoc.ApplyPatternArea( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), |
514 | 0 | aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), |
515 | 0 | aMarkData, aPattern ); |
516 | 0 | } |
517 | |
|
518 | 0 | SCCOL nEndCol = aWorkRange.aEnd.Col(); |
519 | 0 | SCROW nEndRow = aWorkRange.aEnd.Row(); |
520 | 0 | rDoc.ExtendMerge( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), nEndCol, nEndRow, pTabs[i], true ); |
521 | 0 | } |
522 | 0 | } |
523 | | |
524 | | // paint |
525 | 0 | PaintPartFlags nPaint = PaintPartFlags::Grid; |
526 | 0 | switch (eCmd) |
527 | 0 | { |
528 | 0 | case DelCellCmd::Rows: |
529 | 0 | nPaint |= PaintPartFlags::Left; |
530 | 0 | aWorkRange.aEnd.SetRow(rDoc.MaxRow()); |
531 | 0 | break; |
532 | 0 | case DelCellCmd::CellsUp: |
533 | 0 | for( i=0; i<nCount; i++ ) |
534 | 0 | { |
535 | 0 | aWorkRange.aEnd.SetRow(rDoc.MaxRow()); |
536 | 0 | if ( rDocShell.AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i] )) |
537 | 0 | { |
538 | 0 | aWorkRange.aStart.SetCol(0); |
539 | 0 | aWorkRange.aEnd.SetCol(rDoc.MaxCol()); |
540 | 0 | nPaint |= PaintPartFlags::Left; |
541 | 0 | } |
542 | 0 | } |
543 | 0 | break; |
544 | 0 | case DelCellCmd::Cols: |
545 | 0 | nPaint |= PaintPartFlags::Top; // top bar |
546 | 0 | [[fallthrough]]; |
547 | 0 | case DelCellCmd::CellsLeft: |
548 | 0 | for( i=0; i<nCount; i++ ) |
549 | 0 | { |
550 | 0 | aWorkRange.aEnd.SetCol(rDoc.MaxCol()); // to the far right |
551 | 0 | if ( rDocShell.AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i] ) ) |
552 | 0 | { |
553 | 0 | aWorkRange.aStart.SetCol(0); |
554 | 0 | aWorkRange.aEnd.SetRow(rDoc.MaxRow()); |
555 | 0 | nPaint |= PaintPartFlags::Left; |
556 | 0 | } |
557 | 0 | } |
558 | 0 | break; |
559 | 0 | default: |
560 | 0 | { |
561 | | // added to avoid warnings |
562 | 0 | } |
563 | 0 | } |
564 | | |
565 | 0 | for( i=0; i<nCount; i++ ) |
566 | 0 | { |
567 | 0 | rDocShell.PostPaint( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i], |
568 | 0 | aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i]+pScenarios[i], nPaint, SC_PF_LINES ); |
569 | 0 | } |
570 | | // Selection not until EndUndo |
571 | |
|
572 | 0 | rDocShell.PostDataChanged(); |
573 | | // CellContentChanged comes with the selection |
574 | |
|
575 | 0 | if (!pViewShell) |
576 | 0 | return; |
577 | | |
578 | 0 | if (!comphelper::LibreOfficeKit::isActive()) |
579 | 0 | return; |
580 | | |
581 | 0 | SCTAB nTab = pViewShell->GetViewData().GetTabNumber(); |
582 | 0 | bool bColsAffected = (eCmd == DelCellCmd::Cols || eCmd == DelCellCmd::CellsLeft); |
583 | 0 | bool bRowsAffected = (eCmd == DelCellCmd::Rows || eCmd == DelCellCmd::CellsUp); |
584 | |
|
585 | 0 | if (bColsAffected) |
586 | 0 | ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, COLUMN_HEADER, nTab); |
587 | |
|
588 | 0 | if (bRowsAffected) |
589 | 0 | ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, ROW_HEADER, nTab); |
590 | |
|
591 | 0 | ScTabViewShell::notifyAllViewsSheetGeomInvalidation( |
592 | 0 | pViewShell, |
593 | 0 | bColsAffected, bRowsAffected, |
594 | 0 | true /* bSizes*/, true /* bHidden */, true /* bFiltered */, |
595 | 0 | true /* bGroups */, nTab); |
596 | |
|
597 | 0 | } |
598 | | |
599 | | void ScUndoDeleteCells::Undo() |
600 | 0 | { |
601 | 0 | weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference |
602 | 0 | BeginUndo(); |
603 | 0 | DoChange( true ); |
604 | |
|
605 | 0 | sc::UndoSheetViewSortData::restore(rDocShell, true); |
606 | |
|
607 | 0 | EndUndo(); |
608 | |
|
609 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
610 | | |
611 | | // Now that DBData have been restored in ScMoveUndo::EndUndo() via its |
612 | | // pRefUndoDoc we can apply the AutoFilter buttons. |
613 | | // Add one row for cases undoing deletion right above a cut AutoFilter |
614 | | // range so the buttons are removed. |
615 | 0 | SCROW nRefreshEndRow = std::min<SCROW>( aEffRange.aEnd.Row() + 1, rDoc.MaxRow()); |
616 | 0 | for (SCTAB i=0; i < nCount; ++i) |
617 | 0 | { |
618 | 0 | rDoc.RefreshAutoFilter( aEffRange.aStart.Col(), aEffRange.aStart.Row(), |
619 | 0 | aEffRange.aEnd.Col(), nRefreshEndRow, pTabs[i]); |
620 | 0 | } |
621 | |
|
622 | 0 | SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); |
623 | | |
624 | | // Selection not until EndUndo |
625 | 0 | ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); |
626 | 0 | if (pViewShell) |
627 | 0 | { |
628 | 0 | for( SCTAB i=0; i<nCount; i++ ) |
629 | 0 | { |
630 | 0 | pViewShell->MarkRange( ScRange(aEffRange.aStart.Col(), aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Col(), aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i]) ); |
631 | 0 | } |
632 | 0 | } |
633 | |
|
634 | 0 | for (SCTAB i = 0; i < nCount; ++i) |
635 | 0 | rDoc.SetDrawPageSize(pTabs[i]); |
636 | 0 | } |
637 | | |
638 | | void ScUndoDeleteCells::Redo() |
639 | 0 | { |
640 | 0 | weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference |
641 | 0 | BeginRedo(); |
642 | 0 | DoChange( false); |
643 | |
|
644 | 0 | sc::UndoSheetViewSortData::restore(rDocShell, false); |
645 | |
|
646 | 0 | EndRedo(); |
647 | |
|
648 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
649 | |
|
650 | 0 | for (SCTAB i=0; i < nCount; ++i) |
651 | 0 | { |
652 | 0 | rDoc.RefreshAutoFilter( aEffRange.aStart.Col(), aEffRange.aStart.Row(), |
653 | 0 | aEffRange.aEnd.Col(), aEffRange.aEnd.Row(), pTabs[i]); |
654 | 0 | } |
655 | |
|
656 | 0 | SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); |
657 | |
|
658 | 0 | ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); |
659 | 0 | if (pViewShell) |
660 | 0 | pViewShell->DoneBlockMode(); // current way |
661 | |
|
662 | 0 | for (SCTAB i = 0; i < nCount; ++i) |
663 | 0 | rDoc.SetDrawPageSize(pTabs[i]); |
664 | 0 | } |
665 | | |
666 | | void ScUndoDeleteCells::Repeat(SfxRepeatTarget& rTarget) |
667 | 0 | { |
668 | 0 | if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget) ) |
669 | 0 | pViewTarget->GetViewShell().DeleteCells( eCmd ); |
670 | 0 | } |
671 | | |
672 | | bool ScUndoDeleteCells::CanRepeat(SfxRepeatTarget& rTarget) const |
673 | 0 | { |
674 | 0 | return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr; |
675 | 0 | } |
676 | | |
677 | | // delete cells in multiselection |
678 | | ScUndoDeleteMulti::ScUndoDeleteMulti( |
679 | | ScDocShell& rNewDocShell, |
680 | | bool bNewRows, bool bNeedsRefresh, SCTAB nNewTab, |
681 | | std::vector<sc::ColRowSpan>&& rSpans, |
682 | | ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData ) : |
683 | 0 | ScMoveUndo( rNewDocShell, std::move(pUndoDocument), std::move(pRefData) ), |
684 | 0 | mbRows(bNewRows), |
685 | 0 | mbRefresh(bNeedsRefresh), |
686 | 0 | nTab( nNewTab ), |
687 | 0 | maSpans(std::move(rSpans)) |
688 | 0 | { |
689 | 0 | SetChangeTrack(); |
690 | 0 | } |
691 | | |
692 | | ScUndoDeleteMulti::~ScUndoDeleteMulti() |
693 | 0 | { |
694 | 0 | } |
695 | | |
696 | | OUString ScUndoDeleteMulti::GetComment() const |
697 | 0 | { |
698 | 0 | return ScResId( STR_UNDO_DELETECELLS ); // like DeleteCells |
699 | 0 | } |
700 | | |
701 | | void ScUndoDeleteMulti::DoChange() const |
702 | 0 | { |
703 | 0 | SCCOL nStartCol; |
704 | 0 | SCROW nStartRow; |
705 | 0 | PaintPartFlags nPaint; |
706 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
707 | 0 | if (mbRows) |
708 | 0 | { |
709 | 0 | nStartCol = 0; |
710 | 0 | nStartRow = static_cast<SCROW>(maSpans[0].mnStart); |
711 | 0 | nPaint = PaintPartFlags::Grid | PaintPartFlags::Left; |
712 | 0 | } |
713 | 0 | else |
714 | 0 | { |
715 | 0 | nStartCol = static_cast<SCCOL>(maSpans[0].mnStart); |
716 | 0 | nStartRow = 0; |
717 | 0 | nPaint = PaintPartFlags::Grid | PaintPartFlags::Top; |
718 | 0 | } |
719 | |
|
720 | 0 | if (mbRefresh) |
721 | 0 | { |
722 | 0 | SCCOL nEndCol = rDoc.MaxCol(); |
723 | 0 | SCROW nEndRow = rDoc.MaxRow(); |
724 | 0 | rDoc.RemoveFlagsTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, ScMF::Hor | ScMF::Ver ); |
725 | 0 | rDoc.ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nTab, true ); |
726 | 0 | } |
727 | |
|
728 | 0 | rDocShell.PostPaint( nStartCol, nStartRow, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, nPaint ); |
729 | 0 | rDocShell.PostDataChanged(); |
730 | 0 | ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); |
731 | 0 | if (pViewShell) |
732 | 0 | pViewShell->CellContentChanged(); |
733 | |
|
734 | 0 | ShowTable( nTab ); |
735 | 0 | } |
736 | | |
737 | | void ScUndoDeleteMulti::SetChangeTrack() |
738 | 0 | { |
739 | 0 | ScChangeTrack* pChangeTrack = rDocShell.GetDocument().GetChangeTrack(); |
740 | 0 | if ( pChangeTrack ) |
741 | 0 | { |
742 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
743 | 0 | nStartChangeAction = pChangeTrack->GetActionMax() + 1; |
744 | 0 | ScRange aRange( 0, 0, nTab, 0, 0, nTab ); |
745 | 0 | if (mbRows) |
746 | 0 | aRange.aEnd.SetCol( rDoc.MaxCol() ); |
747 | 0 | else |
748 | 0 | aRange.aEnd.SetRow( rDoc.MaxRow() ); |
749 | | // delete in reverse |
750 | 0 | std::vector<sc::ColRowSpan>::const_reverse_iterator ri = maSpans.rbegin(), riEnd = maSpans.rend(); |
751 | 0 | for (; ri != riEnd; ++ri) |
752 | 0 | { |
753 | 0 | SCCOLROW nEnd = ri->mnEnd; |
754 | 0 | SCCOLROW nStart = ri->mnStart; |
755 | 0 | if (mbRows) |
756 | 0 | { |
757 | 0 | aRange.aStart.SetRow( nStart ); |
758 | 0 | aRange.aEnd.SetRow( nEnd ); |
759 | 0 | } |
760 | 0 | else |
761 | 0 | { |
762 | 0 | aRange.aStart.SetCol( static_cast<SCCOL>(nStart) ); |
763 | 0 | aRange.aEnd.SetCol( static_cast<SCCOL>(nEnd) ); |
764 | 0 | } |
765 | 0 | sal_uLong nDummyStart; |
766 | 0 | pChangeTrack->AppendDeleteRange( aRange, pRefUndoDoc.get(), |
767 | 0 | nDummyStart, nEndChangeAction ); |
768 | 0 | } |
769 | 0 | } |
770 | 0 | else |
771 | 0 | nStartChangeAction = nEndChangeAction = 0; |
772 | 0 | } |
773 | | |
774 | | void ScUndoDeleteMulti::Undo() |
775 | 0 | { |
776 | 0 | weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference |
777 | 0 | BeginUndo(); |
778 | |
|
779 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
780 | | |
781 | | // reverse delete -> forward insert |
782 | 0 | for (const auto& rSpan : maSpans) |
783 | 0 | { |
784 | 0 | SCCOLROW nStart = rSpan.mnStart; |
785 | 0 | SCCOLROW nEnd = rSpan.mnEnd; |
786 | 0 | if (mbRows) |
787 | 0 | rDoc.InsertRow( 0,nTab, rDoc.MaxCol(),nTab, nStart,static_cast<SCSIZE>(nEnd-nStart+1) ); |
788 | 0 | else |
789 | 0 | rDoc.InsertCol( 0,nTab, rDoc.MaxRow(),nTab, static_cast<SCCOL>(nStart), static_cast<SCSIZE>(nEnd-nStart+1) ); |
790 | 0 | } |
791 | |
|
792 | 0 | for (const auto& rSpan : maSpans) |
793 | 0 | { |
794 | 0 | SCCOLROW nStart = rSpan.mnStart; |
795 | 0 | SCCOLROW nEnd = rSpan.mnEnd; |
796 | 0 | if (mbRows) |
797 | 0 | pRefUndoDoc->CopyToDocument(0, nStart, nTab, rDoc.MaxCol(), nEnd, nTab, InsertDeleteFlags::ALL, false, rDoc); |
798 | 0 | else |
799 | 0 | pRefUndoDoc->CopyToDocument(static_cast<SCCOL>(nStart),0,nTab, |
800 | 0 | static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab, InsertDeleteFlags::ALL, false, rDoc); |
801 | 0 | } |
802 | |
|
803 | 0 | ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack(); |
804 | 0 | if ( pChangeTrack ) |
805 | 0 | pChangeTrack->Undo( nStartChangeAction, nEndChangeAction ); |
806 | |
|
807 | 0 | DoChange(); |
808 | | |
809 | | //! redrawing the selection is not possible at the moment |
810 | | //! since no data for selection exist |
811 | |
|
812 | 0 | EndUndo(); |
813 | 0 | SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); |
814 | 0 | } |
815 | | |
816 | | void ScUndoDeleteMulti::Redo() |
817 | 0 | { |
818 | 0 | weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference |
819 | 0 | BeginRedo(); |
820 | |
|
821 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
822 | | |
823 | | // reverse delete |
824 | 0 | std::vector<sc::ColRowSpan>::const_reverse_iterator ri = maSpans.rbegin(), riEnd = maSpans.rend(); |
825 | 0 | for (; ri != riEnd; ++ri) |
826 | 0 | { |
827 | 0 | SCCOLROW nEnd = ri->mnEnd; |
828 | 0 | SCCOLROW nStart = ri->mnStart; |
829 | 0 | if (mbRows) |
830 | 0 | rDoc.DeleteRow( 0,nTab, rDoc.MaxCol(),nTab, nStart,static_cast<SCSIZE>(nEnd-nStart+1) ); |
831 | 0 | else |
832 | 0 | rDoc.DeleteCol( 0,nTab, rDoc.MaxRow(),nTab, static_cast<SCCOL>(nStart), static_cast<SCSIZE>(nEnd-nStart+1) ); |
833 | 0 | } |
834 | |
|
835 | 0 | SetChangeTrack(); |
836 | |
|
837 | 0 | DoChange(); |
838 | |
|
839 | 0 | EndRedo(); |
840 | 0 | SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); |
841 | 0 | } |
842 | | |
843 | | void ScUndoDeleteMulti::Repeat(SfxRepeatTarget& rTarget) |
844 | 0 | { |
845 | | // if single selection |
846 | 0 | if (auto pTabViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget)) |
847 | 0 | pTabViewTarget->GetViewShell().DeleteCells( DelCellCmd::Rows ); |
848 | 0 | } |
849 | | |
850 | | bool ScUndoDeleteMulti::CanRepeat(SfxRepeatTarget& rTarget) const |
851 | 0 | { |
852 | 0 | return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr; |
853 | 0 | } |
854 | | |
855 | | ScUndoCut::ScUndoCut(ScDocShell& rNewDocShell, const ScRange& aRange, const ScAddress& aOldEnd, |
856 | | const ScMarkData& rMark, ScDocumentUniquePtr pNewUndoDoc) |
857 | 0 | : ScBlockUndo(rNewDocShell, ScRange(aRange.aStart, aOldEnd), SC_UNDO_AUTOHEIGHT) |
858 | 0 | , aMarkData(rMark) |
859 | 0 | , pUndoDoc(std::move(pNewUndoDoc)) |
860 | 0 | , aExtendedRange(aRange) |
861 | 0 | { |
862 | 0 | SetChangeTrack(); |
863 | 0 | } |
864 | | |
865 | | ScUndoCut::~ScUndoCut() |
866 | 0 | { |
867 | 0 | } |
868 | | |
869 | | OUString ScUndoCut::GetComment() const |
870 | 0 | { |
871 | 0 | return ScResId( STR_UNDO_CUT ); // "cut" |
872 | 0 | } |
873 | | |
874 | | void ScUndoCut::SetChangeTrack() |
875 | 0 | { |
876 | 0 | ScChangeTrack* pChangeTrack = rDocShell.GetDocument().GetChangeTrack(); |
877 | 0 | if ( pChangeTrack ) |
878 | 0 | pChangeTrack->AppendContentRange( aBlockRange, *pUndoDoc, |
879 | 0 | nStartChangeAction, nEndChangeAction, SC_CACM_CUT ); |
880 | 0 | else |
881 | 0 | nStartChangeAction = nEndChangeAction = 0; |
882 | 0 | } |
883 | | |
884 | | void ScUndoCut::DoChange( const bool bUndo ) |
885 | 0 | { |
886 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
887 | 0 | sal_uInt16 nExtFlags = 0; |
888 | | |
889 | | // do not undo/redo objects and note captions, they are handled via drawing undo |
890 | 0 | InsertDeleteFlags nUndoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS; |
891 | |
|
892 | 0 | if (bUndo) // only for Undo |
893 | 0 | { |
894 | | // all sheets - CopyToDocument skips those that don't exist in pUndoDoc |
895 | 0 | SCTAB nTabCount = rDoc.GetTableCount(); |
896 | 0 | ScRange aCopyRange = aExtendedRange; |
897 | 0 | aCopyRange.aStart.SetTab(0); |
898 | 0 | aCopyRange.aEnd.SetTab(nTabCount-1); |
899 | 0 | pUndoDoc->CopyToDocument(aCopyRange, nUndoFlags, false, rDoc); |
900 | 0 | ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack(); |
901 | 0 | if ( pChangeTrack ) |
902 | 0 | pChangeTrack->Undo( nStartChangeAction, nEndChangeAction ); |
903 | |
|
904 | 0 | BroadcastChanges(aCopyRange); |
905 | 0 | } |
906 | 0 | else // only for Redo |
907 | 0 | { |
908 | 0 | rDocShell.UpdatePaintExt( nExtFlags, aExtendedRange ); |
909 | 0 | rDoc.DeleteArea( aBlockRange.aStart.Col(), aBlockRange.aStart.Row(), |
910 | 0 | aBlockRange.aEnd.Col(), aBlockRange.aEnd.Row(), aMarkData, nUndoFlags ); |
911 | 0 | SetChangeTrack(); |
912 | 0 | } |
913 | |
|
914 | 0 | ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); |
915 | 0 | if ( !( pViewShell && pViewShell->AdjustBlockHeight() ) ) |
916 | 0 | /*A*/ rDocShell.PostPaint( aExtendedRange, PaintPartFlags::Grid, nExtFlags ); |
917 | |
|
918 | 0 | if ( !bUndo ) // draw redo after updating row heights |
919 | 0 | RedoSdrUndoAction( pDrawUndo.get() ); //! include in ScBlockUndo? |
920 | |
|
921 | 0 | rDocShell.PostDataChanged(); |
922 | 0 | if (pViewShell) |
923 | 0 | pViewShell->CellContentChanged(); |
924 | 0 | } |
925 | | |
926 | | void ScUndoCut::Undo() |
927 | 0 | { |
928 | 0 | BeginUndo(); |
929 | 0 | DoChange( true ); |
930 | 0 | EndUndo(); |
931 | 0 | } |
932 | | |
933 | | void ScUndoCut::Redo() |
934 | 0 | { |
935 | 0 | BeginRedo(); |
936 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
937 | 0 | EnableDrawAdjust( &rDoc, false ); //! include in ScBlockUndo? |
938 | 0 | DoChange( false ); |
939 | 0 | EnableDrawAdjust( &rDoc, true ); //! include in ScBlockUndo? |
940 | 0 | EndRedo(); |
941 | 0 | } |
942 | | |
943 | | void ScUndoCut::Repeat(SfxRepeatTarget& rTarget) |
944 | 0 | { |
945 | 0 | if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget)) |
946 | 0 | pViewTarget->GetViewShell().CutToClip(); |
947 | 0 | } |
948 | | |
949 | | bool ScUndoCut::CanRepeat(SfxRepeatTarget& rTarget) const |
950 | 0 | { |
951 | 0 | return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr; |
952 | 0 | } |
953 | | |
954 | | ScUndoPaste::ScUndoPaste( ScDocShell& rNewDocShell, const ScRangeList& rRanges, |
955 | | const ScMarkData& rMark, |
956 | | ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc, |
957 | | InsertDeleteFlags nNewFlags, |
958 | | std::unique_ptr<ScRefUndoData> pRefData, |
959 | | bool bRedoIsFilled, const ScUndoPasteOptions* pOptions ) : |
960 | 0 | ScMultiBlockUndo( rNewDocShell, rRanges ), |
961 | 0 | aMarkData( rMark ), |
962 | 0 | pUndoDoc( std::move(pNewUndoDoc) ), |
963 | 0 | pRedoDoc( std::move(pNewRedoDoc) ), |
964 | 0 | nFlags( nNewFlags ), |
965 | 0 | pRefUndoData( std::move(pRefData) ), |
966 | 0 | bRedoFilled( bRedoIsFilled ) |
967 | 0 | { |
968 | 0 | if ( pRefUndoData ) |
969 | 0 | pRefUndoData->DeleteUnchanged( rDocShell.GetDocument() ); |
970 | |
|
971 | 0 | if ( pOptions ) |
972 | 0 | aPasteOptions = *pOptions; // used only for Repeat |
973 | |
|
974 | 0 | SetChangeTrack(); |
975 | 0 | } |
976 | | |
977 | | ScUndoPaste::~ScUndoPaste() |
978 | 0 | { |
979 | 0 | pUndoDoc.reset(); |
980 | 0 | pRedoDoc.reset(); |
981 | 0 | pRefUndoData.reset(); |
982 | 0 | pRefRedoData.reset(); |
983 | 0 | } |
984 | | |
985 | | OUString ScUndoPaste::GetComment() const |
986 | 0 | { |
987 | 0 | return ScResId( STR_UNDO_PASTE ); // "paste" |
988 | 0 | } |
989 | | |
990 | | void ScUndoPaste::SetChangeTrack() |
991 | 0 | { |
992 | 0 | ScChangeTrack* pChangeTrack = rDocShell.GetDocument().GetChangeTrack(); |
993 | 0 | if ( pChangeTrack && (nFlags & InsertDeleteFlags::CONTENTS) ) |
994 | 0 | { |
995 | 0 | for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i) |
996 | 0 | { |
997 | 0 | pChangeTrack->AppendContentRange(maBlockRanges[i], *pUndoDoc, |
998 | 0 | nStartChangeAction, nEndChangeAction, SC_CACM_PASTE ); |
999 | 0 | } |
1000 | 0 | } |
1001 | 0 | else |
1002 | 0 | nStartChangeAction = nEndChangeAction = 0; |
1003 | 0 | } |
1004 | | |
1005 | | void ScUndoPaste::DoChange(bool bUndo) |
1006 | 0 | { |
1007 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
1008 | | |
1009 | | // RefUndoData for redo is created before first undo |
1010 | | // (with DeleteUnchanged after the DoUndo call) |
1011 | 0 | bool bCreateRedoData = ( bUndo && pRefUndoData && !pRefRedoData ); |
1012 | 0 | if ( bCreateRedoData ) |
1013 | 0 | pRefRedoData.reset( new ScRefUndoData( rDoc ) ); |
1014 | |
|
1015 | 0 | ScRefUndoData* pWorkRefData = bUndo ? pRefUndoData.get() : pRefRedoData.get(); |
1016 | | |
1017 | | // Always back-up either all or none of the content for Undo |
1018 | 0 | InsertDeleteFlags nUndoFlags = InsertDeleteFlags::NONE; |
1019 | 0 | if (nFlags & InsertDeleteFlags::CONTENTS) |
1020 | 0 | nUndoFlags |= InsertDeleteFlags::CONTENTS; |
1021 | 0 | if (nFlags & InsertDeleteFlags::ATTRIB) |
1022 | 0 | nUndoFlags |= InsertDeleteFlags::ATTRIB; |
1023 | | |
1024 | | // do not undo/redo objects and note captions, they are handled via drawing undo |
1025 | 0 | nUndoFlags &= ~InsertDeleteFlags::OBJECTS; |
1026 | 0 | nUndoFlags |= InsertDeleteFlags::NOCAPTIONS; |
1027 | |
|
1028 | 0 | bool bPaintAll = false; |
1029 | |
|
1030 | 0 | ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); |
1031 | |
|
1032 | 0 | SCTAB nTabCount = rDoc.GetTableCount(); |
1033 | 0 | if ( bUndo && !bRedoFilled ) |
1034 | 0 | { |
1035 | 0 | if (!pRedoDoc) |
1036 | 0 | { |
1037 | 0 | bool bColInfo = true; |
1038 | 0 | bool bRowInfo = true; |
1039 | 0 | for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i) |
1040 | 0 | { |
1041 | 0 | const ScRange& r = maBlockRanges[i]; |
1042 | 0 | bColInfo &= (r.aStart.Row() == 0 && r.aEnd.Row() == rDoc.MaxRow()); |
1043 | 0 | bRowInfo &= (r.aStart.Col() == 0 && r.aEnd.Col() == rDoc.MaxCol()); |
1044 | 0 | if (!bColInfo && !bRowInfo) |
1045 | 0 | break; |
1046 | 0 | } |
1047 | |
|
1048 | 0 | pRedoDoc.reset( new ScDocument( SCDOCMODE_UNDO ) ); |
1049 | 0 | pRedoDoc->InitUndoSelected( rDoc, aMarkData, bColInfo, bRowInfo ); |
1050 | 0 | } |
1051 | | // read "redo" data from the document in the first undo |
1052 | | // all sheets - CopyToDocument skips those that don't exist in pRedoDoc |
1053 | 0 | for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i) |
1054 | 0 | { |
1055 | 0 | ScRange aCopyRange = maBlockRanges[i]; |
1056 | 0 | aCopyRange.aStart.SetTab(0); |
1057 | 0 | aCopyRange.aEnd.SetTab(nTabCount-1); |
1058 | 0 | rDoc.CopyToDocument(aCopyRange, nUndoFlags, false, *pRedoDoc); |
1059 | 0 | bRedoFilled = true; |
1060 | 0 | } |
1061 | 0 | } |
1062 | |
|
1063 | 0 | sal_uInt16 nExtFlags = 0; |
1064 | 0 | rDocShell.UpdatePaintExt(nExtFlags, maBlockRanges.Combine()); |
1065 | | // tdf#167042 - cell comments texts should not be deleted but |
1066 | | // the note text should be remembered in maNoteData to be able |
1067 | | // to later reconstruct a caption from it. |
1068 | 0 | rDoc.ForgetNoteCaptions(maBlockRanges, true); |
1069 | 0 | aMarkData.MarkToMulti(); |
1070 | 0 | rDoc.DeleteSelection(nUndoFlags, aMarkData, false); // no broadcasting here |
1071 | 0 | for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i) |
1072 | 0 | rDoc.BroadcastCells(maBlockRanges[i], SfxHintId::ScDataChanged); |
1073 | |
|
1074 | 0 | aMarkData.MarkToSimple(); |
1075 | |
|
1076 | 0 | SCTAB nFirstSelected = aMarkData.GetFirstSelected(); |
1077 | |
|
1078 | 0 | if ( !bUndo && pRedoDoc ) // Redo: UndoToDocument before handling RefData |
1079 | 0 | { |
1080 | 0 | for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i) |
1081 | 0 | { |
1082 | 0 | ScRange aRange = maBlockRanges[i]; |
1083 | 0 | aRange.aStart.SetTab(nFirstSelected); |
1084 | 0 | aRange.aEnd.SetTab(nFirstSelected); |
1085 | 0 | pRedoDoc->UndoToDocument(aRange, nUndoFlags, false, rDoc); |
1086 | 0 | for (const auto& rTab : aMarkData) |
1087 | 0 | { |
1088 | 0 | if (rTab >= nTabCount) |
1089 | 0 | break; |
1090 | | |
1091 | 0 | if (rTab == nFirstSelected) |
1092 | 0 | continue; |
1093 | | |
1094 | 0 | aRange.aStart.SetTab(rTab); |
1095 | 0 | aRange.aEnd.SetTab(rTab); |
1096 | 0 | pRedoDoc->CopyToDocument(aRange, nUndoFlags, false, rDoc); |
1097 | 0 | } |
1098 | 0 | } |
1099 | 0 | } |
1100 | |
|
1101 | 0 | if (pWorkRefData) |
1102 | 0 | { |
1103 | 0 | pWorkRefData->DoUndo( rDoc, true ); // true = bSetChartRangeLists for SetChartListenerCollection |
1104 | 0 | if (!maBlockRanges.empty() && |
1105 | 0 | rDoc.RefreshAutoFilter(0, 0, rDoc.MaxCol(), rDoc.MaxRow(), maBlockRanges[0].aStart.Tab())) |
1106 | 0 | bPaintAll = true; |
1107 | 0 | } |
1108 | |
|
1109 | 0 | if ( bCreateRedoData && pRefRedoData ) |
1110 | 0 | pRefRedoData->DeleteUnchanged( rDoc ); |
1111 | |
|
1112 | 0 | if (bUndo) // Undo: UndoToDocument after handling RefData |
1113 | 0 | { |
1114 | 0 | for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i) |
1115 | 0 | { |
1116 | 0 | ScRange aRange = maBlockRanges[i]; |
1117 | 0 | for (const auto& rTab : aMarkData) |
1118 | 0 | { |
1119 | 0 | if (rTab >= nTabCount) |
1120 | 0 | break; |
1121 | 0 | aRange.aStart.SetTab(rTab); |
1122 | 0 | aRange.aEnd.SetTab(rTab); |
1123 | 0 | pUndoDoc->UndoToDocument(aRange, nUndoFlags, false, rDoc); |
1124 | 0 | } |
1125 | 0 | } |
1126 | 0 | } |
1127 | |
|
1128 | 0 | if ( bUndo ) |
1129 | 0 | { |
1130 | 0 | ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack(); |
1131 | 0 | if ( pChangeTrack ) |
1132 | 0 | pChangeTrack->Undo( nStartChangeAction, nEndChangeAction ); |
1133 | 0 | } |
1134 | 0 | else |
1135 | 0 | SetChangeTrack(); |
1136 | |
|
1137 | 0 | ScRangeList aDrawRanges(maBlockRanges); |
1138 | 0 | PaintPartFlags nPaint = PaintPartFlags::Grid; |
1139 | | |
1140 | | // For sheet geometry invalidation. |
1141 | 0 | bool bColsAffected = false; |
1142 | 0 | bool bRowsAffected = false; |
1143 | |
|
1144 | 0 | for (size_t i = 0, n = aDrawRanges.size(); i < n; ++i) |
1145 | 0 | { |
1146 | 0 | ScRange& rDrawRange = aDrawRanges[i]; |
1147 | 0 | rDoc.ExtendMerge(rDrawRange, true); // only needed for single sheet (text/rtf etc.) |
1148 | 0 | ScRangeList aRangeList(rDrawRange); |
1149 | 0 | ScMarkData aData(rDoc.GetSheetLimits(), aRangeList); |
1150 | 0 | if (bPaintAll) |
1151 | 0 | { |
1152 | 0 | rDrawRange.aStart.SetCol(0); |
1153 | 0 | rDrawRange.aStart.SetRow(0); |
1154 | 0 | rDrawRange.aEnd.SetCol(rDoc.MaxCol()); |
1155 | 0 | rDrawRange.aEnd.SetRow(rDoc.MaxRow()); |
1156 | 0 | nPaint |= PaintPartFlags::Top | PaintPartFlags::Left; |
1157 | 0 | if (pViewShell) |
1158 | 0 | pViewShell->AdjustBlockHeight(false, &aData); |
1159 | 0 | } |
1160 | 0 | else |
1161 | 0 | { |
1162 | 0 | if (maBlockRanges[i].aStart.Row() == 0 && maBlockRanges[i].aEnd.Row() == rDoc.MaxRow()) // whole column |
1163 | 0 | { |
1164 | 0 | nPaint |= PaintPartFlags::Top; |
1165 | 0 | rDrawRange.aEnd.SetCol(rDoc.MaxCol()); |
1166 | 0 | bColsAffected = true; |
1167 | 0 | } |
1168 | 0 | if (maBlockRanges[i].aStart.Col() == 0 && maBlockRanges[i].aEnd.Col() == rDoc.MaxCol()) // whole row |
1169 | 0 | { |
1170 | 0 | nPaint |= PaintPartFlags::Left; |
1171 | 0 | rDrawRange.aEnd.SetRow(rDoc.MaxRow()); |
1172 | 0 | bRowsAffected = true; |
1173 | 0 | } |
1174 | 0 | if (pViewShell && pViewShell->AdjustBlockHeight(false, &aData)) |
1175 | 0 | { |
1176 | 0 | rDrawRange.aStart.SetCol(0); |
1177 | 0 | rDrawRange.aStart.SetRow(0); |
1178 | 0 | rDrawRange.aEnd.SetCol(rDoc.MaxCol()); |
1179 | 0 | rDrawRange.aEnd.SetRow(rDoc.MaxRow()); |
1180 | 0 | nPaint |= PaintPartFlags::Left; |
1181 | 0 | } |
1182 | 0 | rDocShell.UpdatePaintExt(nExtFlags, rDrawRange); |
1183 | 0 | } |
1184 | 0 | } |
1185 | |
|
1186 | 0 | if ( !bUndo ) // draw redo after updating row heights |
1187 | 0 | RedoSdrUndoAction(mpDrawUndo.get()); |
1188 | |
|
1189 | 0 | rDocShell.PostPaint(aDrawRanges, nPaint, nExtFlags); |
1190 | |
|
1191 | 0 | rDocShell.PostDataChanged(); |
1192 | 0 | if (!pViewShell) |
1193 | 0 | return; |
1194 | | |
1195 | 0 | pViewShell->CellContentChanged(); |
1196 | |
|
1197 | 0 | if (bColsAffected || bRowsAffected) |
1198 | 0 | ScTabViewShell::notifyAllViewsSheetGeomInvalidation( |
1199 | 0 | pViewShell, |
1200 | 0 | bColsAffected, bRowsAffected, |
1201 | 0 | true /* bSizes*/, true /* bHidden */, true /* bFiltered */, |
1202 | 0 | true /* bGroups */, aDrawRanges[0].aStart.Tab()); |
1203 | 0 | } |
1204 | | |
1205 | | void ScUndoPaste::Undo() |
1206 | 0 | { |
1207 | 0 | BeginUndo(); |
1208 | 0 | DoChange(true); |
1209 | 0 | if (!maBlockRanges.empty()) |
1210 | 0 | ShowTable(maBlockRanges.front()); |
1211 | 0 | EndUndo(); |
1212 | 0 | SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); |
1213 | 0 | } |
1214 | | |
1215 | | void ScUndoPaste::Redo() |
1216 | 0 | { |
1217 | 0 | BeginRedo(); |
1218 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
1219 | 0 | EnableDrawAdjust( &rDoc, false ); //! include in ScBlockUndo? |
1220 | 0 | DoChange( false ); |
1221 | 0 | EnableDrawAdjust( &rDoc, true ); //! include in ScBlockUndo? |
1222 | 0 | EndRedo(); |
1223 | 0 | SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); |
1224 | 0 | } |
1225 | | |
1226 | | void ScUndoPaste::Repeat(SfxRepeatTarget& rTarget) |
1227 | 0 | { |
1228 | 0 | auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget); |
1229 | 0 | if (!pViewTarget) |
1230 | 0 | return; |
1231 | | |
1232 | 0 | ScTabViewShell& rViewSh = pViewTarget->GetViewShell(); |
1233 | | // keep a reference in case the clipboard is changed during PasteFromClip |
1234 | 0 | const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(rViewSh.GetViewData().GetActiveWin())); |
1235 | 0 | if (pOwnClip) |
1236 | 0 | { |
1237 | 0 | rViewSh.PasteFromClip( nFlags, pOwnClip->GetDocument(), |
1238 | 0 | aPasteOptions.nFunction, aPasteOptions.bSkipEmptyCells, aPasteOptions.bTranspose, |
1239 | 0 | aPasteOptions.bAsLink, aPasteOptions.eMoveMode, InsertDeleteFlags::NONE, |
1240 | 0 | true ); // allow warning dialog |
1241 | 0 | } |
1242 | 0 | } |
1243 | | |
1244 | | bool ScUndoPaste::CanRepeat(SfxRepeatTarget& rTarget) const |
1245 | 0 | { |
1246 | 0 | return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr; |
1247 | 0 | } |
1248 | | |
1249 | | ScUndoDragDrop::ScUndoDragDrop( ScDocShell& rNewDocShell, |
1250 | | const ScRange& rRange, const ScAddress& aNewDestPos, bool bNewCut, |
1251 | | ScDocumentUniquePtr pUndoDocument, bool bScenario ) : |
1252 | 0 | ScMoveUndo( rNewDocShell, std::move(pUndoDocument), nullptr ), |
1253 | 0 | mnPaintExtFlags( 0 ), |
1254 | 0 | aSrcRange( rRange ), |
1255 | 0 | bCut( bNewCut ), |
1256 | 0 | bKeepScenarioFlags( bScenario ) |
1257 | 0 | { |
1258 | 0 | ScAddress aDestEnd(aNewDestPos); |
1259 | 0 | aDestEnd.IncRow(aSrcRange.aEnd.Row() - aSrcRange.aStart.Row()); |
1260 | 0 | aDestEnd.IncCol(aSrcRange.aEnd.Col() - aSrcRange.aStart.Col()); |
1261 | 0 | aDestEnd.IncTab(aSrcRange.aEnd.Tab() - aSrcRange.aStart.Tab()); |
1262 | |
|
1263 | 0 | bool bIncludeFiltered = bCut; |
1264 | 0 | if ( !bIncludeFiltered ) |
1265 | 0 | { |
1266 | | // find number of non-filtered rows |
1267 | 0 | SCROW nPastedCount = rDocShell.GetDocument().CountNonFilteredRows( |
1268 | 0 | aSrcRange.aStart.Row(), aSrcRange.aEnd.Row(), aSrcRange.aStart.Tab()); |
1269 | |
|
1270 | 0 | if ( nPastedCount == 0 ) |
1271 | 0 | nPastedCount = 1; |
1272 | 0 | aDestEnd.SetRow( aNewDestPos.Row() + nPastedCount - 1 ); |
1273 | 0 | } |
1274 | |
|
1275 | 0 | aDestRange.aStart = aNewDestPos; |
1276 | 0 | aDestRange.aEnd = aDestEnd; |
1277 | |
|
1278 | 0 | SetChangeTrack(); |
1279 | 0 | } |
1280 | | |
1281 | | ScUndoDragDrop::~ScUndoDragDrop() |
1282 | 0 | { |
1283 | 0 | } |
1284 | | |
1285 | | OUString ScUndoDragDrop::GetComment() const |
1286 | 0 | { // "Move" : "Copy" |
1287 | 0 | return bCut ? |
1288 | 0 | ScResId( STR_UNDO_MOVE ) : |
1289 | 0 | ScResId( STR_UNDO_COPY ); |
1290 | 0 | } |
1291 | | |
1292 | | void ScUndoDragDrop::SetChangeTrack() |
1293 | 0 | { |
1294 | 0 | ScChangeTrack* pChangeTrack = rDocShell.GetDocument().GetChangeTrack(); |
1295 | 0 | if ( pChangeTrack ) |
1296 | 0 | { |
1297 | 0 | if ( bCut ) |
1298 | 0 | { |
1299 | 0 | nStartChangeAction = pChangeTrack->GetActionMax() + 1; |
1300 | 0 | pChangeTrack->AppendMove( aSrcRange, aDestRange, pRefUndoDoc.get() ); |
1301 | 0 | nEndChangeAction = pChangeTrack->GetActionMax(); |
1302 | 0 | } |
1303 | 0 | else |
1304 | 0 | pChangeTrack->AppendContentRange( aDestRange, *pRefUndoDoc, |
1305 | 0 | nStartChangeAction, nEndChangeAction ); |
1306 | 0 | } |
1307 | 0 | else |
1308 | 0 | nStartChangeAction = nEndChangeAction = 0; |
1309 | 0 | } |
1310 | | |
1311 | | void ScUndoDragDrop::PaintArea( ScRange aRange, sal_uInt16 nExtFlags ) const |
1312 | 0 | { |
1313 | 0 | PaintPartFlags nPaint = PaintPartFlags::Grid; |
1314 | 0 | ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); |
1315 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
1316 | |
|
1317 | 0 | if (pViewShell) |
1318 | 0 | { |
1319 | 0 | ScopedVclPtrInstance< VirtualDevice > pVirtDev; |
1320 | 0 | ScViewData& rViewData = pViewShell->GetViewData(); |
1321 | 0 | sc::RowHeightContext aCxt( |
1322 | 0 | rDoc.MaxRow(), rViewData.GetPPTX(), rViewData.GetPPTY(), rViewData.GetZoomX(), rViewData.GetZoomY(), |
1323 | 0 | pVirtDev); |
1324 | |
|
1325 | 0 | if (rDoc.SetOptimalHeight(aCxt, aRange.aStart.Row(), aRange.aEnd.Row(), aRange.aStart.Tab(), true)) |
1326 | 0 | { |
1327 | | // tdf#76183: recalculate objects' positions |
1328 | 0 | rDoc.SetDrawPageSize(aRange.aStart.Tab()); |
1329 | 0 | aRange.aStart.SetCol(0); |
1330 | 0 | aRange.aEnd.SetCol(rDoc.MaxCol()); |
1331 | 0 | aRange.aEnd.SetRow(rDoc.MaxRow()); |
1332 | 0 | nPaint |= PaintPartFlags::Left; |
1333 | 0 | } |
1334 | 0 | } |
1335 | |
|
1336 | 0 | if ( bKeepScenarioFlags ) |
1337 | 0 | { |
1338 | | // Copy scenario -> also paint scenario boarder |
1339 | 0 | aRange.aStart.SetCol(0); |
1340 | 0 | aRange.aStart.SetRow(0); |
1341 | 0 | aRange.aEnd.SetCol(rDoc.MaxCol()); |
1342 | 0 | aRange.aEnd.SetRow(rDoc.MaxRow()); |
1343 | 0 | } |
1344 | | |
1345 | | // column/row info (width/height) included if whole columns/rows were copied |
1346 | 0 | if ( aSrcRange.aStart.Col() == 0 && aSrcRange.aEnd.Col() == rDoc.MaxCol() ) |
1347 | 0 | { |
1348 | 0 | nPaint |= PaintPartFlags::Left; |
1349 | 0 | aRange.aEnd.SetRow(rDoc.MaxRow()); |
1350 | 0 | } |
1351 | 0 | if ( aSrcRange.aStart.Row() == 0 && aSrcRange.aEnd.Row() == rDoc.MaxRow() ) |
1352 | 0 | { |
1353 | 0 | nPaint |= PaintPartFlags::Top; |
1354 | 0 | aRange.aEnd.SetCol(rDoc.MaxCol()); |
1355 | 0 | } |
1356 | |
|
1357 | 0 | rDocShell.PostPaint( aRange, nPaint, nExtFlags ); |
1358 | 0 | } |
1359 | | |
1360 | | void ScUndoDragDrop::DoUndo( ScRange aRange ) |
1361 | 0 | { |
1362 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
1363 | |
|
1364 | 0 | ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack(); |
1365 | 0 | if ( pChangeTrack ) |
1366 | 0 | pChangeTrack->Undo( nStartChangeAction, nEndChangeAction ); |
1367 | | |
1368 | | // Database range before data, so that the Autofilter button match up in ExtendMerge |
1369 | |
|
1370 | 0 | ScRange aPaintRange = aRange; |
1371 | 0 | rDoc.ExtendMerge( aPaintRange ); // before deleting |
1372 | |
|
1373 | 0 | rDocShell.UpdatePaintExt(mnPaintExtFlags, aPaintRange); |
1374 | | |
1375 | | // do not undo objects and note captions, they are handled via drawing undo |
1376 | 0 | InsertDeleteFlags nUndoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS; |
1377 | | |
1378 | | // Additionally discard/forget caption ownership during deletion, as |
1379 | | // Drag&Drop is a special case in that the Undo holds captions of the |
1380 | | // transferred target range, which would get deleted and |
1381 | | // SdrGroupUndo::Undo() would attempt to access invalidated captions and |
1382 | | // crash, tdf#92995 |
1383 | 0 | InsertDeleteFlags nDelFlags = nUndoFlags | InsertDeleteFlags::FORGETCAPTIONS; |
1384 | |
|
1385 | 0 | rDoc.DeleteAreaTab( aRange, nDelFlags ); |
1386 | 0 | pRefUndoDoc->CopyToDocument(aRange, nUndoFlags, false, rDoc); |
1387 | 0 | if ( rDoc.HasAttrib( aRange, HasAttrFlags::Merged ) ) |
1388 | 0 | rDoc.ExtendMerge( aRange, true ); |
1389 | |
|
1390 | 0 | aPaintRange.aEnd.SetCol( std::max( aPaintRange.aEnd.Col(), aRange.aEnd.Col() ) ); |
1391 | 0 | aPaintRange.aEnd.SetRow( std::max( aPaintRange.aEnd.Row(), aRange.aEnd.Row() ) ); |
1392 | |
|
1393 | 0 | rDocShell.UpdatePaintExt(mnPaintExtFlags, aPaintRange); |
1394 | 0 | maPaintRanges.Join(aPaintRange); |
1395 | |
|
1396 | 0 | if (ScTabViewShell* pTabViewShell = ScTabViewShell::GetActiveViewShell()) |
1397 | 0 | { |
1398 | 0 | if (comphelper::LibreOfficeKit::isActive()) |
1399 | 0 | { |
1400 | 0 | pTabViewShell->OnLOKSetWidthOrHeight(aPaintRange.aStart.Col(), true); |
1401 | 0 | pTabViewShell->OnLOKSetWidthOrHeight(aPaintRange.aStart.Row(), false); |
1402 | 0 | } |
1403 | |
|
1404 | 0 | ScTabViewShell::notifyAllViewsSheetGeomInvalidation( |
1405 | 0 | pTabViewShell, |
1406 | 0 | true /* bColumns */, true /* bRows */, |
1407 | 0 | true /* bSizes */, true /* bHidden */, true /* bFiltered */, |
1408 | 0 | true /* bGroups */, aPaintRange.aStart.Tab()); |
1409 | 0 | } |
1410 | |
|
1411 | 0 | } |
1412 | | |
1413 | | void ScUndoDragDrop::Undo() |
1414 | 0 | { |
1415 | 0 | mnPaintExtFlags = 0; |
1416 | 0 | maPaintRanges.RemoveAll(); |
1417 | |
|
1418 | 0 | BeginUndo(); |
1419 | |
|
1420 | 0 | if (bCut) |
1421 | 0 | { |
1422 | | // During undo, we move cells from aDestRange to aSrcRange. |
1423 | |
|
1424 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
1425 | |
|
1426 | 0 | SCCOL nColDelta = aSrcRange.aStart.Col() - aDestRange.aStart.Col(); |
1427 | 0 | SCROW nRowDelta = aSrcRange.aStart.Row() - aDestRange.aStart.Row(); |
1428 | 0 | SCTAB nTabDelta = aSrcRange.aStart.Tab() - aDestRange.aStart.Tab(); |
1429 | |
|
1430 | 0 | sc::RefUpdateContext aCxt(rDoc); |
1431 | 0 | aCxt.meMode = URM_MOVE; |
1432 | 0 | aCxt.maRange = aSrcRange; |
1433 | 0 | aCxt.mnColDelta = nColDelta; |
1434 | 0 | aCxt.mnRowDelta = nRowDelta; |
1435 | 0 | aCxt.mnTabDelta = nTabDelta; |
1436 | | |
1437 | | // Global range names. |
1438 | 0 | ScRangeName& rName = rDoc.GetRangeName(); |
1439 | 0 | rName.UpdateReference(aCxt); |
1440 | |
|
1441 | 0 | SCTAB nTabCount = rDoc.GetTableCount(); |
1442 | 0 | for (SCTAB nTab = 0; nTab < nTabCount; ++nTab) |
1443 | 0 | { |
1444 | | // Sheet-local range names. |
1445 | 0 | ScRangeName* pName = rDoc.GetRangeName(nTab); |
1446 | 0 | if (pName) |
1447 | 0 | pName->UpdateReference(aCxt, nTab); |
1448 | 0 | } |
1449 | |
|
1450 | 0 | ScValidationDataList* pValidList = rDoc.GetValidationList(); |
1451 | 0 | if (pValidList) |
1452 | 0 | { |
1453 | | // Update the references of validation entries. |
1454 | 0 | pValidList->UpdateReference(aCxt); |
1455 | 0 | } |
1456 | |
|
1457 | 0 | DoUndo(aDestRange); |
1458 | 0 | DoUndo(aSrcRange); |
1459 | |
|
1460 | 0 | rDoc.BroadcastCells(aSrcRange, SfxHintId::ScDataChanged, false); |
1461 | 0 | } |
1462 | 0 | else |
1463 | 0 | DoUndo(aDestRange); |
1464 | |
|
1465 | 0 | for (size_t i = 0; i < maPaintRanges.size(); ++i) |
1466 | 0 | { |
1467 | 0 | const ScRange& r = maPaintRanges[i]; |
1468 | 0 | PaintArea(r, mnPaintExtFlags); |
1469 | 0 | } |
1470 | |
|
1471 | 0 | EndUndo(); |
1472 | 0 | SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); |
1473 | 0 | } |
1474 | | |
1475 | | void ScUndoDragDrop::Redo() |
1476 | 0 | { |
1477 | 0 | BeginRedo(); |
1478 | |
|
1479 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
1480 | 0 | ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP )); |
1481 | |
|
1482 | 0 | EnableDrawAdjust( &rDoc, false ); //! include in ScBlockUndo? |
1483 | | |
1484 | | // do not undo/redo objects and note captions, they are handled via drawing undo |
1485 | 0 | constexpr InsertDeleteFlags nRedoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS; |
1486 | | |
1487 | | /* TODO: Redoing note captions is quite tricky due to the fact that a |
1488 | | helper clip document is used. While (re-)pasting the contents to the |
1489 | | destination area, the original pointers to the captions created while |
1490 | | dropping have to be restored. A simple CopyFromClip() would create new |
1491 | | caption objects that are not tracked by drawing undo, and the captions |
1492 | | restored by drawing redo would live without cell note objects pointing |
1493 | | to them. So, first, CopyToClip() and CopyFromClip() are called without |
1494 | | cloning the caption objects. This leads to cell notes pointing to the |
1495 | | wrong captions from source area that will be removed by drawing redo |
1496 | | later. Second, the pointers to the new captions have to be restored. |
1497 | | Sadly, currently these pointers are not stored anywhere but in the list |
1498 | | of drawing undo actions. */ |
1499 | |
|
1500 | 0 | SCTAB nTab; |
1501 | 0 | ScMarkData aSourceMark(rDoc.GetSheetLimits()); |
1502 | 0 | for (nTab=aSrcRange.aStart.Tab(); nTab<=aSrcRange.aEnd.Tab(); nTab++) |
1503 | 0 | aSourceMark.SelectTable( nTab, true ); |
1504 | | |
1505 | | // do not clone objects and note captions into clipdoc (see above) |
1506 | | // but at least copy notes |
1507 | 0 | ScClipParam aClipParam(aSrcRange, bCut); |
1508 | 0 | rDoc.CopyToClip(aClipParam, pClipDoc.get(), &aSourceMark, bKeepScenarioFlags, false); |
1509 | |
|
1510 | 0 | if (bCut) |
1511 | 0 | { |
1512 | 0 | ScRange aSrcPaintRange = aSrcRange; |
1513 | 0 | rDoc.ExtendMerge( aSrcPaintRange ); // before deleting |
1514 | 0 | sal_uInt16 nExtFlags = 0; |
1515 | 0 | rDocShell.UpdatePaintExt( nExtFlags, aSrcPaintRange ); |
1516 | 0 | rDoc.DeleteAreaTab( aSrcRange, nRedoFlags ); |
1517 | 0 | PaintArea( aSrcPaintRange, nExtFlags ); |
1518 | 0 | } |
1519 | |
|
1520 | 0 | ScMarkData aDestMark(rDoc.GetSheetLimits()); |
1521 | 0 | for (nTab=aDestRange.aStart.Tab(); nTab<=aDestRange.aEnd.Tab(); nTab++) |
1522 | 0 | aDestMark.SelectTable( nTab, true ); |
1523 | |
|
1524 | 0 | bool bIncludeFiltered = bCut; |
1525 | | // TODO: restore old note captions instead of cloning new captions... |
1526 | 0 | rDoc.CopyFromClip( aDestRange, aDestMark, InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS, nullptr, pClipDoc.get(), true, false, bIncludeFiltered ); |
1527 | |
|
1528 | 0 | if (bCut) |
1529 | 0 | for (nTab=aSrcRange.aStart.Tab(); nTab<=aSrcRange.aEnd.Tab(); nTab++) |
1530 | 0 | rDoc.RefreshAutoFilter( aSrcRange.aStart.Col(), aSrcRange.aStart.Row(), |
1531 | 0 | aSrcRange.aEnd.Col(), aSrcRange.aEnd.Row(), nTab ); |
1532 | | |
1533 | | // skipped rows and merged cells don't mix |
1534 | 0 | if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() ) |
1535 | 0 | rDocShell.GetDocFunc().UnmergeCells( aDestRange, false, nullptr ); |
1536 | |
|
1537 | 0 | for (nTab=aDestRange.aStart.Tab(); nTab<=aDestRange.aEnd.Tab(); nTab++) |
1538 | 0 | { |
1539 | 0 | SCCOL nEndCol = aDestRange.aEnd.Col(); |
1540 | 0 | SCROW nEndRow = aDestRange.aEnd.Row(); |
1541 | 0 | rDoc.ExtendMerge( aDestRange.aStart.Col(), aDestRange.aStart.Row(), |
1542 | 0 | nEndCol, nEndRow, nTab, true ); |
1543 | 0 | PaintArea( ScRange( aDestRange.aStart.Col(), aDestRange.aStart.Row(), nTab, |
1544 | 0 | nEndCol, nEndRow, nTab ), 0 ); |
1545 | 0 | } |
1546 | |
|
1547 | 0 | SetChangeTrack(); |
1548 | |
|
1549 | 0 | pClipDoc.reset(); |
1550 | 0 | ShowTable( aDestRange.aStart.Tab() ); |
1551 | |
|
1552 | 0 | RedoSdrUndoAction( pDrawUndo.get() ); //! include in ScBlockUndo? |
1553 | 0 | EnableDrawAdjust( &rDoc, true ); //! include in ScBlockUndo? |
1554 | |
|
1555 | 0 | EndRedo(); |
1556 | 0 | SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); |
1557 | |
|
1558 | 0 | if (comphelper::LibreOfficeKit::isActive()) |
1559 | 0 | { |
1560 | 0 | SCCOL nStartCol = aDestRange.aStart.Col(); |
1561 | 0 | SCROW nStartRow = aDestRange.aStart.Row(); |
1562 | 0 | if (bCut) |
1563 | 0 | { |
1564 | 0 | nStartCol = std::min(nStartCol, aSrcRange.aStart.Col()); |
1565 | 0 | nStartRow = std::min(nStartRow, aSrcRange.aStart.Row()); |
1566 | 0 | } |
1567 | |
|
1568 | 0 | if (ScTabViewShell* pTabViewShell = ScTabViewShell::GetActiveViewShell()) |
1569 | 0 | { |
1570 | 0 | pTabViewShell->OnLOKSetWidthOrHeight(nStartCol, true); |
1571 | 0 | pTabViewShell->OnLOKSetWidthOrHeight(nStartRow, false); |
1572 | |
|
1573 | 0 | SCTAB nStartTab = aDestRange.aStart.Tab(); |
1574 | 0 | SCTAB nEndTab = aDestRange.aEnd.Tab(); |
1575 | 0 | if (bCut) |
1576 | 0 | { |
1577 | 0 | nStartTab = std::min(nStartTab, aSrcRange.aStart.Tab()); |
1578 | 0 | nEndTab = std::max(nEndTab, aSrcRange.aEnd.Tab()); |
1579 | 0 | } |
1580 | 0 | for (nTab = nStartTab; nTab <= nEndTab; ++nTab) |
1581 | 0 | { |
1582 | 0 | ScTabViewShell::notifyAllViewsSheetGeomInvalidation( |
1583 | 0 | pTabViewShell, true /* bColumns */, true /* bRows */, |
1584 | 0 | true /* bSizes */, true /* bHidden */, true /* bFiltered */, true /* bGroups */, |
1585 | 0 | nTab); |
1586 | 0 | } |
1587 | 0 | } |
1588 | 0 | } |
1589 | 0 | } |
1590 | | |
1591 | | void ScUndoDragDrop::Repeat(SfxRepeatTarget& /* rTarget */) |
1592 | 0 | { |
1593 | 0 | } |
1594 | | |
1595 | | bool ScUndoDragDrop::CanRepeat(SfxRepeatTarget& /* rTarget */) const |
1596 | 0 | { |
1597 | 0 | return false; // not possible |
1598 | 0 | } |
1599 | | |
1600 | | // Insert list containing range names |
1601 | | // (Insert|Name|Insert =>[List]) |
1602 | | ScUndoListNames::ScUndoListNames(ScDocShell& rNewDocShell, const ScRange& rRange, |
1603 | | ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc) |
1604 | 0 | : ScBlockUndo(rNewDocShell, rRange, SC_UNDO_AUTOHEIGHT) |
1605 | 0 | , xUndoDoc(std::move(pNewUndoDoc)) |
1606 | 0 | , xRedoDoc(std::move(pNewRedoDoc)) |
1607 | 0 | { |
1608 | 0 | } |
1609 | | |
1610 | | OUString ScUndoListNames::GetComment() const |
1611 | 0 | { |
1612 | 0 | return ScResId( STR_UNDO_LISTNAMES ); |
1613 | 0 | } |
1614 | | |
1615 | | void ScUndoListNames::DoChange( ScDocument* pSrcDoc ) const |
1616 | 0 | { |
1617 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
1618 | |
|
1619 | 0 | rDoc.DeleteAreaTab( aBlockRange, InsertDeleteFlags::ALL ); |
1620 | 0 | pSrcDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ALL, false, rDoc); |
1621 | 0 | rDocShell.PostPaint( aBlockRange, PaintPartFlags::Grid ); |
1622 | 0 | rDocShell.PostDataChanged(); |
1623 | 0 | ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); |
1624 | 0 | if (pViewShell) |
1625 | 0 | pViewShell->CellContentChanged(); |
1626 | 0 | } |
1627 | | |
1628 | | void ScUndoListNames::Undo() |
1629 | 0 | { |
1630 | 0 | BeginUndo(); |
1631 | 0 | DoChange(xUndoDoc.get()); |
1632 | 0 | EndUndo(); |
1633 | 0 | } |
1634 | | |
1635 | | void ScUndoListNames::Redo() |
1636 | 0 | { |
1637 | 0 | BeginRedo(); |
1638 | 0 | DoChange(xRedoDoc.get()); |
1639 | 0 | EndRedo(); |
1640 | 0 | } |
1641 | | |
1642 | | void ScUndoListNames::Repeat(SfxRepeatTarget& rTarget) |
1643 | 0 | { |
1644 | 0 | if (auto pTabViewTarget = dynamic_cast<ScTabViewTarget*>(&rTarget)) |
1645 | 0 | pTabViewTarget->GetViewShell().InsertNameList(); |
1646 | 0 | } |
1647 | | |
1648 | | bool ScUndoListNames::CanRepeat(SfxRepeatTarget& rTarget) const |
1649 | 0 | { |
1650 | 0 | return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr; |
1651 | 0 | } |
1652 | | |
1653 | | ScUndoConditionalFormat::ScUndoConditionalFormat(ScDocShell& rNewDocShell, SCTAB nTab): |
1654 | 0 | ScSimpleUndo( rNewDocShell ), |
1655 | 0 | mnTab(nTab), |
1656 | 0 | mpUndoDoc(createUndoRedoData()) |
1657 | 0 | { |
1658 | 0 | } |
1659 | | |
1660 | | ScUndoConditionalFormat::~ScUndoConditionalFormat() |
1661 | 0 | { |
1662 | 0 | } |
1663 | | |
1664 | | ScDocumentUniquePtr ScUndoConditionalFormat::createUndoRedoData() |
1665 | 0 | { |
1666 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
1667 | 0 | ScDocumentUniquePtr pUndoRedoDoc(new ScDocument(SCDOCMODE_UNDO)); |
1668 | 0 | pUndoRedoDoc->InitUndo(rDoc, mnTab, mnTab); |
1669 | 0 | if (const auto* pList = rDoc.GetCondFormList(mnTab)) |
1670 | 0 | pUndoRedoDoc->SetCondFormList(pList->Clone(*pUndoRedoDoc), mnTab); |
1671 | 0 | return pUndoRedoDoc; |
1672 | 0 | } |
1673 | | |
1674 | | OUString ScUndoConditionalFormat::GetComment() const |
1675 | 0 | { |
1676 | 0 | return ScResId( STR_UNDO_CONDFORMAT ); |
1677 | 0 | } |
1678 | | |
1679 | | void ScUndoConditionalFormat::Undo() |
1680 | 0 | { |
1681 | 0 | DoChange(mpUndoDoc.get()); |
1682 | 0 | } |
1683 | | |
1684 | | void ScUndoConditionalFormat::Redo() |
1685 | 0 | { |
1686 | 0 | DoChange(mpRedoDoc.get()); |
1687 | 0 | } |
1688 | | |
1689 | | void ScUndoConditionalFormat::DoChange(const ScDocument* pSrcDoc) |
1690 | 0 | { |
1691 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
1692 | | |
1693 | | // Restore all conditional formats in the tab. This is simpler and more reliable, than |
1694 | | // restoring formats in a specific range, and then trying to join selectively the restored |
1695 | | // formats with the other formats in the tab, to get the correct state. |
1696 | 0 | ScRangeList aCombinedRange; |
1697 | 0 | if (const auto* pOldList = rDoc.GetCondFormList(mnTab)) |
1698 | 0 | { |
1699 | 0 | aCombinedRange = pOldList->GetCombinedRange(); |
1700 | | // Clear all existing CF keys from cells' attributes |
1701 | 0 | for (auto& pFormat : *pOldList) |
1702 | 0 | rDoc.RemoveCondFormatData(aCombinedRange, mnTab, pFormat->GetKey()); |
1703 | 0 | } |
1704 | |
|
1705 | 0 | if (const auto* pNewList = pSrcDoc->GetCondFormList(mnTab)) |
1706 | 0 | { |
1707 | 0 | for (const auto& cond : *pNewList) |
1708 | 0 | { |
1709 | | // Restore the CF keys to cell attributes |
1710 | 0 | rDoc.AddCondFormatData(cond->GetRange(), mnTab, cond->GetKey()); |
1711 | 0 | for (const auto& range : cond->GetRange()) |
1712 | 0 | aCombinedRange.Join(range); |
1713 | 0 | } |
1714 | 0 | rDoc.SetCondFormList(pNewList->Clone(rDoc), mnTab); |
1715 | 0 | } |
1716 | 0 | else |
1717 | 0 | { |
1718 | 0 | rDoc.SetCondFormList(nullptr, mnTab); |
1719 | 0 | } |
1720 | 0 | rDocShell.PostPaint(aCombinedRange, PaintPartFlags::Grid); |
1721 | 0 | rDocShell.PostDataChanged(); |
1722 | 0 | ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); |
1723 | 0 | if (pViewShell) |
1724 | 0 | pViewShell->CellContentChanged(); |
1725 | 0 | } |
1726 | | |
1727 | | void ScUndoConditionalFormat::Repeat(SfxRepeatTarget& ) |
1728 | 0 | { |
1729 | 0 | } |
1730 | | |
1731 | | bool ScUndoConditionalFormat::CanRepeat(SfxRepeatTarget& ) const |
1732 | 0 | { |
1733 | 0 | return false; |
1734 | 0 | } |
1735 | | |
1736 | | ScUndoConditionalFormatList::ScUndoConditionalFormatList(ScDocShell& rNewDocShell, |
1737 | | ScDocumentUniquePtr pUndoDoc, ScDocumentUniquePtr pRedoDoc, SCTAB nTab): |
1738 | 0 | ScSimpleUndo( rNewDocShell ), |
1739 | 0 | mpUndoDoc(std::move(pUndoDoc)), |
1740 | 0 | mpRedoDoc(std::move(pRedoDoc)), |
1741 | 0 | mnTab(nTab) |
1742 | 0 | { |
1743 | 0 | } |
1744 | | |
1745 | | ScUndoConditionalFormatList::~ScUndoConditionalFormatList() |
1746 | 0 | { |
1747 | 0 | } |
1748 | | |
1749 | | OUString ScUndoConditionalFormatList::GetComment() const |
1750 | 0 | { |
1751 | 0 | return ScResId( STR_UNDO_CONDFORMAT_LIST ); |
1752 | 0 | } |
1753 | | |
1754 | | void ScUndoConditionalFormatList::Undo() |
1755 | 0 | { |
1756 | 0 | DoChange(mpUndoDoc.get()); |
1757 | 0 | } |
1758 | | |
1759 | | void ScUndoConditionalFormatList::Redo() |
1760 | 0 | { |
1761 | 0 | DoChange(mpRedoDoc.get()); |
1762 | 0 | } |
1763 | | |
1764 | | void ScUndoConditionalFormatList::DoChange(const ScDocument* pSrcDoc) |
1765 | 0 | { |
1766 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
1767 | |
|
1768 | 0 | if (pSrcDoc == mpUndoDoc.get()) |
1769 | 0 | { |
1770 | 0 | mpRedoDoc->GetCondFormList(mnTab)->RemoveFromDocument(rDoc); |
1771 | 0 | mpUndoDoc->GetCondFormList(mnTab)->AddToDocument(rDoc); |
1772 | 0 | } |
1773 | 0 | else |
1774 | 0 | { |
1775 | 0 | mpUndoDoc->GetCondFormList(mnTab)->RemoveFromDocument(rDoc); |
1776 | 0 | mpRedoDoc->GetCondFormList(mnTab)->AddToDocument(rDoc); |
1777 | 0 | } |
1778 | 0 | rDoc.SetCondFormList(pSrcDoc->GetCondFormList(mnTab)->Clone(rDoc), mnTab); |
1779 | |
|
1780 | 0 | rDocShell.PostPaintGridAll(); |
1781 | 0 | rDocShell.PostDataChanged(); |
1782 | 0 | ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); |
1783 | 0 | if (pViewShell) |
1784 | 0 | pViewShell->CellContentChanged(); |
1785 | 0 | } |
1786 | | |
1787 | | void ScUndoConditionalFormatList::Repeat(SfxRepeatTarget& ) |
1788 | 0 | { |
1789 | 0 | } |
1790 | | |
1791 | | bool ScUndoConditionalFormatList::CanRepeat(SfxRepeatTarget& ) const |
1792 | 0 | { |
1793 | 0 | return false; |
1794 | 0 | } |
1795 | | |
1796 | | ScUndoUseScenario::ScUndoUseScenario( ScDocShell& rNewDocShell, |
1797 | | const ScMarkData& rMark, |
1798 | | const ScArea& rDestArea, |
1799 | | ScDocumentUniquePtr pNewUndoDoc, |
1800 | | OUString aNewName ) : |
1801 | 0 | ScSimpleUndo( rNewDocShell ), |
1802 | 0 | pUndoDoc( std::move(pNewUndoDoc) ), |
1803 | 0 | aMarkData( rMark ), |
1804 | 0 | aName(std::move( aNewName )) |
1805 | 0 | { |
1806 | 0 | aRange.aStart.SetCol(rDestArea.nColStart); |
1807 | 0 | aRange.aStart.SetRow(rDestArea.nRowStart); |
1808 | 0 | aRange.aStart.SetTab(rDestArea.nTab); |
1809 | 0 | aRange.aEnd.SetCol(rDestArea.nColEnd); |
1810 | 0 | aRange.aEnd.SetRow(rDestArea.nRowEnd); |
1811 | 0 | aRange.aEnd.SetTab(rDestArea.nTab); |
1812 | 0 | } |
1813 | | |
1814 | | ScUndoUseScenario::~ScUndoUseScenario() |
1815 | 0 | { |
1816 | 0 | } |
1817 | | |
1818 | | OUString ScUndoUseScenario::GetComment() const |
1819 | 0 | { |
1820 | 0 | return ScResId( STR_UNDO_USESCENARIO ); |
1821 | 0 | } |
1822 | | |
1823 | | void ScUndoUseScenario::Undo() |
1824 | 0 | { |
1825 | 0 | BeginUndo(); |
1826 | |
|
1827 | 0 | ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); |
1828 | 0 | if (pViewShell) |
1829 | 0 | { |
1830 | 0 | pViewShell->DoneBlockMode(); |
1831 | 0 | pViewShell->InitOwnBlockMode( aRange ); |
1832 | 0 | } |
1833 | |
|
1834 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
1835 | 0 | rDoc.DeleteSelection( InsertDeleteFlags::ALL, aMarkData ); |
1836 | 0 | pUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::ALL, true, rDoc, &aMarkData); |
1837 | | |
1838 | | // scenario table |
1839 | 0 | bool bFrame = false; |
1840 | 0 | SCTAB nTab = aRange.aStart.Tab(); |
1841 | 0 | SCTAB nEndTab = nTab; |
1842 | 0 | while ( pUndoDoc->HasTable(nEndTab+1) && pUndoDoc->IsScenario(nEndTab+1) ) |
1843 | 0 | ++nEndTab; |
1844 | 0 | for (SCTAB i = nTab+1; i<=nEndTab; i++) |
1845 | 0 | { |
1846 | | // Flags always |
1847 | 0 | OUString aComment; |
1848 | 0 | Color aColor; |
1849 | 0 | ScScenarioFlags nScenFlags; |
1850 | 0 | pUndoDoc->GetScenarioData( i, aComment, aColor, nScenFlags ); |
1851 | 0 | rDoc.SetScenarioData( i, aComment, aColor, nScenFlags ); |
1852 | 0 | bool bActive = pUndoDoc->IsActiveScenario( i ); |
1853 | 0 | rDoc.SetActiveScenario( i, bActive ); |
1854 | | // For copy-back scenario also consider content |
1855 | 0 | if ( nScenFlags & ScScenarioFlags::TwoWay ) |
1856 | 0 | { |
1857 | 0 | rDoc.DeleteAreaTab( 0,0, rDoc.MaxCol(),rDoc.MaxRow(), i, InsertDeleteFlags::ALL ); |
1858 | 0 | pUndoDoc->CopyToDocument(0,0,i, rDoc.MaxCol(),rDoc.MaxRow(),i, InsertDeleteFlags::ALL,false, rDoc); |
1859 | 0 | } |
1860 | 0 | if ( nScenFlags & ScScenarioFlags::ShowFrame ) |
1861 | 0 | bFrame = true; |
1862 | 0 | } |
1863 | | |
1864 | | // if visible borders, then paint all |
1865 | 0 | if (bFrame) |
1866 | 0 | rDocShell.PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid | PaintPartFlags::Extras ); |
1867 | 0 | else |
1868 | 0 | rDocShell.PostPaint( aRange, PaintPartFlags::Grid | PaintPartFlags::Extras ); |
1869 | 0 | rDocShell.PostDataChanged(); |
1870 | 0 | if (pViewShell) |
1871 | 0 | pViewShell->CellContentChanged(); |
1872 | |
|
1873 | 0 | ShowTable( aRange.aStart.Tab() ); |
1874 | |
|
1875 | 0 | EndUndo(); |
1876 | 0 | } |
1877 | | |
1878 | | void ScUndoUseScenario::Redo() |
1879 | 0 | { |
1880 | 0 | SCTAB nTab = aRange.aStart.Tab(); |
1881 | 0 | BeginRedo(); |
1882 | |
|
1883 | 0 | ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); |
1884 | 0 | if (pViewShell) |
1885 | 0 | { |
1886 | 0 | pViewShell->SetTabNo( nTab ); |
1887 | 0 | pViewShell->DoneBlockMode(); |
1888 | 0 | pViewShell->InitOwnBlockMode( aRange ); |
1889 | 0 | } |
1890 | |
|
1891 | 0 | rDocShell.UseScenario( nTab, aName, false ); |
1892 | |
|
1893 | 0 | EndRedo(); |
1894 | 0 | } |
1895 | | |
1896 | | void ScUndoUseScenario::Repeat(SfxRepeatTarget& rTarget) |
1897 | 0 | { |
1898 | 0 | if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget)) |
1899 | 0 | { |
1900 | 0 | OUString aTemp = aName; |
1901 | 0 | pViewTarget->GetViewShell().UseScenario(aTemp); |
1902 | 0 | } |
1903 | 0 | } |
1904 | | |
1905 | | bool ScUndoUseScenario::CanRepeat(SfxRepeatTarget& rTarget) const |
1906 | 0 | { |
1907 | 0 | if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget)) |
1908 | 0 | { |
1909 | 0 | ScViewData& rViewData = pViewTarget->GetViewShell().GetViewData(); |
1910 | 0 | return !rViewData.GetDocument().IsScenario( rViewData.CurrentTabForData() ); |
1911 | 0 | } |
1912 | 0 | return false; |
1913 | 0 | } |
1914 | | |
1915 | | ScUndoSelectionStyle::ScUndoSelectionStyle( ScDocShell& rNewDocShell, |
1916 | | const ScMarkData& rMark, |
1917 | | const ScRange& rRange, |
1918 | | OUString aName, |
1919 | | ScDocumentUniquePtr pNewUndoDoc ) : |
1920 | 0 | ScSimpleUndo( rNewDocShell ), |
1921 | 0 | aMarkData( rMark ), |
1922 | 0 | pUndoDoc( std::move(pNewUndoDoc) ), |
1923 | 0 | aStyleName(std::move( aName )), |
1924 | 0 | aRange( rRange ) |
1925 | 0 | { |
1926 | 0 | aMarkData.MarkToMulti(); |
1927 | 0 | } |
1928 | | |
1929 | | ScUndoSelectionStyle::~ScUndoSelectionStyle() |
1930 | 0 | { |
1931 | 0 | } |
1932 | | |
1933 | | OUString ScUndoSelectionStyle::GetComment() const |
1934 | 0 | { |
1935 | 0 | return ScResId( STR_UNDO_APPLYCELLSTYLE ); |
1936 | 0 | } |
1937 | | |
1938 | | void ScUndoSelectionStyle::DoChange( const bool bUndo ) |
1939 | 0 | { |
1940 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
1941 | |
|
1942 | 0 | SetViewMarkData( aMarkData ); |
1943 | |
|
1944 | 0 | ScRange aWorkRange( aRange ); |
1945 | 0 | if ( rDoc.HasAttrib( aWorkRange, HasAttrFlags::Merged ) ) // Merged cells? |
1946 | 0 | rDoc.ExtendMerge( aWorkRange, true ); |
1947 | |
|
1948 | 0 | sal_uInt16 nExtFlags = 0; |
1949 | 0 | rDocShell.UpdatePaintExt( nExtFlags, aWorkRange ); |
1950 | |
|
1951 | 0 | if (bUndo) // if Undo then push back all old data again |
1952 | 0 | { |
1953 | 0 | SCTAB nTabCount = rDoc.GetTableCount(); |
1954 | 0 | ScRange aCopyRange = aWorkRange; |
1955 | 0 | aCopyRange.aStart.SetTab(0); |
1956 | 0 | aCopyRange.aEnd.SetTab(nTabCount-1); |
1957 | 0 | pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData); |
1958 | 0 | } |
1959 | 0 | else // if Redo, then reapply style |
1960 | 0 | { |
1961 | 0 | ScStyleSheetPool* pStlPool = rDoc.GetStyleSheetPool(); |
1962 | 0 | ScStyleSheet* pStyleSheet = |
1963 | 0 | static_cast<ScStyleSheet*>( pStlPool->Find( aStyleName, SfxStyleFamily::Para ) ); |
1964 | 0 | if (!pStyleSheet) |
1965 | 0 | { |
1966 | 0 | OSL_FAIL("StyleSheet not found"); |
1967 | 0 | return; |
1968 | 0 | } |
1969 | 0 | rDoc.ApplySelectionStyle( *pStyleSheet, aMarkData ); |
1970 | 0 | } |
1971 | | |
1972 | 0 | rDocShell.UpdatePaintExt( nExtFlags, aWorkRange ); |
1973 | |
|
1974 | 0 | ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); |
1975 | 0 | if ( !( pViewShell && pViewShell->AdjustBlockHeight() ) ) |
1976 | 0 | /*A*/ rDocShell.PostPaint( aWorkRange, PaintPartFlags::Grid | PaintPartFlags::Extras, nExtFlags ); |
1977 | |
|
1978 | 0 | ShowTable( aWorkRange.aStart.Tab() ); |
1979 | 0 | } |
1980 | | |
1981 | | void ScUndoSelectionStyle::Undo() |
1982 | 0 | { |
1983 | 0 | BeginUndo(); |
1984 | 0 | DoChange( true ); |
1985 | 0 | EndUndo(); |
1986 | 0 | } |
1987 | | |
1988 | | void ScUndoSelectionStyle::Redo() |
1989 | 0 | { |
1990 | 0 | BeginRedo(); |
1991 | 0 | DoChange( false ); |
1992 | 0 | EndRedo(); |
1993 | 0 | } |
1994 | | |
1995 | | void ScUndoSelectionStyle::Repeat(SfxRepeatTarget& rTarget) |
1996 | 0 | { |
1997 | 0 | if (dynamic_cast<const ScTabViewTarget*>( &rTarget) == nullptr) |
1998 | 0 | return; |
1999 | | |
2000 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
2001 | 0 | ScStyleSheetPool* pStlPool = rDoc.GetStyleSheetPool(); |
2002 | 0 | ScStyleSheet* pStyleSheet = static_cast<ScStyleSheet*>( pStlPool-> |
2003 | 0 | Find( aStyleName, SfxStyleFamily::Para )); |
2004 | 0 | if (!pStyleSheet) |
2005 | 0 | { |
2006 | 0 | OSL_FAIL("StyleSheet not found"); |
2007 | 0 | return; |
2008 | 0 | } |
2009 | | |
2010 | 0 | ScTabViewShell& rViewShell = static_cast<ScTabViewTarget&>(rTarget).GetViewShell(); |
2011 | 0 | rViewShell.SetStyleSheetToMarked( pStyleSheet ); |
2012 | 0 | } |
2013 | | |
2014 | | bool ScUndoSelectionStyle::CanRepeat(SfxRepeatTarget& rTarget) const |
2015 | 0 | { |
2016 | 0 | return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr; |
2017 | 0 | } |
2018 | | |
2019 | | ScUndoEnterMatrix::ScUndoEnterMatrix( ScDocShell& rNewDocShell, const ScRange& rArea, |
2020 | | ScDocumentUniquePtr pNewUndoDoc, OUString aForm, |
2021 | | std::unique_ptr<ScTokenArray> pArray, |
2022 | | bool bDynamicArrayMaster) : |
2023 | 0 | ScBlockUndo( rNewDocShell, rArea, SC_UNDO_SIMPLE ), |
2024 | 0 | pUndoDoc( std::move(pNewUndoDoc) ), |
2025 | 0 | aFormula(std::move( aForm )), |
2026 | 0 | pTokenArray(std::move(pArray)), |
2027 | 0 | mbDynamicArrayMaster(bDynamicArrayMaster) |
2028 | 0 | { |
2029 | 0 | SetChangeTrack(); |
2030 | 0 | } |
2031 | | |
2032 | | ScUndoEnterMatrix::~ScUndoEnterMatrix() |
2033 | 0 | { |
2034 | 0 | } |
2035 | | |
2036 | | OUString ScUndoEnterMatrix::GetComment() const |
2037 | 0 | { |
2038 | 0 | return ScResId( STR_UNDO_ENTERMATRIX ); |
2039 | 0 | } |
2040 | | |
2041 | | void ScUndoEnterMatrix::SetChangeTrack() |
2042 | 0 | { |
2043 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
2044 | 0 | ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack(); |
2045 | 0 | if ( pChangeTrack ) |
2046 | 0 | pChangeTrack->AppendContentRange( aBlockRange, *pUndoDoc, |
2047 | 0 | nStartChangeAction, nEndChangeAction ); |
2048 | 0 | else |
2049 | 0 | nStartChangeAction = nEndChangeAction = 0; |
2050 | 0 | } |
2051 | | |
2052 | | void ScUndoEnterMatrix::Undo() |
2053 | 0 | { |
2054 | 0 | BeginUndo(); |
2055 | |
|
2056 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
2057 | |
|
2058 | 0 | rDoc.DeleteAreaTab( aBlockRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE ); |
2059 | 0 | pUndoDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc); |
2060 | 0 | rDocShell.PostPaint( aBlockRange, PaintPartFlags::Grid ); |
2061 | 0 | rDocShell.PostDataChanged(); |
2062 | 0 | ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); |
2063 | 0 | if (pViewShell) |
2064 | 0 | pViewShell->CellContentChanged(); |
2065 | |
|
2066 | 0 | ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack(); |
2067 | 0 | if ( pChangeTrack ) |
2068 | 0 | pChangeTrack->Undo( nStartChangeAction, nEndChangeAction ); |
2069 | |
|
2070 | 0 | EndUndo(); |
2071 | 0 | } |
2072 | | |
2073 | | void ScUndoEnterMatrix::Redo() |
2074 | 0 | { |
2075 | 0 | BeginRedo(); |
2076 | |
|
2077 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
2078 | |
|
2079 | 0 | ScMarkData aDestMark(rDoc.GetSheetLimits()); |
2080 | 0 | aDestMark.SelectOneTable( aBlockRange.aStart.Tab() ); |
2081 | 0 | aDestMark.SetMarkArea( aBlockRange ); |
2082 | |
|
2083 | 0 | rDoc.InsertMatrixFormula( aBlockRange.aStart.Col(), aBlockRange.aStart.Row(), |
2084 | 0 | aBlockRange.aEnd.Col(), aBlockRange.aEnd.Row(), |
2085 | 0 | aDestMark, aFormula, pTokenArray.get(), |
2086 | 0 | formula::FormulaGrammar::GRAM_DEFAULT, |
2087 | 0 | mbDynamicArrayMaster); |
2088 | |
|
2089 | 0 | SetChangeTrack(); |
2090 | |
|
2091 | 0 | EndRedo(); |
2092 | 0 | } |
2093 | | |
2094 | | void ScUndoEnterMatrix::Repeat(SfxRepeatTarget& rTarget) |
2095 | 0 | { |
2096 | 0 | if (auto pTabViewTarget = dynamic_cast<ScTabViewTarget*>(&rTarget)) |
2097 | 0 | { |
2098 | 0 | OUString aTemp = aFormula; |
2099 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
2100 | 0 | pTabViewTarget->GetViewShell().EnterMatrix(aTemp, rDoc.GetGrammar()); |
2101 | 0 | } |
2102 | 0 | } |
2103 | | |
2104 | | bool ScUndoEnterMatrix::CanRepeat(SfxRepeatTarget& rTarget) const |
2105 | 0 | { |
2106 | 0 | return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr; |
2107 | 0 | } |
2108 | | |
2109 | | static ScRange lcl_GetMultiMarkRange( const ScMarkData& rMark ) |
2110 | 0 | { |
2111 | 0 | OSL_ENSURE( rMark.IsMultiMarked(), "wrong mark type" ); |
2112 | 0 | return rMark.GetMultiMarkArea(); |
2113 | 0 | } |
2114 | | |
2115 | | ScUndoIndent::ScUndoIndent( ScDocShell& rNewDocShell, const ScMarkData& rMark, |
2116 | | ScDocumentUniquePtr pNewUndoDoc, bool bIncrement ) : |
2117 | 0 | ScBlockUndo( rNewDocShell, lcl_GetMultiMarkRange(rMark), SC_UNDO_AUTOHEIGHT ), |
2118 | 0 | aMarkData( rMark ), |
2119 | 0 | pUndoDoc( std::move(pNewUndoDoc) ), |
2120 | 0 | bIsIncrement( bIncrement ) |
2121 | 0 | { |
2122 | 0 | } |
2123 | | |
2124 | | ScUndoIndent::~ScUndoIndent() |
2125 | 0 | { |
2126 | 0 | } |
2127 | | |
2128 | | OUString ScUndoIndent::GetComment() const |
2129 | 0 | { |
2130 | 0 | TranslateId pId = bIsIncrement ? STR_UNDO_INC_INDENT : STR_UNDO_DEC_INDENT; |
2131 | 0 | return ScResId(pId); |
2132 | 0 | } |
2133 | | |
2134 | | void ScUndoIndent::Undo() |
2135 | 0 | { |
2136 | 0 | BeginUndo(); |
2137 | |
|
2138 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
2139 | 0 | SCTAB nTabCount = rDoc.GetTableCount(); |
2140 | 0 | ScRange aCopyRange = aBlockRange; |
2141 | 0 | aCopyRange.aStart.SetTab(0); |
2142 | 0 | aCopyRange.aEnd.SetTab(nTabCount-1); |
2143 | 0 | pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData); |
2144 | 0 | rDocShell.PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE ); |
2145 | |
|
2146 | 0 | EndUndo(); |
2147 | 0 | } |
2148 | | |
2149 | | void ScUndoIndent::Redo() |
2150 | 0 | { |
2151 | 0 | BeginRedo(); |
2152 | |
|
2153 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
2154 | 0 | rDoc.ChangeSelectionIndent( bIsIncrement, aMarkData ); |
2155 | 0 | rDocShell.PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE ); |
2156 | |
|
2157 | 0 | EndRedo(); |
2158 | 0 | } |
2159 | | |
2160 | | void ScUndoIndent::Repeat(SfxRepeatTarget& rTarget) |
2161 | 0 | { |
2162 | 0 | if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget)) |
2163 | 0 | pViewTarget->GetViewShell().ChangeIndent( bIsIncrement ); |
2164 | 0 | } |
2165 | | |
2166 | | bool ScUndoIndent::CanRepeat(SfxRepeatTarget& rTarget) const |
2167 | 0 | { |
2168 | 0 | return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr; |
2169 | 0 | } |
2170 | | |
2171 | | ScUndoTransliterate::ScUndoTransliterate( ScDocShell& rNewDocShell, const ScMarkData& rMark, |
2172 | | ScDocumentUniquePtr pNewUndoDoc, TransliterationFlags nType ) : |
2173 | 0 | ScBlockUndo( rNewDocShell, lcl_GetMultiMarkRange(rMark), SC_UNDO_AUTOHEIGHT ), |
2174 | 0 | aMarkData( rMark ), |
2175 | 0 | pUndoDoc( std::move(pNewUndoDoc) ), |
2176 | 0 | nTransliterationType( nType ) |
2177 | 0 | { |
2178 | 0 | } |
2179 | | |
2180 | | ScUndoTransliterate::~ScUndoTransliterate() |
2181 | 0 | { |
2182 | 0 | } |
2183 | | |
2184 | | OUString ScUndoTransliterate::GetComment() const |
2185 | 0 | { |
2186 | 0 | return ScResId( STR_UNDO_TRANSLITERATE ); |
2187 | 0 | } |
2188 | | |
2189 | | void ScUndoTransliterate::Undo() |
2190 | 0 | { |
2191 | 0 | BeginUndo(); |
2192 | |
|
2193 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
2194 | 0 | SCTAB nTabCount = rDoc.GetTableCount(); |
2195 | 0 | ScRange aCopyRange = aBlockRange; |
2196 | 0 | aCopyRange.aStart.SetTab(0); |
2197 | 0 | aCopyRange.aEnd.SetTab(nTabCount-1); |
2198 | 0 | pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::CONTENTS, true, rDoc, &aMarkData); |
2199 | 0 | rDocShell.PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE ); |
2200 | |
|
2201 | 0 | EndUndo(); |
2202 | 0 | } |
2203 | | |
2204 | | void ScUndoTransliterate::Redo() |
2205 | 0 | { |
2206 | 0 | BeginRedo(); |
2207 | |
|
2208 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
2209 | 0 | rDoc.TransliterateText( aMarkData, nTransliterationType ); |
2210 | 0 | rDocShell.PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE ); |
2211 | |
|
2212 | 0 | EndRedo(); |
2213 | 0 | } |
2214 | | |
2215 | | void ScUndoTransliterate::Repeat(SfxRepeatTarget& rTarget) |
2216 | 0 | { |
2217 | 0 | if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget)) |
2218 | 0 | pViewTarget->GetViewShell().TransliterateText( nTransliterationType ); |
2219 | 0 | } |
2220 | | |
2221 | | bool ScUndoTransliterate::CanRepeat(SfxRepeatTarget& rTarget) const |
2222 | 0 | { |
2223 | 0 | return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr; |
2224 | 0 | } |
2225 | | |
2226 | | ScUndoClearItems::ScUndoClearItems( ScDocShell& rNewDocShell, const ScMarkData& rMark, |
2227 | | ScDocumentUniquePtr pNewUndoDoc, const sal_uInt16* pW ) : |
2228 | 0 | ScBlockUndo( rNewDocShell, lcl_GetMultiMarkRange(rMark), SC_UNDO_AUTOHEIGHT ), |
2229 | 0 | aMarkData( rMark ), |
2230 | 0 | pUndoDoc( std::move(pNewUndoDoc) ) |
2231 | 0 | { |
2232 | 0 | assert(pW && "ScUndoClearItems: Which-Pointer is Null"); |
2233 | |
|
2234 | 0 | sal_uInt16 nCount = 0; |
2235 | 0 | while ( pW[nCount] ) |
2236 | 0 | ++nCount; |
2237 | 0 | pWhich.reset( new sal_uInt16[nCount+1] ); |
2238 | 0 | for (sal_uInt16 i=0; i<=nCount; i++) |
2239 | 0 | pWhich[i] = pW[i]; |
2240 | 0 | } |
2241 | | |
2242 | | ScUndoClearItems::~ScUndoClearItems() |
2243 | 0 | { |
2244 | 0 | } |
2245 | | |
2246 | | OUString ScUndoClearItems::GetComment() const |
2247 | 0 | { |
2248 | 0 | return ScResId( STR_UNDO_DELETECONTENTS ); |
2249 | 0 | } |
2250 | | |
2251 | | void ScUndoClearItems::Undo() |
2252 | 0 | { |
2253 | 0 | BeginUndo(); |
2254 | |
|
2255 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
2256 | 0 | pUndoDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData); |
2257 | 0 | rDocShell.PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE ); |
2258 | |
|
2259 | 0 | EndUndo(); |
2260 | 0 | } |
2261 | | |
2262 | | void ScUndoClearItems::Redo() |
2263 | 0 | { |
2264 | 0 | BeginRedo(); |
2265 | |
|
2266 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
2267 | 0 | rDoc.ClearSelectionItems( pWhich.get(), aMarkData ); |
2268 | 0 | rDocShell.PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE ); |
2269 | |
|
2270 | 0 | EndRedo(); |
2271 | 0 | } |
2272 | | |
2273 | | void ScUndoClearItems::Repeat(SfxRepeatTarget& rTarget) |
2274 | 0 | { |
2275 | 0 | if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget)) |
2276 | 0 | { |
2277 | 0 | ScViewData& rViewData = pViewTarget->GetViewShell().GetViewData(); |
2278 | 0 | rViewData.GetDocFunc().ClearItems( rViewData.GetMarkData(), pWhich.get(), false ); |
2279 | 0 | } |
2280 | 0 | } |
2281 | | |
2282 | | bool ScUndoClearItems::CanRepeat(SfxRepeatTarget& rTarget) const |
2283 | 0 | { |
2284 | 0 | return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr; |
2285 | 0 | } |
2286 | | |
2287 | | // remove all line breaks of a table |
2288 | | ScUndoRemoveBreaks::ScUndoRemoveBreaks( ScDocShell& rNewDocShell, |
2289 | | SCTAB nNewTab, ScDocumentUniquePtr pNewUndoDoc ) : |
2290 | 0 | ScSimpleUndo( rNewDocShell ), |
2291 | 0 | nTab( nNewTab ), |
2292 | 0 | pUndoDoc( std::move(pNewUndoDoc) ) |
2293 | 0 | { |
2294 | 0 | } |
2295 | | |
2296 | | ScUndoRemoveBreaks::~ScUndoRemoveBreaks() |
2297 | 0 | { |
2298 | 0 | } |
2299 | | |
2300 | | OUString ScUndoRemoveBreaks::GetComment() const |
2301 | 0 | { |
2302 | 0 | return ScResId( STR_UNDO_REMOVEBREAKS ); |
2303 | 0 | } |
2304 | | |
2305 | | void ScUndoRemoveBreaks::Undo() |
2306 | 0 | { |
2307 | 0 | BeginUndo(); |
2308 | |
|
2309 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
2310 | 0 | ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); |
2311 | |
|
2312 | 0 | pUndoDoc->CopyToDocument(0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, InsertDeleteFlags::NONE, false, rDoc); |
2313 | 0 | if (pViewShell) |
2314 | 0 | pViewShell->UpdatePageBreakData( true ); |
2315 | 0 | rDocShell.PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid ); |
2316 | |
|
2317 | 0 | EndUndo(); |
2318 | 0 | } |
2319 | | |
2320 | | void ScUndoRemoveBreaks::Redo() |
2321 | 0 | { |
2322 | 0 | BeginRedo(); |
2323 | |
|
2324 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
2325 | 0 | ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); |
2326 | |
|
2327 | 0 | rDoc.RemoveManualBreaks(nTab); |
2328 | 0 | rDoc.UpdatePageBreaks(nTab); |
2329 | 0 | if (pViewShell) |
2330 | 0 | pViewShell->UpdatePageBreakData( true ); |
2331 | 0 | rDocShell.PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid ); |
2332 | |
|
2333 | 0 | EndRedo(); |
2334 | 0 | } |
2335 | | |
2336 | | void ScUndoRemoveBreaks::Repeat(SfxRepeatTarget& rTarget) |
2337 | 0 | { |
2338 | 0 | if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget)) |
2339 | 0 | { |
2340 | 0 | ScTabViewShell& rViewShell = pViewTarget->GetViewShell(); |
2341 | 0 | rViewShell.RemoveManualBreaks(); |
2342 | 0 | } |
2343 | 0 | } |
2344 | | |
2345 | | bool ScUndoRemoveBreaks::CanRepeat(SfxRepeatTarget& rTarget) const |
2346 | 0 | { |
2347 | 0 | return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr; |
2348 | 0 | } |
2349 | | |
2350 | | ScUndoRemoveMerge::ScUndoRemoveMerge( ScDocShell& rNewDocShell, |
2351 | | const ScCellMergeOption& rOption, ScDocumentUniquePtr pNewUndoDoc ) : |
2352 | 0 | ScBlockUndo( rNewDocShell, rOption.getFirstSingleRange(), SC_UNDO_SIMPLE ), |
2353 | 0 | pUndoDoc( std::move(pNewUndoDoc) ) |
2354 | 0 | { |
2355 | 0 | maOptions.push_back( rOption); |
2356 | 0 | } |
2357 | | |
2358 | | ScUndoRemoveMerge::ScUndoRemoveMerge( ScDocShell& rNewDocShell, |
2359 | | const ScRange& rRange, ScDocumentUniquePtr pNewUndoDoc ) : |
2360 | 0 | ScBlockUndo( rNewDocShell, rRange, SC_UNDO_SIMPLE ), |
2361 | 0 | pUndoDoc( std::move(pNewUndoDoc) ) |
2362 | 0 | { |
2363 | 0 | } |
2364 | | |
2365 | | ScUndoRemoveMerge::~ScUndoRemoveMerge() |
2366 | 0 | { |
2367 | 0 | } |
2368 | | |
2369 | | OUString ScUndoRemoveMerge::GetComment() const |
2370 | 0 | { |
2371 | 0 | return ScResId( STR_UNDO_REMERGE ); // "remove merge" |
2372 | 0 | } |
2373 | | |
2374 | | ScDocument* ScUndoRemoveMerge::GetUndoDoc() |
2375 | 0 | { |
2376 | 0 | return pUndoDoc.get(); |
2377 | 0 | } |
2378 | | |
2379 | | void ScUndoRemoveMerge::AddCellMergeOption( const ScCellMergeOption& rOption ) |
2380 | 0 | { |
2381 | 0 | maOptions.push_back( rOption); |
2382 | 0 | } |
2383 | | |
2384 | | void ScUndoRemoveMerge::Undo() |
2385 | 0 | { |
2386 | 0 | SetCurTab(); |
2387 | 0 | BeginUndo(); |
2388 | |
|
2389 | 0 | ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); |
2390 | |
|
2391 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
2392 | 0 | for (const auto & rOption : maOptions) |
2393 | 0 | { |
2394 | 0 | for (const auto& rTab : rOption.maTabs) |
2395 | 0 | { |
2396 | 0 | OSL_ENSURE(pUndoDoc, "NULL pUndoDoc!"); |
2397 | 0 | if (!pUndoDoc) |
2398 | 0 | continue; |
2399 | | // There is no need to extend merge area because it's already been extended. |
2400 | 0 | ScRange aRange = rOption.getSingleRange(rTab); |
2401 | 0 | rDoc.DeleteAreaTab(aRange, InsertDeleteFlags::ATTRIB); |
2402 | 0 | pUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::ATTRIB, false, rDoc); |
2403 | |
|
2404 | 0 | bool bDidPaint = false; |
2405 | 0 | if ( pViewShell ) |
2406 | 0 | { |
2407 | 0 | pViewShell->SetTabNo(rTab); |
2408 | 0 | bDidPaint = pViewShell->AdjustRowHeight(rOption.mnStartRow, rOption.mnEndRow, true); |
2409 | 0 | } |
2410 | 0 | if (!bDidPaint) |
2411 | 0 | ScUndoUtil::PaintMore(rDocShell, aRange); |
2412 | 0 | } |
2413 | 0 | } |
2414 | |
|
2415 | 0 | EndUndo(); |
2416 | 0 | } |
2417 | | |
2418 | | void ScUndoRemoveMerge::Redo() |
2419 | 0 | { |
2420 | 0 | SetCurTab(); |
2421 | 0 | BeginRedo(); |
2422 | |
|
2423 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
2424 | 0 | ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); |
2425 | |
|
2426 | 0 | for (const auto & rOption : maOptions) |
2427 | 0 | { |
2428 | 0 | for (const SCTAB nTab : rOption.maTabs) |
2429 | 0 | { |
2430 | | // There is no need to extend merge area because it's already been extended. |
2431 | 0 | ScRange aRange = rOption.getSingleRange(nTab); |
2432 | |
|
2433 | 0 | const SfxPoolItem& rDefAttr = rDoc.GetPool()->GetUserOrPoolDefaultItem( ATTR_MERGE ); |
2434 | 0 | ScPatternAttr aPattern(rDoc.getCellAttributeHelper()); |
2435 | 0 | aPattern.ItemSetPut(rDefAttr); |
2436 | 0 | rDoc.ApplyPatternAreaTab( rOption.mnStartCol, rOption.mnStartRow, |
2437 | 0 | rOption.mnEndCol, rOption.mnEndRow, nTab, |
2438 | 0 | aPattern ); |
2439 | |
|
2440 | 0 | rDoc.RemoveFlagsTab( rOption.mnStartCol, rOption.mnStartRow, |
2441 | 0 | rOption.mnEndCol, rOption.mnEndRow, nTab, |
2442 | 0 | ScMF::Hor | ScMF::Ver ); |
2443 | |
|
2444 | 0 | rDoc.ExtendMerge(aRange, true); |
2445 | | |
2446 | | // Paint |
2447 | |
|
2448 | 0 | bool bDidPaint = false; |
2449 | 0 | if ( pViewShell ) |
2450 | 0 | { |
2451 | 0 | pViewShell->SetTabNo(nTab); |
2452 | 0 | bDidPaint = pViewShell->AdjustRowHeight(rOption.mnStartRow, rOption.mnEndRow, true); |
2453 | 0 | } |
2454 | 0 | if (!bDidPaint) |
2455 | 0 | ScUndoUtil::PaintMore(rDocShell, aRange); |
2456 | 0 | } |
2457 | 0 | } |
2458 | |
|
2459 | 0 | EndRedo(); |
2460 | 0 | } |
2461 | | |
2462 | | void ScUndoRemoveMerge::Repeat(SfxRepeatTarget& rTarget) |
2463 | 0 | { |
2464 | 0 | if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget)) |
2465 | 0 | pViewTarget->GetViewShell().RemoveMerge(); |
2466 | 0 | } |
2467 | | |
2468 | | bool ScUndoRemoveMerge::CanRepeat(SfxRepeatTarget& rTarget) const |
2469 | 0 | { |
2470 | 0 | return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr; |
2471 | 0 | } |
2472 | | |
2473 | | void ScUndoRemoveMerge::SetCurTab() |
2474 | 0 | { |
2475 | 0 | SCTAB nCurTab = ScDocShell::GetCurTab(); |
2476 | 0 | aBlockRange.aStart.SetTab(nCurTab); |
2477 | 0 | aBlockRange.aEnd.SetTab(nCurTab); |
2478 | 0 | } |
2479 | | |
2480 | | /** set only border, for ScRangeList (StarOne) */ |
2481 | | static ScRange lcl_TotalRange( const ScRangeList& rRanges ) |
2482 | 0 | { |
2483 | 0 | ScRange aTotal; |
2484 | 0 | if ( !rRanges.empty() ) |
2485 | 0 | { |
2486 | 0 | aTotal = rRanges[ 0 ]; |
2487 | 0 | for ( size_t i = 1, nCount = rRanges.size(); i < nCount; ++i ) |
2488 | 0 | { |
2489 | 0 | ScRange const & rRange = rRanges[ i ]; |
2490 | 0 | if (rRange.aStart.Col() < aTotal.aStart.Col()) aTotal.aStart.SetCol(rRange.aStart.Col()); |
2491 | 0 | if (rRange.aStart.Row() < aTotal.aStart.Row()) aTotal.aStart.SetRow(rRange.aStart.Row()); |
2492 | 0 | if (rRange.aStart.Tab() < aTotal.aStart.Tab()) aTotal.aStart.SetTab(rRange.aStart.Tab()); |
2493 | 0 | if (rRange.aEnd.Col() > aTotal.aEnd.Col() ) aTotal.aEnd.SetCol( rRange.aEnd.Col() ); |
2494 | 0 | if (rRange.aEnd.Row() > aTotal.aEnd.Row() ) aTotal.aEnd.SetRow( rRange.aEnd.Row() ); |
2495 | 0 | if (rRange.aEnd.Tab() > aTotal.aEnd.Tab() ) aTotal.aEnd.SetTab(rRange.aEnd.Tab() ); |
2496 | 0 | } |
2497 | 0 | } |
2498 | 0 | return aTotal; |
2499 | 0 | } |
2500 | | |
2501 | | ScUndoBorder::ScUndoBorder(ScDocShell& rNewDocShell, |
2502 | | const ScRangeList& rRangeList, ScDocumentUniquePtr pNewUndoDoc, |
2503 | | const SvxBoxItem& rNewOuter, const SvxBoxInfoItem& rNewInner) |
2504 | 0 | : ScBlockUndo(rNewDocShell, lcl_TotalRange(rRangeList), SC_UNDO_SIMPLE) |
2505 | 0 | , xUndoDoc(std::move(pNewUndoDoc)) |
2506 | 0 | { |
2507 | 0 | xRanges.reset(new ScRangeList(rRangeList)); |
2508 | 0 | xOuter.reset(new SvxBoxItem(rNewOuter)); |
2509 | 0 | xInner.reset(new SvxBoxInfoItem(rNewInner)); |
2510 | 0 | } |
2511 | | |
2512 | | OUString ScUndoBorder::GetComment() const |
2513 | 0 | { |
2514 | 0 | return ScResId( STR_UNDO_SELATTRLINES ); //! own string? |
2515 | 0 | } |
2516 | | |
2517 | | void ScUndoBorder::Undo() |
2518 | 0 | { |
2519 | 0 | BeginUndo(); |
2520 | |
|
2521 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); |
2522 | 0 | ScMarkData aMarkData(rDoc.GetSheetLimits()); |
2523 | 0 | aMarkData.MarkFromRangeList(*xRanges, false); |
2524 | 0 | xUndoDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData); |
2525 | 0 | rDocShell.PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE ); |
2526 | |
|
2527 | 0 | EndUndo(); |
2528 | 0 | } |
2529 | | |
2530 | | void ScUndoBorder::Redo() |
2531 | 0 | { |
2532 | 0 | BeginRedo(); |
2533 | |
|
2534 | 0 | ScDocument& rDoc = rDocShell.GetDocument(); // call function at docfunc |
2535 | 0 | size_t nCount = xRanges->size(); |
2536 | 0 | for (size_t i = 0; i < nCount; ++i ) |
2537 | 0 | { |
2538 | 0 | ScRange const & rRange = (*xRanges)[i]; |
2539 | 0 | SCTAB nTab = rRange.aStart.Tab(); |
2540 | |
|
2541 | 0 | ScMarkData aMark(rDoc.GetSheetLimits()); |
2542 | 0 | aMark.SetMarkArea( rRange ); |
2543 | 0 | aMark.SelectTable( nTab, true ); |
2544 | |
|
2545 | 0 | rDoc.ApplySelectionFrame(aMark, *xOuter, xInner.get()); |
2546 | 0 | } |
2547 | 0 | for (size_t i = 0; i < nCount; ++i) |
2548 | 0 | rDocShell.PostPaint( (*xRanges)[i], PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE ); |
2549 | |
|
2550 | 0 | EndRedo(); |
2551 | 0 | } |
2552 | | |
2553 | | void ScUndoBorder::Repeat(SfxRepeatTarget& /* rTarget */) |
2554 | 0 | { |
2555 | | //TODO later (when the function has moved from cellsuno to docfunc) |
2556 | 0 | } |
2557 | | |
2558 | | bool ScUndoBorder::CanRepeat(SfxRepeatTarget& /* rTarget */) const |
2559 | 0 | { |
2560 | 0 | return false; // See above |
2561 | 0 | } |
2562 | | |
2563 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |