File: | home/maarten/src/libreoffice/core/sc/source/core/tool/chgtrack.cxx |
Warning: | line 347, column 16 Attempt to delete released memory |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | |||
2 | /* | |||
3 | * This file is part of the LibreOffice project. | |||
4 | * | |||
5 | * This Source 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 <chgtrack.hxx> | |||
21 | #include <compiler.hxx> | |||
22 | #include <formulacell.hxx> | |||
23 | #include <document.hxx> | |||
24 | #include <dociter.hxx> | |||
25 | #include <global.hxx> | |||
26 | #include <rechead.hxx> | |||
27 | #include <scerrors.hxx> | |||
28 | #include <scmod.hxx> | |||
29 | #include <inputopt.hxx> | |||
30 | #include <patattr.hxx> | |||
31 | #include <hints.hxx> | |||
32 | #include <markdata.hxx> | |||
33 | #include <globstr.hrc> | |||
34 | #include <scresid.hxx> | |||
35 | #include <editutil.hxx> | |||
36 | #include <tokenarray.hxx> | |||
37 | #include <refupdatecontext.hxx> | |||
38 | #include <refupdat.hxx> | |||
39 | ||||
40 | #include <osl/diagnose.h> | |||
41 | #include <svl/zforlist.hxx> | |||
42 | #include <svl/itemset.hxx> | |||
43 | #include <svl/isethint.hxx> | |||
44 | #include <svl/itempool.hxx> | |||
45 | #include <sfx2/app.hxx> | |||
46 | #include <sfx2/objsh.hxx> | |||
47 | #include <unotools/useroptions.hxx> | |||
48 | #include <unotools/datetime.hxx> | |||
49 | #include <sfx2/sfxsids.hrc> | |||
50 | #include <tools/json_writer.hxx> | |||
51 | #include <algorithm> | |||
52 | #include <memory> | |||
53 | #include <boost/property_tree/json_parser.hpp> | |||
54 | ||||
55 | ScChangeAction::ScChangeAction( ScChangeActionType eTypeP, const ScRange& rRange ) | |||
56 | : | |||
57 | aBigRange( rRange ), | |||
58 | aDateTime( DateTime::SYSTEM ), | |||
59 | pNext( nullptr ), | |||
60 | pPrev( nullptr ), | |||
61 | pLinkAny( nullptr ), | |||
62 | pLinkDeletedIn( nullptr ), | |||
63 | pLinkDeleted( nullptr ), | |||
64 | pLinkDependent( nullptr ), | |||
65 | nAction( 0 ), | |||
66 | nRejectAction( 0 ), | |||
67 | eType( eTypeP ), | |||
68 | eState( SC_CAS_VIRGIN ) | |||
69 | { | |||
70 | aDateTime.ConvertToUTC(); | |||
71 | } | |||
72 | ||||
73 | ScChangeAction::ScChangeAction( | |||
74 | ScChangeActionType eTypeP, const ScBigRange& rRange, | |||
75 | const sal_uLong nTempAction, const sal_uLong nTempRejectAction, | |||
76 | const ScChangeActionState eTempState, const DateTime& aTempDateTime, | |||
77 | const OUString& aTempUser, const OUString& aTempComment) : | |||
78 | aBigRange( rRange ), | |||
79 | aDateTime( aTempDateTime ), | |||
80 | aUser( aTempUser ), | |||
81 | aComment( aTempComment ), | |||
82 | pNext( nullptr ), | |||
83 | pPrev( nullptr ), | |||
84 | pLinkAny( nullptr ), | |||
85 | pLinkDeletedIn( nullptr ), | |||
86 | pLinkDeleted( nullptr ), | |||
87 | pLinkDependent( nullptr ), | |||
88 | nAction( nTempAction ), | |||
89 | nRejectAction( nTempRejectAction ), | |||
90 | eType( eTypeP ), | |||
91 | eState( eTempState ) | |||
92 | { | |||
93 | } | |||
94 | ||||
95 | ScChangeAction::ScChangeAction( ScChangeActionType eTypeP, const ScBigRange& rRange, | |||
96 | const sal_uLong nTempAction) | |||
97 | : | |||
98 | aBigRange( rRange ), | |||
99 | aDateTime( DateTime::SYSTEM ), | |||
100 | pNext( nullptr ), | |||
101 | pPrev( nullptr ), | |||
102 | pLinkAny( nullptr ), | |||
103 | pLinkDeletedIn( nullptr ), | |||
104 | pLinkDeleted( nullptr ), | |||
105 | pLinkDependent( nullptr ), | |||
106 | nAction( nTempAction ), | |||
107 | nRejectAction( 0 ), | |||
108 | eType( eTypeP ), | |||
109 | eState( SC_CAS_VIRGIN ) | |||
110 | { | |||
111 | aDateTime.ConvertToUTC(); | |||
112 | } | |||
113 | ||||
114 | ScChangeAction::~ScChangeAction() | |||
115 | { | |||
116 | RemoveAllLinks(); | |||
117 | } | |||
118 | ||||
119 | bool ScChangeAction::IsInsertType() const | |||
120 | { | |||
121 | return eType == SC_CAT_INSERT_COLS || eType == SC_CAT_INSERT_ROWS || eType == SC_CAT_INSERT_TABS; | |||
122 | } | |||
123 | ||||
124 | bool ScChangeAction::IsDeleteType() const | |||
125 | { | |||
126 | return eType == SC_CAT_DELETE_COLS || eType == SC_CAT_DELETE_ROWS || eType == SC_CAT_DELETE_TABS; | |||
127 | } | |||
128 | ||||
129 | bool ScChangeAction::IsVirgin() const | |||
130 | { | |||
131 | return eState == SC_CAS_VIRGIN; | |||
132 | } | |||
133 | ||||
134 | bool ScChangeAction::IsAccepted() const | |||
135 | { | |||
136 | return eState == SC_CAS_ACCEPTED; | |||
137 | } | |||
138 | ||||
139 | bool ScChangeAction::IsRejected() const | |||
140 | { | |||
141 | return eState == SC_CAS_REJECTED; | |||
142 | } | |||
143 | ||||
144 | bool ScChangeAction::IsRejecting() const | |||
145 | { | |||
146 | return nRejectAction != 0; | |||
147 | } | |||
148 | ||||
149 | bool ScChangeAction::IsVisible() const | |||
150 | { | |||
151 | // sequence order of execution is significant! | |||
152 | if ( IsRejected() || GetType() == SC_CAT_DELETE_TABS || IsDeletedIn() ) | |||
153 | return false; | |||
154 | if ( GetType() == SC_CAT_CONTENT ) | |||
155 | return static_cast<const ScChangeActionContent*>(this)->IsTopContent(); | |||
156 | return true; | |||
157 | } | |||
158 | ||||
159 | bool ScChangeAction::IsTouchable() const | |||
160 | { | |||
161 | // sequence order of execution is significant! | |||
162 | if ( IsRejected() || GetType() == SC_CAT_REJECT || IsDeletedIn() ) | |||
163 | return false; | |||
164 | // content may reject and be touchable if on top | |||
165 | if ( GetType() == SC_CAT_CONTENT ) | |||
166 | return static_cast<const ScChangeActionContent*>(this)->IsTopContent(); | |||
167 | if ( IsRejecting() ) | |||
168 | return false; | |||
169 | return true; | |||
170 | } | |||
171 | ||||
172 | bool ScChangeAction::IsClickable() const | |||
173 | { | |||
174 | // sequence order of execution is significant! | |||
175 | if ( !IsVirgin() ) | |||
176 | return false; | |||
177 | if ( IsDeletedIn() ) | |||
178 | return false; | |||
179 | if ( GetType() == SC_CAT_CONTENT ) | |||
180 | { | |||
181 | ScChangeActionContentCellType eCCT = | |||
182 | ScChangeActionContent::GetContentCellType( | |||
183 | static_cast<const ScChangeActionContent*>(this)->GetNewCell() ); | |||
184 | if ( eCCT == SC_CACCT_MATREF ) | |||
185 | return false; | |||
186 | if ( eCCT == SC_CACCT_MATORG ) | |||
187 | { // no Accept-Select if one of the references is in a deleted col/row | |||
188 | const ScChangeActionLinkEntry* pL = | |||
189 | static_cast<const ScChangeActionContent*>(this)->GetFirstDependentEntry(); | |||
190 | while ( pL ) | |||
191 | { | |||
192 | ScChangeAction* p = const_cast<ScChangeAction*>(pL->GetAction()); | |||
193 | if ( p && p->IsDeletedIn() ) | |||
194 | return false; | |||
195 | pL = pL->GetNext(); | |||
196 | } | |||
197 | } | |||
198 | return true; // for Select() a content doesn't have to be touchable | |||
199 | } | |||
200 | return IsTouchable(); // Accept()/Reject() only on touchables | |||
201 | } | |||
202 | ||||
203 | bool ScChangeAction::IsRejectable() const | |||
204 | { | |||
205 | // sequence order of execution is significant! | |||
206 | if ( !IsClickable() ) | |||
207 | return false; | |||
208 | if ( GetType() == SC_CAT_CONTENT ) | |||
209 | { | |||
210 | if ( static_cast<const ScChangeActionContent*>(this)->IsOldMatrixReference() ) | |||
211 | return false; | |||
212 | ScChangeActionContent* pNextContent = | |||
213 | static_cast<const ScChangeActionContent*>(this)->GetNextContent(); | |||
214 | if ( pNextContent == nullptr ) | |||
215 | return true; // *this is TopContent | |||
216 | return pNextContent->IsRejected(); // *this is next rejectable | |||
217 | } | |||
218 | return IsTouchable(); | |||
219 | } | |||
220 | ||||
221 | bool ScChangeAction::IsInternalRejectable() const | |||
222 | { | |||
223 | // sequence order of execution is significant! | |||
224 | if ( !IsVirgin() ) | |||
225 | return false; | |||
226 | if ( IsDeletedIn() ) | |||
227 | return false; | |||
228 | if ( GetType() == SC_CAT_CONTENT ) | |||
229 | { | |||
230 | ScChangeActionContent* pNextContent = | |||
231 | static_cast<const ScChangeActionContent*>(this)->GetNextContent(); | |||
232 | if ( pNextContent == nullptr ) | |||
233 | return true; // *this is TopContent | |||
234 | return pNextContent->IsRejected(); // *this is next rejectable | |||
235 | } | |||
236 | return IsTouchable(); | |||
237 | } | |||
238 | ||||
239 | bool ScChangeAction::IsDialogRoot() const | |||
240 | { | |||
241 | return IsInternalRejectable(); // only rejectables in root | |||
242 | } | |||
243 | ||||
244 | bool ScChangeAction::IsDialogParent() const | |||
245 | { | |||
246 | // sequence order of execution is significant! | |||
247 | if ( GetType() == SC_CAT_CONTENT ) | |||
248 | { | |||
249 | if ( !IsDialogRoot() ) | |||
250 | return false; | |||
251 | if ( static_cast<const ScChangeActionContent*>(this)->IsMatrixOrigin() && HasDependent() ) | |||
252 | return true; | |||
253 | ScChangeActionContent* pPrevContent = | |||
254 | static_cast<const ScChangeActionContent*>(this)->GetPrevContent(); | |||
255 | return pPrevContent && pPrevContent->IsVirgin(); | |||
256 | } | |||
257 | if ( HasDependent() ) | |||
258 | return IsDeleteType() || !IsDeletedIn(); | |||
259 | if ( HasDeleted() ) | |||
260 | { | |||
261 | if ( IsDeleteType() ) | |||
262 | { | |||
263 | if ( IsDialogRoot() ) | |||
264 | return true; | |||
265 | ScChangeActionLinkEntry* pL = pLinkDeleted; | |||
266 | while ( pL ) | |||
267 | { | |||
268 | ScChangeAction* p = pL->GetAction(); | |||
269 | if ( p && p->GetType() != eType ) | |||
270 | return true; | |||
271 | pL = pL->GetNext(); | |||
272 | } | |||
273 | } | |||
274 | else | |||
275 | return true; | |||
276 | } | |||
277 | return false; | |||
278 | } | |||
279 | ||||
280 | bool ScChangeAction::IsMasterDelete() const | |||
281 | { | |||
282 | if ( !IsDeleteType() ) | |||
283 | return false; | |||
284 | const ScChangeActionDel* pDel = static_cast<const ScChangeActionDel*>(this); | |||
285 | return pDel->IsMultiDelete() && (pDel->IsTopDelete() || pDel->IsRejectable()); | |||
286 | } | |||
287 | ||||
288 | void ScChangeAction::RemoveAllLinks() | |||
289 | { | |||
290 | while (pLinkAny) | |||
291 | { | |||
292 | // coverity[use_after_free] - Moves up by itself | |||
293 | delete pLinkAny; | |||
294 | } | |||
295 | ||||
296 | RemoveAllDeletedIn(); | |||
297 | ||||
298 | while (pLinkDeleted) | |||
299 | { | |||
300 | // coverity[use_after_free] - Moves up by itself | |||
301 | delete pLinkDeleted; | |||
302 | } | |||
303 | ||||
304 | RemoveAllDependent(); | |||
305 | } | |||
306 | ||||
307 | bool ScChangeAction::RemoveDeletedIn( const ScChangeAction* p ) | |||
308 | { | |||
309 | bool bRemoved = false; | |||
310 | ScChangeActionLinkEntry* pL = GetDeletedIn(); | |||
311 | while ( pL ) | |||
312 | { | |||
313 | ScChangeActionLinkEntry* pNextLink = pL->GetNext(); | |||
314 | if ( pL->GetAction() == p ) | |||
315 | { | |||
316 | delete pL; | |||
317 | bRemoved = true; | |||
318 | } | |||
319 | pL = pNextLink; | |||
320 | } | |||
321 | return bRemoved; | |||
322 | } | |||
323 | ||||
324 | bool ScChangeAction::IsDeletedIn() const | |||
325 | { | |||
326 | return GetDeletedIn() != nullptr; | |||
327 | } | |||
328 | ||||
329 | bool ScChangeAction::IsDeletedIn( const ScChangeAction* p ) const | |||
330 | { | |||
331 | ScChangeActionLinkEntry* pL = GetDeletedIn(); | |||
332 | while ( pL ) | |||
333 | { | |||
334 | if ( pL->GetAction() == p ) | |||
335 | return true; | |||
336 | pL = pL->GetNext(); | |||
337 | } | |||
338 | return false; | |||
339 | } | |||
340 | ||||
341 | void ScChangeAction::RemoveAllDeletedIn() | |||
342 | { | |||
343 | //TODO: Not from TopContent, but really this one | |||
344 | while (pLinkDeletedIn) | |||
345 | { | |||
346 | // coverity[use_after_free] - Moves up by itself | |||
347 | delete pLinkDeletedIn; | |||
| ||||
348 | } | |||
349 | } | |||
350 | ||||
351 | bool ScChangeAction::IsDeletedInDelType( ScChangeActionType eDelType ) const | |||
352 | { | |||
353 | ScChangeActionLinkEntry* pL = GetDeletedIn(); | |||
354 | if ( pL ) | |||
355 | { | |||
356 | // InsertType for MergePrepare/MergeOwn | |||
357 | ScChangeActionType eInsType; | |||
358 | switch ( eDelType ) | |||
359 | { | |||
360 | case SC_CAT_DELETE_COLS : | |||
361 | eInsType = SC_CAT_INSERT_COLS; | |||
362 | break; | |||
363 | case SC_CAT_DELETE_ROWS : | |||
364 | eInsType = SC_CAT_INSERT_ROWS; | |||
365 | break; | |||
366 | case SC_CAT_DELETE_TABS : | |||
367 | eInsType = SC_CAT_INSERT_TABS; | |||
368 | break; | |||
369 | default: | |||
370 | eInsType = SC_CAT_NONE; | |||
371 | } | |||
372 | while ( pL ) | |||
373 | { | |||
374 | ScChangeAction* p = pL->GetAction(); | |||
375 | if ( p != nullptr && (p->GetType() == eDelType || p->GetType() == eInsType) ) | |||
376 | return true; | |||
377 | pL = pL->GetNext(); | |||
378 | } | |||
379 | } | |||
380 | return false; | |||
381 | } | |||
382 | ||||
383 | bool ScChangeAction::HasDependent() const | |||
384 | { | |||
385 | return pLinkDependent != nullptr; | |||
386 | } | |||
387 | ||||
388 | bool ScChangeAction::HasDeleted() const | |||
389 | { | |||
390 | return pLinkDeleted != nullptr; | |||
391 | } | |||
392 | ||||
393 | void ScChangeAction::SetDeletedIn( ScChangeAction* p ) | |||
394 | { | |||
395 | ScChangeActionLinkEntry* pLink1 = new ScChangeActionLinkEntry( GetDeletedInAddress(), p ); | |||
396 | ScChangeActionLinkEntry* pLink2; | |||
397 | if ( GetType() == SC_CAT_CONTENT ) | |||
398 | pLink2 = p->AddDeleted( static_cast<ScChangeActionContent*>(this)->GetTopContent() ); | |||
399 | else | |||
400 | pLink2 = p->AddDeleted( this ); | |||
401 | pLink1->SetLink( pLink2 ); | |||
402 | } | |||
403 | ||||
404 | void ScChangeAction::RemoveAllDependent() | |||
405 | { | |||
406 | while (pLinkDependent) | |||
407 | { | |||
408 | // coverity[use_after_free] - Moves up by itself | |||
409 | delete pLinkDependent; | |||
410 | } | |||
411 | } | |||
412 | ||||
413 | DateTime ScChangeAction::GetDateTime() const | |||
414 | { | |||
415 | DateTime aDT( aDateTime ); | |||
416 | aDT.ConvertToLocalTime(); | |||
417 | return aDT; | |||
418 | } | |||
419 | ||||
420 | void ScChangeAction::UpdateReference( const ScChangeTrack* /* pTrack */, | |||
421 | UpdateRefMode eMode, const ScBigRange& rRange, | |||
422 | sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz ) | |||
423 | { | |||
424 | ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, GetBigRange() ); | |||
425 | } | |||
426 | ||||
427 | void ScChangeAction::GetDescription( | |||
428 | OUString& rStr, ScDocument& /* rDoc */, bool /* bSplitRange */, bool bWarning ) const | |||
429 | { | |||
430 | if (!IsRejecting() || !bWarning) | |||
431 | return; | |||
432 | ||||
433 | // Add comment if rejection may have resulted in references | |||
434 | // not properly restored in formulas. See specification at | |||
435 | // http://specs.openoffice.org/calc/ease-of-use/redlining_comment.sxw | |||
436 | ||||
437 | OUStringBuffer aBuf(rStr); // Take the original string. | |||
438 | if (GetType() == SC_CAT_MOVE) | |||
439 | { | |||
440 | aBuf.append( | |||
441 | ScResId(STR_CHANGED_MOVE_REJECTION_WARNINGreinterpret_cast<char const *>("STR_CHANGED_MOVE_REJECTION_WARNING" "\004" u8"WARNING: This action may have resulted in unintended changes to cell references in formulas." ))).append(" "); | |||
442 | rStr = aBuf.makeStringAndClear(); | |||
443 | return; | |||
444 | } | |||
445 | ||||
446 | if (IsInsertType()) | |||
447 | { | |||
448 | aBuf.append( | |||
449 | ScResId(STR_CHANGED_DELETE_REJECTION_WARNINGreinterpret_cast<char const *>("STR_CHANGED_DELETE_REJECTION_WARNING" "\004" u8"WARNING: This action may have resulted in references to the deleted area not being restored." ))).append(" "); | |||
450 | rStr = aBuf.makeStringAndClear(); | |||
451 | return; | |||
452 | } | |||
453 | ||||
454 | const ScChangeTrack* pCT = GetChangeTrack(); | |||
455 | if (!pCT) | |||
456 | return; | |||
457 | ||||
458 | ScChangeAction* pReject = pCT->GetActionOrGenerated(GetRejectAction()); | |||
459 | ||||
460 | if (!pReject) | |||
461 | return; | |||
462 | ||||
463 | if (pReject->GetType() == SC_CAT_MOVE) | |||
464 | { | |||
465 | aBuf.append( | |||
466 | ScResId(STR_CHANGED_MOVE_REJECTION_WARNINGreinterpret_cast<char const *>("STR_CHANGED_MOVE_REJECTION_WARNING" "\004" u8"WARNING: This action may have resulted in unintended changes to cell references in formulas." ))); | |||
467 | aBuf.append(' '); | |||
468 | rStr = aBuf.makeStringAndClear(); | |||
469 | return; | |||
470 | } | |||
471 | ||||
472 | if (pReject->IsDeleteType()) | |||
473 | { | |||
474 | aBuf.append( | |||
475 | ScResId(STR_CHANGED_DELETE_REJECTION_WARNINGreinterpret_cast<char const *>("STR_CHANGED_DELETE_REJECTION_WARNING" "\004" u8"WARNING: This action may have resulted in references to the deleted area not being restored." ))); | |||
476 | aBuf.append(' '); | |||
477 | rStr = aBuf.makeStringAndClear(); | |||
478 | return; | |||
479 | } | |||
480 | ||||
481 | if (!pReject->HasDependent()) | |||
482 | return; | |||
483 | ||||
484 | ScChangeActionMap aMap; | |||
485 | pCT->GetDependents( pReject, aMap, false, true ); | |||
486 | ScChangeActionMap::iterator itChangeAction = std::find_if(aMap.begin(), aMap.end(), | |||
487 | [&pReject](const ScChangeActionMap::value_type& rEntry) { | |||
488 | return rEntry.second->GetType() == SC_CAT_MOVE || pReject->IsDeleteType(); }); | |||
489 | if (itChangeAction == aMap.end()) | |||
490 | return; | |||
491 | ||||
492 | if( itChangeAction->second->GetType() == SC_CAT_MOVE) | |||
493 | aBuf.append( | |||
494 | ScResId(STR_CHANGED_MOVE_REJECTION_WARNINGreinterpret_cast<char const *>("STR_CHANGED_MOVE_REJECTION_WARNING" "\004" u8"WARNING: This action may have resulted in unintended changes to cell references in formulas." ))); | |||
495 | else | |||
496 | aBuf.append( | |||
497 | ScResId(STR_CHANGED_DELETE_REJECTION_WARNINGreinterpret_cast<char const *>("STR_CHANGED_DELETE_REJECTION_WARNING" "\004" u8"WARNING: This action may have resulted in references to the deleted area not being restored." ))); | |||
498 | ||||
499 | aBuf.append(' '); | |||
500 | rStr = aBuf.makeStringAndClear(); | |||
501 | return; | |||
502 | } | |||
503 | ||||
504 | OUString ScChangeAction::GetRefString( | |||
505 | const ScBigRange& rRange, const ScDocument& rDoc, bool bFlag3D ) const | |||
506 | { | |||
507 | OUStringBuffer aBuf; | |||
508 | ScRefFlags nFlags = ( rRange.IsValid( rDoc ) ? ScRefFlags::VALID : ScRefFlags::ZERO ); | |||
509 | if ( nFlags == ScRefFlags::ZERO ) | |||
510 | aBuf.append(ScCompiler::GetNativeSymbol(ocErrRef)); | |||
511 | else | |||
512 | { | |||
513 | ScRange aTmpRange( rRange.MakeRange() ); | |||
514 | switch ( GetType() ) | |||
515 | { | |||
516 | case SC_CAT_INSERT_COLS : | |||
517 | case SC_CAT_DELETE_COLS : | |||
518 | if ( bFlag3D ) | |||
519 | { | |||
520 | OUString aTmp; | |||
521 | rDoc.GetName( aTmpRange.aStart.Tab(), aTmp ); | |||
522 | aBuf.append(aTmp); | |||
523 | aBuf.append('.'); | |||
524 | } | |||
525 | aBuf.append(ScColToAlpha(aTmpRange.aStart.Col())); | |||
526 | aBuf.append(':'); | |||
527 | aBuf.append(ScColToAlpha(aTmpRange.aEnd.Col())); | |||
528 | break; | |||
529 | case SC_CAT_INSERT_ROWS : | |||
530 | case SC_CAT_DELETE_ROWS : | |||
531 | if ( bFlag3D ) | |||
532 | { | |||
533 | OUString aTmp; | |||
534 | rDoc.GetName( aTmpRange.aStart.Tab(), aTmp ); | |||
535 | aBuf.append(aTmp); | |||
536 | aBuf.append('.'); | |||
537 | } | |||
538 | aBuf.append(static_cast<sal_Int32>(aTmpRange.aStart.Row()+1)); | |||
539 | aBuf.append(':'); | |||
540 | aBuf.append(static_cast<sal_Int32>(aTmpRange.aEnd.Row()+1)); | |||
541 | break; | |||
542 | default: | |||
543 | { | |||
544 | if ( bFlag3D || GetType() == SC_CAT_INSERT_TABS ) | |||
545 | nFlags |= ScRefFlags::TAB_3D; | |||
546 | ||||
547 | aBuf.append(aTmpRange.Format(rDoc, nFlags, rDoc.GetAddressConvention())); | |||
548 | } | |||
549 | } | |||
550 | if ( (bFlag3D && IsDeleteType()) || IsDeletedIn() ) | |||
551 | { | |||
552 | aBuf.insert(0, '('); | |||
553 | aBuf.append(')'); | |||
554 | } | |||
555 | } | |||
556 | return aBuf.makeStringAndClear(); | |||
557 | } | |||
558 | ||||
559 | void ScChangeAction::SetUser( const OUString& r ) | |||
560 | { | |||
561 | aUser = r; | |||
562 | } | |||
563 | ||||
564 | void ScChangeAction::SetComment( const OUString& rStr ) | |||
565 | { | |||
566 | aComment = rStr; | |||
567 | } | |||
568 | ||||
569 | void ScChangeAction::GetRefString( | |||
570 | OUString& rStr, ScDocument& rDoc, bool bFlag3D ) const | |||
571 | { | |||
572 | rStr = GetRefString( GetBigRange(), rDoc, bFlag3D ); | |||
573 | } | |||
574 | ||||
575 | void ScChangeAction::Accept() | |||
576 | { | |||
577 | if ( IsVirgin() ) | |||
578 | { | |||
579 | SetState( SC_CAS_ACCEPTED ); | |||
580 | DeleteCellEntries(); | |||
581 | } | |||
582 | } | |||
583 | ||||
584 | void ScChangeAction::SetRejected() | |||
585 | { | |||
586 | if ( IsVirgin() ) | |||
587 | { | |||
588 | SetState( SC_CAS_REJECTED ); | |||
589 | RemoveAllLinks(); | |||
590 | DeleteCellEntries(); | |||
591 | } | |||
592 | } | |||
593 | ||||
594 | void ScChangeAction::RejectRestoreContents( ScChangeTrack* pTrack, | |||
595 | SCCOL nDx, SCROW nDy ) | |||
596 | { | |||
597 | // Construct list of Contents | |||
598 | std::vector<ScChangeActionContent*> aContentsList; | |||
599 | for ( ScChangeActionLinkEntry* pL = pLinkDeleted; pL; pL = pL->GetNext() ) | |||
600 | { | |||
601 | ScChangeAction* p = pL->GetAction(); | |||
602 | if ( p && p->GetType() == SC_CAT_CONTENT ) | |||
603 | { | |||
604 | aContentsList.push_back(static_cast<ScChangeActionContent*>(p) ); | |||
605 | } | |||
606 | } | |||
607 | SetState( SC_CAS_REJECTED ); // Before UpdateReference for Move | |||
608 | pTrack->UpdateReference( this, true ); // Free LinkDeleted | |||
609 | OSL_ENSURE( !pLinkDeleted, "ScChangeAction::RejectRestoreContents: pLinkDeleted != NULL" )do { if (true && (!(!pLinkDeleted))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/chgtrack.cxx" ":" "609" ": "), "%s", "ScChangeAction::RejectRestoreContents: pLinkDeleted != NULL" ); } } while (false); | |||
610 | ||||
611 | // Work through list of Contents and delete | |||
612 | ScDocument& rDoc = pTrack->GetDocument(); | |||
613 | for (ScChangeActionContent* pContent : aContentsList) | |||
614 | { | |||
615 | if ( !pContent->IsDeletedIn() && | |||
616 | pContent->GetBigRange().aStart.IsValid( rDoc ) ) | |||
617 | pContent->PutNewValueToDoc( &rDoc, nDx, nDy ); | |||
618 | } | |||
619 | DeleteCellEntries(); // Remove generated ones | |||
620 | } | |||
621 | ||||
622 | void ScChangeAction::SetDeletedInThis( sal_uLong nActionNumber, | |||
623 | const ScChangeTrack* pTrack ) | |||
624 | { | |||
625 | if ( nActionNumber ) | |||
626 | { | |||
627 | ScChangeAction* pAct = pTrack->GetActionOrGenerated( nActionNumber ); | |||
628 | OSL_ENSURE( pAct, "ScChangeAction::SetDeletedInThis: missing Action" )do { if (true && (!(pAct))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/chgtrack.cxx" ":" "628" ": "), "%s", "ScChangeAction::SetDeletedInThis: missing Action" ); } } while (false); | |||
629 | if ( pAct ) | |||
630 | pAct->SetDeletedIn( this ); | |||
631 | } | |||
632 | } | |||
633 | ||||
634 | void ScChangeAction::AddDependent( sal_uLong nActionNumber, | |||
635 | const ScChangeTrack* pTrack ) | |||
636 | { | |||
637 | if ( nActionNumber ) | |||
638 | { | |||
639 | ScChangeAction* pAct = pTrack->GetActionOrGenerated( nActionNumber ); | |||
640 | OSL_ENSURE( pAct, "ScChangeAction::AddDependent: missing Action" )do { if (true && (!(pAct))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/chgtrack.cxx" ":" "640" ": "), "%s", "ScChangeAction::AddDependent: missing Action" ); } } while (false); | |||
641 | if ( pAct ) | |||
642 | { | |||
643 | ScChangeActionLinkEntry* pLink = AddDependent( pAct ); | |||
644 | pAct->AddLink( this, pLink ); | |||
645 | } | |||
646 | } | |||
647 | } | |||
648 | ||||
649 | // ScChangeActionIns | |||
650 | ScChangeActionIns::ScChangeActionIns( const ScDocument* pDoc, const ScRange& rRange, bool bEndOfList ) : | |||
651 | ScChangeAction(SC_CAT_NONE, rRange), | |||
652 | mbEndOfList(bEndOfList) | |||
653 | { | |||
654 | if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == pDoc->MaxCol() ) | |||
655 | { | |||
656 | aBigRange.aStart.SetCol( nInt32Min ); | |||
657 | aBigRange.aEnd.SetCol( nInt32Max ); | |||
658 | if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == pDoc->MaxRow() ) | |||
659 | { | |||
660 | SetType( SC_CAT_INSERT_TABS ); | |||
661 | aBigRange.aStart.SetRow( nInt32Min ); | |||
662 | aBigRange.aEnd.SetRow( nInt32Max ); | |||
663 | } | |||
664 | else | |||
665 | SetType( SC_CAT_INSERT_ROWS ); | |||
666 | } | |||
667 | else if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == pDoc->MaxRow() ) | |||
668 | { | |||
669 | SetType( SC_CAT_INSERT_COLS ); | |||
670 | aBigRange.aStart.SetRow( nInt32Min ); | |||
671 | aBigRange.aEnd.SetRow( nInt32Max ); | |||
672 | } | |||
673 | else | |||
674 | { | |||
675 | OSL_FAIL( "ScChangeActionIns: Block not supported!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/chgtrack.cxx" ":" "675" ": "), "%s", "ScChangeActionIns: Block not supported!" ); } } while (false); | |||
676 | } | |||
677 | } | |||
678 | ||||
679 | ScChangeActionIns::ScChangeActionIns( | |||
680 | const sal_uLong nActionNumber, const ScChangeActionState eStateP, | |||
681 | const sal_uLong nRejectingNumber, const ScBigRange& aBigRangeP, | |||
682 | const OUString& aUserP, const DateTime& aDateTimeP, | |||
683 | const OUString& sComment, const ScChangeActionType eTypeP, | |||
684 | bool bEndOfList ) : | |||
685 | ScChangeAction(eTypeP, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment), | |||
686 | mbEndOfList(bEndOfList) | |||
687 | { | |||
688 | } | |||
689 | ||||
690 | ScChangeActionIns::~ScChangeActionIns() | |||
691 | { | |||
692 | } | |||
| ||||
693 | ||||
694 | void ScChangeActionIns::GetDescription( | |||
695 | OUString& rStr, ScDocument& rDoc, bool bSplitRange, bool bWarning ) const | |||
696 | { | |||
697 | ScChangeAction::GetDescription( rStr, rDoc, bSplitRange, bWarning ); | |||
698 | ||||
699 | const char* pWhatId; | |||
700 | switch ( GetType() ) | |||
701 | { | |||
702 | case SC_CAT_INSERT_COLS : | |||
703 | pWhatId = STR_COLUMNreinterpret_cast<char const *>("STR_COLUMN" "\004" u8"Column" ); | |||
704 | break; | |||
705 | case SC_CAT_INSERT_ROWS : | |||
706 | pWhatId = STR_ROWreinterpret_cast<char const *>("STR_ROW" "\004" u8"Row" ); | |||
707 | break; | |||
708 | default: | |||
709 | pWhatId = STR_AREAreinterpret_cast<char const *>("STR_AREA" "\004" u8"Range" ); | |||
710 | } | |||
711 | ||||
712 | OUString aRsc = ScResId(STR_CHANGED_INSERTreinterpret_cast<char const *>("STR_CHANGED_INSERT" "\004" u8"#1 inserted")); | |||
713 | sal_Int32 nPos = aRsc.indexOf("#1"); | |||
714 | if (nPos < 0) | |||
715 | return; | |||
716 | ||||
717 | // Construct a range string to replace '#1' first. | |||
718 | OUStringBuffer aBuf(ScResId(pWhatId)); | |||
719 | aBuf.append(' '); | |||
720 | aBuf.append(GetRefString(GetBigRange(), rDoc)); | |||
721 | OUString aRangeStr = aBuf.makeStringAndClear(); | |||
722 | ||||
723 | aRsc = aRsc.replaceAt(nPos, 2, aRangeStr); // replace '#1' with the range string. | |||
724 | ||||
725 | aBuf.append(rStr).append(aRsc); | |||
726 | rStr = aBuf.makeStringAndClear(); | |||
727 | } | |||
728 | ||||
729 | bool ScChangeActionIns::IsEndOfList() const | |||
730 | { | |||
731 | return mbEndOfList; | |||
732 | } | |||
733 | ||||
734 | bool ScChangeActionIns::Reject( ScDocument& rDoc ) | |||
735 | { | |||
736 | if ( !aBigRange.IsValid( rDoc ) ) | |||
737 | return false; | |||
738 | ||||
739 | ScRange aRange( aBigRange.MakeRange() ); | |||
740 | if ( !rDoc.IsBlockEditable( aRange.aStart.Tab(), aRange.aStart.Col(), | |||
741 | aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row() ) ) | |||
742 | return false; | |||
743 | ||||
744 | switch ( GetType() ) | |||
745 | { | |||
746 | case SC_CAT_INSERT_COLS : | |||
747 | rDoc.DeleteCol( aRange ); | |||
748 | break; | |||
749 | case SC_CAT_INSERT_ROWS : | |||
750 | rDoc.DeleteRow( aRange ); | |||
751 | break; | |||
752 | case SC_CAT_INSERT_TABS : | |||
753 | rDoc.DeleteTab( aRange.aStart.Tab() ); | |||
754 | break; | |||
755 | default: | |||
756 | { | |||
757 | // added to avoid warnings | |||
758 | } | |||
759 | } | |||
760 | SetState( SC_CAS_REJECTED ); | |||
761 | RemoveAllLinks(); | |||
762 | return true; | |||
763 | } | |||
764 | ||||
765 | // ScChangeActionDel | |||
766 | ScChangeActionDel::ScChangeActionDel( const ScDocument* pDoc, const ScRange& rRange, | |||
767 | SCCOL nDxP, SCROW nDyP, ScChangeTrack* pTrackP ) | |||
768 | : | |||
769 | ScChangeAction( SC_CAT_NONE, rRange ), | |||
770 | pTrack( pTrackP ), | |||
771 | pCutOff( nullptr ), | |||
772 | nCutOff( 0 ), | |||
773 | pLinkMove( nullptr ), | |||
774 | nDx( nDxP ), | |||
775 | nDy( nDyP ) | |||
776 | { | |||
777 | if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == pDoc->MaxCol() ) | |||
778 | { | |||
779 | aBigRange.aStart.SetCol( nInt32Min ); | |||
780 | aBigRange.aEnd.SetCol( nInt32Max ); | |||
781 | if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == pDoc->MaxRow() ) | |||
782 | { | |||
783 | SetType( SC_CAT_DELETE_TABS ); | |||
784 | aBigRange.aStart.SetRow( nInt32Min ); | |||
785 | aBigRange.aEnd.SetRow( nInt32Max ); | |||
786 | } | |||
787 | else | |||
788 | SetType( SC_CAT_DELETE_ROWS ); | |||
789 | } | |||
790 | else if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == pDoc->MaxRow() ) | |||
791 | { | |||
792 | SetType( SC_CAT_DELETE_COLS ); | |||
793 | aBigRange.aStart.SetRow( nInt32Min ); | |||
794 | aBigRange.aEnd.SetRow( nInt32Max ); | |||
795 | } | |||
796 | else | |||
797 | { | |||
798 | OSL_FAIL( "ScChangeActionDel: Block not supported!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/chgtrack.cxx" ":" "798" ": "), "%s", "ScChangeActionDel: Block not supported!" ); } } while (false); | |||
799 | } | |||
800 | } | |||
801 | ||||
802 | ScChangeActionDel::ScChangeActionDel( | |||
803 | const sal_uLong nActionNumber, const ScChangeActionState eStateP, | |||
804 | const sal_uLong nRejectingNumber, const ScBigRange& aBigRangeP, | |||
805 | const OUString& aUserP, const DateTime& aDateTimeP, const OUString &sComment, | |||
806 | const ScChangeActionType eTypeP, const SCCOLROW nD, ScChangeTrack* pTrackP) : // which of nDx and nDy is set depends on the type | |||
807 | ScChangeAction(eTypeP, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment), | |||
808 | pTrack( pTrackP ), | |||
809 | pCutOff( nullptr ), | |||
810 | nCutOff( 0 ), | |||
811 | pLinkMove( nullptr ), | |||
812 | nDx( 0 ), | |||
813 | nDy( 0 ) | |||
814 | { | |||
815 | if (eType == SC_CAT_DELETE_COLS) | |||
816 | nDx = static_cast<SCCOL>(nD); | |||
817 | else if (eType == SC_CAT_DELETE_ROWS) | |||
818 | nDy = static_cast<SCROW>(nD); | |||
819 | } | |||
820 | ||||
821 | ScChangeActionDel::~ScChangeActionDel() | |||
822 | { | |||
823 | DeleteCellEntries(); | |||
824 | while (pLinkMove) | |||
825 | { | |||
826 | // coverity[use_after_free] - Moves up by itself | |||
827 | delete pLinkMove; | |||
828 | } | |||
829 | } | |||
830 | ||||
831 | void ScChangeActionDel::AddContent( ScChangeActionContent* pContent ) | |||
832 | { | |||
833 | mvCells.push_back(pContent); | |||
834 | } | |||
835 | ||||
836 | void ScChangeActionDel::DeleteCellEntries() | |||
837 | { | |||
838 | pTrack->DeleteCellEntries( mvCells, this ); | |||
839 | } | |||
840 | ||||
841 | bool ScChangeActionDel::IsBaseDelete() const | |||
842 | { | |||
843 | return !GetDx() && !GetDy(); | |||
844 | } | |||
845 | ||||
846 | bool ScChangeActionDel::IsTopDelete() const | |||
847 | { | |||
848 | const ScChangeAction* p = GetNext(); | |||
849 | if ( !p || p->GetType() != GetType() ) | |||
850 | return true; | |||
851 | return static_cast<const ScChangeActionDel*>(p)->IsBaseDelete(); | |||
852 | } | |||
853 | ||||
854 | bool ScChangeActionDel::IsMultiDelete() const | |||
855 | { | |||
856 | if ( GetDx() || GetDy() ) | |||
857 | return true; | |||
858 | const ScChangeAction* p = GetNext(); | |||
859 | if ( !p || p->GetType() != GetType() ) | |||
860 | return false; | |||
861 | const ScChangeActionDel* pDel = static_cast<const ScChangeActionDel*>(p); | |||
862 | return (pDel->GetDx() > GetDx() || pDel->GetDy() > GetDy()) && | |||
863 | pDel->GetBigRange() == aBigRange; | |||
864 | } | |||
865 | ||||
866 | bool ScChangeActionDel::IsTabDeleteCol() const | |||
867 | { | |||
868 | if ( GetType() != SC_CAT_DELETE_COLS ) | |||
869 | return false; | |||
870 | const ScChangeAction* p = this; | |||
871 | while ( p && p->GetType() == SC_CAT_DELETE_COLS && | |||
872 | !static_cast<const ScChangeActionDel*>(p)->IsTopDelete() ) | |||
873 | p = p->GetNext(); | |||
874 | return p && p->GetType() == SC_CAT_DELETE_TABS; | |||
875 | } | |||
876 | ||||
877 | ScChangeActionDelMoveEntry* ScChangeActionDel::AddCutOffMove( | |||
878 | ScChangeActionMove* pMove, short nFrom, short nTo ) | |||
879 | { | |||
880 | return new ScChangeActionDelMoveEntry(&pLinkMove, pMove, nFrom, nTo); | |||
881 | } | |||
882 | ||||
883 | void ScChangeActionDel::UpdateReference( const ScChangeTrack* /* pTrack */, | |||
884 | UpdateRefMode eMode, const ScBigRange& rRange, | |||
885 | sal_Int32 nDxP, sal_Int32 nDyP, sal_Int32 nDz ) | |||
886 | { | |||
887 | ScRefUpdate::Update( eMode, rRange, nDxP, nDyP, nDz, GetBigRange() ); | |||
888 | ||||
889 | if ( !IsDeletedIn() ) | |||
890 | return ; | |||
891 | ||||
892 | // Correct in the ones who slipped through | |||
893 | for ( ScChangeActionLinkEntry* pL = pLinkDeleted; pL; pL = pL->GetNext() ) | |||
894 | { | |||
895 | ScChangeAction* p = pL->GetAction(); | |||
896 | if ( p && p->GetType() == SC_CAT_CONTENT && | |||
897 | !GetBigRange().In( p->GetBigRange() ) ) | |||
898 | { | |||
899 | switch ( GetType() ) | |||
900 | { | |||
901 | case SC_CAT_DELETE_COLS : | |||
902 | p->GetBigRange().aStart.SetCol( GetBigRange().aStart.Col() ); | |||
903 | p->GetBigRange().aEnd.SetCol( GetBigRange().aStart.Col() ); | |||
904 | break; | |||
905 | case SC_CAT_DELETE_ROWS : | |||
906 | p->GetBigRange().aStart.SetRow( GetBigRange().aStart.Row() ); | |||
907 | p->GetBigRange().aEnd.SetRow( GetBigRange().aStart.Row() ); | |||
908 | break; | |||
909 | case SC_CAT_DELETE_TABS : | |||
910 | p->GetBigRange().aStart.SetTab( GetBigRange().aStart.Tab() ); | |||
911 | p->GetBigRange().aEnd.SetTab( GetBigRange().aStart.Tab() ); | |||
912 | break; | |||
913 | default: | |||
914 | { | |||
915 | // added to avoid warnings | |||
916 | } | |||
917 | } | |||
918 | } | |||
919 | } | |||
920 | } | |||
921 | ||||
922 | ScBigRange ScChangeActionDel::GetOverAllRange() const | |||
923 | { | |||
924 | ScBigRange aTmpRange( GetBigRange() ); | |||
925 | aTmpRange.aEnd.SetCol( aTmpRange.aEnd.Col() + GetDx() ); | |||
926 | aTmpRange.aEnd.SetRow( aTmpRange.aEnd.Row() + GetDy() ); | |||
927 | return aTmpRange; | |||
928 | } | |||
929 | ||||
930 | void ScChangeActionDel::GetDescription( | |||
931 | OUString& rStr, ScDocument& rDoc, bool bSplitRange, bool bWarning ) const | |||
932 | { | |||
933 | ScChangeAction::GetDescription( rStr, rDoc, bSplitRange, bWarning ); | |||
934 | ||||
935 | const char* pWhatId; | |||
936 | switch ( GetType() ) | |||
937 | { | |||
938 | case SC_CAT_DELETE_COLS : | |||
939 | pWhatId = STR_COLUMNreinterpret_cast<char const *>("STR_COLUMN" "\004" u8"Column" ); | |||
940 | break; | |||
941 | case SC_CAT_DELETE_ROWS : | |||
942 | pWhatId = STR_ROWreinterpret_cast<char const *>("STR_ROW" "\004" u8"Row" ); | |||
943 | break; | |||
944 | default: | |||
945 | pWhatId = STR_AREAreinterpret_cast<char const *>("STR_AREA" "\004" u8"Range" ); | |||
946 | } | |||
947 | ||||
948 | ScBigRange aTmpRange( GetBigRange() ); | |||
949 | if ( !IsRejected() ) | |||
950 | { | |||
951 | if ( bSplitRange ) | |||
952 | { | |||
953 | aTmpRange.aStart.SetCol( aTmpRange.aStart.Col() + GetDx() ); | |||
954 | aTmpRange.aStart.SetRow( aTmpRange.aStart.Row() + GetDy() ); | |||
955 | } | |||
956 | aTmpRange.aEnd.SetCol( aTmpRange.aEnd.Col() + GetDx() ); | |||
957 | aTmpRange.aEnd.SetRow( aTmpRange.aEnd.Row() + GetDy() ); | |||
958 | } | |||
959 | ||||
960 | OUString aRsc = ScResId(STR_CHANGED_DELETEreinterpret_cast<char const *>("STR_CHANGED_DELETE" "\004" u8"#1 deleted")); | |||
961 | sal_Int32 nPos = aRsc.indexOf("#1"); | |||
962 | if (nPos < 0) | |||
963 | return; | |||
964 | ||||
965 | // Build a string to replace with. | |||
966 | OUStringBuffer aBuf; | |||
967 | aBuf.append(ScResId(pWhatId)); | |||
968 | aBuf.append(' '); | |||
969 | aBuf.append(GetRefString(aTmpRange, rDoc)); | |||
970 | OUString aRangeStr = aBuf.makeStringAndClear(); | |||
971 | aRsc = aRsc.replaceAt(nPos, 2, aRangeStr); // replace '#1' with the string. | |||
972 | ||||
973 | aBuf.append(rStr).append(aRsc); | |||
974 | rStr = aBuf.makeStringAndClear(); // append to the original. | |||
975 | } | |||
976 | ||||
977 | bool ScChangeActionDel::Reject( ScDocument& rDoc ) | |||
978 | { | |||
979 | if ( !aBigRange.IsValid( rDoc ) && GetType() != SC_CAT_DELETE_TABS ) | |||
980 | return false; | |||
981 | ||||
982 | if ( IsTopDelete() ) | |||
983 | { // Restore whole section in one go | |||
984 | bool bOk = true; | |||
985 | ScBigRange aTmpRange( GetOverAllRange() ); | |||
986 | if ( !aTmpRange.IsValid( rDoc ) ) | |||
987 | { | |||
988 | if ( GetType() == SC_CAT_DELETE_TABS ) | |||
989 | { // Do we attach a Tab? | |||
990 | if ( aTmpRange.aStart.Tab() > rDoc.GetMaxTableNumber() ) | |||
991 | bOk = false; | |||
992 | } | |||
993 | else | |||
994 | bOk = false; | |||
995 | } | |||
996 | if ( bOk ) | |||
997 | { | |||
998 | ScRange aRange( aTmpRange.MakeRange() ); | |||
999 | // InDelete... for formula UpdateReference in Document | |||
1000 | pTrack->SetInDeleteRange( aRange ); | |||
1001 | pTrack->SetInDeleteTop( true ); | |||
1002 | pTrack->SetInDeleteUndo( true ); | |||
1003 | pTrack->SetInDelete( true ); | |||
1004 | switch ( GetType() ) | |||
1005 | { | |||
1006 | case SC_CAT_DELETE_COLS : | |||
1007 | if ( aRange.aStart.Col() != 0 || aRange.aEnd.Col() != rDoc.MaxCol() ) | |||
1008 | { // Only if not TabDelete | |||
1009 | bOk = rDoc.CanInsertCol( aRange ) && rDoc.InsertCol( aRange ); | |||
1010 | } | |||
1011 | break; | |||
1012 | case SC_CAT_DELETE_ROWS : | |||
1013 | bOk = rDoc.CanInsertRow( aRange ) && rDoc.InsertRow( aRange ); | |||
1014 | break; | |||
1015 | case SC_CAT_DELETE_TABS : | |||
1016 | { | |||
1017 | //TODO: Remember table names? | |||
1018 | OUString aName; | |||
1019 | rDoc.CreateValidTabName( aName ); | |||
1020 | bOk = rDoc.ValidNewTabName( aName ) && rDoc.InsertTab( aRange.aStart.Tab(), aName ); | |||
1021 | } | |||
1022 | break; | |||
1023 | default: | |||
1024 | { | |||
1025 | // added to avoid warnings | |||
1026 | } | |||
1027 | } | |||
1028 | pTrack->SetInDelete( false ); | |||
1029 | pTrack->SetInDeleteUndo( false ); | |||
1030 | } | |||
1031 | if ( !bOk ) | |||
1032 | { | |||
1033 | pTrack->SetInDeleteTop( false ); | |||
1034 | return false; | |||
1035 | } | |||
1036 | // Keep InDeleteTop for UpdateReference Undo | |||
1037 | } | |||
1038 | ||||
1039 | // Sets rejected and calls UpdateReference-Undo and DeleteCellEntries | |||
1040 | RejectRestoreContents( pTrack, GetDx(), GetDy() ); | |||
1041 | ||||
1042 | pTrack->SetInDeleteTop( false ); | |||
1043 | RemoveAllLinks(); | |||
1044 | return true; | |||
1045 | } | |||
1046 | ||||
1047 | void ScChangeActionDel::UndoCutOffMoves() | |||
1048 | { // Restore cut off Moves; delete Entries/Links | |||
1049 | while ( pLinkMove ) | |||
1050 | { | |||
1051 | // coverity[deref_arg] - the call on delete pLinkMove at the block end Moves a new entry into pLinkMode by itself | |||
1052 | ScChangeActionMove* pMove = pLinkMove->GetMove(); | |||
1053 | short nFrom = pLinkMove->GetCutOffFrom(); | |||
1054 | short nTo = pLinkMove->GetCutOffTo(); | |||
1055 | switch ( GetType() ) | |||
1056 | { | |||
1057 | case SC_CAT_DELETE_COLS : | |||
1058 | if ( nFrom > 0 ) | |||
1059 | pMove->GetFromRange().aStart.IncCol( -nFrom ); | |||
1060 | else if ( nFrom < 0 ) | |||
1061 | pMove->GetFromRange().aEnd.IncCol( -nFrom ); | |||
1062 | if ( nTo > 0 ) | |||
1063 | pMove->GetBigRange().aStart.IncCol( -nTo ); | |||
1064 | else if ( nTo < 0 ) | |||
1065 | pMove->GetBigRange().aEnd.IncCol( -nTo ); | |||
1066 | break; | |||
1067 | case SC_CAT_DELETE_ROWS : | |||
1068 | if ( nFrom > 0 ) | |||
1069 | pMove->GetFromRange().aStart.IncRow( -nFrom ); | |||
1070 | else if ( nFrom < 0 ) | |||
1071 | pMove->GetFromRange().aEnd.IncRow( -nFrom ); | |||
1072 | if ( nTo > 0 ) | |||
1073 | pMove->GetBigRange().aStart.IncRow( -nTo ); | |||
1074 | else if ( nTo < 0 ) | |||
1075 | pMove->GetBigRange().aEnd.IncRow( -nTo ); | |||
1076 | break; | |||
1077 | case SC_CAT_DELETE_TABS : | |||
1078 | if ( nFrom > 0 ) | |||
1079 | pMove->GetFromRange().aStart.IncTab( -nFrom ); | |||
1080 | else if ( nFrom < 0 ) | |||
1081 | pMove->GetFromRange().aEnd.IncTab( -nFrom ); | |||
1082 | if ( nTo > 0 ) | |||
1083 | pMove->GetBigRange().aStart.IncTab( -nTo ); | |||
1084 | else if ( nTo < 0 ) | |||
1085 | pMove->GetBigRange().aEnd.IncTab( -nTo ); | |||
1086 | break; | |||
1087 | default: | |||
1088 | { | |||
1089 | // added to avoid warnings | |||
1090 | } | |||
1091 | } | |||
1092 | delete pLinkMove; // Moves up by itself | |||
1093 | } | |||
1094 | } | |||
1095 | ||||
1096 | void ScChangeActionDel::UndoCutOffInsert() | |||
1097 | { //Restore cut off Insert | |||
1098 | if ( !pCutOff ) | |||
1099 | return; | |||
1100 | ||||
1101 | switch ( pCutOff->GetType() ) | |||
1102 | { | |||
1103 | case SC_CAT_INSERT_COLS : | |||
1104 | if ( nCutOff < 0 ) | |||
1105 | pCutOff->GetBigRange().aEnd.IncCol( -nCutOff ); | |||
1106 | else | |||
1107 | pCutOff->GetBigRange().aStart.IncCol( -nCutOff ); | |||
1108 | break; | |||
1109 | case SC_CAT_INSERT_ROWS : | |||
1110 | if ( nCutOff < 0 ) | |||
1111 | pCutOff->GetBigRange().aEnd.IncRow( -nCutOff ); | |||
1112 | else | |||
1113 | pCutOff->GetBigRange().aStart.IncRow( -nCutOff ); | |||
1114 | break; | |||
1115 | case SC_CAT_INSERT_TABS : | |||
1116 | if ( nCutOff < 0 ) | |||
1117 | pCutOff->GetBigRange().aEnd.IncTab( -nCutOff ); | |||
1118 | else | |||
1119 | pCutOff->GetBigRange().aStart.IncTab( -nCutOff ); | |||
1120 | break; | |||
1121 | default: | |||
1122 | { | |||
1123 | // added to avoid warnings | |||
1124 | } | |||
1125 | } | |||
1126 | SetCutOffInsert( nullptr, 0 ); | |||
1127 | } | |||
1128 | ||||
1129 | // ScChangeActionMove | |||
1130 | ScChangeActionMove::ScChangeActionMove( | |||
1131 | const sal_uLong nActionNumber, const ScChangeActionState eStateP, | |||
1132 | const sal_uLong nRejectingNumber, const ScBigRange& aToBigRange, | |||
1133 | const OUString& aUserP, const DateTime& aDateTimeP, | |||
1134 | const OUString &sComment, const ScBigRange& aFromBigRange, | |||
1135 | ScChangeTrack* pTrackP) : // which of nDx and nDy is set depends on the type | |||
1136 | ScChangeAction(SC_CAT_MOVE, aToBigRange, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment), | |||
1137 | aFromRange(aFromBigRange), | |||
1138 | pTrack( pTrackP ), | |||
1139 | nStartLastCut(0), | |||
1140 | nEndLastCut(0) | |||
1141 | { | |||
1142 | } | |||
1143 | ||||
1144 | ScChangeActionMove::~ScChangeActionMove() | |||
1145 | { | |||
1146 | DeleteCellEntries(); | |||
1147 | } | |||
1148 | ||||
1149 | void ScChangeActionMove::AddContent( ScChangeActionContent* pContent ) | |||
1150 | { | |||
1151 | mvCells.push_back(pContent); | |||
1152 | } | |||
1153 | ||||
1154 | void ScChangeActionMove::DeleteCellEntries() | |||
1155 | { | |||
1156 | pTrack->DeleteCellEntries( mvCells, this ); | |||
1157 | } | |||
1158 | ||||
1159 | void ScChangeActionMove::UpdateReference( const ScChangeTrack* /* pTrack */, | |||
1160 | UpdateRefMode eMode, const ScBigRange& rRange, | |||
1161 | sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz ) | |||
1162 | { | |||
1163 | ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, aFromRange ); | |||
1164 | ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, GetBigRange() ); | |||
1165 | } | |||
1166 | ||||
1167 | void ScChangeActionMove::GetDelta( sal_Int32& nDx, sal_Int32& nDy, sal_Int32& nDz ) const | |||
1168 | { | |||
1169 | const ScBigAddress& rToPos = GetBigRange().aStart; | |||
1170 | const ScBigAddress& rFromPos = GetFromRange().aStart; | |||
1171 | nDx = rToPos.Col() - rFromPos.Col(); | |||
1172 | nDy = rToPos.Row() - rFromPos.Row(); | |||
1173 | nDz = rToPos.Tab() - rFromPos.Tab(); | |||
1174 | } | |||
1175 | ||||
1176 | void ScChangeActionMove::GetDescription( | |||
1177 | OUString& rStr, ScDocument& rDoc, bool bSplitRange, bool bWarning ) const | |||
1178 | { | |||
1179 | ScChangeAction::GetDescription( rStr, rDoc, bSplitRange, bWarning ); | |||
1180 | ||||
1181 | bool bFlag3D = GetFromRange().aStart.Tab() != GetBigRange().aStart.Tab(); | |||
1182 | ||||
1183 | OUString aRsc = ScResId(STR_CHANGED_MOVEreinterpret_cast<char const *>("STR_CHANGED_MOVE" "\004" u8"Range moved from #1 to #2")); | |||
1184 | ||||
1185 | OUString aTmpStr = ScChangeAction::GetRefString(GetFromRange(), rDoc, bFlag3D); | |||
1186 | sal_Int32 nPos = aRsc.indexOf("#1"); | |||
1187 | if (nPos >= 0) | |||
1188 | { | |||
1189 | aRsc = aRsc.replaceAt(nPos, 2, aTmpStr); | |||
1190 | nPos += aTmpStr.getLength(); | |||
1191 | } | |||
1192 | ||||
1193 | aTmpStr = ScChangeAction::GetRefString(GetBigRange(), rDoc, bFlag3D); | |||
1194 | nPos = nPos >= 0 ? aRsc.indexOf("#2", nPos) : -1; | |||
1195 | if (nPos >= 0) | |||
1196 | { | |||
1197 | aRsc = aRsc.replaceAt(nPos, 2, aTmpStr); | |||
1198 | } | |||
1199 | ||||
1200 | rStr += aRsc; // append to the original string. | |||
1201 | } | |||
1202 | ||||
1203 | void ScChangeActionMove::GetRefString( | |||
1204 | OUString& rStr, ScDocument& rDoc, bool bFlag3D ) const | |||
1205 | { | |||
1206 | if ( !bFlag3D ) | |||
1207 | bFlag3D = ( GetFromRange().aStart.Tab() != GetBigRange().aStart.Tab() ); | |||
1208 | ||||
1209 | // overwrite existing string value. | |||
1210 | rStr = ScChangeAction::GetRefString(GetFromRange(), rDoc, bFlag3D) | |||
1211 | + ", " | |||
1212 | + ScChangeAction::GetRefString(GetBigRange(), rDoc, bFlag3D); | |||
1213 | } | |||
1214 | ||||
1215 | bool ScChangeActionMove::Reject( ScDocument& rDoc ) | |||
1216 | { | |||
1217 | if ( !(aBigRange.IsValid( rDoc ) && aFromRange.IsValid( rDoc )) ) | |||
1218 | return false; | |||
1219 | ||||
1220 | ScRange aToRange( aBigRange.MakeRange() ); | |||
1221 | ScRange aFrmRange( aFromRange.MakeRange() ); | |||
1222 | ||||
1223 | bool bOk = rDoc.IsBlockEditable( aToRange.aStart.Tab(), | |||
1224 | aToRange.aStart.Col(), aToRange.aStart.Row(), | |||
1225 | aToRange.aEnd.Col(), aToRange.aEnd.Row() ); | |||
1226 | if ( bOk ) | |||
1227 | bOk = rDoc.IsBlockEditable( aFrmRange.aStart.Tab(), | |||
1228 | aFrmRange.aStart.Col(), aFrmRange.aStart.Row(), | |||
1229 | aFrmRange.aEnd.Col(), aFrmRange.aEnd.Row() ); | |||
1230 | if ( !bOk ) | |||
1231 | return false; | |||
1232 | ||||
1233 | pTrack->LookUpContents( aToRange, &rDoc, 0, 0, 0 ); // Contents to be moved | |||
1234 | ||||
1235 | rDoc.DeleteAreaTab( aToRange, InsertDeleteFlags::ALL ); | |||
1236 | rDoc.DeleteAreaTab( aFrmRange, InsertDeleteFlags::ALL ); | |||
1237 | // Adjust formula in the Document | |||
1238 | sc::RefUpdateContext aCxt(rDoc); | |||
1239 | aCxt.meMode = URM_MOVE; | |||
1240 | aCxt.maRange = aFrmRange; | |||
1241 | aCxt.mnColDelta = aFrmRange.aStart.Col() - aToRange.aStart.Col(); | |||
1242 | aCxt.mnRowDelta = aFrmRange.aStart.Row() - aToRange.aStart.Row(); | |||
1243 | aCxt.mnTabDelta = aFrmRange.aStart.Tab() - aToRange.aStart.Tab(); | |||
1244 | rDoc.UpdateReference(aCxt); | |||
1245 | ||||
1246 | // Free LinkDependent, set succeeding UpdateReference Undo | |||
1247 | // ToRange->FromRange Dependents | |||
1248 | RemoveAllDependent(); | |||
1249 | ||||
1250 | // Sets rejected and calls UpdateReference Undo and DeleteCellEntries | |||
1251 | RejectRestoreContents( pTrack, 0, 0 ); | |||
1252 | ||||
1253 | while ( pLinkDependent ) | |||
1254 | { | |||
1255 | ScChangeAction* p = pLinkDependent->GetAction(); | |||
1256 | if ( p && p->GetType() == SC_CAT_CONTENT ) | |||
1257 | { | |||
1258 | ScChangeActionContent* pContent = static_cast<ScChangeActionContent*>(p); | |||
1259 | if ( !pContent->IsDeletedIn() && | |||
1260 | pContent->GetBigRange().aStart.IsValid( rDoc ) ) | |||
1261 | pContent->PutNewValueToDoc( &rDoc, 0, 0 ); | |||
1262 | // Delete the ones created in LookUpContents | |||
1263 | if ( pTrack->IsGenerated( pContent->GetActionNumber() ) && | |||
1264 | !pContent->IsDeletedIn() ) | |||
1265 | { | |||
1266 | pLinkDependent->UnLink(); // Else this one is also deleted! | |||
1267 | pTrack->DeleteGeneratedDelContent( pContent ); | |||
1268 | } | |||
1269 | } | |||
1270 | delete pLinkDependent; | |||
1271 | } | |||
1272 | ||||
1273 | RemoveAllLinks(); | |||
1274 | return true; | |||
1275 | } | |||
1276 | ||||
1277 | ScChangeActionContent::ScChangeActionContent( const ScRange& rRange ) : | |||
1278 | ScChangeAction(SC_CAT_CONTENT, rRange), | |||
1279 | pNextContent(nullptr), | |||
1280 | pPrevContent(nullptr), | |||
1281 | pNextInSlot(nullptr), | |||
1282 | ppPrevInSlot(nullptr) | |||
1283 | {} | |||
1284 | ||||
1285 | ScChangeActionContent::ScChangeActionContent( const sal_uLong nActionNumber, | |||
1286 | const ScChangeActionState eStateP, const sal_uLong nRejectingNumber, | |||
1287 | const ScBigRange& aBigRangeP, const OUString& aUserP, | |||
1288 | const DateTime& aDateTimeP, const OUString& sComment, | |||
1289 | const ScCellValue& rOldCell, const ScDocument* pDoc, const OUString& sOldValue ) : | |||
1290 | ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment), | |||
1291 | maOldCell(rOldCell), | |||
1292 | maOldValue(sOldValue), | |||
1293 | pNextContent(nullptr), | |||
1294 | pPrevContent(nullptr), | |||
1295 | pNextInSlot(nullptr), | |||
1296 | ppPrevInSlot(nullptr) | |||
1297 | { | |||
1298 | if (!maOldCell.isEmpty()) | |||
1299 | SetCell(maOldValue, maOldCell, 0, pDoc); | |||
1300 | ||||
1301 | if (!sOldValue.isEmpty()) // #i40704# don't overwrite SetCell result with empty string | |||
1302 | maOldValue = sOldValue; // set again, because SetCell removes it | |||
1303 | } | |||
1304 | ||||
1305 | ScChangeActionContent::ScChangeActionContent( const sal_uLong nActionNumber, | |||
1306 | const ScCellValue& rNewCell, const ScBigRange& aBigRangeP, | |||
1307 | const ScDocument* pDoc, const OUString& sNewValue ) : | |||
1308 | ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber), | |||
1309 | maNewCell(rNewCell), | |||
1310 | maNewValue(sNewValue), | |||
1311 | pNextContent(nullptr), | |||
1312 | pPrevContent(nullptr), | |||
1313 | pNextInSlot(nullptr), | |||
1314 | ppPrevInSlot(nullptr) | |||
1315 | { | |||
1316 | if (!maNewCell.isEmpty()) | |||
1317 | SetCell(maNewValue, maNewCell, 0, pDoc); | |||
1318 | ||||
1319 | if (!sNewValue.isEmpty()) // #i40704# don't overwrite SetCell result with empty string | |||
1320 | maNewValue = sNewValue; // set again, because SetCell removes it | |||
1321 | } | |||
1322 | ||||
1323 | ScChangeActionContent::~ScChangeActionContent() | |||
1324 | { | |||
1325 | ClearTrack(); | |||
1326 | } | |||
1327 | ||||
1328 | void ScChangeActionContent::ClearTrack() | |||
1329 | { | |||
1330 | RemoveFromSlot(); | |||
1331 | if ( pPrevContent ) | |||
1332 | pPrevContent->pNextContent = pNextContent; | |||
1333 | if ( pNextContent ) | |||
1334 | pNextContent->pPrevContent = pPrevContent; | |||
1335 | } | |||
1336 | ||||
1337 | ScChangeActionContent* ScChangeActionContent::GetTopContent() const | |||
1338 | { | |||
1339 | if ( pNextContent ) | |||
1340 | { | |||
1341 | ScChangeActionContent* pContent = pNextContent; | |||
1342 | while ( pContent->pNextContent && pContent != pContent->pNextContent ) | |||
1343 | pContent = pContent->pNextContent; | |||
1344 | return pContent; | |||
1345 | } | |||
1346 | return const_cast<ScChangeActionContent*>(this); | |||
1347 | } | |||
1348 | ||||
1349 | ScChangeActionLinkEntry* ScChangeActionContent::GetDeletedIn() const | |||
1350 | { | |||
1351 | if ( pNextContent ) | |||
1352 | return GetTopContent()->pLinkDeletedIn; | |||
1353 | return pLinkDeletedIn; | |||
1354 | } | |||
1355 | ||||
1356 | ScChangeActionLinkEntry** ScChangeActionContent::GetDeletedInAddress() | |||
1357 | { | |||
1358 | if ( pNextContent ) | |||
1359 | return GetTopContent()->GetDeletedInAddress(); | |||
1360 | return &pLinkDeletedIn; | |||
1361 | } | |||
1362 | ||||
1363 | void ScChangeActionContent::SetOldValue( | |||
1364 | const ScCellValue& rCell, const ScDocument* pFromDoc, ScDocument* pToDoc, sal_uLong nFormat ) | |||
1365 | { | |||
1366 | SetValue(maOldValue, maOldCell, nFormat, rCell, pFromDoc, pToDoc); | |||
1367 | } | |||
1368 | ||||
1369 | void ScChangeActionContent::SetOldValue( | |||
1370 | const ScCellValue& rCell, const ScDocument* pFromDoc, ScDocument* pToDoc ) | |||
1371 | { | |||
1372 | SetValue(maOldValue, maOldCell, aBigRange.aStart.MakeAddress(), rCell, pFromDoc, pToDoc); | |||
1373 | } | |||
1374 | ||||
1375 | void ScChangeActionContent::SetNewValue( const ScCellValue& rCell, ScDocument* pDoc ) | |||
1376 | { | |||
1377 | SetValue(maNewValue, maNewCell, aBigRange.aStart.MakeAddress(), rCell, pDoc, pDoc); | |||
1378 | } | |||
1379 | ||||
1380 | void ScChangeActionContent::SetOldNewCells( | |||
1381 | const ScCellValue& rOldCell, sal_uLong nOldFormat, const ScCellValue& rNewCell, | |||
1382 | sal_uLong nNewFormat, const ScDocument* pDoc ) | |||
1383 | { | |||
1384 | maOldCell = rOldCell; | |||
1385 | maNewCell = rNewCell; | |||
1386 | SetCell(maOldValue, maOldCell, nOldFormat, pDoc); | |||
1387 | SetCell(maNewValue, maNewCell, nNewFormat, pDoc); | |||
1388 | } | |||
1389 | ||||
1390 | void ScChangeActionContent::SetNewCell( | |||
1391 | const ScCellValue& rCell, const ScDocument* pDoc, const OUString& rFormatted ) | |||
1392 | { | |||
1393 | maNewCell = rCell; | |||
1394 | SetCell(maNewValue, maNewCell, 0, pDoc); | |||
1395 | ||||
1396 | // #i40704# allow to set formatted text here - don't call SetNewValue with string from XML filter | |||
1397 | if (!rFormatted.isEmpty()) | |||
1398 | maNewValue = rFormatted; | |||
1399 | } | |||
1400 | ||||
1401 | void ScChangeActionContent::SetValueString( | |||
1402 | OUString& rValue, ScCellValue& rCell, const OUString& rStr, ScDocument* pDoc ) | |||
1403 | { | |||
1404 | rCell.clear(); | |||
1405 | if ( rStr.getLength() > 1 && rStr[0] == '=' ) | |||
1406 | { | |||
1407 | rValue = EMPTY_OUSTRINGScGlobal::GetEmptyOUString(); | |||
1408 | rCell.meType = CELLTYPE_FORMULA; | |||
1409 | rCell.mpFormula = new ScFormulaCell( | |||
1410 | *pDoc, aBigRange.aStart.MakeAddress(), rStr, | |||
1411 | pDoc->GetGrammar() ); | |||
1412 | rCell.mpFormula->SetInChangeTrack(true); | |||
1413 | } | |||
1414 | else | |||
1415 | rValue = rStr; | |||
1416 | } | |||
1417 | ||||
1418 | void ScChangeActionContent::SetOldValue( const OUString& rOld, ScDocument* pDoc ) | |||
1419 | { | |||
1420 | SetValueString(maOldValue, maOldCell, rOld, pDoc); | |||
1421 | } | |||
1422 | ||||
1423 | void ScChangeActionContent::GetOldString( OUString& rStr, const ScDocument* pDoc ) const | |||
1424 | { | |||
1425 | GetValueString(rStr, maOldValue, maOldCell, pDoc); | |||
1426 | } | |||
1427 | ||||
1428 | void ScChangeActionContent::GetNewString( OUString& rStr, const ScDocument* pDoc ) const | |||
1429 | { | |||
1430 | GetValueString(rStr, maNewValue, maNewCell, pDoc); | |||
1431 | } | |||
1432 | ||||
1433 | void ScChangeActionContent::GetDescription( | |||
1434 | OUString& rStr, ScDocument& rDoc, bool bSplitRange, bool bWarning ) const | |||
1435 | { | |||
1436 | ScChangeAction::GetDescription( rStr, rDoc, bSplitRange, bWarning ); | |||
1437 | ||||
1438 | OUString aRsc = ScResId(STR_CHANGED_CELLreinterpret_cast<char const *>("STR_CHANGED_CELL" "\004" u8"Cell #1 changed from '#2' to '#3'")); | |||
1439 | ||||
1440 | OUString aTmpStr; | |||
1441 | GetRefString(aTmpStr, rDoc); | |||
1442 | ||||
1443 | sal_Int32 nPos = aRsc.indexOf("#1", 0); | |||
1444 | if (nPos >= 0) | |||
1445 | { | |||
1446 | aRsc = aRsc.replaceAt(nPos, 2, aTmpStr); | |||
1447 | nPos += aTmpStr.getLength(); | |||
1448 | } | |||
1449 | ||||
1450 | GetOldString( aTmpStr, &rDoc ); | |||
1451 | if (aTmpStr.isEmpty()) | |||
1452 | aTmpStr = ScResId( STR_CHANGED_BLANKreinterpret_cast<char const *>("STR_CHANGED_BLANK" "\004" u8"<empty>") ); | |||
1453 | ||||
1454 | nPos = nPos >= 0 ? aRsc.indexOf("#2", nPos) : -1; | |||
1455 | if (nPos >= 0) | |||
1456 | { | |||
1457 | aRsc = aRsc.replaceAt(nPos, 2, aTmpStr); | |||
1458 | nPos += aTmpStr.getLength(); | |||
1459 | } | |||
1460 | ||||
1461 | GetNewString( aTmpStr, &rDoc ); | |||
1462 | if (aTmpStr.isEmpty()) | |||
1463 | aTmpStr = ScResId( STR_CHANGED_BLANKreinterpret_cast<char const *>("STR_CHANGED_BLANK" "\004" u8"<empty>") ); | |||
1464 | ||||
1465 | nPos = nPos >= 0 ? aRsc.indexOf("#3", nPos) : -1; | |||
1466 | if (nPos >= 0) | |||
1467 | { | |||
1468 | aRsc = aRsc.replaceAt(nPos, 2, aTmpStr); | |||
1469 | } | |||
1470 | ||||
1471 | rStr += aRsc; // append to the original string. | |||
1472 | } | |||
1473 | ||||
1474 | void ScChangeActionContent::GetRefString( | |||
1475 | OUString& rStr, ScDocument& rDoc, bool bFlag3D ) const | |||
1476 | { | |||
1477 | ScRefFlags nFlags = ( GetBigRange().IsValid( rDoc ) ? ScRefFlags::VALID : ScRefFlags::ZERO ); | |||
1478 | if ( nFlags != ScRefFlags::ZERO ) | |||
1479 | { | |||
1480 | const ScCellValue& rCell = GetNewCell(); | |||
1481 | if ( GetContentCellType(rCell) == SC_CACCT_MATORG ) | |||
1482 | { | |||
1483 | ScBigRange aLocalBigRange( GetBigRange() ); | |||
1484 | SCCOL nC; | |||
1485 | SCROW nR; | |||
1486 | rCell.mpFormula->GetMatColsRows( nC, nR ); | |||
1487 | aLocalBigRange.aEnd.IncCol( nC-1 ); | |||
1488 | aLocalBigRange.aEnd.IncRow( nR-1 ); | |||
1489 | rStr = ScChangeAction::GetRefString( aLocalBigRange, rDoc, bFlag3D ); | |||
1490 | ||||
1491 | return ; | |||
1492 | } | |||
1493 | ||||
1494 | ScAddress aTmpAddress( GetBigRange().aStart.MakeAddress() ); | |||
1495 | if ( bFlag3D ) | |||
1496 | nFlags |= ScRefFlags::TAB_3D; | |||
1497 | rStr = aTmpAddress.Format(nFlags, &rDoc, rDoc.GetAddressConvention()); | |||
1498 | if ( IsDeletedIn() ) | |||
1499 | { | |||
1500 | // Insert the parentheses. | |||
1501 | rStr = "(" + rStr + ")"; | |||
1502 | } | |||
1503 | } | |||
1504 | else | |||
1505 | rStr = ScCompiler::GetNativeSymbol(ocErrRef); | |||
1506 | } | |||
1507 | ||||
1508 | bool ScChangeActionContent::Reject( ScDocument& rDoc ) | |||
1509 | { | |||
1510 | if ( !aBigRange.IsValid( rDoc ) ) | |||
1511 | return false; | |||
1512 | ||||
1513 | PutOldValueToDoc( &rDoc, 0, 0 ); | |||
1514 | ||||
1515 | SetState( SC_CAS_REJECTED ); | |||
1516 | RemoveAllLinks(); | |||
1517 | ||||
1518 | return true; | |||
1519 | } | |||
1520 | ||||
1521 | bool ScChangeActionContent::Select( ScDocument& rDoc, ScChangeTrack* pTrack, | |||
1522 | bool bOldest, ::std::stack<ScChangeActionContent*>* pRejectActions ) | |||
1523 | { | |||
1524 | if ( !aBigRange.IsValid( rDoc ) ) | |||
1525 | return false; | |||
1526 | ||||
1527 | ScChangeActionContent* pContent = this; | |||
1528 | // accept previous contents | |||
1529 | while ( ( pContent = pContent->pPrevContent ) != nullptr ) | |||
1530 | { | |||
1531 | if ( pContent->IsVirgin() ) | |||
1532 | pContent->SetState( SC_CAS_ACCEPTED ); | |||
1533 | } | |||
1534 | ScChangeActionContent* pEnd = pContent = this; | |||
1535 | // reject subsequent contents | |||
1536 | while ( ( pContent = pContent->pNextContent ) != nullptr ) | |||
1537 | { | |||
1538 | // MatrixOrigin may have dependents, no dependency recursion needed | |||
1539 | const ScChangeActionLinkEntry* pL = pContent->GetFirstDependentEntry(); | |||
1540 | while ( pL ) | |||
1541 | { | |||
1542 | ScChangeAction* p = const_cast<ScChangeAction*>(pL->GetAction()); | |||
1543 | if ( p ) | |||
1544 | p->SetRejected(); | |||
1545 | pL = pL->GetNext(); | |||
1546 | } | |||
1547 | pContent->SetRejected(); | |||
1548 | pEnd = pContent; | |||
1549 | } | |||
1550 | ||||
1551 | // If not oldest: Is it anyone else than the last one? | |||
1552 | if ( bOldest || pEnd != this ) | |||
1553 | { ScRange aRange( aBigRange.aStart.MakeAddress() ); | |||
1554 | const ScAddress& rPos = aRange.aStart; | |||
1555 | ||||
1556 | ScChangeActionContent* pNew = new ScChangeActionContent( aRange ); | |||
1557 | ScCellValue aCell; | |||
1558 | aCell.assign(rDoc, rPos); | |||
1559 | pNew->SetOldValue(aCell, &rDoc, &rDoc); | |||
1560 | ||||
1561 | if ( bOldest ) | |||
1562 | PutOldValueToDoc( &rDoc, 0, 0 ); | |||
1563 | else | |||
1564 | PutNewValueToDoc( &rDoc, 0, 0 ); | |||
1565 | ||||
1566 | pNew->SetRejectAction( bOldest ? GetActionNumber() : pEnd->GetActionNumber() ); | |||
1567 | pNew->SetState( SC_CAS_ACCEPTED ); | |||
1568 | if ( pRejectActions ) | |||
1569 | pRejectActions->push( pNew ); | |||
1570 | else | |||
1571 | { | |||
1572 | aCell.assign(rDoc, rPos); | |||
1573 | pNew->SetNewValue(aCell, &rDoc); | |||
1574 | pTrack->Append( pNew ); | |||
1575 | } | |||
1576 | } | |||
1577 | ||||
1578 | if ( bOldest ) | |||
1579 | SetRejected(); | |||
1580 | else | |||
1581 | SetState( SC_CAS_ACCEPTED ); | |||
1582 | ||||
1583 | return true; | |||
1584 | } | |||
1585 | ||||
1586 | void ScChangeActionContent::GetStringOfCell( | |||
1587 | OUString& rStr, const ScCellValue& rCell, const ScDocument* pDoc, const ScAddress& rPos ) | |||
1588 | { | |||
1589 | if (NeedsNumberFormat(rCell)) | |||
1590 | GetStringOfCell(rStr, rCell, pDoc, pDoc->GetNumberFormat(rPos)); | |||
1591 | else | |||
1592 | GetStringOfCell(rStr, rCell, pDoc, 0); | |||
1593 | } | |||
1594 | ||||
1595 | void ScChangeActionContent::GetStringOfCell( | |||
1596 | OUString& rStr, const ScCellValue& rCell, const ScDocument* pDoc, sal_uLong nFormat ) | |||
1597 | { | |||
1598 | rStr = EMPTY_OUSTRINGScGlobal::GetEmptyOUString(); | |||
1599 | ||||
1600 | if (!GetContentCellType(rCell)) | |||
1601 | return; | |||
1602 | ||||
1603 | switch (rCell.meType) | |||
1604 | { | |||
1605 | case CELLTYPE_VALUE: | |||
1606 | pDoc->GetFormatTable()->GetInputLineString(rCell.mfValue, nFormat, rStr); | |||
1607 | break; | |||
1608 | case CELLTYPE_STRING: | |||
1609 | rStr = rCell.mpString->getString(); | |||
1610 | break; | |||
1611 | case CELLTYPE_EDIT: | |||
1612 | if (rCell.mpEditText) | |||
1613 | rStr = ScEditUtil::GetString(*rCell.mpEditText, pDoc); | |||
1614 | break; | |||
1615 | case CELLTYPE_FORMULA: | |||
1616 | rCell.mpFormula->GetFormula(rStr); | |||
1617 | break; | |||
1618 | default: | |||
1619 | ; | |||
1620 | } | |||
1621 | } | |||
1622 | ||||
1623 | ScChangeActionContentCellType ScChangeActionContent::GetContentCellType( const ScCellValue& rCell ) | |||
1624 | { | |||
1625 | switch (rCell.meType) | |||
1626 | { | |||
1627 | case CELLTYPE_VALUE : | |||
1628 | case CELLTYPE_STRING : | |||
1629 | case CELLTYPE_EDIT : | |||
1630 | return SC_CACCT_NORMAL; | |||
1631 | case CELLTYPE_FORMULA : | |||
1632 | switch (rCell.mpFormula->GetMatrixFlag()) | |||
1633 | { | |||
1634 | case ScMatrixMode::NONE : | |||
1635 | return SC_CACCT_NORMAL; | |||
1636 | case ScMatrixMode::Formula : | |||
1637 | return SC_CACCT_MATORG; | |||
1638 | case ScMatrixMode::Reference : | |||
1639 | return SC_CACCT_MATREF; | |||
1640 | } | |||
1641 | return SC_CACCT_NORMAL; | |||
1642 | default: | |||
1643 | return SC_CACCT_NONE; | |||
1644 | } | |||
1645 | } | |||
1646 | ||||
1647 | ScChangeActionContentCellType ScChangeActionContent::GetContentCellType( const ScRefCellValue& rCell ) | |||
1648 | { | |||
1649 | switch (rCell.meType) | |||
1650 | { | |||
1651 | case CELLTYPE_VALUE: | |||
1652 | case CELLTYPE_STRING: | |||
1653 | case CELLTYPE_EDIT: | |||
1654 | return SC_CACCT_NORMAL; | |||
1655 | case CELLTYPE_FORMULA: | |||
1656 | { | |||
1657 | const ScFormulaCell* pCell = rCell.mpFormula; | |||
1658 | switch (pCell->GetMatrixFlag()) | |||
1659 | { | |||
1660 | case ScMatrixMode::NONE : | |||
1661 | return SC_CACCT_NORMAL; | |||
1662 | case ScMatrixMode::Formula : | |||
1663 | return SC_CACCT_MATORG; | |||
1664 | case ScMatrixMode::Reference : | |||
1665 | return SC_CACCT_MATREF; | |||
1666 | } | |||
1667 | return SC_CACCT_NORMAL; | |||
1668 | } | |||
1669 | default: | |||
1670 | ; | |||
1671 | } | |||
1672 | ||||
1673 | return SC_CACCT_NONE; | |||
1674 | } | |||
1675 | ||||
1676 | bool ScChangeActionContent::NeedsNumberFormat( const ScCellValue& rVal ) | |||
1677 | { | |||
1678 | return rVal.meType == CELLTYPE_VALUE; | |||
1679 | } | |||
1680 | ||||
1681 | void ScChangeActionContent::SetValue( | |||
1682 | OUString& rStr, ScCellValue& rCell, const ScAddress& rPos, const ScCellValue& rOrgCell, | |||
1683 | const ScDocument* pFromDoc, ScDocument* pToDoc ) | |||
1684 | { | |||
1685 | sal_uInt32 nFormat = NeedsNumberFormat(rOrgCell) ? pFromDoc->GetNumberFormat(rPos) : 0; | |||
1686 | SetValue(rStr, rCell, nFormat, rOrgCell, pFromDoc, pToDoc); | |||
1687 | } | |||
1688 | ||||
1689 | void ScChangeActionContent::SetValue( | |||
1690 | OUString& rStr, ScCellValue& rCell, sal_uLong nFormat, const ScCellValue& rOrgCell, | |||
1691 | const ScDocument* pFromDoc, ScDocument* pToDoc ) | |||
1692 | { | |||
1693 | rStr.clear(); | |||
1694 | ||||
1695 | if (GetContentCellType(rOrgCell)) | |||
1696 | { | |||
1697 | rCell.assign(rOrgCell, *pToDoc); | |||
1698 | switch (rOrgCell.meType) | |||
1699 | { | |||
1700 | case CELLTYPE_VALUE : | |||
1701 | { // E.g.: Remember date as such | |||
1702 | pFromDoc->GetFormatTable()->GetInputLineString( | |||
1703 | rOrgCell.mfValue, nFormat, rStr); | |||
1704 | } | |||
1705 | break; | |||
1706 | case CELLTYPE_FORMULA : | |||
1707 | rCell.mpFormula->SetInChangeTrack(true); | |||
1708 | break; | |||
1709 | default: | |||
1710 | { | |||
1711 | // added to avoid warnings | |||
1712 | } | |||
1713 | } | |||
1714 | } | |||
1715 | else | |||
1716 | rCell.clear(); | |||
1717 | } | |||
1718 | ||||
1719 | void ScChangeActionContent::SetCell( OUString& rStr, ScCellValue& rCell, sal_uLong nFormat, const ScDocument* pDoc ) | |||
1720 | { | |||
1721 | rStr.clear(); | |||
1722 | if (rCell.isEmpty()) | |||
1723 | return; | |||
1724 | ||||
1725 | switch (rCell.meType) | |||
1726 | { | |||
1727 | case CELLTYPE_VALUE : | |||
1728 | // e.g. remember date as date string | |||
1729 | pDoc->GetFormatTable()->GetInputLineString(rCell.mfValue, nFormat, rStr); | |||
1730 | break; | |||
1731 | case CELLTYPE_FORMULA : | |||
1732 | rCell.mpFormula->SetInChangeTrack(true); | |||
1733 | break; | |||
1734 | default: | |||
1735 | { | |||
1736 | // added to avoid warnings | |||
1737 | } | |||
1738 | } | |||
1739 | } | |||
1740 | ||||
1741 | void ScChangeActionContent::GetValueString( | |||
1742 | OUString& rStr, const OUString& rValue, const ScCellValue& rCell, const ScDocument* pDoc ) const | |||
1743 | { | |||
1744 | if (!rValue.isEmpty()) | |||
1745 | { | |||
1746 | rStr = rValue; | |||
1747 | return; | |||
1748 | } | |||
1749 | ||||
1750 | switch (rCell.meType) | |||
1751 | { | |||
1752 | case CELLTYPE_STRING : | |||
1753 | rStr = rCell.mpString->getString(); | |||
1754 | break; | |||
1755 | case CELLTYPE_EDIT : | |||
1756 | if (rCell.mpEditText) | |||
1757 | rStr = ScEditUtil::GetString(*rCell.mpEditText, pDoc); | |||
1758 | break; | |||
1759 | case CELLTYPE_VALUE : // Is always in rValue | |||
1760 | rStr = rValue; | |||
1761 | break; | |||
1762 | case CELLTYPE_FORMULA : | |||
1763 | GetFormulaString(rStr, rCell.mpFormula); | |||
1764 | break; | |||
1765 | case CELLTYPE_NONE: | |||
1766 | default: | |||
1767 | rStr.clear(); | |||
1768 | } | |||
1769 | } | |||
1770 | ||||
1771 | void ScChangeActionContent::GetFormulaString( | |||
1772 | OUString& rStr, const ScFormulaCell* pCell ) const | |||
1773 | { | |||
1774 | ScAddress aPos( aBigRange.aStart.MakeAddress() ); | |||
1775 | if ( aPos == pCell->aPos || IsDeletedIn() ) | |||
1776 | pCell->GetFormula( rStr ); | |||
1777 | else | |||
1778 | { | |||
1779 | OSL_FAIL( "ScChangeActionContent::GetFormulaString: aPos != pCell->aPos" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/chgtrack.cxx" ":" "1779" ": "), "%s", "ScChangeActionContent::GetFormulaString: aPos != pCell->aPos" ); } } while (false); | |||
1780 | std::unique_ptr<ScFormulaCell> pNew(new ScFormulaCell( *pCell, pCell->GetDocument(), aPos )); | |||
1781 | pNew->GetFormula( rStr ); | |||
1782 | } | |||
1783 | } | |||
1784 | ||||
1785 | void ScChangeActionContent::PutOldValueToDoc( ScDocument* pDoc, | |||
1786 | SCCOL nDx, SCROW nDy ) const | |||
1787 | { | |||
1788 | PutValueToDoc(maOldCell, maOldValue, pDoc, nDx, nDy); | |||
1789 | } | |||
1790 | ||||
1791 | void ScChangeActionContent::PutNewValueToDoc( ScDocument* pDoc, | |||
1792 | SCCOL nDx, SCROW nDy ) const | |||
1793 | { | |||
1794 | PutValueToDoc(maNewCell, maNewValue, pDoc, nDx, nDy); | |||
1795 | } | |||
1796 | ||||
1797 | void ScChangeActionContent::PutValueToDoc( | |||
1798 | const ScCellValue& rCell, const OUString& rValue, ScDocument* pDoc, | |||
1799 | SCCOL nDx, SCROW nDy ) const | |||
1800 | { | |||
1801 | ScAddress aPos( aBigRange.aStart.MakeAddress() ); | |||
1802 | if ( nDx ) | |||
1803 | aPos.IncCol( nDx ); | |||
1804 | if ( nDy ) | |||
1805 | aPos.IncRow( nDy ); | |||
1806 | ||||
1807 | if (!rValue.isEmpty()) | |||
1808 | { | |||
1809 | pDoc->SetString(aPos, rValue); | |||
1810 | return; | |||
1811 | } | |||
1812 | ||||
1813 | if (rCell.isEmpty()) | |||
1814 | { | |||
1815 | pDoc->SetEmptyCell(aPos); | |||
1816 | return; | |||
1817 | } | |||
1818 | ||||
1819 | if (rCell.meType == CELLTYPE_VALUE) | |||
1820 | { | |||
1821 | pDoc->SetString( aPos.Col(), aPos.Row(), aPos.Tab(), rValue ); | |||
1822 | return; | |||
1823 | } | |||
1824 | ||||
1825 | switch (GetContentCellType(rCell)) | |||
1826 | { | |||
1827 | case SC_CACCT_MATORG : | |||
1828 | { | |||
1829 | SCCOL nC; | |||
1830 | SCROW nR; | |||
1831 | rCell.mpFormula->GetMatColsRows(nC, nR); | |||
1832 | OSL_ENSURE( nC>0 && nR>0, "ScChangeActionContent::PutValueToDoc: MatColsRows?" )do { if (true && (!(nC>0 && nR>0))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/chgtrack.cxx" ":" "1832" ": "), "%s", "ScChangeActionContent::PutValueToDoc: MatColsRows?" ); } } while (false); | |||
1833 | ScRange aRange( aPos ); | |||
1834 | if ( nC > 1 ) | |||
1835 | aRange.aEnd.IncCol( nC-1 ); | |||
1836 | if ( nR > 1 ) | |||
1837 | aRange.aEnd.IncRow( nR-1 ); | |||
1838 | ScMarkData aDestMark(pDoc->GetSheetLimits()); | |||
1839 | aDestMark.SelectOneTable( aPos.Tab() ); | |||
1840 | aDestMark.SetMarkArea( aRange ); | |||
1841 | pDoc->InsertMatrixFormula( aPos.Col(), aPos.Row(), | |||
1842 | aRange.aEnd.Col(), aRange.aEnd.Row(), | |||
1843 | aDestMark, EMPTY_OUSTRINGScGlobal::GetEmptyOUString(), rCell.mpFormula->GetCode()); | |||
1844 | } | |||
1845 | break; | |||
1846 | case SC_CACCT_MATREF : | |||
1847 | // nothing | |||
1848 | break; | |||
1849 | default: | |||
1850 | rCell.commit(*pDoc, aPos); | |||
1851 | } | |||
1852 | } | |||
1853 | ||||
1854 | static void lcl_InvalidateReference( const ScDocument& rDoc, formula::FormulaToken& rTok, const ScBigAddress& rPos ) | |||
1855 | { | |||
1856 | ScSingleRefData& rRef1 = *rTok.GetSingleRef(); | |||
1857 | if ( rPos.Col() < 0 || rDoc.MaxCol() < rPos.Col() ) | |||
1858 | { | |||
1859 | rRef1.SetColDeleted( true ); | |||
1860 | } | |||
1861 | if ( rPos.Row() < 0 || rDoc.MaxRow() < rPos.Row() ) | |||
1862 | { | |||
1863 | rRef1.SetRowDeleted( true ); | |||
1864 | } | |||
1865 | if ( rPos.Tab() < 0 || MAXTAB < rPos.Tab() ) | |||
1866 | { | |||
1867 | rRef1.SetTabDeleted( true ); | |||
1868 | } | |||
1869 | if ( rTok.GetType() != formula::svDoubleRef ) | |||
1870 | return; | |||
1871 | ||||
1872 | ScSingleRefData& rRef2 = rTok.GetDoubleRef()->Ref2; | |||
1873 | if ( rPos.Col() < 0 || rDoc.MaxCol() < rPos.Col() ) | |||
1874 | { | |||
1875 | rRef2.SetColDeleted( true ); | |||
1876 | } | |||
1877 | if ( rPos.Row() < 0 || rDoc.MaxRow() < rPos.Row() ) | |||
1878 | { | |||
1879 | rRef2.SetRowDeleted( true ); | |||
1880 | } | |||
1881 | if ( rPos.Tab() < 0 || MAXTAB < rPos.Tab() ) | |||
1882 | { | |||
1883 | rRef2.SetTabDeleted( true ); | |||
1884 | } | |||
1885 | } | |||
1886 | ||||
1887 | void ScChangeActionContent::UpdateReference( const ScChangeTrack* pTrack, | |||
1888 | UpdateRefMode eMode, const ScBigRange& rRange, | |||
1889 | sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz ) | |||
1890 | { | |||
1891 | SCSIZE nOldSlot = pTrack->ComputeContentSlot( aBigRange.aStart.Row() ); | |||
1892 | ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, aBigRange ); | |||
1893 | SCSIZE nNewSlot = pTrack->ComputeContentSlot( aBigRange.aStart.Row() ); | |||
1894 | if ( nNewSlot != nOldSlot ) | |||
1895 | { | |||
1896 | RemoveFromSlot(); | |||
1897 | InsertInSlot( &(pTrack->GetContentSlots()[nNewSlot]) ); | |||
1898 | } | |||
1899 | ||||
1900 | if ( pTrack->IsInDelete() && !pTrack->IsInDeleteTop() ) | |||
1901 | return ; // Formula only update whole range | |||
1902 | ||||
1903 | bool bOldFormula = maOldCell.meType == CELLTYPE_FORMULA; | |||
1904 | bool bNewFormula = maNewCell.meType == CELLTYPE_FORMULA; | |||
1905 | if ( !(bOldFormula || bNewFormula) ) | |||
1906 | return; | |||
1907 | ||||
1908 | // Adjust UpdateReference via ScFormulaCell (there) | |||
1909 | if ( pTrack->IsInDelete() ) | |||
1910 | { | |||
1911 | const ScRange& rDelRange = pTrack->GetInDeleteRange(); | |||
1912 | if ( nDx > 0 ) | |||
1913 | nDx = rDelRange.aEnd.Col() - rDelRange.aStart.Col() + 1; | |||
1914 | else if ( nDx < 0 ) | |||
1915 | nDx = -(rDelRange.aEnd.Col() - rDelRange.aStart.Col() + 1); | |||
1916 | if ( nDy > 0 ) | |||
1917 | nDy = rDelRange.aEnd.Row() - rDelRange.aStart.Row() + 1; | |||
1918 | else if ( nDy < 0 ) | |||
1919 | nDy = -(rDelRange.aEnd.Row() - rDelRange.aStart.Row() + 1); | |||
1920 | if ( nDz > 0 ) | |||
1921 | nDz = rDelRange.aEnd.Tab() - rDelRange.aStart.Tab() + 1; | |||
1922 | else if ( nDz < 0 ) | |||
1923 | nDz = -(rDelRange.aEnd.Tab() - rDelRange.aStart.Tab() + 1); | |||
1924 | } | |||
1925 | ScBigRange aTmpRange( rRange ); | |||
1926 | switch ( eMode ) | |||
1927 | { | |||
1928 | case URM_INSDEL : | |||
1929 | if ( nDx < 0 || nDy < 0 || nDz < 0 ) | |||
1930 | { // Delete starts there after removed range | |||
1931 | // Position is changed there | |||
1932 | if ( nDx ) | |||
1933 | aTmpRange.aStart.IncCol( -nDx ); | |||
1934 | if ( nDy ) | |||
1935 | aTmpRange.aStart.IncRow( -nDy ); | |||
1936 | if ( nDz ) | |||
1937 | aTmpRange.aStart.IncTab( -nDz ); | |||
1938 | } | |||
1939 | break; | |||
1940 | case URM_MOVE : | |||
1941 | // Move is Source here and Target there | |||
1942 | // Position needs to be adjusted before that | |||
1943 | if ( bOldFormula ) | |||
1944 | maOldCell.mpFormula->aPos = aBigRange.aStart.MakeAddress(); | |||
1945 | if ( bNewFormula ) | |||
1946 | maNewCell.mpFormula->aPos = aBigRange.aStart.MakeAddress(); | |||
1947 | if ( nDx ) | |||
1948 | { | |||
1949 | aTmpRange.aStart.IncCol( nDx ); | |||
1950 | aTmpRange.aEnd.IncCol( nDx ); | |||
1951 | } | |||
1952 | if ( nDy ) | |||
1953 | { | |||
1954 | aTmpRange.aStart.IncRow( nDy ); | |||
1955 | aTmpRange.aEnd.IncRow( nDy ); | |||
1956 | } | |||
1957 | if ( nDz ) | |||
1958 | { | |||
1959 | aTmpRange.aStart.IncTab( nDz ); | |||
1960 | aTmpRange.aEnd.IncTab( nDz ); | |||
1961 | } | |||
1962 | break; | |||
1963 | default: | |||
1964 | { | |||
1965 | // added to avoid warnings | |||
1966 | } | |||
1967 | } | |||
1968 | ScRange aRange( aTmpRange.MakeRange() ); | |||
1969 | ||||
1970 | sc::RefUpdateContext aRefCxt(pTrack->GetDocument()); | |||
1971 | aRefCxt.meMode = eMode; | |||
1972 | aRefCxt.maRange = aRange; | |||
1973 | aRefCxt.mnColDelta = nDx; | |||
1974 | aRefCxt.mnRowDelta = nDy; | |||
1975 | aRefCxt.mnTabDelta = nDz; | |||
1976 | ||||
1977 | if ( bOldFormula ) | |||
1978 | maOldCell.mpFormula->UpdateReference(aRefCxt); | |||
1979 | if ( bNewFormula ) | |||
1980 | maNewCell.mpFormula->UpdateReference(aRefCxt); | |||
1981 | ||||
1982 | if ( aBigRange.aStart.IsValid( pTrack->GetDocument() ) ) | |||
1983 | return; | |||
1984 | ||||
1985 | //FIXME: | |||
1986 | // UpdateReference cannot handle positions outside of the Document. | |||
1987 | // Therefore set everything to #REF! | |||
1988 | //TODO: Remove the need for this hack! This means big changes to ScAddress etc.! | |||
1989 | const ScBigAddress& rPos = aBigRange.aStart; | |||
1990 | if ( bOldFormula ) | |||
1991 | { | |||
1992 | formula::FormulaToken* t; | |||
1993 | ScTokenArray* pArr = maOldCell.mpFormula->GetCode(); | |||
1994 | formula::FormulaTokenArrayPlainIterator aIter(*pArr); | |||
1995 | while ( ( t = aIter.GetNextReference() ) != nullptr ) | |||
1996 | lcl_InvalidateReference( pTrack->GetDocument(), *t, rPos ); | |||
1997 | aIter.Reset(); | |||
1998 | while ( ( t = aIter.GetNextReferenceRPN() ) != nullptr ) | |||
1999 | lcl_InvalidateReference( pTrack->GetDocument(), *t, rPos ); | |||
2000 | } | |||
2001 | if ( bNewFormula ) | |||
2002 | { | |||
2003 | formula::FormulaToken* t; | |||
2004 | ScTokenArray* pArr = maNewCell.mpFormula->GetCode(); | |||
2005 | formula::FormulaTokenArrayPlainIterator aIter(*pArr); | |||
2006 | while ( ( t = aIter.GetNextReference() ) != nullptr ) | |||
2007 | lcl_InvalidateReference( pTrack->GetDocument(), *t, rPos ); | |||
2008 | aIter.Reset(); | |||
2009 | while ( ( t = aIter.GetNextReferenceRPN() ) != nullptr ) | |||
2010 | lcl_InvalidateReference( pTrack->GetDocument(), *t, rPos ); | |||
2011 | } | |||
2012 | } | |||
2013 | ||||
2014 | bool ScChangeActionContent::IsMatrixOrigin() const | |||
2015 | { | |||
2016 | return GetContentCellType(GetNewCell()) == SC_CACCT_MATORG; | |||
2017 | } | |||
2018 | ||||
2019 | bool ScChangeActionContent::IsOldMatrixReference() const | |||
2020 | { | |||
2021 | return GetContentCellType(GetOldCell()) == SC_CACCT_MATREF; | |||
2022 | } | |||
2023 | ||||
2024 | // ScChangeActionReject | |||
2025 | ScChangeActionReject::ScChangeActionReject( | |||
2026 | const sal_uLong nActionNumber, const ScChangeActionState eStateP, | |||
2027 | const sal_uLong nRejectingNumber, | |||
2028 | const ScBigRange& aBigRangeP, const OUString& aUserP, | |||
2029 | const DateTime& aDateTimeP, const OUString& sComment) : | |||
2030 | ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment) | |||
2031 | { | |||
2032 | } | |||
2033 | ||||
2034 | bool ScChangeActionReject::Reject(ScDocument& /*rDoc*/) | |||
2035 | { | |||
2036 | return false; | |||
2037 | } | |||
2038 | ||||
2039 | SCSIZE ScChangeTrack::ComputeContentSlot( sal_Int32 nRow ) const | |||
2040 | { | |||
2041 | if ( nRow < 0 || nRow > rDoc.GetSheetLimits().mnMaxRow ) | |||
2042 | return mnContentSlots - 1; | |||
2043 | return static_cast< SCSIZE >( nRow / mnContentRowsPerSlot ); | |||
2044 | } | |||
2045 | ||||
2046 | SCROW ScChangeTrack::InitContentRowsPerSlot() | |||
2047 | { | |||
2048 | const SCSIZE nMaxSlots = 0xffe0 / sizeof( ScChangeActionContent* ) - 2; | |||
2049 | SCROW nRowsPerSlot = rDoc.GetSheetLimits().GetMaxRowCount() / nMaxSlots; | |||
2050 | if ( nRowsPerSlot * nMaxSlots < sal::static_int_cast<SCSIZE>(rDoc.GetSheetLimits().GetMaxRowCount()) ) | |||
2051 | ++nRowsPerSlot; | |||
2052 | return nRowsPerSlot; | |||
2053 | } | |||
2054 | ||||
2055 | ScChangeTrack::ScChangeTrack( ScDocument& rDocP ) : | |||
2056 | aFixDateTime( DateTime::SYSTEM ), | |||
2057 | rDoc( rDocP ) | |||
2058 | { | |||
2059 | Init(); | |||
2060 | SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule ::Calc)) )->GetUserOptions().AddListener(this); | |||
2061 | ||||
2062 | ppContentSlots.reset( new ScChangeActionContent* [ mnContentSlots ] ); | |||
2063 | memset( ppContentSlots.get(), 0, mnContentSlots * sizeof( ScChangeActionContent* ) ); | |||
2064 | } | |||
2065 | ||||
2066 | ScChangeTrack::ScChangeTrack( ScDocument& rDocP, const std::set<OUString>& aTempUserCollection) : | |||
2067 | maUserCollection(aTempUserCollection), | |||
2068 | aFixDateTime( DateTime::SYSTEM ), | |||
2069 | rDoc( rDocP ) | |||
2070 | { | |||
2071 | Init(); | |||
2072 | SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule ::Calc)) )->GetUserOptions().AddListener(this); | |||
2073 | ppContentSlots.reset( new ScChangeActionContent* [ mnContentSlots ] ); | |||
2074 | memset( ppContentSlots.get(), 0, mnContentSlots * sizeof( ScChangeActionContent* ) ); | |||
2075 | } | |||
2076 | ||||
2077 | ScChangeTrack::~ScChangeTrack() | |||
2078 | { | |||
2079 | SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule ::Calc)) )->GetUserOptions().RemoveListener(this); | |||
2080 | DtorClear(); | |||
2081 | } | |||
2082 | ||||
2083 | void ScChangeTrack::Init() | |||
2084 | { | |||
2085 | mnContentRowsPerSlot = InitContentRowsPerSlot(); | |||
2086 | mnContentSlots = rDoc.GetSheetLimits().GetMaxRowCount() / InitContentRowsPerSlot() + 2; | |||
2087 | ||||
2088 | pFirst = nullptr; | |||
2089 | pLast = nullptr; | |||
2090 | pFirstGeneratedDelContent = nullptr; | |||
2091 | pLastCutMove = nullptr; | |||
2092 | pLinkInsertCol = nullptr; | |||
2093 | pLinkInsertRow = nullptr; | |||
2094 | pLinkInsertTab = nullptr; | |||
2095 | pLinkMove = nullptr; | |||
2096 | xBlockModifyMsg.reset(); | |||
2097 | nActionMax = 0; | |||
2098 | nGeneratedMin = SC_CHGTRACK_GENERATED_START(sal_uInt32(0xfffffff0)); | |||
2099 | nMarkLastSaved = 0; | |||
2100 | nStartLastCut = 0; | |||
2101 | nEndLastCut = 0; | |||
2102 | nLastMerge = 0; | |||
2103 | eMergeState = SC_CTMS_NONE; | |||
2104 | bInDelete = false; | |||
2105 | bInDeleteTop = false; | |||
2106 | bInDeleteUndo = false; | |||
2107 | bInPasteCut = false; | |||
2108 | bUseFixDateTime = false; | |||
2109 | bTimeNanoSeconds = true; | |||
2110 | ||||
2111 | const SvtUserOptions& rUserOpt = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule ::Calc)) )->GetUserOptions(); | |||
2112 | OUStringBuffer aBuf; | |||
2113 | aBuf.append(rUserOpt.GetFirstName()); | |||
2114 | aBuf.append(' '); | |||
2115 | aBuf.append(rUserOpt.GetLastName()); | |||
2116 | maUser = aBuf.makeStringAndClear(); | |||
2117 | maUserCollection.insert(maUser); | |||
2118 | } | |||
2119 | ||||
2120 | void ScChangeTrack::DtorClear() | |||
2121 | { | |||
2122 | ScChangeAction* p; | |||
2123 | ScChangeAction* pNext; | |||
2124 | for ( p = GetFirst(); p; p = pNext ) | |||
2125 | { | |||
2126 | pNext = p->GetNext(); | |||
2127 | delete p; | |||
2128 | } | |||
2129 | for ( p = pFirstGeneratedDelContent; p; p = pNext ) | |||
2130 | { | |||
2131 | pNext = p->GetNext(); | |||
2132 | delete p; | |||
2133 | } | |||
2134 | for( const auto& rEntry : aPasteCutMap ) | |||
2135 | { | |||
2136 | delete rEntry.second; | |||
2137 | } | |||
2138 | pLastCutMove.reset(); | |||
2139 | ClearMsgQueue(); | |||
2140 | } | |||
2141 | ||||
2142 | void ScChangeTrack::ClearMsgQueue() | |||
2143 | { | |||
2144 | xBlockModifyMsg.reset(); | |||
2145 | aMsgStackTmp.clear(); | |||
2146 | aMsgStackFinal.clear(); | |||
2147 | aMsgQueue.clear(); | |||
2148 | } | |||
2149 | ||||
2150 | void ScChangeTrack::Clear() | |||
2151 | { | |||
2152 | DtorClear(); | |||
2153 | aMap.clear(); | |||
2154 | aGeneratedMap.clear(); | |||
2155 | aPasteCutMap.clear(); | |||
2156 | maUserCollection.clear(); | |||
2157 | maUser.clear(); | |||
2158 | Init(); | |||
2159 | } | |||
2160 | ||||
2161 | bool ScChangeTrack::IsGenerated( sal_uLong nAction ) const | |||
2162 | { | |||
2163 | return nAction >= nGeneratedMin; | |||
2164 | } | |||
2165 | ||||
2166 | ScChangeAction* ScChangeTrack::GetAction( sal_uLong nAction ) const | |||
2167 | { | |||
2168 | ScChangeActionMap::const_iterator it = aMap.find( nAction ); | |||
2169 | if( it != aMap.end() ) | |||
2170 | return it->second; | |||
2171 | else | |||
2172 | return nullptr; | |||
2173 | } | |||
2174 | ||||
2175 | ScChangeAction* ScChangeTrack::GetGenerated( sal_uLong nGenerated ) const | |||
2176 | { | |||
2177 | ScChangeActionMap::const_iterator it = aGeneratedMap.find( nGenerated ); | |||
2178 | if( it != aGeneratedMap.end() ) | |||
2179 | return it->second; | |||
2180 | else | |||
2181 | return nullptr; | |||
2182 | } | |||
2183 | ||||
2184 | ScChangeAction* ScChangeTrack::GetActionOrGenerated( sal_uLong nAction ) const | |||
2185 | { | |||
2186 | return IsGenerated( nAction ) ? | |||
2187 | GetGenerated( nAction ) : | |||
2188 | GetAction( nAction ); | |||
2189 | } | |||
2190 | sal_uLong ScChangeTrack::GetLastSavedActionNumber() const | |||
2191 | { | |||
2192 | return nMarkLastSaved; | |||
2193 | } | |||
2194 | ||||
2195 | void ScChangeTrack::SetLastSavedActionNumber(sal_uLong nNew) | |||
2196 | { | |||
2197 | nMarkLastSaved = nNew; | |||
2198 | } | |||
2199 | ||||
2200 | ScChangeAction* ScChangeTrack::GetLastSaved() const | |||
2201 | { | |||
2202 | ScChangeActionMap::const_iterator it = aMap.find( nMarkLastSaved ); | |||
2203 | if( it != aMap.end() ) | |||
2204 | return it->second; | |||
2205 | else | |||
2206 | return nullptr; | |||
2207 | } | |||
2208 | ||||
2209 | void ScChangeTrack::ConfigurationChanged( utl::ConfigurationBroadcaster*, ConfigurationHints ) | |||
2210 | { | |||
2211 | if ( rDoc.IsInDtorClear() ) | |||
2212 | return; | |||
2213 | ||||
2214 | const SvtUserOptions& rUserOptions = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule ::Calc)) )->GetUserOptions(); | |||
2215 | size_t nOldCount = maUserCollection.size(); | |||
2216 | ||||
2217 | OUStringBuffer aBuf; | |||
2218 | aBuf.append(rUserOptions.GetFirstName()); | |||
2219 | aBuf.append(' '); | |||
2220 | aBuf.append(rUserOptions.GetLastName()); | |||
2221 | SetUser(aBuf.makeStringAndClear()); | |||
2222 | ||||
2223 | if ( maUserCollection.size() != nOldCount ) | |||
2224 | { | |||
2225 | // New user in collection -> have to repaint because | |||
2226 | // colors may be different now (#106697#). | |||
2227 | // (Has to be done in the Notify handler, to be sure | |||
2228 | // the user collection has already been updated) | |||
2229 | ||||
2230 | SfxObjectShell* pDocSh = rDoc.GetDocumentShell(); | |||
2231 | if (pDocSh) | |||
2232 | pDocSh->Broadcast( ScPaintHint( ScRange(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB), PaintPartFlags::Grid ) ); | |||
2233 | } | |||
2234 | } | |||
2235 | ||||
2236 | void ScChangeTrack::SetUser( const OUString& rUser ) | |||
2237 | { | |||
2238 | maUser = rUser; | |||
2239 | maUserCollection.insert(maUser); | |||
2240 | } | |||
2241 | ||||
2242 | void ScChangeTrack::StartBlockModify( ScChangeTrackMsgType eMsgType, | |||
2243 | sal_uLong nStartAction ) | |||
2244 | { | |||
2245 | if ( aModifiedLink.IsSet() ) | |||
2246 | { | |||
2247 | if ( xBlockModifyMsg ) | |||
2248 | aMsgStackTmp.push_back( *xBlockModifyMsg ); // Block in Block | |||
2249 | xBlockModifyMsg = ScChangeTrackMsgInfo(); | |||
2250 | xBlockModifyMsg->eMsgType = eMsgType; | |||
2251 | xBlockModifyMsg->nStartAction = nStartAction; | |||
2252 | xBlockModifyMsg->nEndAction = 0; | |||
2253 | } | |||
2254 | } | |||
2255 | ||||
2256 | void ScChangeTrack::EndBlockModify( sal_uLong nEndAction ) | |||
2257 | { | |||
2258 | if ( !aModifiedLink.IsSet() ) | |||
2259 | return; | |||
2260 | ||||
2261 | if ( xBlockModifyMsg ) | |||
2262 | { | |||
2263 | if ( xBlockModifyMsg->nStartAction <= nEndAction ) | |||
2264 | { | |||
2265 | xBlockModifyMsg->nEndAction = nEndAction; | |||
2266 | // Blocks dissolved in Blocks | |||
2267 | aMsgStackFinal.push_back( *xBlockModifyMsg ); | |||
2268 | } | |||
2269 | else | |||
2270 | xBlockModifyMsg.reset(); | |||
2271 | if (aMsgStackTmp.empty()) | |||
2272 | xBlockModifyMsg.reset(); | |||
2273 | else | |||
2274 | { | |||
2275 | xBlockModifyMsg = aMsgStackTmp.back(); // Maybe Block in Block | |||
2276 | aMsgStackTmp.pop_back(); | |||
2277 | } | |||
2278 | } | |||
2279 | if ( !xBlockModifyMsg ) | |||
2280 | { | |||
2281 | bool bNew = !aMsgStackFinal.empty(); | |||
2282 | aMsgQueue.reserve(aMsgQueue.size() + aMsgStackFinal.size()); | |||
2283 | aMsgQueue.insert(aMsgQueue.end(), aMsgStackFinal.rbegin(), aMsgStackFinal.rend()); | |||
2284 | aMsgStackFinal.clear(); | |||
2285 | if ( bNew ) | |||
2286 | aModifiedLink.Call( *this ); | |||
2287 | } | |||
2288 | } | |||
2289 | ||||
2290 | ScChangeTrackMsgQueue& ScChangeTrack::GetMsgQueue() | |||
2291 | { | |||
2292 | return aMsgQueue; | |||
2293 | } | |||
2294 | ||||
2295 | void ScChangeTrack::NotifyModified( ScChangeTrackMsgType eMsgType, | |||
2296 | sal_uLong nStartAction, sal_uLong nEndAction ) | |||
2297 | { | |||
2298 | if ( aModifiedLink.IsSet() ) | |||
2299 | { | |||
2300 | if ( !xBlockModifyMsg || xBlockModifyMsg->eMsgType != eMsgType || | |||
2301 | (IsGenerated( nStartAction ) && | |||
2302 | (eMsgType == ScChangeTrackMsgType::Append || eMsgType == ScChangeTrackMsgType::Remove)) ) | |||
2303 | { // Append within Append e.g. not | |||
2304 | StartBlockModify( eMsgType, nStartAction ); | |||
2305 | EndBlockModify( nEndAction ); | |||
2306 | } | |||
2307 | } | |||
2308 | } | |||
2309 | ||||
2310 | void ScChangeTrack::MasterLinks( ScChangeAction* pAppend ) | |||
2311 | { | |||
2312 | ScChangeActionType eType = pAppend->GetType(); | |||
2313 | ||||
2314 | if ( eType == SC_CAT_CONTENT ) | |||
2315 | { | |||
2316 | if ( !IsGenerated( pAppend->GetActionNumber() ) ) | |||
2317 | { | |||
2318 | SCSIZE nSlot = ComputeContentSlot( | |||
2319 | pAppend->GetBigRange().aStart.Row() ); | |||
2320 | static_cast<ScChangeActionContent*>(pAppend)->InsertInSlot( | |||
2321 | &ppContentSlots[nSlot] ); | |||
2322 | } | |||
2323 | return ; | |||
2324 | } | |||
2325 | ||||
2326 | if ( pAppend->IsRejecting() ) | |||
2327 | return ; // Rejects do not have dependencies | |||
2328 | ||||
2329 | switch ( eType ) | |||
2330 | { | |||
2331 | case SC_CAT_INSERT_COLS : | |||
2332 | { | |||
2333 | ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry( | |||
2334 | &pLinkInsertCol, pAppend ); | |||
2335 | pAppend->AddLink( nullptr, pLink ); | |||
2336 | } | |||
2337 | break; | |||
2338 | case SC_CAT_INSERT_ROWS : | |||
2339 | { | |||
2340 | ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry( | |||
2341 | &pLinkInsertRow, pAppend ); | |||
2342 | pAppend->AddLink( nullptr, pLink ); | |||
2343 | } | |||
2344 | break; | |||
2345 | case SC_CAT_INSERT_TABS : | |||
2346 | { | |||
2347 | ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry( | |||
2348 | &pLinkInsertTab, pAppend ); | |||
2349 | pAppend->AddLink( nullptr, pLink ); | |||
2350 | } | |||
2351 | break; | |||
2352 | case SC_CAT_MOVE : | |||
2353 | { | |||
2354 | ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry( | |||
2355 | &pLinkMove, pAppend ); | |||
2356 | pAppend->AddLink( nullptr, pLink ); | |||
2357 | } | |||
2358 | break; | |||
2359 | default: | |||
2360 | { | |||
2361 | // added to avoid warnings | |||
2362 | } | |||
2363 | } | |||
2364 | } | |||
2365 | ||||
2366 | void ScChangeTrack::AppendLoaded( std::unique_ptr<ScChangeAction> pActionParam ) | |||
2367 | { | |||
2368 | ScChangeAction* pAppend = pActionParam.release(); | |||
2369 | aMap.insert( ::std::make_pair( pAppend->GetActionNumber(), pAppend ) ); | |||
2370 | if ( !pLast ) | |||
2371 | pFirst = pLast = pAppend; | |||
2372 | else | |||
2373 | { | |||
2374 | pLast->pNext = pAppend; | |||
2375 | pAppend->pPrev = pLast; | |||
2376 | pLast = pAppend; | |||
2377 | } | |||
2378 | MasterLinks( pAppend ); | |||
2379 | } | |||
2380 | ||||
2381 | void ScChangeTrack::Append( ScChangeAction* pAppend, sal_uLong nAction ) | |||
2382 | { | |||
2383 | if ( nActionMax < nAction ) | |||
2384 | nActionMax = nAction; | |||
2385 | pAppend->SetUser( maUser ); | |||
2386 | if ( bUseFixDateTime ) | |||
2387 | pAppend->SetDateTimeUTC( aFixDateTime ); | |||
2388 | pAppend->SetActionNumber( nAction ); | |||
2389 | aMap.insert( ::std::make_pair( nAction, pAppend ) ); | |||
2390 | // UpdateReference Inserts before Dependencies. | |||
2391 | // Delete rejecting Insert which had UpdateReference with Delete Undo. | |||
2392 | // UpdateReference also with pLast==NULL, as pAppend can be a Delete, | |||
2393 | // which could have generated DelContents. | |||
2394 | if ( pAppend->IsInsertType() && !pAppend->IsRejecting() ) | |||
2395 | UpdateReference( pAppend, false ); | |||
2396 | if ( !pLast ) | |||
2397 | pFirst = pLast = pAppend; | |||
2398 | else | |||
2399 | { | |||
2400 | pLast->pNext = pAppend; | |||
2401 | pAppend->pPrev = pLast; | |||
2402 | pLast = pAppend; | |||
2403 | Dependencies( pAppend ); | |||
2404 | } | |||
2405 | // UpdateReference does not Insert() after Dependencies. | |||
2406 | // Move rejecting Move, which had UpdateReference with Move Undo. | |||
2407 | // Do not delete content in ToRange. | |||
2408 | if ( !pAppend->IsInsertType() && | |||
2409 | !(pAppend->GetType() == SC_CAT_MOVE && pAppend->IsRejecting()) ) | |||
2410 | UpdateReference( pAppend, false ); | |||
2411 | MasterLinks( pAppend ); | |||
2412 | ||||
2413 | if ( !aModifiedLink.IsSet() ) | |||
2414 | return; | |||
2415 | ||||
2416 | NotifyModified( ScChangeTrackMsgType::Append, nAction, nAction ); | |||
2417 | if ( pAppend->GetType() == SC_CAT_CONTENT ) | |||
2418 | { | |||
2419 | ScChangeActionContent* pContent = static_cast<ScChangeActionContent*>(pAppend); | |||
2420 | if ( ( pContent = pContent->GetPrevContent() ) != nullptr ) | |||
2421 | { | |||
2422 | sal_uLong nMod = pContent->GetActionNumber(); | |||
2423 | NotifyModified( ScChangeTrackMsgType::Change, nMod, nMod ); | |||
2424 | } | |||
2425 | } | |||
2426 | else | |||
2427 | NotifyModified( ScChangeTrackMsgType::Change, pFirst->GetActionNumber(), | |||
2428 | pLast->GetActionNumber() ); | |||
2429 | } | |||
2430 | ||||
2431 | void ScChangeTrack::Append( ScChangeAction* pAppend ) | |||
2432 | { | |||
2433 | Append( pAppend, ++nActionMax ); | |||
2434 | } | |||
2435 | ||||
2436 | void ScChangeTrack::AppendDeleteRange( const ScRange& rRange, | |||
2437 | ScDocument* pRefDoc, sal_uLong& nStartAction, sal_uLong& nEndAction, SCTAB nDz ) | |||
2438 | { | |||
2439 | nStartAction = GetActionMax() + 1; | |||
2440 | AppendDeleteRange( rRange, pRefDoc, nDz, 0 ); | |||
2441 | nEndAction = GetActionMax(); | |||
2442 | } | |||
2443 | ||||
2444 | void ScChangeTrack::AppendDeleteRange( const ScRange& rRange, | |||
2445 | ScDocument* pRefDoc, SCTAB nDz, sal_uLong nRejectingInsert ) | |||
2446 | { | |||
2447 | SetInDeleteRange( rRange ); | |||
2448 | StartBlockModify( ScChangeTrackMsgType::Append, GetActionMax() + 1 ); | |||
2449 | SCCOL nCol1; | |||
2450 | SCROW nRow1; | |||
2451 | SCTAB nTab1; | |||
2452 | SCCOL nCol2; | |||
2453 | SCROW nRow2; | |||
2454 | SCTAB nTab2; | |||
2455 | rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); | |||
2456 | for ( SCTAB nTab = nTab1; nTab <= nTab2; nTab++ ) | |||
2457 | { | |||
2458 | if ( !pRefDoc || nTab < pRefDoc->GetTableCount() ) | |||
2459 | { | |||
2460 | if ( nCol1 == 0 && nCol2 == rDoc.MaxCol() ) | |||
2461 | { // Whole Row and/or Tables | |||
2462 | if ( nRow1 == 0 && nRow2 == rDoc.MaxRow() ) | |||
2463 | { // Whole Table | |||
2464 | // TODO: Can't we do the whole Table as a whole? | |||
2465 | ScRange aRange( 0, 0, nTab, 0, rDoc.MaxRow(), nTab ); | |||
2466 | for ( SCCOL nCol = nCol1; nCol <= nCol2; nCol++ ) | |||
2467 | { // Column by column is less than row by row | |||
2468 | aRange.aStart.SetCol( nCol ); | |||
2469 | aRange.aEnd.SetCol( nCol ); | |||
2470 | if ( nCol == nCol2 ) | |||
2471 | SetInDeleteTop( true ); | |||
2472 | AppendOneDeleteRange( aRange, pRefDoc, nCol-nCol1, 0, | |||
2473 | nTab-nTab1 + nDz, nRejectingInsert ); | |||
2474 | } | |||
2475 | // Still InDeleteTop! | |||
2476 | AppendOneDeleteRange( rRange, pRefDoc, 0, 0, | |||
2477 | nTab-nTab1 + nDz, nRejectingInsert ); | |||
2478 | } | |||
2479 | else | |||
2480 | { // Whole rows | |||
2481 | ScRange aRange( 0, 0, nTab, rDoc.MaxCol(), 0, nTab ); | |||
2482 | for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ ) | |||
2483 | { | |||
2484 | aRange.aStart.SetRow( nRow ); | |||
2485 | aRange.aEnd.SetRow( nRow ); | |||
2486 | if ( nRow == nRow2 ) | |||
2487 | SetInDeleteTop( true ); | |||
2488 | AppendOneDeleteRange( aRange, pRefDoc, 0, nRow-nRow1, | |||
2489 | 0, nRejectingInsert ); | |||
2490 | } | |||
2491 | } | |||
2492 | } | |||
2493 | else if ( nRow1 == 0 && nRow2 == rDoc.MaxRow() ) | |||
2494 | { // Whole columns | |||
2495 | ScRange aRange( 0, 0, nTab, 0, rDoc.MaxRow(), nTab ); | |||
2496 | for ( SCCOL nCol = nCol1; nCol <= nCol2; nCol++ ) | |||
2497 | { | |||
2498 | aRange.aStart.SetCol( nCol ); | |||
2499 | aRange.aEnd.SetCol( nCol ); | |||
2500 | if ( nCol == nCol2 ) | |||
2501 | SetInDeleteTop( true ); | |||
2502 | AppendOneDeleteRange( aRange, pRefDoc, nCol-nCol1, 0, | |||
2503 | 0, nRejectingInsert ); | |||
2504 | } | |||
2505 | } | |||
2506 | else | |||
2507 | { | |||
2508 | OSL_FAIL( "ScChangeTrack::AppendDeleteRange: Block not supported!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/chgtrack.cxx" ":" "2508" ": "), "%s", "ScChangeTrack::AppendDeleteRange: Block not supported!" ); } } while (false); | |||
2509 | } | |||
2510 | SetInDeleteTop( false ); | |||
2511 | } | |||
2512 | } | |||
2513 | EndBlockModify( GetActionMax() ); | |||
2514 | } | |||
2515 | ||||
2516 | void ScChangeTrack::AppendOneDeleteRange( const ScRange& rOrgRange, | |||
2517 | ScDocument* pRefDoc, SCCOL nDx, SCROW nDy, SCTAB nDz, | |||
2518 | sal_uLong nRejectingInsert ) | |||
2519 | { | |||
2520 | ScRange aTrackRange( rOrgRange ); | |||
2521 | if ( nDx ) | |||
2522 | { | |||
2523 | aTrackRange.aStart.IncCol( -nDx ); | |||
2524 | aTrackRange.aEnd.IncCol( -nDx ); | |||
2525 | } | |||
2526 | if ( nDy ) | |||
2527 | { | |||
2528 | aTrackRange.aStart.IncRow( -nDy ); | |||
2529 | aTrackRange.aEnd.IncRow( -nDy ); | |||
2530 | } | |||
2531 | if ( nDz ) | |||
2532 | { | |||
2533 | aTrackRange.aStart.IncTab( -nDz ); | |||
2534 | aTrackRange.aEnd.IncTab( -nDz ); | |||
2535 | } | |||
2536 | ScChangeActionDel* pAct = new ScChangeActionDel( &rDoc, aTrackRange, nDx, nDy, | |||
2537 | this ); | |||
2538 | // TabDelete not Contents; they are in separate columns | |||
2539 | if ( !(rOrgRange.aStart.Col() == 0 && rOrgRange.aStart.Row() == 0 && | |||
2540 | rOrgRange.aEnd.Col() == rDoc.MaxCol() && rOrgRange.aEnd.Row() == rDoc.MaxRow()) ) | |||
2541 | LookUpContents( rOrgRange, pRefDoc, -nDx, -nDy, -nDz ); | |||
2542 | if ( nRejectingInsert ) | |||
2543 | { | |||
2544 | pAct->SetRejectAction( nRejectingInsert ); | |||
2545 | pAct->SetState( SC_CAS_ACCEPTED ); | |||
2546 | } | |||
2547 | Append( pAct ); | |||
2548 | } | |||
2549 | ||||
2550 | void ScChangeTrack::LookUpContents( const ScRange& rOrgRange, | |||
2551 | ScDocument* pRefDoc, SCCOL nDx, SCROW nDy, SCTAB nDz ) | |||
2552 | { | |||
2553 | if (!pRefDoc) | |||
2554 | return; | |||
2555 | ||||
2556 | ScAddress aPos; | |||
2557 | ScBigAddress aBigPos; | |||
2558 | ScCellIterator aIter( *pRefDoc, rOrgRange ); | |||
2559 | for (bool bHas = aIter.first(); bHas; bHas = aIter.next()) | |||
2560 | { | |||
2561 | if (!ScChangeActionContent::GetContentCellType(aIter.getRefCellValue())) | |||
2562 | continue; | |||
2563 | ||||
2564 | aBigPos.Set( aIter.GetPos().Col() + nDx, aIter.GetPos().Row() + nDy, | |||
2565 | aIter.GetPos().Tab() + nDz ); | |||
2566 | ScChangeActionContent* pContent = SearchContentAt( aBigPos, nullptr ); | |||
2567 | if (pContent) | |||
2568 | continue; | |||
2569 | ||||
2570 | // Untracked Contents | |||
2571 | aPos.Set( aIter.GetPos().Col() + nDx, aIter.GetPos().Row() + nDy, | |||
2572 | aIter.GetPos().Tab() + nDz ); | |||
2573 | ||||
2574 | GenerateDelContent(aPos, aIter.getCellValue(), pRefDoc); | |||
2575 | // The Content is _not_ added with AddContent here, but in UpdateReference. | |||
2576 | // We do this in order to e.g. handle intersecting Deletes correctly | |||
2577 | } | |||
2578 | } | |||
2579 | ||||
2580 | void ScChangeTrack::AppendMove( const ScRange& rFromRange, | |||
2581 | const ScRange& rToRange, ScDocument* pRefDoc ) | |||
2582 | { | |||
2583 | ScChangeActionMove* pAct = new ScChangeActionMove( rFromRange, rToRange, this ); | |||
2584 | LookUpContents( rToRange, pRefDoc, 0, 0, 0 ); // Overwritten Contents | |||
2585 | Append( pAct ); | |||
2586 | } | |||
2587 | ||||
2588 | bool ScChangeTrack::IsMatrixFormulaRangeDifferent( | |||
2589 | const ScCellValue& rOldCell, const ScCellValue& rNewCell ) | |||
2590 | { | |||
2591 | SCCOL nC1, nC2; | |||
2592 | SCROW nR1, nR2; | |||
2593 | nC1 = nC2 = 0; | |||
2594 | nR1 = nR2 = 0; | |||
2595 | ||||
2596 | if (rOldCell.meType == CELLTYPE_FORMULA && rOldCell.mpFormula->GetMatrixFlag() == ScMatrixMode::Formula) | |||
2597 | rOldCell.mpFormula->GetMatColsRows(nC1, nR1); | |||
2598 | ||||
2599 | if (rNewCell.meType == CELLTYPE_FORMULA && rNewCell.mpFormula->GetMatrixFlag() == ScMatrixMode::Formula) | |||
2600 | rNewCell.mpFormula->GetMatColsRows(nC1, nR1); | |||
2601 | ||||
2602 | return nC1 != nC2 || nR1 != nR2; | |||
2603 | } | |||
2604 | ||||
2605 | void ScChangeTrack::AppendContent( | |||
2606 | const ScAddress& rPos, const ScCellValue& rOldCell, sal_uLong nOldFormat, ScDocument* pRefDoc ) | |||
2607 | { | |||
2608 | if ( !pRefDoc ) | |||
2609 | pRefDoc = &rDoc; | |||
2610 | ||||
2611 | OUString aOldValue; | |||
2612 | ScChangeActionContent::GetStringOfCell(aOldValue, rOldCell, pRefDoc, nOldFormat); | |||
2613 | ||||
2614 | OUString aNewValue; | |||
2615 | ScCellValue aNewCell; | |||
2616 | aNewCell.assign(rDoc, rPos); | |||
2617 | ScChangeActionContent::GetStringOfCell(aNewValue, aNewCell, &rDoc, rPos); | |||
2618 | ||||
2619 | if (aOldValue != aNewValue || IsMatrixFormulaRangeDifferent(rOldCell, aNewCell)) | |||
2620 | { // Only track real changes | |||
2621 | ScRange aRange( rPos ); | |||
2622 | ScChangeActionContent* pAct = new ScChangeActionContent( aRange ); | |||
2623 | pAct->SetOldValue(rOldCell, pRefDoc, &rDoc, nOldFormat); | |||
2624 | pAct->SetNewValue(aNewCell, &rDoc); | |||
2625 | Append( pAct ); | |||
2626 | } | |||
2627 | } | |||
2628 | ||||
2629 | void ScChangeTrack::AppendContent( const ScAddress& rPos, | |||
2630 | const ScDocument* pRefDoc ) | |||
2631 | { | |||
2632 | OUString aOldValue; | |||
2633 | ScCellValue aOldCell; | |||
2634 | aOldCell.assign(*pRefDoc, rPos); | |||
2635 | ScChangeActionContent::GetStringOfCell(aOldValue, aOldCell, pRefDoc, rPos); | |||
2636 | ||||
2637 | OUString aNewValue; | |||
2638 | ScCellValue aNewCell; | |||
2639 | aNewCell.assign(rDoc, rPos); | |||
2640 | ScChangeActionContent::GetStringOfCell(aNewValue, aNewCell, &rDoc, rPos); | |||
2641 | ||||
2642 | if (aOldValue != aNewValue || IsMatrixFormulaRangeDifferent(aOldCell, aNewCell)) | |||
2643 | { // Only track real changes | |||
2644 | ScRange aRange( rPos ); | |||
2645 | ScChangeActionContent* pAct = new ScChangeActionContent( aRange ); | |||
2646 | pAct->SetOldValue(aOldCell, pRefDoc, &rDoc); | |||
2647 | pAct->SetNewValue(aNewCell, &rDoc); | |||
2648 | Append( pAct ); | |||
2649 | } | |||
2650 | } | |||
2651 | ||||
2652 | void ScChangeTrack::AppendContent( const ScAddress& rPos, const ScCellValue& rOldCell ) | |||
2653 | { | |||
2654 | if (ScChangeActionContent::NeedsNumberFormat(rOldCell)) | |||
2655 | AppendContent(rPos, rOldCell, rDoc.GetNumberFormat(rPos), &rDoc); | |||
2656 | else | |||
2657 | AppendContent(rPos, rOldCell, 0, &rDoc); | |||
2658 | } | |||
2659 | ||||
2660 | void ScChangeTrack::SetLastCutMoveRange( const ScRange& rRange, | |||
2661 | ScDocument* pRefDoc ) | |||
2662 | { | |||
2663 | if ( !pLastCutMove ) | |||
2664 | return; | |||
2665 | ||||
2666 | // Do not link ToRange with Deletes and don't change its size | |||
2667 | // This is actually unnecessary, as a delete triggers a ResetLastCut | |||
2668 | // in ScViewFunc::PasteFromClip before that | |||
2669 | ScBigRange& r = pLastCutMove->GetBigRange(); | |||
2670 | r.aEnd.SetCol( -1 ); | |||
2671 | r.aEnd.SetRow( -1 ); | |||
2672 | r.aEnd.SetTab( -1 ); | |||
2673 | r.aStart.SetCol( -1 - (rRange.aEnd.Col() - rRange.aStart.Col()) ); | |||
2674 | r.aStart.SetRow( -1 - (rRange.aEnd.Row() - rRange.aStart.Row()) ); | |||
2675 | r.aStart.SetTab( -1 - (rRange.aEnd.Tab() - rRange.aStart.Tab()) ); | |||
2676 | // Contents in FromRange we should overwrite | |||
2677 | LookUpContents( rRange, pRefDoc, 0, 0, 0 ); | |||
2678 | } | |||
2679 | ||||
2680 | void ScChangeTrack::AppendContentRange( const ScRange& rRange, | |||
2681 | ScDocument* pRefDoc, sal_uLong& nStartAction, sal_uLong& nEndAction, | |||
2682 | ScChangeActionClipMode eClipMode ) | |||
2683 | { | |||
2684 | if ( eClipMode == SC_CACM_CUT ) | |||
2685 | { | |||
2686 | ResetLastCut(); | |||
2687 | pLastCutMove.reset(new ScChangeActionMove( rRange, rRange, this )); | |||
2688 | SetLastCutMoveRange( rRange, pRefDoc ); | |||
2689 | } | |||
2690 | SCCOL nCol1; | |||
2691 | SCROW nRow1; | |||
2692 | SCTAB nTab1; | |||
2693 | SCCOL nCol2; | |||
2694 | SCROW nRow2; | |||
2695 | SCTAB nTab2; | |||
2696 | rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); | |||
2697 | bool bDoContents; | |||
2698 | if ( eClipMode == SC_CACM_PASTE && HasLastCut() ) | |||
2699 | { | |||
2700 | bDoContents = false; | |||
2701 | SetInPasteCut( true ); | |||
2702 | // Adjust Paste and Cut; Paste can be larger a Range | |||
2703 | ScRange aRange( rRange ); | |||
2704 | ScBigRange& r = pLastCutMove->GetBigRange(); | |||
2705 | SCCOL nTmpCol; | |||
2706 | if ( (nTmpCol = static_cast<SCCOL>(r.aEnd.Col() - r.aStart.Col())) != (nCol2 - nCol1) ) | |||
2707 | { | |||
2708 | aRange.aEnd.SetCol( aRange.aStart.Col() + nTmpCol ); | |||
2709 | nCol1 += nTmpCol + 1; | |||
2710 | bDoContents = true; | |||
2711 | } | |||
2712 | SCROW nTmpRow; | |||
2713 | if ( (nTmpRow = static_cast<SCROW>(r.aEnd.Row() - r.aStart.Row())) != (nRow2 - nRow1) ) | |||
2714 | { | |||
2715 | aRange.aEnd.SetRow( aRange.aStart.Row() + nTmpRow ); | |||
2716 | nRow1 += nTmpRow + 1; | |||
2717 | bDoContents = true; | |||
2718 | } | |||
2719 | SCTAB nTmpTab; | |||
2720 | if ( (nTmpTab = static_cast<SCTAB>(r.aEnd.Tab() - r.aStart.Tab())) != (nTab2 - nTab1) ) | |||
2721 | { | |||
2722 | aRange.aEnd.SetTab( aRange.aStart.Tab() + nTmpTab ); | |||
2723 | nTab1 += nTmpTab + 1; | |||
2724 | bDoContents = true; | |||
2725 | } | |||
2726 | r = aRange; | |||
2727 | Undo( nStartLastCut, nEndLastCut ); // Remember Cuts here | |||
2728 | // StartAction only after Undo! | |||
2729 | nStartAction = GetActionMax() + 1; | |||
2730 | StartBlockModify( ScChangeTrackMsgType::Append, nStartAction ); | |||
2731 | // Contents to overwrite in ToRange | |||
2732 | LookUpContents( aRange, pRefDoc, 0, 0, 0 ); | |||
2733 | pLastCutMove->SetStartLastCut( nStartLastCut ); | |||
2734 | pLastCutMove->SetEndLastCut( nEndLastCut ); | |||
2735 | Append( pLastCutMove.release() ); | |||
2736 | ResetLastCut(); | |||
2737 | SetInPasteCut( false ); | |||
2738 | } | |||
2739 | else | |||
2740 | { | |||
2741 | bDoContents = true; | |||
2742 | nStartAction = GetActionMax() + 1; | |||
2743 | StartBlockModify( ScChangeTrackMsgType::Append, nStartAction ); | |||
2744 | } | |||
2745 | if ( bDoContents ) | |||
2746 | { | |||
2747 | ScAddress aPos; | |||
2748 | for ( SCTAB nTab = nTab1; nTab <= nTab2; nTab++ ) | |||
2749 | { | |||
2750 | aPos.SetTab( nTab ); | |||
2751 | for ( SCCOL nCol = nCol1; nCol <= nCol2; nCol++ ) | |||
2752 | { | |||
2753 | aPos.SetCol( nCol ); | |||
2754 | for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ ) | |||
2755 | { | |||
2756 | aPos.SetRow( nRow ); | |||
2757 | AppendContent( aPos, pRefDoc ); | |||
2758 | } | |||
2759 | } | |||
2760 | } | |||
2761 | } | |||
2762 | nEndAction = GetActionMax(); | |||
2763 | EndBlockModify( nEndAction ); | |||
2764 | if ( eClipMode == SC_CACM_CUT ) | |||
2765 | { | |||
2766 | nStartLastCut = nStartAction; | |||
2767 | nEndLastCut = nEndAction; | |||
2768 | } | |||
2769 | } | |||
2770 | ||||
2771 | void ScChangeTrack::AppendContentsIfInRefDoc( ScDocument& rRefDoc, | |||
2772 | sal_uLong& nStartAction, sal_uLong& nEndAction ) | |||
2773 | { | |||
2774 | ScCellIterator aIter(rRefDoc, ScRange(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB)); | |||
2775 | if (aIter.first()) | |||
2776 | { | |||
2777 | nStartAction = GetActionMax() + 1; | |||
2778 | StartBlockModify( ScChangeTrackMsgType::Append, nStartAction ); | |||
2779 | SvNumberFormatter* pFormatter = rRefDoc.GetFormatTable(); | |||
2780 | do | |||
2781 | { | |||
2782 | const ScAddress& rPos = aIter.GetPos(); | |||
2783 | const ScPatternAttr* pPat = rRefDoc.GetPattern(rPos); | |||
2784 | AppendContent( | |||
2785 | rPos, aIter.getCellValue(), pPat->GetNumberFormat(pFormatter), &rRefDoc); | |||
2786 | } | |||
2787 | while (aIter.next()); | |||
2788 | ||||
2789 | nEndAction = GetActionMax(); | |||
2790 | EndBlockModify( nEndAction ); | |||
2791 | } | |||
2792 | else | |||
2793 | nStartAction = nEndAction = 0; | |||
2794 | } | |||
2795 | ||||
2796 | ScChangeActionContent* ScChangeTrack::AppendContentOnTheFly( | |||
2797 | const ScAddress& rPos, const ScCellValue& rOldCell, const ScCellValue& rNewCell, | |||
2798 | sal_uLong nOldFormat, sal_uLong nNewFormat ) | |||
2799 | { | |||
2800 | ScRange aRange( rPos ); | |||
2801 | ScChangeActionContent* pAct = new ScChangeActionContent( aRange ); | |||
2802 | pAct->SetOldNewCells(rOldCell, nOldFormat, rNewCell, nNewFormat, &rDoc); | |||
2803 | Append( pAct ); | |||
2804 | return pAct; | |||
2805 | } | |||
2806 | ||||
2807 | void ScChangeTrack::AppendInsert( const ScRange& rRange, bool bEndOfList ) | |||
2808 | { | |||
2809 | ScChangeActionIns* pAct = new ScChangeActionIns(&rDoc, rRange, bEndOfList); | |||
2810 | Append( pAct ); | |||
2811 | } | |||
2812 | ||||
2813 | void ScChangeTrack::DeleteCellEntries( std::vector<ScChangeActionContent*>& rCellList, | |||
2814 | const ScChangeAction* pDeletor ) | |||
2815 | { | |||
2816 | for (ScChangeActionContent* pContent : rCellList) | |||
2817 | { | |||
2818 | pContent->RemoveDeletedIn( pDeletor ); | |||
2819 | if ( IsGenerated( pContent->GetActionNumber() ) && | |||
2820 | !pContent->IsDeletedIn() ) | |||
2821 | DeleteGeneratedDelContent( pContent ); | |||
2822 | } | |||
2823 | rCellList.clear(); | |||
2824 | } | |||
2825 | ||||
2826 | ScChangeActionContent* ScChangeTrack::GenerateDelContent( | |||
2827 | const ScAddress& rPos, const ScCellValue& rCell, const ScDocument* pFromDoc ) | |||
2828 | { | |||
2829 | ScChangeActionContent* pContent = new ScChangeActionContent( | |||
2830 | ScRange( rPos ) ); | |||
2831 | pContent->SetActionNumber( --nGeneratedMin ); | |||
2832 | // Only NewValue | |||
2833 | ScChangeActionContent::SetValue( pContent->maNewValue, pContent->maNewCell, | |||
2834 | rPos, rCell, pFromDoc, &rDoc ); | |||
2835 | // pNextContent and pPrevContent are not set | |||
2836 | if ( pFirstGeneratedDelContent ) | |||
2837 | { // Insert at front | |||
2838 | pFirstGeneratedDelContent->pPrev = pContent; | |||
2839 | pContent->pNext = pFirstGeneratedDelContent; | |||
2840 | } | |||
2841 | pFirstGeneratedDelContent = pContent; | |||
2842 | aGeneratedMap.insert( std::make_pair( nGeneratedMin, pContent ) ); | |||
2843 | NotifyModified( ScChangeTrackMsgType::Append, nGeneratedMin, nGeneratedMin ); | |||
2844 | return pContent; | |||
2845 | } | |||
2846 | ||||
2847 | void ScChangeTrack::DeleteGeneratedDelContent( ScChangeActionContent* pContent ) | |||
2848 | { | |||
2849 | sal_uLong nAct = pContent->GetActionNumber(); | |||
2850 | aGeneratedMap.erase( nAct ); | |||
2851 | if ( pFirstGeneratedDelContent == pContent ) | |||
2852 | pFirstGeneratedDelContent = static_cast<ScChangeActionContent*>(pContent->pNext); | |||
2853 | if ( pContent->pNext ) | |||
2854 | pContent->pNext->pPrev = pContent->pPrev; | |||
2855 | if ( pContent->pPrev ) | |||
2856 | pContent->pPrev->pNext = pContent->pNext; | |||
2857 | delete pContent; | |||
2858 | NotifyModified( ScChangeTrackMsgType::Remove, nAct, nAct ); | |||
2859 | if ( nAct == nGeneratedMin ) | |||
2860 | ++nGeneratedMin; // Only after NotifyModified due to IsGenerated! | |||
2861 | } | |||
2862 | ||||
2863 | ScChangeActionContent* ScChangeTrack::SearchContentAt( | |||
2864 | const ScBigAddress& rPos, const ScChangeAction* pButNotThis ) const | |||
2865 | { | |||
2866 | SCSIZE nSlot = ComputeContentSlot( rPos.Row() ); | |||
2867 | for ( ScChangeActionContent* p = ppContentSlots[nSlot]; p; | |||
2868 | p = p->GetNextInSlot() ) | |||
2869 | { | |||
2870 | if ( p != pButNotThis && !p->IsDeletedIn() && | |||
2871 | p->GetBigRange().aStart == rPos ) | |||
2872 | { | |||
2873 | ScChangeActionContent* pContent = p->GetTopContent(); | |||
2874 | if ( !pContent->IsDeletedIn() ) | |||
2875 | return pContent; | |||
2876 | } | |||
2877 | } | |||
2878 | return nullptr; | |||
2879 | } | |||
2880 | ||||
2881 | void ScChangeTrack::AddDependentWithNotify( ScChangeAction* pParent, | |||
2882 | ScChangeAction* pDependent ) | |||
2883 | { | |||
2884 | ScChangeActionLinkEntry* pLink = pParent->AddDependent( pDependent ); | |||
2885 | pDependent->AddLink( pParent, pLink ); | |||
2886 | if ( aModifiedLink.IsSet() ) | |||
2887 | { | |||
2888 | sal_uLong nMod = pParent->GetActionNumber(); | |||
2889 | NotifyModified( ScChangeTrackMsgType::Parent, nMod, nMod ); | |||
2890 | } | |||
2891 | } | |||
2892 | ||||
2893 | void ScChangeTrack::Dependencies( ScChangeAction* pAct ) | |||
2894 | { | |||
2895 | // Find the last dependency for Col/Row/Tab each | |||
2896 | // Concatenate Content at the same position | |||
2897 | // Move dependencies | |||
2898 | ScChangeActionType eActType = pAct->GetType(); | |||
2899 | if ( eActType == SC_CAT_REJECT || | |||
2900 | (eActType == SC_CAT_MOVE && pAct->IsRejecting()) ) | |||
2901 | return ; // These Rejects are not dependent | |||
2902 | ||||
2903 | if ( eActType == SC_CAT_CONTENT ) | |||
2904 | { | |||
2905 | if ( !(static_cast<ScChangeActionContent*>(pAct)->GetNextContent() || | |||
2906 | static_cast<ScChangeActionContent*>(pAct)->GetPrevContent()) ) | |||
2907 | { // Concatenate Contents at same position | |||
2908 | ScChangeActionContent* pContent = SearchContentAt( | |||
2909 | pAct->GetBigRange().aStart, pAct ); | |||
2910 | if ( pContent ) | |||
2911 | { | |||
2912 | pContent->SetNextContent( static_cast<ScChangeActionContent*>(pAct) ); | |||
2913 | static_cast<ScChangeActionContent*>(pAct)->SetPrevContent( pContent ); | |||
2914 | } | |||
2915 | } | |||
2916 | const ScCellValue& rCell = static_cast<ScChangeActionContent*>(pAct)->GetNewCell(); | |||
2917 | if ( ScChangeActionContent::GetContentCellType(rCell) == SC_CACCT_MATREF ) | |||
2918 | { | |||
2919 | ScAddress aOrg; | |||
2920 | bool bOrgFound = rCell.mpFormula->GetMatrixOrigin(rDoc, aOrg); | |||
2921 | ScChangeActionContent* pContent = (bOrgFound ? SearchContentAt( aOrg, pAct ) : nullptr); | |||
2922 | if ( pContent && pContent->IsMatrixOrigin() ) | |||
2923 | { | |||
2924 | AddDependentWithNotify( pContent, pAct ); | |||
2925 | } | |||
2926 | else | |||
2927 | { | |||
2928 | OSL_FAIL( "ScChangeTrack::Dependencies: MatOrg not found" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/chgtrack.cxx" ":" "2928" ": "), "%s", "ScChangeTrack::Dependencies: MatOrg not found" ); } } while (false); | |||
2929 | } | |||
2930 | } | |||
2931 | } | |||
2932 | ||||
2933 | if ( !(pLinkInsertCol || pLinkInsertRow || pLinkInsertTab || pLinkMove) ) | |||
2934 | return ; // No Dependencies | |||
2935 | if ( pAct->IsRejecting() ) | |||
2936 | return ; // Except for Content no Dependencies | |||
2937 | ||||
2938 | // Insert in a corresponding Insert depends on it or else we would need | |||
2939 | // to split the preceding one. | |||
2940 | // Intersecting Inserts and Deletes are not dependent, everything else | |||
2941 | // is dependent. | |||
2942 | // The Insert last linked in is at the beginning of a chain, just the way we need it | |||
2943 | ||||
2944 | const ScBigRange& rRange = pAct->GetBigRange(); | |||
2945 | bool bActNoInsert = !pAct->IsInsertType(); | |||
2946 | bool bActColDel = ( eActType == SC_CAT_DELETE_COLS ); | |||
2947 | bool bActRowDel = ( eActType == SC_CAT_DELETE_ROWS ); | |||
2948 | bool bActTabDel = ( eActType == SC_CAT_DELETE_TABS ); | |||
2949 | ||||
2950 | if ( pLinkInsertCol && (eActType == SC_CAT_INSERT_COLS || | |||
2951 | (bActNoInsert && !bActRowDel && !bActTabDel)) ) | |||
2952 | { | |||
2953 | for ( ScChangeActionLinkEntry* pL = pLinkInsertCol; pL; pL = pL->GetNext() ) | |||
2954 | { | |||
2955 | ScChangeActionIns* pTest = static_cast<ScChangeActionIns*>(pL->GetAction()); | |||
2956 | if ( !pTest->IsRejected() && | |||
2957 | pTest->GetBigRange().Intersects( rRange ) ) | |||
2958 | { | |||
2959 | AddDependentWithNotify( pTest, pAct ); | |||
2960 | break; // for | |||
2961 | } | |||
2962 | } | |||
2963 | } | |||
2964 | if ( pLinkInsertRow && (eActType == SC_CAT_INSERT_ROWS || | |||
2965 | (bActNoInsert && !bActColDel && !bActTabDel)) ) | |||
2966 | { | |||
2967 | for ( ScChangeActionLinkEntry* pL = pLinkInsertRow; pL; pL = pL->GetNext() ) | |||
2968 | { | |||
2969 | ScChangeActionIns* pTest = static_cast<ScChangeActionIns*>(pL->GetAction()); | |||
2970 | if ( !pTest->IsRejected() && | |||
2971 | pTest->GetBigRange().Intersects( rRange ) ) | |||
2972 | { | |||
2973 | AddDependentWithNotify( pTest, pAct ); | |||
2974 | break; // for | |||
2975 | } | |||
2976 | } | |||
2977 | } | |||
2978 | if ( pLinkInsertTab && (eActType == SC_CAT_INSERT_TABS || | |||
2979 | (bActNoInsert && !bActColDel && !bActRowDel)) ) | |||
2980 | { | |||
2981 | for ( ScChangeActionLinkEntry* pL = pLinkInsertTab; pL; pL = pL->GetNext() ) | |||
2982 | { | |||
2983 | ScChangeActionIns* pTest = static_cast<ScChangeActionIns*>(pL->GetAction()); | |||
2984 | if ( !pTest->IsRejected() && | |||
2985 | pTest->GetBigRange().Intersects( rRange ) ) | |||
2986 | { | |||
2987 | AddDependentWithNotify( pTest, pAct ); | |||
2988 | break; // for | |||
2989 | } | |||
2990 | } | |||
2991 | } | |||
2992 | ||||
2993 | if ( !pLinkMove ) | |||
2994 | return; | |||
2995 | ||||
2996 | if ( eActType == SC_CAT_CONTENT ) | |||
2997 | { // Content is depending on FromRange | |||
2998 | const ScBigAddress& rPos = rRange.aStart; | |||
2999 | for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() ) | |||
3000 | { | |||
3001 | ScChangeActionMove* pTest = static_cast<ScChangeActionMove*>(pL->GetAction()); | |||
3002 | if ( !pTest->IsRejected() && | |||
3003 | pTest->GetFromRange().In( rPos ) ) | |||
3004 | { | |||
3005 | AddDependentWithNotify( pTest, pAct ); | |||
3006 | } | |||
3007 | } | |||
3008 | } | |||
3009 | else if ( eActType == SC_CAT_MOVE ) | |||
3010 | { // Move FromRange is depending on ToRange | |||
3011 | const ScBigRange& rFromRange = static_cast<ScChangeActionMove*>(pAct)->GetFromRange(); | |||
3012 | for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() ) | |||
3013 | { | |||
3014 | ScChangeActionMove* pTest = static_cast<ScChangeActionMove*>(pL->GetAction()); | |||
3015 | if ( !pTest->IsRejected() && | |||
3016 | pTest->GetBigRange().Intersects( rFromRange ) ) | |||
3017 | { | |||
3018 | AddDependentWithNotify( pTest, pAct ); | |||
3019 | } | |||
3020 | } | |||
3021 | } | |||
3022 | else | |||
3023 | { // Inserts and Deletes are depending as soon as they cross FromRange or | |||
3024 | // ToRange | |||
3025 | for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() ) | |||
3026 | { | |||
3027 | ScChangeActionMove* pTest = static_cast<ScChangeActionMove*>(pL->GetAction()); | |||
3028 | if ( !pTest->IsRejected() && | |||
3029 | (pTest->GetFromRange().Intersects( rRange ) || | |||
3030 | pTest->GetBigRange().Intersects( rRange )) ) | |||
3031 | { | |||
3032 | AddDependentWithNotify( pTest, pAct ); | |||
3033 | } | |||
3034 | } | |||
3035 | } | |||
3036 | } | |||
3037 | ||||
3038 | void ScChangeTrack::Remove( ScChangeAction* pRemove ) | |||
3039 | { | |||
3040 | // Remove from Track | |||
3041 | sal_uLong nAct = pRemove->GetActionNumber(); | |||
3042 | aMap.erase( nAct ); | |||
3043 | if ( nAct == nActionMax ) | |||
3044 | --nActionMax; | |||
3045 | if ( pRemove == pLast ) | |||
3046 | pLast = pRemove->pPrev; | |||
3047 | if ( pRemove == pFirst ) | |||
3048 | pFirst = pRemove->pNext; | |||
3049 | if ( nAct == nMarkLastSaved ) | |||
3050 | nMarkLastSaved = | |||
3051 | ( pRemove->pPrev ? pRemove->pPrev->GetActionNumber() : 0 ); | |||
3052 | ||||
3053 | // Remove from global chain | |||
3054 | if ( pRemove->pNext ) | |||
3055 | pRemove->pNext->pPrev = pRemove->pPrev; | |||
3056 | if ( pRemove->pPrev ) | |||
3057 | pRemove->pPrev->pNext = pRemove->pNext; | |||
3058 | ||||
3059 | // Don't delete Dependencies | |||
3060 | // That happens automatically on delete by LinkEntry without traversing lists | |||
3061 | if ( aModifiedLink.IsSet() ) | |||
3062 | { | |||
3063 | NotifyModified( ScChangeTrackMsgType::Remove, nAct, nAct ); | |||
3064 | if ( pRemove->GetType() == SC_CAT_CONTENT ) | |||
3065 | { | |||
3066 | ScChangeActionContent* pContent = static_cast<ScChangeActionContent*>(pRemove); | |||
3067 | if ( ( pContent = pContent->GetPrevContent() ) != nullptr ) | |||
3068 | { | |||
3069 | sal_uLong nMod = pContent->GetActionNumber(); | |||
3070 | NotifyModified( ScChangeTrackMsgType::Change, nMod, nMod ); | |||
3071 | } | |||
3072 | } | |||
3073 | else if ( pLast ) | |||
3074 | NotifyModified( ScChangeTrackMsgType::Change, pFirst->GetActionNumber(), | |||
3075 | pLast->GetActionNumber() ); | |||
3076 | } | |||
3077 | ||||
3078 | if ( IsInPasteCut() && pRemove->GetType() == SC_CAT_CONTENT ) | |||
3079 | { // Content is reused! | |||
3080 | ScChangeActionContent* pContent = static_cast<ScChangeActionContent*>(pRemove); | |||
3081 | pContent->RemoveAllLinks(); | |||
3082 | pContent->ClearTrack(); | |||
3083 | pContent->pNext = pContent->pPrev = nullptr; | |||
3084 | pContent->pNextContent = pContent->pPrevContent = nullptr; | |||
3085 | } | |||
3086 | } | |||
3087 | ||||
3088 | void ScChangeTrack::Undo( sal_uLong nStartAction, sal_uLong nEndAction, bool bMerge ) | |||
3089 | { | |||
3090 | // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong | |||
3091 | if ( bMerge ) | |||
3092 | { | |||
3093 | SetMergeState( SC_CTMS_UNDO ); | |||
3094 | } | |||
3095 | ||||
3096 | if ( nStartAction == 0 ) | |||
3097 | ++nStartAction; | |||
3098 | if ( nEndAction > nActionMax ) | |||
3099 | nEndAction = nActionMax; | |||
3100 | if ( nEndAction && nStartAction <= nEndAction ) | |||
3101 | { | |||
3102 | if ( nStartAction == nStartLastCut && nEndAction == nEndLastCut && | |||
3103 | !IsInPasteCut() ) | |||
3104 | ResetLastCut(); | |||
3105 | StartBlockModify( ScChangeTrackMsgType::Remove, nStartAction ); | |||
3106 | for ( sal_uLong j = nEndAction; j >= nStartAction; --j ) | |||
3107 | { // Traverse backwards to recycle nActionMax and for faster access via pLast | |||
3108 | // Deletes are in right order | |||
3109 | ScChangeAction* pAct = IsLastAction(j) ? pLast : GetAction(j); | |||
3110 | ||||
3111 | if (!pAct) | |||
3112 | continue; | |||
3113 | ||||
3114 | if ( pAct->IsDeleteType() ) | |||
3115 | { | |||
3116 | if (j == nEndAction || (pAct != pLast && static_cast<ScChangeActionDel*>(pAct)->IsTopDelete())) | |||
3117 | { | |||
3118 | SetInDeleteTop( true ); | |||
3119 | SetInDeleteRange( static_cast<ScChangeActionDel*>(pAct)->GetOverAllRange().MakeRange() ); | |||
3120 | } | |||
3121 | } | |||
3122 | UpdateReference( pAct, true ); | |||
3123 | SetInDeleteTop( false ); | |||
3124 | Remove( pAct ); | |||
3125 | if ( IsInPasteCut() ) | |||
3126 | { | |||
3127 | aPasteCutMap.insert( ::std::make_pair( pAct->GetActionNumber(), pAct ) ); | |||
3128 | continue; | |||
3129 | } | |||
3130 | ||||
3131 | if ( j == nStartAction && pAct->GetType() == SC_CAT_MOVE ) | |||
3132 | { | |||
3133 | ScChangeActionMove* pMove = static_cast<ScChangeActionMove*>(pAct); | |||
3134 | sal_uLong nStart = pMove->GetStartLastCut(); | |||
3135 | sal_uLong nEnd = pMove->GetEndLastCut(); | |||
3136 | if ( nStart && nStart <= nEnd ) | |||
3137 | { // Recover LastCut | |||
3138 | // Break Links before Cut Append! | |||
3139 | pMove->RemoveAllLinks(); | |||
3140 | StartBlockModify( ScChangeTrackMsgType::Append, nStart ); | |||
3141 | for ( sal_uLong nCut = nStart; nCut <= nEnd; nCut++ ) | |||
3142 | { | |||
3143 | ScChangeActionMap::iterator itCut = aPasteCutMap.find( nCut ); | |||
3144 | ||||
3145 | if ( itCut != aPasteCutMap.end() ) | |||
3146 | { | |||
3147 | OSL_ENSURE( aMap.find( nCut ) == aMap.end(), "ScChangeTrack::Undo: nCut dup" )do { if (true && (!(aMap.find( nCut ) == aMap.end())) ) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/chgtrack.cxx" ":" "3147" ": "), "%s", "ScChangeTrack::Undo: nCut dup"); } } while (false); | |||
3148 | Append( itCut->second, nCut ); | |||
3149 | aPasteCutMap.erase( itCut ); | |||
3150 | } | |||
3151 | else | |||
3152 | { | |||
3153 | OSL_FAIL( "ScChangeTrack::Undo: nCut not found" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/chgtrack.cxx" ":" "3153" ": "), "%s", "ScChangeTrack::Undo: nCut not found" ); } } while (false); | |||
3154 | } | |||
3155 | } | |||
3156 | EndBlockModify( nEnd ); | |||
3157 | ResetLastCut(); | |||
3158 | nStartLastCut = nStart; | |||
3159 | nEndLastCut = nEnd; | |||
3160 | pLastCutMove.reset(pMove); | |||
3161 | SetLastCutMoveRange( | |||
3162 | pMove->GetFromRange().MakeRange(), &rDoc ); | |||
3163 | } | |||
3164 | else | |||
3165 | delete pMove; | |||
3166 | } | |||
3167 | else | |||
3168 | delete pAct; | |||
3169 | } | |||
3170 | EndBlockModify( nEndAction ); | |||
3171 | } | |||
3172 | ||||
3173 | // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong | |||
3174 | if ( bMerge ) | |||
3175 | { | |||
3176 | SetMergeState( SC_CTMS_OTHER ); | |||
3177 | } | |||
3178 | } | |||
3179 | ||||
3180 | bool ScChangeTrack::MergeIgnore( const ScChangeAction& rAction, sal_uLong nFirstMerge ) | |||
3181 | { | |||
3182 | if ( rAction.IsRejected() ) | |||
3183 | return true; // There's still a suitable Reject Action coming | |||
3184 | ||||
3185 | if ( rAction.IsRejecting() && rAction.GetRejectAction() >= nFirstMerge ) | |||
3186 | return true; // There it is | |||
3187 | ||||
3188 | return false; // Everything else | |||
3189 | } | |||
3190 | ||||
3191 | void ScChangeTrack::MergePrepare( const ScChangeAction* pFirstMerge, bool bShared ) | |||
3192 | { | |||
3193 | SetMergeState( SC_CTMS_PREPARE ); | |||
3194 | sal_uLong nFirstMerge = pFirstMerge->GetActionNumber(); | |||
3195 | ScChangeAction* pAct = GetLast(); | |||
3196 | if ( pAct ) | |||
3197 | { | |||
3198 | SetLastMerge( pAct->GetActionNumber() ); | |||
3199 | while ( pAct ) | |||
3200 | { // Traverse backwards; Deletes in right order | |||
3201 | // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong | |||
3202 | if ( bShared || !ScChangeTrack::MergeIgnore( *pAct, nFirstMerge ) ) | |||
3203 | { | |||
3204 | if ( pAct->IsDeleteType() ) | |||
3205 | { | |||
3206 | if ( static_cast<ScChangeActionDel*>(pAct)->IsTopDelete() ) | |||
3207 | { | |||
3208 | SetInDeleteTop( true ); | |||
3209 | SetInDeleteRange( static_cast<ScChangeActionDel*>(pAct)-> | |||
3210 | GetOverAllRange().MakeRange() ); | |||
3211 | } | |||
3212 | } | |||
3213 | UpdateReference( pAct, true ); | |||
3214 | SetInDeleteTop( false ); | |||
3215 | pAct->DeleteCellEntries(); // Else segfault in Track Clear() | |||
3216 | } | |||
3217 | pAct = ( pAct == pFirstMerge ? nullptr : pAct->GetPrev() ); | |||
3218 | } | |||
3219 | } | |||
3220 | SetMergeState( SC_CTMS_OTHER ); // Preceding by default MergeOther! | |||
3221 | } | |||
3222 | ||||
3223 | void ScChangeTrack::MergeOwn( ScChangeAction* pAct, sal_uLong nFirstMerge, bool bShared ) | |||
3224 | { | |||
3225 | // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong | |||
3226 | if ( !bShared && ScChangeTrack::MergeIgnore( *pAct, nFirstMerge ) ) | |||
3227 | return; | |||
3228 | ||||
3229 | SetMergeState( SC_CTMS_OWN ); | |||
3230 | if ( pAct->IsDeleteType() ) | |||
3231 | { | |||
3232 | if ( static_cast<ScChangeActionDel*>(pAct)->IsTopDelete() ) | |||
3233 | { | |||
3234 | SetInDeleteTop( true ); | |||
3235 | SetInDeleteRange( static_cast<ScChangeActionDel*>(pAct)-> | |||
3236 | GetOverAllRange().MakeRange() ); | |||
3237 | } | |||
3238 | } | |||
3239 | UpdateReference( pAct, false ); | |||
3240 | SetInDeleteTop( false ); | |||
3241 | SetMergeState( SC_CTMS_OTHER ); // Preceding by default MergeOther! | |||
3242 | } | |||
3243 | ||||
3244 | void ScChangeTrack::UpdateReference( ScChangeAction* pAct, bool bUndo ) | |||
3245 | { | |||
3246 | ScChangeActionType eActType = pAct->GetType(); | |||
3247 | if ( eActType == SC_CAT_CONTENT || eActType == SC_CAT_REJECT ) | |||
3248 | return ; | |||
3249 | ||||
3250 | // Formula cells are not in the Document! | |||
3251 | bool bOldAutoCalc = rDoc.GetAutoCalc(); | |||
3252 | rDoc.SetAutoCalc( false ); | |||
3253 | bool bOldNoListening = rDoc.GetNoListening(); | |||
3254 | rDoc.SetNoListening( true ); | |||
3255 | ||||
3256 | // Formula cells ExpandRefs synchronized to the ones in the Document! | |||
3257 | bool bOldExpandRefs = rDoc.IsExpandRefs(); | |||
3258 | if ( (!bUndo && pAct->IsInsertType()) || (bUndo && pAct->IsDeleteType()) ) | |||
3259 | rDoc.SetExpandRefs( SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule ::Calc)) )->GetInputOptions().GetExpandRefs() ); | |||
3260 | ||||
3261 | if ( pAct->IsDeleteType() ) | |||
3262 | { | |||
3263 | SetInDeleteUndo( bUndo ); | |||
3264 | SetInDelete( true ); | |||
3265 | } | |||
3266 | else if ( GetMergeState() == SC_CTMS_OWN ) | |||
3267 | { | |||
3268 | // Recover references of formula cells | |||
3269 | // Previous MergePrepare behaved like a Delete when Inserting | |||
3270 | if ( pAct->IsInsertType() ) | |||
3271 | SetInDeleteUndo( true ); | |||
3272 | } | |||
3273 | ||||
3274 | // First the generated ones, as if they were tracked previously! | |||
3275 | if ( pFirstGeneratedDelContent ) | |||
3276 | UpdateReference( reinterpret_cast<ScChangeAction**>(&pFirstGeneratedDelContent), pAct, | |||
3277 | bUndo ); | |||
3278 | UpdateReference( &pFirst, pAct, bUndo ); | |||
3279 | ||||
3280 | SetInDelete( false ); | |||
3281 | SetInDeleteUndo( false ); | |||
3282 | ||||
3283 | rDoc.SetExpandRefs( bOldExpandRefs ); | |||
3284 | rDoc.SetNoListening( bOldNoListening ); | |||
3285 | rDoc.SetAutoCalc( bOldAutoCalc ); | |||
3286 | } | |||
3287 | ||||
3288 | void ScChangeTrack::UpdateReference( ScChangeAction** ppFirstAction, | |||
3289 | ScChangeAction* pAct, bool bUndo ) | |||
3290 | { | |||
3291 | ScChangeActionType eActType = pAct->GetType(); | |||
3292 | bool bGeneratedDelContents = | |||
3293 | ( ppFirstAction == reinterpret_cast<ScChangeAction**>(&pFirstGeneratedDelContent) ); | |||
3294 | const ScBigRange& rOrgRange = pAct->GetBigRange(); | |||
3295 | ScBigRange aRange( rOrgRange ); | |||
3296 | ScBigRange aDelRange( rOrgRange ); | |||
3297 | sal_Int32 nDx, nDy, nDz; | |||
3298 | nDx = nDy = nDz = 0; | |||
3299 | UpdateRefMode eMode = URM_INSDEL; | |||
3300 | bool bDel = false; | |||
3301 | switch ( eActType ) | |||
3302 | { | |||
3303 | case SC_CAT_INSERT_COLS : | |||
3304 | aRange.aEnd.SetCol( nInt32Max ); | |||
3305 | nDx = rOrgRange.aEnd.Col() - rOrgRange.aStart.Col() + 1; | |||
3306 | break; | |||
3307 | case SC_CAT_INSERT_ROWS : | |||
3308 | aRange.aEnd.SetRow( nInt32Max ); | |||
3309 | nDy = rOrgRange.aEnd.Row() - rOrgRange.aStart.Row() + 1; | |||
3310 | break; | |||
3311 | case SC_CAT_INSERT_TABS : | |||
3312 | aRange.aEnd.SetTab( nInt32Max ); | |||
3313 | nDz = rOrgRange.aEnd.Tab() - rOrgRange.aStart.Tab() + 1; | |||
3314 | break; | |||
3315 | case SC_CAT_DELETE_COLS : | |||
3316 | aRange.aEnd.SetCol( nInt32Max ); | |||
3317 | nDx = -(rOrgRange.aEnd.Col() - rOrgRange.aStart.Col() + 1); | |||
3318 | aDelRange.aEnd.SetCol( aDelRange.aStart.Col() - nDx - 1 ); | |||
3319 | bDel = true; | |||
3320 | break; | |||
3321 | case SC_CAT_DELETE_ROWS : | |||
3322 | aRange.aEnd.SetRow( nInt32Max ); | |||
3323 | nDy = -(rOrgRange.aEnd.Row() - rOrgRange.aStart.Row() + 1); | |||
3324 | aDelRange.aEnd.SetRow( aDelRange.aStart.Row() - nDy - 1 ); | |||
3325 | bDel = true; | |||
3326 | break; | |||
3327 | case SC_CAT_DELETE_TABS : | |||
3328 | aRange.aEnd.SetTab( nInt32Max ); | |||
3329 | nDz = -(rOrgRange.aEnd.Tab() - rOrgRange.aStart.Tab() + 1); | |||
3330 | aDelRange.aEnd.SetTab( aDelRange.aStart.Tab() - nDz - 1 ); | |||
3331 | bDel = true; | |||
3332 | break; | |||
3333 | case SC_CAT_MOVE : | |||
3334 | eMode = URM_MOVE; | |||
3335 | static_cast<ScChangeActionMove*>(pAct)->GetDelta( nDx, nDy, nDz ); | |||
3336 | break; | |||
3337 | default: | |||
3338 | OSL_FAIL( "ScChangeTrack::UpdateReference: unknown Type" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/chgtrack.cxx" ":" "3338" ": "), "%s", "ScChangeTrack::UpdateReference: unknown Type" ); } } while (false); | |||
3339 | } | |||
3340 | if ( bUndo ) | |||
3341 | { | |||
3342 | nDx = -nDx; | |||
3343 | nDy = -nDy; | |||
3344 | nDz = -nDz; | |||
3345 | } | |||
3346 | if ( bDel ) | |||
3347 | { // For this mechanism we assume: | |||
3348 | // There's only a whole, simple deleted row/column | |||
3349 | ScChangeActionDel* pActDel = static_cast<ScChangeActionDel*>(pAct); | |||
3350 | if ( !bUndo ) | |||
3351 | { // Delete | |||
3352 | ScChangeActionType eInsType = SC_CAT_NONE; // for Insert Undo "Deletes" | |||
3353 | switch ( eActType ) | |||
3354 | { | |||
3355 | case SC_CAT_DELETE_COLS : | |||
3356 | eInsType = SC_CAT_INSERT_COLS; | |||
3357 | break; | |||
3358 | case SC_CAT_DELETE_ROWS : | |||
3359 | eInsType = SC_CAT_INSERT_ROWS; | |||
3360 | break; | |||
3361 | case SC_CAT_DELETE_TABS : | |||
3362 | eInsType = SC_CAT_INSERT_TABS; | |||
3363 | break; | |||
3364 | default: | |||
3365 | { | |||
3366 | // added to avoid warnings | |||
3367 | } | |||
3368 | } | |||
3369 | for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) | |||
3370 | { | |||
3371 | if ( p == pAct ) | |||
3372 | continue; // for | |||
3373 | bool bUpdate = true; | |||
3374 | if ( GetMergeState() == SC_CTMS_OTHER && | |||
3375 | p->GetActionNumber() <= GetLastMerge() ) | |||
3376 | { // Delete in merged Document, Action in the one to be merged | |||
3377 | if ( p->IsInsertType() ) | |||
3378 | { | |||
3379 | // On Insert only adjust references if the Delete does | |||
3380 | // not intersect the Insert | |||
3381 | if ( !aDelRange.Intersects( p->GetBigRange() ) ) | |||
3382 | p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); | |||
3383 | bUpdate = false; | |||
3384 | } | |||
3385 | else if ( p->GetType() == SC_CAT_CONTENT && | |||
3386 | p->IsDeletedInDelType( eInsType ) ) | |||
3387 | { // Content in Insert Undo "Delete" | |||
3388 | // Do not adjust if this Delete would be in the Insert "Delete" (was just moved) | |||
3389 | if ( aDelRange.In( p->GetBigRange().aStart ) ) | |||
3390 | bUpdate = false; | |||
3391 | else | |||
3392 | { | |||
3393 | const ScChangeActionLinkEntry* pLink = p->GetDeletedIn(); | |||
3394 | while ( pLink && bUpdate ) | |||
3395 | { | |||
3396 | const ScChangeAction* pDel = pLink->GetAction(); | |||
3397 | if ( pDel && pDel->GetType() == eInsType && | |||
3398 | pDel->GetBigRange().In( aDelRange ) ) | |||
3399 | bUpdate = false; | |||
3400 | pLink = pLink->GetNext(); | |||
3401 | } | |||
3402 | } | |||
3403 | } | |||
3404 | if ( !bUpdate ) | |||
3405 | continue; // for | |||
3406 | } | |||
3407 | if ( aDelRange.In( p->GetBigRange() ) ) | |||
3408 | { | |||
3409 | // Do not adjust within a just deleted range, | |||
3410 | // instead assign the range. | |||
3411 | // Stack up ranges that have been deleted multiple times. | |||
3412 | // Intersecting Deletes cause "multiple delete" to be set. | |||
3413 | if ( !p->IsDeletedInDelType( eActType ) ) | |||
3414 | { | |||
3415 | p->SetDeletedIn( pActDel ); | |||
3416 | // Add GeneratedDelContent to the to-be-deleted list | |||
3417 | if ( bGeneratedDelContents ) | |||
3418 | pActDel->AddContent( static_cast<ScChangeActionContent*>(p) ); | |||
3419 | } | |||
3420 | bUpdate = false; | |||
3421 | } | |||
3422 | else | |||
3423 | { | |||
3424 | // Cut off inserted ranges, if Start/End is within the Delete, | |||
3425 | // but the Insert is not completely within the Delete or | |||
3426 | // the Delete is not completely within the Insert. | |||
3427 | // The Delete remembers which Insert it has cut off from; | |||
3428 | // it can also just be a single Insert (because Delete has | |||
3429 | // a single column/is a single row). | |||
3430 | // There can be a lot of cut-off Moves. | |||
3431 | // | |||
3432 | // ! A Delete is always a single column/a single row, therefore | |||
3433 | // ! 1 without calculating the intersection. | |||
3434 | switch ( p->GetType() ) | |||
3435 | { | |||
3436 | case SC_CAT_INSERT_COLS : | |||
3437 | if ( eActType == SC_CAT_DELETE_COLS ) | |||
3438 | { | |||
3439 | if ( aDelRange.In( p->GetBigRange().aStart ) ) | |||
3440 | { | |||
3441 | pActDel->SetCutOffInsert( | |||
3442 | static_cast<ScChangeActionIns*>(p), 1 ); | |||
3443 | p->GetBigRange().aStart.IncCol(); | |||
3444 | } | |||
3445 | else if ( aDelRange.In( p->GetBigRange().aEnd ) ) | |||
3446 | { | |||
3447 | pActDel->SetCutOffInsert( | |||
3448 | static_cast<ScChangeActionIns*>(p), -1 ); | |||
3449 | p->GetBigRange().aEnd.IncCol( -1 ); | |||
3450 | } | |||
3451 | } | |||
3452 | break; | |||
3453 | case SC_CAT_INSERT_ROWS : | |||
3454 | if ( eActType == SC_CAT_DELETE_ROWS ) | |||
3455 | { | |||
3456 | if ( aDelRange.In( p->GetBigRange().aStart ) ) | |||
3457 | { | |||
3458 | pActDel->SetCutOffInsert( | |||
3459 | static_cast<ScChangeActionIns*>(p), 1 ); | |||
3460 | p->GetBigRange().aStart.IncRow(); | |||
3461 | } | |||
3462 | else if ( aDelRange.In( p->GetBigRange().aEnd ) ) | |||
3463 | { | |||
3464 | pActDel->SetCutOffInsert( | |||
3465 | static_cast<ScChangeActionIns*>(p), -1 ); | |||
3466 | p->GetBigRange().aEnd.IncRow( -1 ); | |||
3467 | } | |||
3468 | } | |||
3469 | break; | |||
3470 | case SC_CAT_INSERT_TABS : | |||
3471 | if ( eActType == SC_CAT_DELETE_TABS ) | |||
3472 | { | |||
3473 | if ( aDelRange.In( p->GetBigRange().aStart ) ) | |||
3474 | { | |||
3475 | pActDel->SetCutOffInsert( | |||
3476 | static_cast<ScChangeActionIns*>(p), 1 ); | |||
3477 | p->GetBigRange().aStart.IncTab(); | |||
3478 | } | |||
3479 | else if ( aDelRange.In( p->GetBigRange().aEnd ) ) | |||
3480 | { | |||
3481 | pActDel->SetCutOffInsert( | |||
3482 | static_cast<ScChangeActionIns*>(p), -1 ); | |||
3483 | p->GetBigRange().aEnd.IncTab( -1 ); | |||
3484 | } | |||
3485 | } | |||
3486 | break; | |||
3487 | case SC_CAT_MOVE : | |||
3488 | { | |||
3489 | ScChangeActionMove* pMove = static_cast<ScChangeActionMove*>(p); | |||
3490 | short nFrom = 0; | |||
3491 | short nTo = 0; | |||
3492 | if ( aDelRange.In( pMove->GetBigRange().aStart ) ) | |||
3493 | nTo = 1; | |||
3494 | else if ( aDelRange.In( pMove->GetBigRange().aEnd ) ) | |||
3495 | nTo = -1; | |||
3496 | if ( aDelRange.In( pMove->GetFromRange().aStart ) ) | |||
3497 | nFrom = 1; | |||
3498 | else if ( aDelRange.In( pMove->GetFromRange().aEnd ) ) | |||
3499 | nFrom = -1; | |||
3500 | if ( nFrom ) | |||
3501 | { | |||
3502 | switch ( eActType ) | |||
3503 | { | |||
3504 | case SC_CAT_DELETE_COLS : | |||
3505 | if ( nFrom > 0 ) | |||
3506 | pMove->GetFromRange().aStart.IncCol( nFrom ); | |||
3507 | else | |||
3508 | pMove->GetFromRange().aEnd.IncCol( nFrom ); | |||
3509 | break; | |||
3510 | case SC_CAT_DELETE_ROWS : | |||
3511 | if ( nFrom > 0 ) | |||
3512 | pMove->GetFromRange().aStart.IncRow( nFrom ); | |||
3513 | else | |||
3514 | pMove->GetFromRange().aEnd.IncRow( nFrom ); | |||
3515 | break; | |||
3516 | case SC_CAT_DELETE_TABS : | |||
3517 | if ( nFrom > 0 ) | |||
3518 | pMove->GetFromRange().aStart.IncTab( nFrom ); | |||
3519 | else | |||
3520 | pMove->GetFromRange().aEnd.IncTab( nFrom ); | |||
3521 | break; | |||
3522 | default: | |||
3523 | { | |||
3524 | // added to avoid warnings | |||
3525 | } | |||
3526 | } | |||
3527 | } | |||
3528 | if ( nTo ) | |||
3529 | { | |||
3530 | switch ( eActType ) | |||
3531 | { | |||
3532 | case SC_CAT_DELETE_COLS : | |||
3533 | if ( nTo > 0 ) | |||
3534 | pMove->GetBigRange().aStart.IncCol( nTo ); | |||
3535 | else | |||
3536 | pMove->GetBigRange().aEnd.IncCol( nTo ); | |||
3537 | break; | |||
3538 | case SC_CAT_DELETE_ROWS : | |||
3539 | if ( nTo > 0 ) | |||
3540 | pMove->GetBigRange().aStart.IncRow( nTo ); | |||
3541 | else | |||
3542 | pMove->GetBigRange().aEnd.IncRow( nTo ); | |||
3543 | break; | |||
3544 | case SC_CAT_DELETE_TABS : | |||
3545 | if ( nTo > 0 ) | |||
3546 | pMove->GetBigRange().aStart.IncTab( nTo ); | |||
3547 | else | |||
3548 | pMove->GetBigRange().aEnd.IncTab( nTo ); | |||
3549 | break; | |||
3550 | default: | |||
3551 | { | |||
3552 | // added to avoid warnings | |||
3553 | } | |||
3554 | } | |||
3555 | } | |||
3556 | if ( nFrom || nTo ) | |||
3557 | { | |||
3558 | ScChangeActionDelMoveEntry* pLink = | |||
3559 | pActDel->AddCutOffMove( pMove, nFrom, nTo ); | |||
3560 | pMove->AddLink( pActDel, pLink ); | |||
3561 | } | |||
3562 | } | |||
3563 | break; | |||
3564 | default: | |||
3565 | { | |||
3566 | // added to avoid warnings | |||
3567 | } | |||
3568 | } | |||
3569 | } | |||
3570 | if ( bUpdate ) | |||
3571 | { | |||
3572 | p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); | |||
3573 | if ( p->GetType() == eActType && !p->IsRejected() && | |||
3574 | !pActDel->IsDeletedIn() && | |||
3575 | p->GetBigRange().In( aDelRange ) ) | |||
3576 | pActDel->SetDeletedIn( p ); // Slipped underneath it | |||
3577 | } | |||
3578 | } | |||
3579 | } | |||
3580 | else | |||
3581 | { // Undo Delete | |||
3582 | for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) | |||
3583 | { | |||
3584 | if ( p == pAct ) | |||
3585 | continue; // for | |||
3586 | bool bUpdate = true; | |||
3587 | if ( aDelRange.In( p->GetBigRange() ) ) | |||
3588 | { | |||
3589 | // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong | |||
3590 | if ( GetMergeState() == SC_CTMS_UNDO && !p->IsDeletedIn( pAct ) && pAct->IsDeleteType() && | |||
3591 | ( p->GetType() == SC_CAT_CONTENT || | |||
3592 | p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS || | |||
3593 | p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) ) | |||
3594 | { | |||
3595 | p->SetDeletedIn( pAct ); | |||
3596 | } | |||
3597 | ||||
3598 | if ( p->IsDeletedInDelType( eActType ) ) | |||
3599 | { | |||
3600 | if ( p->IsDeletedIn( pActDel ) ) | |||
3601 | { | |||
3602 | if ( p->GetType() != SC_CAT_CONTENT || | |||
3603 | static_cast<ScChangeActionContent*>(p)->IsTopContent() ) | |||
3604 | { // First really remove the TopContent | |||
3605 | p->RemoveDeletedIn( pActDel ); | |||
3606 | // Do NOT delete GeneratedDelContent from the list, we might need | |||
3607 | // it later on for Reject; we delete in DeleteCellEntries | |||
3608 | } | |||
3609 | } | |||
3610 | bUpdate = false; | |||
3611 | } | |||
3612 | else if ( eActType != SC_CAT_DELETE_TABS && | |||
3613 | p->IsDeletedInDelType( SC_CAT_DELETE_TABS ) ) | |||
3614 | { // Do not update in deleted Tables except for when moving Tables | |||
3615 | bUpdate = false; | |||
3616 | } | |||
3617 | if ( p->GetType() == eActType && pActDel->IsDeletedIn( p ) ) | |||
3618 | { | |||
3619 | pActDel->RemoveDeletedIn( p );// Slipped underneath | |||
3620 | bUpdate = true; | |||
3621 | } | |||
3622 | } | |||
3623 | if ( bUpdate ) | |||
3624 | p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); | |||
3625 | } | |||
3626 | if ( !bGeneratedDelContents ) | |||
3627 | { // These are else also needed for the real Undo | |||
3628 | pActDel->UndoCutOffInsert(); | |||
3629 | pActDel->UndoCutOffMoves(); | |||
3630 | } | |||
3631 | } | |||
3632 | } | |||
3633 | else if ( eActType == SC_CAT_MOVE ) | |||
3634 | { | |||
3635 | ScChangeActionMove* pActMove = static_cast<ScChangeActionMove*>(pAct); | |||
3636 | bool bLastCutMove = ( pActMove == pLastCutMove.get() ); | |||
3637 | const ScBigRange& rTo = pActMove->GetBigRange(); | |||
3638 | const ScBigRange& rFrom = pActMove->GetFromRange(); | |||
3639 | if ( !bUndo ) | |||
3640 | { // Move | |||
3641 | for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) | |||
3642 | { | |||
3643 | if ( p == pAct ) | |||
3644 | continue; // for | |||
3645 | if ( p->GetType() == SC_CAT_CONTENT ) | |||
3646 | { | |||
3647 | // Delete content in Target (Move Content to Source) | |||
3648 | if ( rTo.In( p->GetBigRange() ) ) | |||
3649 | { | |||
3650 | if ( !p->IsDeletedIn( pActMove ) ) | |||
3651 | { | |||
3652 | p->SetDeletedIn( pActMove ); | |||
3653 | // Add GeneratedDelContent to the to-be-deleted list | |||
3654 | if ( bGeneratedDelContents ) | |||
3655 | pActMove->AddContent( static_cast<ScChangeActionContent*>(p) ); | |||
3656 | } | |||
3657 | } | |||
3658 | else if ( bLastCutMove && | |||
3659 | p->GetActionNumber() > nEndLastCut && | |||
3660 | rFrom.In( p->GetBigRange() ) ) | |||
3661 | { // Paste Cut: insert new Content inserted after stays | |||
3662 | // Split up the ContentChain | |||
3663 | ScChangeActionContent *pHere, *pTmp; | |||
3664 | pHere = static_cast<ScChangeActionContent*>(p); | |||
3665 | for (;;) | |||
3666 | { | |||
3667 | pTmp = pHere->GetPrevContent(); | |||
3668 | if (!pTmp || pTmp->GetActionNumber() <= nEndLastCut) | |||
3669 | break; | |||
3670 | pHere = pTmp; | |||
3671 | } | |||
3672 | if ( pTmp ) | |||
3673 | { // Becomes TopContent of the Move | |||
3674 | pTmp->SetNextContent( nullptr ); | |||
3675 | pHere->SetPrevContent( nullptr ); | |||
3676 | } | |||
3677 | do | |||
3678 | { // Recover dependency from FromRange | |||
3679 | AddDependentWithNotify( pActMove, pHere ); | |||
3680 | } while ( ( pHere = pHere->GetNextContent() ) != nullptr ); | |||
3681 | } | |||
3682 | // #i87003# [Collaboration] Move range and insert content in FromRange is not merged correctly | |||
3683 | else if ( ( GetMergeState() != SC_CTMS_PREPARE && GetMergeState() != SC_CTMS_OWN ) || p->GetActionNumber() <= pAct->GetActionNumber() ) | |||
3684 | p->UpdateReference( this, eMode, rFrom, nDx, nDy, nDz ); | |||
3685 | } | |||
3686 | } | |||
3687 | } | |||
3688 | else | |||
3689 | { // Undo Move | |||
3690 | bool bActRejected = pActMove->IsRejected(); | |||
3691 | for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) | |||
3692 | { | |||
3693 | if ( p == pAct ) | |||
3694 | continue; // for | |||
3695 | if ( p->GetType() == SC_CAT_CONTENT ) | |||
3696 | { | |||
3697 | // Move Content into Target if not deleted else to delete (FIXME: What?) | |||
3698 | if ( p->IsDeletedIn( pActMove ) ) | |||
3699 | { | |||
3700 | if ( static_cast<ScChangeActionContent*>(p)->IsTopContent() ) | |||
3701 | { // First really remove the TopContent | |||
3702 | p->RemoveDeletedIn( pActMove ); | |||
3703 | // Do NOT delete GeneratedDelContent from the list, we might need | |||
3704 | // it later on for Reject; we delete in DeleteCellEntries | |||
3705 | } | |||
3706 | } | |||
3707 | // #i87003# [Collaboration] Move range and insert content in FromRange is not merged correctly | |||
3708 | else if ( ( GetMergeState() != SC_CTMS_PREPARE && GetMergeState() != SC_CTMS_OWN ) || p->GetActionNumber() <= pAct->GetActionNumber() ) | |||
3709 | p->UpdateReference( this, eMode, rTo, nDx, nDy, nDz ); | |||
3710 | if ( bActRejected && | |||
3711 | static_cast<ScChangeActionContent*>(p)->IsTopContent() && | |||
3712 | rFrom.In( p->GetBigRange() ) ) | |||
3713 | { // Recover dependency to write Content | |||
3714 | ScChangeActionLinkEntry* pLink = | |||
3715 | pActMove->AddDependent( p ); | |||
3716 | p->AddLink( pActMove, pLink ); | |||
3717 | } | |||
3718 | } | |||
3719 | } | |||
3720 | } | |||
3721 | } | |||
3722 | else | |||
3723 | { // Insert/Undo Insert | |||
3724 | switch ( GetMergeState() ) | |||
3725 | { | |||
3726 | case SC_CTMS_NONE : | |||
3727 | case SC_CTMS_OTHER : | |||
3728 | { | |||
3729 | for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) | |||
3730 | { | |||
3731 | if ( p == pAct ) | |||
3732 | continue; // for | |||
3733 | p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); | |||
3734 | } | |||
3735 | } | |||
3736 | break; | |||
3737 | case SC_CTMS_PREPARE : | |||
3738 | { | |||
3739 | // "Delete" in Insert-Undo | |||
3740 | const ScChangeActionLinkEntry* pLink = pAct->GetFirstDependentEntry(); | |||
3741 | while ( pLink ) | |||
3742 | { | |||
3743 | ScChangeAction* p = const_cast<ScChangeAction*>(pLink->GetAction()); | |||
3744 | if ( p ) | |||
3745 | p->SetDeletedIn( pAct ); | |||
3746 | pLink = pLink->GetNext(); | |||
3747 | } | |||
3748 | ||||
3749 | // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly | |||
3750 | for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) | |||
3751 | { | |||
3752 | if ( !p->IsDeletedIn( pAct ) && pAct->IsInsertType() && | |||
3753 | // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong | |||
3754 | ( p->GetType() == SC_CAT_CONTENT || | |||
3755 | p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS || | |||
3756 | p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) && | |||
3757 | pAct->GetBigRange().Intersects( p->GetBigRange() ) ) | |||
3758 | { | |||
3759 | p->SetDeletedIn( pAct ); | |||
3760 | } | |||
3761 | } | |||
3762 | ||||
3763 | for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) | |||
3764 | { | |||
3765 | if ( p == pAct ) | |||
3766 | continue; // for | |||
3767 | if ( !p->IsDeletedIn( pAct ) | |||
3768 | // #i95212# [Collaboration] Bad handling of row insertion in shared spreadsheet | |||
3769 | && p->GetActionNumber() <= pAct->GetActionNumber() ) | |||
3770 | { | |||
3771 | p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); | |||
3772 | } | |||
3773 | } | |||
3774 | } | |||
3775 | break; | |||
3776 | case SC_CTMS_OWN : | |||
3777 | { | |||
3778 | for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) | |||
3779 | { | |||
3780 | if ( p == pAct ) | |||
3781 | continue; // for | |||
3782 | if ( !p->IsDeletedIn( pAct ) | |||
3783 | // #i95212# [Collaboration] Bad handling of row insertion in shared spreadsheet | |||
3784 | && p->GetActionNumber() <= pAct->GetActionNumber() ) | |||
3785 | { | |||
3786 | p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); | |||
3787 | } | |||
3788 | } | |||
3789 | // Undo "Delete" in Insert-Undo | |||
3790 | const ScChangeActionLinkEntry* pLink = pAct->GetFirstDependentEntry(); | |||
3791 | while ( pLink ) | |||
3792 | { | |||
3793 | ScChangeAction* p = const_cast<ScChangeAction*>(pLink->GetAction()); | |||
3794 | if ( p ) | |||
3795 | p->RemoveDeletedIn( pAct ); | |||
3796 | pLink = pLink->GetNext(); | |||
3797 | } | |||
3798 | ||||
3799 | // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly | |||
3800 | for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) | |||
3801 | { | |||
3802 | if ( p->IsDeletedIn( pAct ) && pAct->IsInsertType() && | |||
3803 | // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong | |||
3804 | ( p->GetType() == SC_CAT_CONTENT || | |||
3805 | p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS || | |||
3806 | p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) && | |||
3807 | pAct->GetBigRange().Intersects( p->GetBigRange() ) ) | |||
3808 | { | |||
3809 | p->RemoveDeletedIn( pAct ); | |||
3810 | } | |||
3811 | } | |||
3812 | } | |||
3813 | break; | |||
3814 | // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong | |||
3815 | case SC_CTMS_UNDO : | |||
3816 | { | |||
3817 | for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) | |||
3818 | { | |||
3819 | if ( !p->IsDeletedIn( pAct ) && pAct->IsInsertType() && | |||
3820 | ( p->GetType() == SC_CAT_CONTENT || | |||
3821 | p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS || | |||
3822 | p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) && | |||
3823 | pAct->GetBigRange().Intersects( p->GetBigRange() ) ) | |||
3824 | { | |||
3825 | p->SetDeletedIn( pAct ); | |||
3826 | } | |||
3827 | } | |||
3828 | ||||
3829 | for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) | |||
3830 | { | |||
3831 | if ( p == pAct ) | |||
3832 | { | |||
3833 | continue; | |||
3834 | } | |||
3835 | if ( !p->IsDeletedIn( pAct ) && p->GetActionNumber() <= pAct->GetActionNumber() ) | |||
3836 | { | |||
3837 | p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); | |||
3838 | } | |||
3839 | } | |||
3840 | } | |||
3841 | break; | |||
3842 | } | |||
3843 | } | |||
3844 | } | |||
3845 | ||||
3846 | void ScChangeTrack::GetDependents( ScChangeAction* pAct, | |||
3847 | ScChangeActionMap& rMap, bool bListMasterDelete, bool bAllFlat ) const | |||
3848 | { | |||
3849 | //TODO: bAllFlat==TRUE: called internally from Accept or Reject | |||
3850 | //TODO: => Generated will not be added | |||
3851 | bool bIsDelete = pAct->IsDeleteType(); | |||
3852 | bool bIsMasterDelete = ( bListMasterDelete && pAct->IsMasterDelete() ); | |||
3853 | ||||
3854 | const ScChangeAction* pCur = nullptr; | |||
3855 | ::std::stack<ScChangeAction*> cStack; | |||
3856 | cStack.push(pAct); | |||
3857 | ||||
3858 | while ( !cStack.empty() ) | |||
3859 | { | |||
3860 | pCur = cStack.top(); | |||
3861 | cStack.pop(); | |||
3862 | ||||
3863 | if ( pCur->IsInsertType() ) | |||
3864 | { | |||
3865 | const ScChangeActionLinkEntry* pL = pCur->GetFirstDependentEntry(); | |||
3866 | while ( pL ) | |||
3867 | { | |||
3868 | ScChangeAction* p = const_cast<ScChangeAction*>(pL->GetAction()); | |||
3869 | if ( p != pAct ) | |||
3870 | { | |||
3871 | if ( bAllFlat ) | |||
3872 | { | |||
3873 | sal_uLong n = p->GetActionNumber(); | |||
3874 | if ( !IsGenerated( n ) && rMap.insert( ::std::make_pair( n, p ) ).second ) | |||
3875 | if ( p->HasDependent() ) | |||
3876 | cStack.push( p ); | |||
3877 | } | |||
3878 | else | |||
3879 | { | |||
3880 | if ( p->GetType() == SC_CAT_CONTENT ) | |||
3881 | { | |||
3882 | if ( static_cast<ScChangeActionContent*>(p)->IsTopContent() ) | |||
3883 | rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) ); | |||
3884 | } | |||
3885 | else | |||
3886 | rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) ); | |||
3887 | } | |||
3888 | } | |||
3889 | pL = pL->GetNext(); | |||
3890 | } | |||
3891 | } | |||
3892 | else if ( pCur->IsDeleteType() ) | |||
3893 | { | |||
3894 | if ( bIsDelete ) | |||
3895 | { // Contents of deleted Ranges are only of interest on Delete | |||
3896 | ScChangeActionDel* pDel = const_cast<ScChangeActionDel*>(static_cast<const ScChangeActionDel*>(pCur)); | |||
3897 | if ( !bAllFlat && bIsMasterDelete && pCur == pAct ) | |||
3898 | { | |||
3899 | // Corresponding Deletes to this Delete to the same level, | |||
3900 | // if this Delete is at the top of a Row | |||
3901 | ScChangeActionType eType = pDel->GetType(); | |||
3902 | ScChangeAction* p = pDel; | |||
3903 | for (;;) | |||
3904 | { | |||
3905 | p = p->GetPrev(); | |||
3906 | if (!p || p->GetType() != eType || | |||
3907 | static_cast<ScChangeActionDel*>(p)->IsTopDelete() ) | |||
3908 | break; | |||
3909 | rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) ); | |||
3910 | } | |||
3911 | // delete this in the map too | |||
3912 | rMap.insert( ::std::make_pair( pAct->GetActionNumber(), pAct ) ); | |||
3913 | } | |||
3914 | else | |||
3915 | { | |||
3916 | const ScChangeActionLinkEntry* pL = pCur->GetFirstDeletedEntry(); | |||
3917 | while ( pL ) | |||
3918 | { | |||
3919 | ScChangeAction* p = const_cast<ScChangeAction*>(pL->GetAction()); | |||
3920 | if ( p != pAct ) | |||
3921 | { | |||
3922 | if ( bAllFlat ) | |||
3923 | { | |||
3924 | // Only a TopContent of a chain is in LinkDeleted | |||
3925 | sal_uLong n = p->GetActionNumber(); | |||
3926 | if ( !IsGenerated( n ) && rMap.insert( ::std::make_pair( n, p ) ).second ) | |||
3927 | if ( p->HasDeleted() || | |||
3928 | p->GetType() == SC_CAT_CONTENT ) | |||
3929 | cStack.push( p ); | |||
3930 | } | |||
3931 | else | |||
3932 | { | |||
3933 | if ( p->IsDeleteType() ) | |||
3934 | { // Further TopDeletes to same level: it's not rejectable | |||
3935 | if ( static_cast<ScChangeActionDel*>(p)->IsTopDelete() ) | |||
3936 | rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) ); | |||
3937 | } | |||
3938 | else | |||
3939 | rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) ); | |||
3940 | } | |||
3941 | } | |||
3942 | pL = pL->GetNext(); | |||
3943 | } | |||
3944 | } | |||
3945 | } | |||
3946 | } | |||
3947 | else if ( pCur->GetType() == SC_CAT_MOVE ) | |||
3948 | { | |||
3949 | // Deleted Contents in ToRange | |||
3950 | const ScChangeActionLinkEntry* pL = pCur->GetFirstDeletedEntry(); | |||
3951 | while ( pL ) | |||
3952 | { | |||
3953 | ScChangeAction* p = const_cast<ScChangeAction*>(pL->GetAction()); | |||
3954 | if ( p != pAct && rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) ).second ) | |||
3955 | { | |||
3956 | // Only one TopContent of a chain is in LinkDeleted | |||
3957 | if ( bAllFlat && (p->HasDeleted() || | |||
3958 | p->GetType() == SC_CAT_CONTENT) ) | |||
3959 | cStack.push( p ); | |||
3960 | } | |||
3961 | pL = pL->GetNext(); | |||
3962 | } | |||
3963 | // New Contents in FromRange or new FromRange in ToRange | |||
3964 | // or Inserts/Deletes in FromRange/ToRange | |||
3965 | pL = pCur->GetFirstDependentEntry(); | |||
3966 | while ( pL ) | |||
3967 | { | |||
3968 | ScChangeAction* p = const_cast<ScChangeAction*>(pL->GetAction()); | |||
3969 | if ( p != pAct ) | |||
3970 | { | |||
3971 | if ( bAllFlat ) | |||
3972 | { | |||
3973 | sal_uLong n = p->GetActionNumber(); | |||
3974 | if ( !IsGenerated( n ) && rMap.insert( ::std::make_pair( n, p ) ).second ) | |||
3975 | if ( p->HasDependent() || p->HasDeleted() ) | |||
3976 | cStack.push( p ); | |||
3977 | } | |||
3978 | else | |||
3979 | { | |||
3980 | if ( p->GetType() == SC_CAT_CONTENT ) | |||
3981 | { | |||
3982 | if ( static_cast<ScChangeActionContent*>(p)->IsTopContent() ) | |||
3983 | rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) ); | |||
3984 | } | |||
3985 | else | |||
3986 | rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) ); | |||
3987 | } | |||
3988 | } | |||
3989 | pL = pL->GetNext(); | |||
3990 | } | |||
3991 | } | |||
3992 | else if ( pCur->GetType() == SC_CAT_CONTENT ) | |||
3993 | { // All changes at same position | |||
3994 | ScChangeActionContent* pContent = const_cast<ScChangeActionContent*>(static_cast<const ScChangeActionContent*>(pCur)); | |||
3995 | // All preceding ones | |||
3996 | while ( ( pContent = pContent->GetPrevContent() ) != nullptr ) | |||
3997 | { | |||
3998 | if ( !pContent->IsRejected() ) | |||
3999 | rMap.insert( ::std::make_pair( pContent->GetActionNumber(), pContent ) ); | |||
4000 | } | |||
4001 | pContent = const_cast<ScChangeActionContent*>(static_cast<const ScChangeActionContent*>(pCur)); | |||
4002 | // All succeeding ones | |||
4003 | while ( ( pContent = pContent->GetNextContent() ) != nullptr ) | |||
4004 | { | |||
4005 | if ( !pContent->IsRejected() ) | |||
4006 | rMap.insert( ::std::make_pair( pContent->GetActionNumber(), pContent ) ); | |||
4007 | } | |||
4008 | // all MatrixReferences of a MatrixOrigin | |||
4009 | const ScChangeActionLinkEntry* pL = pCur->GetFirstDependentEntry(); | |||
4010 | while ( pL ) | |||
4011 | { | |||
4012 | ScChangeAction* p = const_cast<ScChangeAction*>(pL->GetAction()); | |||
4013 | if ( p != pAct ) | |||
4014 | { | |||
4015 | if ( bAllFlat ) | |||
4016 | { | |||
4017 | sal_uLong n = p->GetActionNumber(); | |||
4018 | if ( !IsGenerated( n ) && rMap.insert( ::std::make_pair( n, p ) ).second ) | |||
4019 | if ( p->HasDependent() ) | |||
4020 | cStack.push( p ); | |||
4021 | } | |||
4022 | else | |||
4023 | rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) ); | |||
4024 | } | |||
4025 | pL = pL->GetNext(); | |||
4026 | } | |||
4027 | } | |||
4028 | else if ( pCur->GetType() == SC_CAT_REJECT ) | |||
4029 | { | |||
4030 | if ( bAllFlat ) | |||
4031 | { | |||
4032 | ScChangeAction* p = GetAction( | |||
4033 | static_cast<const ScChangeActionReject*>(pCur)->GetRejectAction() ); | |||
4034 | if (p != pAct && rMap.find( p->GetActionNumber() ) == rMap.end()) | |||
4035 | cStack.push( p ); | |||
4036 | } | |||
4037 | } | |||
4038 | } | |||
4039 | } | |||
4040 | ||||
4041 | bool ScChangeTrack::SelectContent( ScChangeAction* pAct, bool bOldest ) | |||
4042 | { | |||
4043 | if ( pAct->GetType() != SC_CAT_CONTENT ) | |||
4044 | return false; | |||
4045 | ||||
4046 | ScChangeActionContent* pContent = static_cast<ScChangeActionContent*>(pAct); | |||
4047 | if ( bOldest ) | |||
4048 | { | |||
4049 | pContent = pContent->GetTopContent(); | |||
4050 | for (;;) | |||
4051 | { | |||
4052 | ScChangeActionContent* pPrevContent = pContent->GetPrevContent(); | |||
4053 | if ( !pPrevContent || !pPrevContent->IsVirgin() ) | |||
4054 | break; | |||
4055 | pContent = pPrevContent; | |||
4056 | } | |||
4057 | } | |||
4058 | ||||
4059 | if ( !pContent->IsClickable() ) | |||
4060 | return false; | |||
4061 | ||||
4062 | ScBigRange aBigRange( pContent->GetBigRange() ); | |||
4063 | const ScCellValue& rCell = (bOldest ? pContent->GetOldCell() : pContent->GetNewCell()); | |||
4064 | if ( ScChangeActionContent::GetContentCellType(rCell) == SC_CACCT_MATORG ) | |||
4065 | { | |||
4066 | SCCOL nC; | |||
4067 | SCROW nR; | |||
4068 | rCell.mpFormula->GetMatColsRows(nC, nR); | |||
4069 | aBigRange.aEnd.IncCol( nC-1 ); | |||
4070 | aBigRange.aEnd.IncRow( nR-1 ); | |||
4071 | } | |||
4072 | ||||
4073 | if ( !aBigRange.IsValid( rDoc ) ) | |||
4074 | return false; | |||
4075 | ||||
4076 | ScRange aRange( aBigRange.MakeRange() ); | |||
4077 | if ( !rDoc.IsBlockEditable( aRange.aStart.Tab(), aRange.aStart.Col(), | |||
4078 | aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row() ) ) | |||
4079 | return false; | |||
4080 | ||||
4081 | if ( pContent->HasDependent() ) | |||
4082 | { | |||
4083 | bool bOk = true; | |||
4084 | ::std::stack<ScChangeActionContent*> aRejectActions; | |||
4085 | const ScChangeActionLinkEntry* pL = pContent->GetFirstDependentEntry(); | |||
4086 | while ( pL ) | |||
4087 | { | |||
4088 | ScChangeAction* p = const_cast<ScChangeAction*>(pL->GetAction()); | |||
4089 | if ( p != pContent ) | |||
4090 | { | |||
4091 | if ( p->GetType() == SC_CAT_CONTENT ) | |||
4092 | { | |||
4093 | // we don't need no recursion here, do we? | |||
4094 | bOk &= static_cast<ScChangeActionContent*>(p)->Select( rDoc, this, | |||
4095 | bOldest, &aRejectActions ); | |||
4096 | } | |||
4097 | else | |||
4098 | { | |||
4099 | OSL_FAIL( "ScChangeTrack::SelectContent: content dependent no content" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/chgtrack.cxx" ":" "4099" ": "), "%s", "ScChangeTrack::SelectContent: content dependent no content" ); } } while (false); | |||
4100 | } | |||
4101 | } | |||
4102 | pL = pL->GetNext(); | |||
4103 | } | |||
4104 | ||||
4105 | bOk &= pContent->Select( rDoc, this, bOldest, nullptr ); | |||
4106 | // now the matrix is inserted and new content values are ready | |||
4107 | ||||
4108 | while ( !aRejectActions.empty() ) | |||
4109 | { | |||
4110 | ScChangeActionContent* pNew = aRejectActions.top(); | |||
4111 | aRejectActions.pop(); | |||
4112 | ScAddress aPos( pNew->GetBigRange().aStart.MakeAddress() ); | |||
4113 | ScCellValue aCell; | |||
4114 | aCell.assign(rDoc, aPos); | |||
4115 | pNew->SetNewValue(aCell, &rDoc); | |||
4116 | Append( pNew ); | |||
4117 | } | |||
4118 | return bOk; | |||
4119 | } | |||
4120 | else | |||
4121 | return pContent->Select( rDoc, this, bOldest, nullptr ); | |||
4122 | } | |||
4123 | ||||
4124 | void ScChangeTrack::AcceptAll() | |||
4125 | { | |||
4126 | for ( ScChangeAction* p = GetFirst(); p; p = p->GetNext() ) | |||
4127 | { | |||
4128 | p->Accept(); | |||
4129 | } | |||
4130 | } | |||
4131 | ||||
4132 | bool ScChangeTrack::Accept( ScChangeAction* pAct ) | |||
4133 | { | |||
4134 | if ( !pAct->IsClickable() ) | |||
4135 | return false; | |||
4136 | ||||
4137 | if ( pAct->IsDeleteType() || pAct->GetType() == SC_CAT_CONTENT ) | |||
4138 | { | |||
4139 | ScChangeActionMap aActionMap; | |||
4140 | ||||
4141 | GetDependents( pAct, aActionMap, false, true ); | |||
4142 | ||||
4143 | for( auto& rEntry : aActionMap ) | |||
4144 | { | |||
4145 | rEntry.second->Accept(); | |||
4146 | } | |||
4147 | } | |||
4148 | pAct->Accept(); | |||
4149 | return true; | |||
4150 | } | |||
4151 | ||||
4152 | bool ScChangeTrack::RejectAll() | |||
4153 | { | |||
4154 | bool bOk = true; | |||
4155 | for ( ScChangeAction* p = GetLast(); p && bOk; p = p->GetPrev() ) | |||
4156 | { //TODO: Traverse backwards as dependencies attached to RejectActions | |||
4157 | if ( p->IsInternalRejectable() ) | |||
4158 | bOk = Reject( p ); | |||
4159 | } | |||
4160 | return bOk; | |||
4161 | } | |||
4162 | ||||
4163 | bool ScChangeTrack::Reject( ScChangeAction* pAct, bool bShared ) | |||
4164 | { | |||
4165 | // #i100895# When collaboration changes are reversed, it must be possible | |||
4166 | // to reject a deleted row above another deleted row. | |||
4167 | if ( bShared && pAct->IsDeletedIn() ) | |||
4168 | pAct->RemoveAllDeletedIn(); | |||
4169 | ||||
4170 | if ( !pAct->IsRejectable() ) | |||
4171 | return false; | |||
4172 | ||||
4173 | std::unique_ptr<ScChangeActionMap> pMap; | |||
4174 | if ( pAct->HasDependent() ) | |||
4175 | { | |||
4176 | pMap.reset(new ScChangeActionMap); | |||
4177 | GetDependents( pAct, *pMap, false, true ); | |||
4178 | } | |||
4179 | bool bRejected = Reject( pAct, pMap.get(), false ); | |||
4180 | return bRejected; | |||
4181 | } | |||
4182 | ||||
4183 | bool ScChangeTrack::Reject( | |||
4184 | ScChangeAction* pAct, ScChangeActionMap* pMap, bool bRecursion ) | |||
4185 | { | |||
4186 | if ( !pAct->IsInternalRejectable() ) | |||
4187 | return false; | |||
4188 | ||||
4189 | bool bOk = true; | |||
4190 | bool bRejected = false; | |||
4191 | if ( pAct->IsInsertType() ) | |||
4192 | { | |||
4193 | if ( pAct->HasDependent() && !bRecursion ) | |||
4194 | { | |||
4195 | OSL_ENSURE( pMap, "ScChangeTrack::Reject: Insert without map" )do { if (true && (!(pMap))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/chgtrack.cxx" ":" "4195" ": "), "%s", "ScChangeTrack::Reject: Insert without map" ); } } while (false); | |||
4196 | ScChangeActionMap::reverse_iterator itChangeAction; | |||
4197 | for (itChangeAction = pMap->rbegin(); | |||
4198 | itChangeAction != pMap->rend() && bOk; ++itChangeAction) | |||
4199 | { | |||
4200 | // Do not restore Contents which would end up being deleted anyways | |||
4201 | if ( itChangeAction->second->GetType() == SC_CAT_CONTENT ) | |||
4202 | itChangeAction->second->SetRejected(); | |||
4203 | else if ( itChangeAction->second->IsDeleteType() ) | |||
4204 | itChangeAction->second->Accept(); // Deleted to Nirvana | |||
4205 | else | |||
4206 | bOk = Reject( itChangeAction->second, nullptr, true ); // Recursion! | |||
4207 | } | |||
4208 | } | |||
4209 | if ( bOk ) | |||
4210 | { | |||
4211 | bRejected = pAct->Reject( rDoc ); | |||
4212 | if ( bRejected ) | |||
4213 | { | |||
4214 | // pRefDoc NULL := Do not save deleted Cells | |||
4215 | AppendDeleteRange( pAct->GetBigRange().MakeRange(), nullptr, short(0), | |||
4216 | pAct->GetActionNumber() ); | |||
4217 | } | |||
4218 | } | |||
4219 | } | |||
4220 | else if ( pAct->IsDeleteType() ) | |||
4221 | { | |||
4222 | OSL_ENSURE( !pMap, "ScChangeTrack::Reject: Delete with map" )do { if (true && (!(!pMap))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/chgtrack.cxx" ":" "4222" ": "), "%s", "ScChangeTrack::Reject: Delete with map" ); } } while (false); | |||
4223 | ScBigRange aDelRange; | |||
4224 | sal_uLong nRejectAction = pAct->GetActionNumber(); | |||
4225 | bool bTabDel, bTabDelOk; | |||
4226 | if ( pAct->GetType() == SC_CAT_DELETE_TABS ) | |||
4227 | { | |||
4228 | bTabDel = true; | |||
4229 | aDelRange = pAct->GetBigRange(); | |||
4230 | bTabDelOk = pAct->Reject( rDoc ); | |||
4231 | bOk = bTabDelOk; | |||
4232 | if ( bOk ) | |||
4233 | { | |||
4234 | pAct = pAct->GetPrev(); | |||
4235 | bOk = ( pAct && pAct->GetType() == SC_CAT_DELETE_COLS ); | |||
4236 | } | |||
4237 | } | |||
4238 | else | |||
4239 | bTabDel = bTabDelOk = false; | |||
4240 | ScChangeActionDel* pDel = static_cast<ScChangeActionDel*>(pAct); | |||
4241 | if ( bOk ) | |||
4242 | { | |||
4243 | aDelRange = pDel->GetOverAllRange(); | |||
4244 | bOk = aDelRange.IsValid( rDoc ); | |||
4245 | } | |||
4246 | bool bOneOk = false; | |||
4247 | if ( bOk ) | |||
4248 | { | |||
4249 | ScChangeActionType eActType = pAct->GetType(); | |||
4250 | switch ( eActType ) | |||
4251 | { | |||
4252 | case SC_CAT_DELETE_COLS : | |||
4253 | aDelRange.aStart.SetCol( aDelRange.aEnd.Col() ); | |||
4254 | break; | |||
4255 | case SC_CAT_DELETE_ROWS : | |||
4256 | aDelRange.aStart.SetRow( aDelRange.aEnd.Row() ); | |||
4257 | break; | |||
4258 | case SC_CAT_DELETE_TABS : | |||
4259 | aDelRange.aStart.SetTab( aDelRange.aEnd.Tab() ); | |||
4260 | break; | |||
4261 | default: | |||
4262 | { | |||
4263 | // added to avoid warnings | |||
4264 | } | |||
4265 | } | |||
4266 | ScChangeAction* p = pAct; | |||
4267 | bool bLoop = true; | |||
4268 | do | |||
4269 | { | |||
4270 | pDel = static_cast<ScChangeActionDel*>(p); | |||
4271 | bOk = pDel->Reject( rDoc ); | |||
4272 | if ( bOk ) | |||
4273 | { | |||
4274 | if ( bOneOk ) | |||
4275 | { | |||
4276 | switch ( pDel->GetType() ) | |||
4277 | { | |||
4278 | case SC_CAT_DELETE_COLS : | |||
4279 | aDelRange.aStart.IncCol( -1 ); | |||
4280 | break; | |||
4281 | case SC_CAT_DELETE_ROWS : | |||
4282 | aDelRange.aStart.IncRow( -1 ); | |||
4283 | break; | |||
4284 | case SC_CAT_DELETE_TABS : | |||
4285 | aDelRange.aStart.IncTab( -1 ); | |||
4286 | break; | |||
4287 | default: | |||
4288 | { | |||
4289 | // added to avoid warnings | |||
4290 | } | |||
4291 | } | |||
4292 | } | |||
4293 | else | |||
4294 | bOneOk = true; | |||
4295 | } | |||
4296 | if ( pDel->IsBaseDelete() ) | |||
4297 | bLoop = false; | |||
4298 | else | |||
4299 | p = p->GetPrev(); | |||
4300 | } while ( bOk && bLoop && p && p->GetType() == eActType && | |||
4301 | !static_cast<ScChangeActionDel*>(p)->IsTopDelete() ); | |||
4302 | } | |||
4303 | bRejected = bOk; | |||
4304 | if ( bOneOk || (bTabDel && bTabDelOk) ) | |||
4305 | { | |||
4306 | // Delete Reject made UpdateReference Undo | |||
4307 | ScChangeActionIns* pReject = new ScChangeActionIns( &rDoc, | |||
4308 | aDelRange.MakeRange() ); | |||
4309 | pReject->SetRejectAction( nRejectAction ); | |||
4310 | pReject->SetState( SC_CAS_ACCEPTED ); | |||
4311 | Append( pReject ); | |||
4312 | } | |||
4313 | } | |||
4314 | else if ( pAct->GetType() == SC_CAT_MOVE ) | |||
4315 | { | |||
4316 | if ( pAct->HasDependent() && !bRecursion ) | |||
4317 | { | |||
4318 | OSL_ENSURE( pMap, "ScChangeTrack::Reject: Move without Map" )do { if (true && (!(pMap))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/chgtrack.cxx" ":" "4318" ": "), "%s", "ScChangeTrack::Reject: Move without Map" ); } } while (false); | |||
4319 | ScChangeActionMap::reverse_iterator itChangeAction; | |||
4320 | ||||
4321 | for( itChangeAction = pMap->rbegin(); itChangeAction != pMap->rend() && bOk; ++itChangeAction ) | |||
4322 | { | |||
4323 | bOk = Reject( itChangeAction->second, nullptr, true ); // Recursion! | |||
4324 | } | |||
4325 | } | |||
4326 | if ( bOk ) | |||
4327 | { | |||
4328 | bRejected = pAct->Reject( rDoc ); | |||
4329 | if ( bRejected ) | |||
4330 | { | |||
4331 | ScChangeActionMove* pReject = new ScChangeActionMove( | |||
4332 | pAct->GetBigRange().MakeRange(), | |||
4333 | static_cast<ScChangeActionMove*>(pAct)->GetFromRange().MakeRange(), this ); | |||
4334 | pReject->SetRejectAction( pAct->GetActionNumber() ); | |||
4335 | pReject->SetState( SC_CAS_ACCEPTED ); | |||
4336 | Append( pReject ); | |||
4337 | } | |||
4338 | } | |||
4339 | } | |||
4340 | else if ( pAct->GetType() == SC_CAT_CONTENT ) | |||
4341 | { | |||
4342 | ScRange aRange; | |||
4343 | ScChangeActionContent* pReject; | |||
4344 | if ( bRecursion ) | |||
4345 | pReject = nullptr; | |||
4346 | else | |||
4347 | { | |||
4348 | aRange = pAct->GetBigRange().aStart.MakeAddress(); | |||
4349 | pReject = new ScChangeActionContent( aRange ); | |||
4350 | ScCellValue aCell; | |||
4351 | aCell.assign(rDoc, aRange.aStart); | |||
4352 | pReject->SetOldValue(aCell, &rDoc, &rDoc); | |||
4353 | } | |||
4354 | bRejected = pAct->Reject( rDoc ); | |||
4355 | if ( bRejected && !bRecursion ) | |||
4356 | { | |||
4357 | ScCellValue aCell; | |||
4358 | aCell.assign(rDoc, aRange.aStart); | |||
4359 | pReject->SetNewValue(aCell, &rDoc); | |||
4360 | pReject->SetRejectAction( pAct->GetActionNumber() ); | |||
4361 | pReject->SetState( SC_CAS_ACCEPTED ); | |||
4362 | Append( pReject ); | |||
4363 | } | |||
4364 | else | |||
4365 | delete pReject; | |||
4366 | } | |||
4367 | else | |||
4368 | { | |||
4369 | OSL_FAIL( "ScChangeTrack::Reject: say what?" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/tool/chgtrack.cxx" ":" "4369" ": "), "%s", "ScChangeTrack::Reject: say what?"); } } while (false); | |||
4370 | } | |||
4371 | ||||
4372 | return bRejected; | |||
4373 | } | |||
4374 | ||||
4375 | bool ScChangeTrack::IsLastAction( sal_uLong nNum ) const | |||
4376 | { | |||
4377 | return nNum == nActionMax && pLast && pLast->GetActionNumber() == nNum; | |||
4378 | } | |||
4379 | ||||
4380 | sal_uLong ScChangeTrack::AddLoadedGenerated( | |||
4381 | const ScCellValue& rNewCell, const ScBigRange& aBigRange, const OUString& sNewValue ) | |||
4382 | { | |||
4383 | ScChangeActionContent* pAct = new ScChangeActionContent( --nGeneratedMin, rNewCell, aBigRange, &rDoc, sNewValue ); | |||
4384 | if ( pFirstGeneratedDelContent ) | |||
4385 | pFirstGeneratedDelContent->pPrev = pAct; | |||
4386 | pAct->pNext = pFirstGeneratedDelContent; | |||
4387 | pFirstGeneratedDelContent = pAct; | |||
4388 | aGeneratedMap.insert( ::std::make_pair( pAct->GetActionNumber(), pAct ) ); | |||
4389 | return pAct->GetActionNumber(); | |||
4390 | } | |||
4391 | ||||
4392 | void ScChangeTrack::AppendCloned( ScChangeAction* pAppend ) | |||
4393 | { | |||
4394 | aMap.insert( ::std::make_pair( pAppend->GetActionNumber(), pAppend ) ); | |||
4395 | if ( !pLast ) | |||
4396 | pFirst = pLast = pAppend; | |||
4397 | else | |||
4398 | { | |||
4399 | pLast->pNext = pAppend; | |||
4400 | pAppend->pPrev = pLast; | |||
4401 | pLast = pAppend; | |||
4402 | } | |||
4403 | } | |||
4404 | ||||
4405 | ScChangeTrack* ScChangeTrack::Clone( ScDocument* pDocument ) const | |||
4406 | { | |||
4407 | if ( !pDocument ) | |||
4408 | { | |||
4409 | return nullptr; | |||
4410 | } | |||
4411 | ||||
4412 | std::unique_ptr<ScChangeTrack> pClonedTrack(new ScChangeTrack( *pDocument )); | |||
4413 | pClonedTrack->SetTimeNanoSeconds( IsTimeNanoSeconds() ); | |||
4414 | ||||
4415 | // clone generated actions | |||
4416 | ::std::stack< const ScChangeAction* > aGeneratedStack; | |||
4417 | const ScChangeAction* pGenerated = GetFirstGenerated(); | |||
4418 | while ( pGenerated ) | |||
4419 | { | |||
4420 | aGeneratedStack.push( pGenerated ); | |||
4421 | pGenerated = pGenerated->GetNext(); | |||
4422 | } | |||
4423 | while ( !aGeneratedStack.empty() ) | |||
4424 | { | |||
4425 | pGenerated = aGeneratedStack.top(); | |||
4426 | aGeneratedStack.pop(); | |||
4427 | const ScChangeActionContent& rContent = dynamic_cast<const ScChangeActionContent&>(*pGenerated); | |||
4428 | const ScCellValue& rNewCell = rContent.GetNewCell(); | |||
4429 | if (!rNewCell.isEmpty()) | |||
4430 | { | |||
4431 | ScCellValue aClonedNewCell; | |||
4432 | aClonedNewCell.assign(rNewCell, *pDocument); | |||
4433 | OUString aNewValue; | |||
4434 | rContent.GetNewString( aNewValue, pDocument ); | |||
4435 | pClonedTrack->nGeneratedMin = pGenerated->GetActionNumber() + 1; | |||
4436 | pClonedTrack->AddLoadedGenerated(aClonedNewCell, pGenerated->GetBigRange(), aNewValue); | |||
4437 | } | |||
4438 | } | |||
4439 | ||||
4440 | // clone actions | |||
4441 | const ScChangeAction* pAction = GetFirst(); | |||
4442 | while ( pAction ) | |||
4443 | { | |||
4444 | ScChangeAction* pClonedAction = nullptr; | |||
4445 | ||||
4446 | switch ( pAction->GetType() ) | |||
4447 | { | |||
4448 | case SC_CAT_INSERT_COLS: | |||
4449 | case SC_CAT_INSERT_ROWS: | |||
4450 | case SC_CAT_INSERT_TABS: | |||
4451 | { | |||
4452 | bool bEndOfList = static_cast<const ScChangeActionIns*>(pAction)->IsEndOfList(); | |||
4453 | pClonedAction = new ScChangeActionIns( | |||
4454 | pAction->GetActionNumber(), | |||
4455 | pAction->GetState(), | |||
4456 | pAction->GetRejectAction(), | |||
4457 | pAction->GetBigRange(), | |||
4458 | pAction->GetUser(), | |||
4459 | pAction->GetDateTimeUTC(), | |||
4460 | pAction->GetComment(), | |||
4461 | pAction->GetType(), | |||
4462 | bEndOfList ); | |||
4463 | } | |||
4464 | break; | |||
4465 | case SC_CAT_DELETE_COLS: | |||
4466 | case SC_CAT_DELETE_ROWS: | |||
4467 | case SC_CAT_DELETE_TABS: | |||
4468 | { | |||
4469 | const ScChangeActionDel& rDelete = dynamic_cast<const ScChangeActionDel&>(*pAction); | |||
4470 | ||||
4471 | SCCOLROW nD = 0; | |||
4472 | ScChangeActionType eType = pAction->GetType(); | |||
4473 | if ( eType == SC_CAT_DELETE_COLS ) | |||
4474 | { | |||
4475 | nD = static_cast< SCCOLROW >( rDelete.GetDx() ); | |||
4476 | } | |||
4477 | else if ( eType == SC_CAT_DELETE_ROWS ) | |||
4478 | { | |||
4479 | nD = static_cast< SCCOLROW >( rDelete.GetDy() ); | |||
4480 | } | |||
4481 | ||||
4482 | pClonedAction = new ScChangeActionDel( | |||
4483 | pAction->GetActionNumber(), | |||
4484 | pAction->GetState(), | |||
4485 | pAction->GetRejectAction(), | |||
4486 | pAction->GetBigRange(), | |||
4487 | pAction->GetUser(), | |||
4488 | pAction->GetDateTimeUTC(), | |||
4489 | pAction->GetComment(), | |||
4490 | eType, | |||
4491 | nD, | |||
4492 | pClonedTrack.get() ); | |||
4493 | } | |||
4494 | break; | |||
4495 | case SC_CAT_MOVE: | |||
4496 | { | |||
4497 | auto pMove = dynamic_cast<const ScChangeActionMove*>(pAction); | |||
4498 | assert(pMove && "ScChangeTrack::Clone: pMove is null!")(static_cast <bool> (pMove && "ScChangeTrack::Clone: pMove is null!" ) ? void (0) : __assert_fail ("pMove && \"ScChangeTrack::Clone: pMove is null!\"" , "/home/maarten/src/libreoffice/core/sc/source/core/tool/chgtrack.cxx" , 4498, __extension__ __PRETTY_FUNCTION__)); | |||
4499 | ||||
4500 | pClonedAction = new ScChangeActionMove( | |||
4501 | pAction->GetActionNumber(), | |||
4502 | pAction->GetState(), | |||
4503 | pAction->GetRejectAction(), | |||
4504 | pAction->GetBigRange(), | |||
4505 | pAction->GetUser(), | |||
4506 | pAction->GetDateTimeUTC(), | |||
4507 | pAction->GetComment(), | |||
4508 | pMove->GetFromRange(), | |||
4509 | pClonedTrack.get() ); | |||
4510 | } | |||
4511 | break; | |||
4512 | case SC_CAT_CONTENT: | |||
4513 | { | |||
4514 | const ScChangeActionContent& rContent = dynamic_cast<const ScChangeActionContent&>(*pAction); | |||
4515 | const ScCellValue& rOldCell = rContent.GetOldCell(); | |||
4516 | ScCellValue aClonedOldCell; | |||
4517 | aClonedOldCell.assign(rOldCell, *pDocument); | |||
4518 | OUString aOldValue; | |||
4519 | rContent.GetOldString( aOldValue, pDocument ); | |||
4520 | ||||
4521 | ScChangeActionContent* pClonedContent = new ScChangeActionContent( | |||
4522 | pAction->GetActionNumber(), | |||
4523 | pAction->GetState(), | |||
4524 | pAction->GetRejectAction(), | |||
4525 | pAction->GetBigRange(), | |||
4526 | pAction->GetUser(), | |||
4527 | pAction->GetDateTimeUTC(), | |||
4528 | pAction->GetComment(), | |||
4529 | aClonedOldCell, | |||
4530 | pDocument, | |||
4531 | aOldValue ); | |||
4532 | ||||
4533 | const ScCellValue& rNewCell = rContent.GetNewCell(); | |||
4534 | if (!rNewCell.isEmpty()) | |||
4535 | { | |||
4536 | ScCellValue aClonedNewCell; | |||
4537 | aClonedNewCell.assign(rNewCell, *pDocument); | |||
4538 | pClonedContent->SetNewValue(aClonedNewCell, pDocument); | |||
4539 | } | |||
4540 | ||||
4541 | pClonedAction = pClonedContent; | |||
4542 | } | |||
4543 | break; | |||
4544 | case SC_CAT_REJECT: | |||
4545 | { | |||
4546 | pClonedAction = new ScChangeActionReject( | |||
4547 | pAction->GetActionNumber(), | |||
4548 | pAction->GetState(), | |||
4549 | pAction->GetRejectAction(), | |||
4550 | pAction->GetBigRange(), | |||
4551 | pAction->GetUser(), | |||
4552 | pAction->GetDateTimeUTC(), | |||
4553 | pAction->GetComment() ); | |||
4554 | } | |||
4555 | break; | |||
4556 | default: | |||
4557 | { | |||
4558 | } | |||
4559 | break; | |||
4560 | } | |||
4561 | ||||
4562 | if ( pClonedAction ) | |||
4563 | { | |||
4564 | pClonedTrack->AppendCloned( pClonedAction ); | |||
4565 | } | |||
4566 | ||||
4567 | pAction = pAction->GetNext(); | |||
4568 | } | |||
4569 | ||||
4570 | if ( pClonedTrack->GetLast() ) | |||
4571 | { | |||
4572 | pClonedTrack->SetActionMax( pClonedTrack->GetLast()->GetActionNumber() ); | |||
4573 | } | |||
4574 | ||||
4575 | // set dependencies for Deleted/DeletedIn | |||
4576 | pAction = GetFirst(); | |||
4577 | while ( pAction ) | |||
4578 | { | |||
4579 | if ( pAction->HasDeleted() ) | |||
4580 | { | |||
4581 | ::std::stack< sal_uLong > aStack; | |||
4582 | const ScChangeActionLinkEntry* pL = pAction->GetFirstDeletedEntry(); | |||
4583 | while ( pL ) | |||
4584 | { | |||
4585 | const ScChangeAction* pDeleted = pL->GetAction(); | |||
4586 | if ( pDeleted ) | |||
4587 | { | |||
4588 | aStack.push( pDeleted->GetActionNumber() ); | |||
4589 | } | |||
4590 | pL = pL->GetNext(); | |||
4591 | } | |||
4592 | ScChangeAction* pClonedAction = pClonedTrack->GetAction( pAction->GetActionNumber() ); | |||
4593 | if ( pClonedAction ) | |||
4594 | { | |||
4595 | while ( !aStack.empty() ) | |||
4596 | { | |||
4597 | ScChangeAction* pClonedDeleted = pClonedTrack->GetActionOrGenerated( aStack.top() ); | |||
4598 | aStack.pop(); | |||
4599 | if ( pClonedDeleted ) | |||
4600 | { | |||
4601 | pClonedDeleted->SetDeletedIn( pClonedAction ); | |||
4602 | } | |||
4603 | } | |||
4604 | } | |||
4605 | } | |||
4606 | pAction = pAction->GetNext(); | |||
4607 | } | |||
4608 | ||||
4609 | // set dependencies for Dependent/Any | |||
4610 | pAction = GetLast(); | |||
4611 | while ( pAction ) | |||
4612 | { | |||
4613 | if ( pAction->HasDependent() ) | |||
4614 | { | |||
4615 | ::std::stack< sal_uLong > aStack; | |||
4616 | const ScChangeActionLinkEntry* pL = pAction->GetFirstDependentEntry(); | |||
4617 | while ( pL ) | |||
4618 | { | |||
4619 | const ScChangeAction* pDependent = pL->GetAction(); | |||
4620 | if ( pDependent ) | |||
4621 | { | |||
4622 | aStack.push( pDependent->GetActionNumber() ); | |||
4623 | } | |||
4624 | pL = pL->GetNext(); | |||
4625 | } | |||
4626 | ScChangeAction* pClonedAction = pClonedTrack->GetAction( pAction->GetActionNumber() ); | |||
4627 | if ( pClonedAction ) | |||
4628 | { | |||
4629 | while ( !aStack.empty() ) | |||
4630 | { | |||
4631 | ScChangeAction* pClonedDependent = pClonedTrack->GetActionOrGenerated( aStack.top() ); | |||
4632 | aStack.pop(); | |||
4633 | if ( pClonedDependent ) | |||
4634 | { | |||
4635 | ScChangeActionLinkEntry* pLink = pClonedAction->AddDependent( pClonedDependent ); | |||
4636 | pClonedDependent->AddLink( pClonedAction, pLink ); | |||
4637 | } | |||
4638 | } | |||
4639 | } | |||
4640 | } | |||
4641 | pAction = pAction->GetPrev(); | |||
4642 | } | |||
4643 | ||||
4644 | // masterlinks | |||
4645 | ScChangeAction* pClonedAction = pClonedTrack->GetFirst(); | |||
4646 | while ( pClonedAction ) | |||
4647 | { | |||
4648 | pClonedTrack->MasterLinks( pClonedAction ); | |||
4649 | pClonedAction = pClonedAction->GetNext(); | |||
4650 | } | |||
4651 | ||||
4652 | if ( IsProtected() ) | |||
4653 | { | |||
4654 | pClonedTrack->SetProtection( GetProtection() ); | |||
4655 | } | |||
4656 | ||||
4657 | if ( pClonedTrack->GetLast() ) | |||
4658 | { | |||
4659 | pClonedTrack->SetLastSavedActionNumber( pClonedTrack->GetLast()->GetActionNumber() ); | |||
4660 | } | |||
4661 | ||||
4662 | auto tmp = pClonedTrack.get(); | |||
4663 | pDocument->SetChangeTrack( std::move(pClonedTrack) ); | |||
4664 | ||||
4665 | return tmp; | |||
4666 | } | |||
4667 | ||||
4668 | void ScChangeTrack::MergeActionState( ScChangeAction* pAct, const ScChangeAction* pOtherAct ) | |||
4669 | { | |||
4670 | if ( !pAct->IsVirgin() ) | |||
4671 | return; | |||
4672 | ||||
4673 | if ( pOtherAct->IsAccepted() ) | |||
4674 | { | |||
4675 | pAct->Accept(); | |||
4676 | if ( pOtherAct->IsRejecting() ) | |||
4677 | { | |||
4678 | pAct->SetRejectAction( pOtherAct->GetRejectAction() ); | |||
4679 | } | |||
4680 | } | |||
4681 | else if ( pOtherAct->IsRejected() ) | |||
4682 | { | |||
4683 | pAct->SetRejected(); | |||
4684 | } | |||
4685 | } | |||
4686 | ||||
4687 | /// Get info about a single ScChangeAction element. | |||
4688 | static void lcl_getTrackedChange(ScDocument& rDoc, int nIndex, const ScChangeAction* pAction, tools::JsonWriter& rRedlines) | |||
4689 | { | |||
4690 | if (pAction->GetType() != SC_CAT_CONTENT) | |||
4691 | return; | |||
4692 | ||||
4693 | auto redlinesNode = rRedlines.startNode(""); | |||
4694 | rRedlines.put("index", static_cast<sal_Int64>(nIndex)); | |||
4695 | ||||
4696 | rRedlines.put("author", pAction->GetUser()); | |||
4697 | ||||
4698 | rRedlines.put("type", "Modify"); | |||
4699 | ||||
4700 | rRedlines.put("comment", pAction->GetComment()); | |||
4701 | ||||
4702 | OUString aDescription; | |||
4703 | pAction->GetDescription(aDescription, rDoc, true); | |||
4704 | rRedlines.put("description", aDescription); | |||
4705 | ||||
4706 | OUString sDateTime = utl::toISO8601(pAction->GetDateTimeUTC().GetUNODateTime()); | |||
4707 | rRedlines.put("dateTime", sDateTime); | |||
4708 | } | |||
4709 | ||||
4710 | void ScChangeTrack::GetChangeTrackInfo(tools::JsonWriter& aRedlines) | |||
4711 | { | |||
4712 | auto redlinesNode = aRedlines.startNode("redlines"); | |||
4713 | ||||
4714 | ScChangeAction* pAction = GetFirst(); | |||
4715 | if (pAction) | |||
4716 | { | |||
4717 | int i = 0; | |||
4718 | lcl_getTrackedChange(rDoc, i++, pAction, aRedlines); | |||
4719 | ScChangeAction* pLastAction = GetLast(); | |||
4720 | while (pAction != pLastAction) | |||
4721 | { | |||
4722 | pAction = pAction->GetNext(); | |||
4723 | lcl_getTrackedChange(rDoc, i++, pAction, aRedlines); | |||
4724 | } | |||
4725 | } | |||
4726 | } | |||
4727 | ||||
4728 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |