Provide (experimental) clang-format file
[TortoiseGit.git] / src / TortoiseMerge / Undo.cpp
blob065e8e893b0c794cdca714ff1bc9f0775acb1d12
1 // TortoiseGitMerge - a Diff/Patch program
3 // Copyright (C) 2006-2007, 2010-2011, 2013,2015 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 #include "Undo.h"
23 #include "BaseView.h"
25 void viewstate::AddViewLineFromView(CBaseView *pView, int nViewLine, bool bAddEmptyLine)
27 // is undo good place for this ?
28 if (!pView || !pView->m_pViewData)
29 return;
30 replacedlines[nViewLine] = pView->m_pViewData->GetData(nViewLine);
31 if (bAddEmptyLine)
33 addedlines.push_back(nViewLine + 1);
34 pView->AddEmptyViewLine(nViewLine);
38 void viewstate::Clear()
40 difflines.clear();
41 linestates.clear();
42 linelines.clear();
43 linesEOL.clear();
44 markedlines.clear();
45 addedlines.clear();
47 removedlines.clear();
48 replacedlines.clear();
49 modifies = false;
52 void CUndo::MarkAsOriginalState(bool bLeft, bool bRight, bool bBottom)
54 // TODO reduce code duplication
55 // find highest index of changing step
56 if (bLeft) // left is selected for mark
58 m_originalstateLeft = m_viewstates.size();
59 std::list<allviewstate>::reverse_iterator i = m_viewstates.rbegin();
60 while (i != m_viewstates.rend() && !i->left.modifies)
62 ++i;
63 --m_originalstateLeft;
66 if (bRight) // right is selected for mark
68 m_originalstateRight = m_viewstates.size();
69 std::list<allviewstate>::reverse_iterator i = m_viewstates.rbegin();
70 while (i != m_viewstates.rend() && !i->right.modifies)
72 ++i;
73 --m_originalstateRight;
76 if (bBottom) // bottom is selected for mark
78 m_originalstateBottom = m_viewstates.size();
79 std::list<allviewstate>::reverse_iterator i = m_viewstates.rbegin();
80 while (i != m_viewstates.rend() && !i->bottom.modifies)
82 ++i;
83 --m_originalstateBottom;
88 CUndo& CUndo::GetInstance()
90 static CUndo instance;
91 return instance;
94 CUndo::CUndo()
96 Clear();
99 CUndo::~CUndo()
103 void CUndo::AddState(const allviewstate& allstate, POINT pt)
105 m_viewstates.push_back(allstate);
106 m_caretpoints.push_back(pt);
107 // a new action that can be undone clears the redo since
108 // after this there is nothing to redo anymore
109 m_redoviewstates.clear();
110 m_redocaretpoints.clear();
111 m_redogroups.clear();
114 bool CUndo::Undo(CBaseView * pLeft, CBaseView * pRight, CBaseView * pBottom)
116 if (!CanUndo())
117 return false;
119 if (m_groups.size() && m_groups.back() == m_caretpoints.size())
121 m_groups.pop_back();
122 std::list<int>::size_type b = m_groups.back();
123 m_redogroups.push_back(b);
124 m_redogroups.push_back(m_caretpoints.size());
125 m_groups.pop_back();
126 while (b < m_caretpoints.size())
127 UndoOne(pLeft, pRight, pBottom);
129 else
130 UndoOne(pLeft, pRight, pBottom);
132 CBaseView* pActiveView = nullptr;
134 if (pBottom && pBottom->IsTarget())
136 pActiveView = pBottom;
138 else
139 if (pRight && pRight->IsTarget())
141 pActiveView = pRight;
143 else
144 //if (pLeft && pLeft->IsTarget())
146 pActiveView = pLeft;
150 if (pActiveView) {
151 pActiveView->ClearSelection();
152 pActiveView->BuildAllScreen2ViewVector();
153 pActiveView->RecalcAllVertScrollBars();
154 pActiveView->RecalcAllHorzScrollBars();
155 pActiveView->EnsureCaretVisible();
156 pActiveView->UpdateCaret();
158 // TODO reduce code duplication
159 if (m_viewstates.size() < m_originalstateLeft)
161 // Left can never get back to original state now
162 m_originalstateLeft = (size_t)-1;
164 if (pLeft)
166 bool bModified = (m_originalstateLeft==(size_t)-1);
167 if (!bModified)
169 std::list<allviewstate>::iterator i = m_viewstates.begin();
170 std::advance(i, m_originalstateLeft);
171 for (; i!=m_viewstates.end(); ++i)
173 if (i->left.modifies)
175 bModified = true;
176 break;
180 pLeft->SetModified(bModified);
181 pLeft->ClearStepModifiedMark();
183 if (m_viewstates.size() < m_originalstateRight)
185 // Right can never get back to original state now
186 m_originalstateRight = (size_t)-1;
188 if (pRight)
190 bool bModified = (m_originalstateRight==(size_t)-1);
191 if (!bModified)
193 std::list<allviewstate>::iterator i = m_viewstates.begin();
194 std::advance(i, m_originalstateRight);
195 for (; i!=m_viewstates.end() && !i->right.modifies; ++i) ;
196 bModified = i!=m_viewstates.end();
198 pRight->SetModified(bModified);
199 pRight->ClearStepModifiedMark();
201 if (m_viewstates.size() < m_originalstateBottom)
203 // Bottom can never get back to original state now
204 m_originalstateBottom = (size_t)-1;
206 if (pBottom)
208 bool bModified = (m_originalstateBottom==(size_t)-1);
209 if (!bModified)
211 std::list<allviewstate>::iterator i = m_viewstates.begin();
212 std::advance(i, m_originalstateBottom);
213 for (; i!=m_viewstates.end(); ++i)
215 if (i->bottom.modifies)
217 bModified = true;
218 break;
222 pBottom->SetModified(bModified);
223 pBottom->ClearStepModifiedMark();
225 pActiveView->RefreshViews();
228 return true;
231 void CUndo::UndoOne(CBaseView * pLeft, CBaseView * pRight, CBaseView * pBottom)
233 allviewstate allstate = m_viewstates.back();
234 POINT pt = m_caretpoints.back();
236 if (pLeft->IsTarget())
237 m_redocaretpoints.push_back(pLeft->GetCaretPosition());
238 else if (pRight->IsTarget())
239 m_redocaretpoints.push_back(pRight->GetCaretPosition());
240 else if (pBottom->IsTarget())
241 m_redocaretpoints.push_back(pBottom->GetCaretPosition());
243 allstate.left = Do(allstate.left, pLeft, pt);
244 allstate.right = Do(allstate.right, pRight, pt);
245 allstate.bottom = Do(allstate.bottom, pBottom, pt);
247 m_redoviewstates.push_back(allstate);
249 m_viewstates.pop_back();
250 m_caretpoints.pop_back();
253 bool CUndo::Redo(CBaseView * pLeft, CBaseView * pRight, CBaseView * pBottom)
255 if (!CanRedo())
256 return false;
258 if (m_redogroups.size() && m_redogroups.back() == m_redocaretpoints.size())
260 m_redogroups.pop_back();
261 std::list<int>::size_type b = m_redogroups.back();
262 m_groups.push_back(b);
263 m_groups.push_back(m_redocaretpoints.size());
264 m_redogroups.pop_back();
265 while (b < m_redocaretpoints.size())
266 RedoOne(pLeft, pRight, pBottom);
268 else
269 RedoOne(pLeft, pRight, pBottom);
271 CBaseView* pActiveView = nullptr;
273 if (pBottom && pBottom->IsTarget())
275 pActiveView = pBottom;
277 else
278 if (pRight && pRight->IsTarget())
280 pActiveView = pRight;
282 else
283 //if (pLeft && pLeft->IsTarget())
285 pActiveView = pLeft;
289 if (pActiveView)
291 pActiveView->ClearSelection();
292 pActiveView->BuildAllScreen2ViewVector();
293 pActiveView->RecalcAllVertScrollBars();
294 pActiveView->RecalcAllHorzScrollBars();
295 pActiveView->EnsureCaretVisible();
296 pActiveView->UpdateCaret();
298 // TODO reduce code duplication
299 if (m_redoviewstates.size() < m_originalstateLeft)
301 // Left can never get back to original state now
302 m_originalstateLeft = (size_t)-1;
304 if (pLeft)
306 bool bModified = (m_originalstateLeft == (size_t)-1);
307 if (!bModified)
309 std::list<allviewstate>::iterator i = m_redoviewstates.begin();
310 std::advance(i, m_originalstateLeft);
311 for (; i != m_redoviewstates.end(); ++i)
313 if (i->left.modifies)
315 bModified = true;
316 break;
320 pLeft->SetModified(bModified);
321 pLeft->ClearStepModifiedMark();
323 if (m_redoviewstates.size() < m_originalstateRight)
325 // Right can never get back to original state now
326 m_originalstateRight = (size_t)-1;
328 if (pRight)
330 bool bModified = (m_originalstateRight == (size_t)-1);
331 if (!bModified)
333 std::list<allviewstate>::iterator i = m_redoviewstates.begin();
334 std::advance(i, m_originalstateRight);
335 for (; i != m_redoviewstates.end() && !i->right.modifies; ++i);
336 bModified = i != m_redoviewstates.end();
338 pRight->SetModified(bModified);
339 pRight->ClearStepModifiedMark();
341 if (m_redoviewstates.size() < m_originalstateBottom)
343 // Bottom can never get back to original state now
344 m_originalstateBottom = (size_t)-1;
346 if (pBottom)
348 bool bModified = (m_originalstateBottom == (size_t)-1);
349 if (!bModified)
351 std::list<allviewstate>::iterator i = m_redoviewstates.begin();
352 std::advance(i, m_originalstateBottom);
353 for (; i != m_redoviewstates.end(); ++i)
355 if (i->bottom.modifies)
357 bModified = true;
358 break;
362 pBottom->SetModified(bModified);
363 pBottom->ClearStepModifiedMark();
365 pActiveView->RefreshViews();
368 return true;
371 void CUndo::RedoOne(CBaseView * pLeft, CBaseView * pRight, CBaseView * pBottom)
373 allviewstate allstate = m_redoviewstates.back();
374 POINT pt = m_redocaretpoints.back();
376 if (pLeft->IsTarget())
377 m_caretpoints.push_back(pLeft->GetCaretPosition());
378 else if (pRight->IsTarget())
379 m_caretpoints.push_back(pRight->GetCaretPosition());
380 else if (pBottom->IsTarget())
381 m_caretpoints.push_back(pBottom->GetCaretPosition());
383 allstate.left = Do(allstate.left, pLeft, pt);
384 allstate.right = Do(allstate.right, pRight, pt);
385 allstate.bottom = Do(allstate.bottom, pBottom, pt);
387 m_viewstates.push_back(allstate);
389 m_redoviewstates.pop_back();
390 m_redocaretpoints.pop_back();
392 viewstate CUndo::Do(const viewstate& state, CBaseView * pView, const POINT& pt)
394 if (!pView)
395 return state;
397 CViewData* viewData = pView->m_pViewData;
398 if (!viewData)
399 return state;
401 viewstate revstate; // the reversed viewstate
403 for (std::list<int>::const_reverse_iterator it = state.addedlines.rbegin(); it != state.addedlines.rend(); ++it)
405 revstate.removedlines[*it] = viewData->GetData(*it);
406 viewData->RemoveData(*it);
408 for (std::map<int, DWORD>::const_iterator it = state.linelines.begin(); it != state.linelines.end(); ++it)
410 revstate.linelines[it->first] = viewData->GetLineNumber(it->first);
411 viewData->SetLineNumber(it->first, it->second);
413 for (std::map<int, DWORD>::const_iterator it = state.linestates.begin(); it != state.linestates.end(); ++it)
415 revstate.linestates[it->first] = viewData->GetState(it->first);
416 viewData->SetState(it->first, (DiffStates)it->second);
418 for (std::map<int, EOL>::const_iterator it = state.linesEOL.begin(); it != state.linesEOL.end(); ++it)
420 revstate.linesEOL[it->first] = viewData->GetLineEnding(it->first);
421 viewData->SetLineEnding(it->first, it->second);
423 for (std::map<int, bool>::const_iterator it = state.markedlines.begin(); it != state.markedlines.end(); ++it)
425 revstate.markedlines[it->first] = viewData->GetMarked(it->first);
426 viewData->SetMarked(it->first, it->second);
428 for (std::map<int, CString>::const_iterator it = state.difflines.begin(); it != state.difflines.end(); ++it)
430 revstate.difflines[it->first] = viewData->GetLine(it->first);
431 viewData->SetLine(it->first, it->second);
433 for (std::map<int, viewdata>::const_iterator it = state.removedlines.begin(); it != state.removedlines.end(); ++it)
435 revstate.addedlines.push_back(it->first);
436 viewData->InsertData(it->first, it->second);
438 for (std::map<int, viewdata>::const_iterator it = state.replacedlines.begin(); it != state.replacedlines.end(); ++it)
440 revstate.replacedlines[it->first] = viewData->GetData(it->first);
441 viewData->SetData(it->first, it->second);
444 if (pView->IsTarget())
446 pView->SetCaretViewPosition(pt);
447 pView->EnsureCaretVisible();
449 return revstate;
452 void CUndo::Clear()
454 m_viewstates.clear();
455 m_caretpoints.clear();
456 m_groups.clear();
457 m_redoviewstates.clear();
458 m_redocaretpoints.clear();
459 m_redogroups.clear();
460 m_originalstateLeft = 0;
461 m_originalstateRight = 0;
462 m_originalstateBottom = 0;
463 m_groupCount = 0;