Correctly deallocate buffer
[TortoiseGit.git] / src / TortoiseMerge / MainFrm.cpp
blob8a93ef88f4fd5e0f6bc5850bdf1eed0227e39e1d
1 // TortoiseGitMerge - a Diff/Patch program
3 // Copyright (C) 2008-2012 - TortoiseGit
4 // Copyright (C) 2004-2012 - TortoiseSVN
5 // Copyright (C) 2012 - Sven Strickroth <email@cs-ware.de>
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software Foundation,
19 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "stdafx.h"
22 #include "TortoiseMerge.h"
23 #include "OpenDlg.h"
24 #include "SysProgressDlg.h"
25 #include "Settings.h"
26 #include "MessageBox.h"
27 #include "AppUtils.h"
28 #include "PathUtils.h"
29 #include "MainFrm.h"
30 #include "LeftView.h"
31 #include "RightView.h"
32 #include "BottomView.h"
33 #include "DiffColors.h"
34 #include "mainfrm.h"
35 #include "SelectFileFilter.h"
36 #include "FormatMessageWrapper.h"
37 #include "TaskbarUUID.h"
39 #ifdef _DEBUG
40 #define new DEBUG_NEW
41 #endif
43 // CMainFrame
44 const UINT TaskBarButtonCreated = RegisterWindowMessage(L"TaskbarButtonCreated");
46 IMPLEMENT_DYNCREATE(CMainFrame, CFrameWndEx)
48 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)
49 ON_WM_CREATE()
50 ON_COMMAND_RANGE(ID_VIEW_APPLOOK_WIN7, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnApplicationLook)
51 ON_UPDATE_COMMAND_UI_RANGE(IDC_STYLEBUTTON, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnUpdateApplicationLook)
52 // Global help commands
53 ON_COMMAND(ID_HELP_FINDER, CFrameWndEx::OnHelpFinder)
54 ON_COMMAND(ID_HELP, CFrameWndEx::OnHelp)
55 ON_COMMAND(ID_CONTEXT_HELP, CFrameWndEx::OnContextHelp)
56 ON_COMMAND(ID_DEFAULT_HELP, CFrameWndEx::OnHelpFinder)
57 ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
58 ON_COMMAND(ID_VIEW_WHITESPACES, OnViewWhitespaces)
59 ON_WM_SIZE()
60 ON_COMMAND(ID_FILE_SAVE, OnFileSave)
61 ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
62 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave)
63 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_AS, OnUpdateFileSaveAs)
64 ON_COMMAND(ID_VIEW_ONEWAYDIFF, OnViewOnewaydiff)
65 ON_UPDATE_COMMAND_UI(ID_VIEW_ONEWAYDIFF, OnUpdateViewOnewaydiff)
66 ON_UPDATE_COMMAND_UI(ID_VIEW_WHITESPACES, OnUpdateViewWhitespaces)
67 ON_COMMAND(ID_VIEW_OPTIONS, OnViewOptions)
68 ON_WM_CLOSE()
69 ON_WM_ACTIVATE()
70 ON_COMMAND(ID_FILE_RELOAD, OnFileReload)
71 ON_COMMAND(ID_VIEW_LINEDOWN, OnViewLinedown)
72 ON_COMMAND(ID_VIEW_LINEUP, OnViewLineup)
73 ON_COMMAND(ID_VIEW_MOVEDBLOCKS, OnViewMovedBlocks)
74 ON_UPDATE_COMMAND_UI(ID_VIEW_MOVEDBLOCKS, OnUpdateViewMovedBlocks)
75 ON_UPDATE_COMMAND_UI(ID_EDIT_MARKASRESOLVED, OnUpdateMergeMarkasresolved)
76 ON_COMMAND(ID_EDIT_MARKASRESOLVED, OnMergeMarkasresolved)
77 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTCONFLICT, OnUpdateMergeNextconflict)
78 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSCONFLICT, OnUpdateMergePreviousconflict)
79 ON_WM_MOVE()
80 ON_WM_MOVING()
81 ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
82 ON_COMMAND(ID_VIEW_SWITCHLEFT, OnViewSwitchleft)
83 ON_UPDATE_COMMAND_UI(ID_VIEW_SWITCHLEFT, OnUpdateViewSwitchleft)
84 ON_COMMAND(ID_VIEW_LINELEFT, &CMainFrame::OnViewLineleft)
85 ON_COMMAND(ID_VIEW_LINERIGHT, &CMainFrame::OnViewLineright)
86 ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWFILELIST, &CMainFrame::OnUpdateViewShowfilelist)
87 ON_COMMAND(ID_VIEW_SHOWFILELIST, &CMainFrame::OnViewShowfilelist)
88 ON_COMMAND(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnEditUseTheirs)
89 ON_COMMAND(ID_EDIT_USEMYBLOCK, &CMainFrame::OnEditUseMine)
90 ON_COMMAND(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnEditUseTheirsThenMine)
91 ON_COMMAND(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnEditUseMineThenTheirs)
92 ON_COMMAND(ID_EDIT_UNDO, &CMainFrame::OnEditUndo)
93 ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, &CMainFrame::OnUpdateEditUndo)
94 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnUpdateEditUseminethentheirblock)
95 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMYBLOCK, &CMainFrame::OnUpdateEditUsemyblock)
96 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnUpdateEditUsetheirblock)
97 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnUpdateEditUsetheirthenmyblock)
98 ON_COMMAND(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnViewInlinediffword)
99 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnUpdateViewInlinediffword)
100 ON_COMMAND(ID_VIEW_INLINEDIFF, &CMainFrame::OnViewInlinediff)
101 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFF, &CMainFrame::OnUpdateViewInlinediff)
102 ON_UPDATE_COMMAND_UI(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnUpdateEditCreateunifieddifffile)
103 ON_COMMAND(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnEditCreateunifieddifffile)
104 ON_UPDATE_COMMAND_UI(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnUpdateViewLinediffbar)
105 ON_COMMAND(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnViewLinediffbar)
106 ON_UPDATE_COMMAND_UI(ID_VIEW_LOCATORBAR, &CMainFrame::OnUpdateViewLocatorbar)
107 ON_COMMAND(ID_VIEW_LOCATORBAR, &CMainFrame::OnViewLocatorbar)
108 ON_COMMAND(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnEditUseleftblock)
109 ON_UPDATE_COMMAND_UI(ID_USEBLOCKS, &CMainFrame::OnUpdateUseBlock)
110 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnUpdateEditUseleftblock)
111 ON_COMMAND(ID_EDIT_USELEFTFILE, &CMainFrame::OnEditUseleftfile)
112 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTFILE, &CMainFrame::OnUpdateEditUseleftfile)
113 ON_COMMAND(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnEditUseblockfromleftbeforeright)
114 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnUpdateEditUseblockfromleftbeforeright)
115 ON_COMMAND(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnEditUseblockfromrightbeforeleft)
116 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnUpdateEditUseblockfromrightbeforeleft)
117 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTDIFFERENCE, &CMainFrame::OnUpdateNavigateNextdifference)
118 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSDIFFERENCE, &CMainFrame::OnUpdateNavigatePreviousdifference)
119 ON_COMMAND(ID_VIEW_COLLAPSED, &CMainFrame::OnViewCollapsed)
120 ON_UPDATE_COMMAND_UI(ID_VIEW_COLLAPSED, &CMainFrame::OnUpdateViewCollapsed)
121 ON_COMMAND(ID_VIEW_COMPAREWHITESPACES, &CMainFrame::OnViewComparewhitespaces)
122 ON_UPDATE_COMMAND_UI(ID_VIEW_COMPAREWHITESPACES, &CMainFrame::OnUpdateViewComparewhitespaces)
123 ON_COMMAND(ID_VIEW_IGNOREWHITESPACECHANGES, &CMainFrame::OnViewIgnorewhitespacechanges)
124 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREWHITESPACECHANGES, &CMainFrame::OnUpdateViewIgnorewhitespacechanges)
125 ON_COMMAND(ID_VIEW_IGNOREALLWHITESPACECHANGES, &CMainFrame::OnViewIgnoreallwhitespacechanges)
126 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREALLWHITESPACECHANGES, &CMainFrame::OnUpdateViewIgnoreallwhitespacechanges)
127 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTINLINEDIFF, &CMainFrame::OnUpdateNavigateNextinlinediff)
128 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVINLINEDIFF, &CMainFrame::OnUpdateNavigatePrevinlinediff)
129 ON_COMMAND(ID_VIEW_WRAPLONGLINES, &CMainFrame::OnViewWraplonglines)
130 ON_UPDATE_COMMAND_UI(ID_VIEW_WRAPLONGLINES, &CMainFrame::OnUpdateViewWraplonglines)
131 ON_REGISTERED_MESSAGE( TaskBarButtonCreated, CMainFrame::OnTaskbarButtonCreated )
132 ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, &CMainFrame::OnUpdateEditPaste)
133 END_MESSAGE_MAP()
135 static UINT indicators[] =
137 ID_SEPARATOR, // status line indicator
138 ID_INDICATOR_LEFTVIEW,
139 ID_INDICATOR_RIGHTVIEW,
140 ID_INDICATOR_BOTTOMVIEW,
141 ID_INDICATOR_CAPS,
142 ID_INDICATOR_NUM,
146 // CMainFrame construction/destruction
148 CMainFrame::CMainFrame()
149 : m_bInitSplitter(FALSE)
150 , m_bReversedPatch(FALSE)
151 , m_bHasConflicts(false)
152 , m_bInlineWordDiff(true)
153 , m_bLineDiff(true)
154 , m_bLocatorBar(true)
155 , m_nMoveMovesToIgnore(0)
156 , m_pwndLeftView(NULL)
157 , m_pwndRightView(NULL)
158 , m_pwndBottomView(NULL)
159 , m_bReadOnly(false)
160 , m_bBlame(false)
161 , m_bCheckReload(false)
162 , m_bSaveRequired(false)
163 , resolveMsgWnd(0)
164 , resolveMsgWParam(0)
165 , resolveMsgLParam(0)
166 , m_regWrapLines(L"Software\\TortoiseGitMerge\\WrapLines", 0)
167 , m_regViewModedBlocks(L"Software\\TortoiseGitMerge\\ViewMovedBlocks", 0)
168 , m_regOneWay(L"Software\\TortoiseGitMerge\\OnePane")
169 , m_regCollapsed(L"Software\\TortoiseGitMerge\\Collapsed", 0)
170 , m_regInlineDiff(L"Software\\TortoiseGitMerge\\DisplayBinDiff", TRUE)
172 m_bOneWay = (0 != ((DWORD)m_regOneWay));
173 theApp.m_nAppLook = theApp.GetInt(_T("ApplicationLook"), ID_VIEW_APPLOOK_VS_2005);
174 m_bCollapsed = !!(DWORD)m_regCollapsed;
175 m_bViewMovedBlocks = !!(DWORD)m_regViewModedBlocks;
176 m_bWrapLines = !!(DWORD)m_regWrapLines;
177 m_bInlineDiff = !!m_regInlineDiff;
178 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
181 CMainFrame::~CMainFrame()
185 LRESULT CMainFrame::OnTaskbarButtonCreated(WPARAM /*wParam*/, LPARAM /*lParam*/)
187 SetUUIDOverlayIcon(m_hWnd);
188 return 0;
192 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
194 if (CFrameWndEx::OnCreate(lpCreateStruct) == -1)
195 return -1;
197 OnApplicationLook(theApp.m_nAppLook);
199 m_wndRibbonBar.Create (this);
200 m_wndRibbonBar.LoadFromResource(IDR_RIBBON);
202 // enable the dialog launch button on the view panel
203 CMFCRibbonCategory * pMainCat = m_wndRibbonBar.GetCategory(1);
204 if (pMainCat)
206 CMFCRibbonPanel * pPanel = pMainCat->GetPanel(3);
207 if (pPanel)
208 pPanel->EnableLaunchButton(ID_VIEW_OPTIONS);
211 if (!m_wndStatusBar.Create(this) ||
212 !m_wndStatusBar.SetIndicators(indicators,
213 _countof(indicators)))
215 TRACE0("Failed to create status bar\n");
216 return -1; // fail to create
219 if (!m_wndLocatorBar.Create(this, IDD_DIFFLOCATOR,
220 CBRS_ALIGN_LEFT | CBRS_SIZE_FIXED, ID_VIEW_LOCATORBAR))
222 TRACE0("Failed to create dialogbar\n");
223 return -1; // fail to create
225 if (!m_wndLineDiffBar.Create(this, IDD_LINEDIFF,
226 CBRS_ALIGN_BOTTOM | CBRS_SIZE_FIXED, ID_VIEW_LINEDIFFBAR))
228 TRACE0("Failed to create dialogbar\n");
229 return -1; // fail to create
231 m_wndLocatorBar.m_pMainFrm = this;
232 m_wndLineDiffBar.m_pMainFrm = this;
234 EnableDocking(CBRS_ALIGN_ANY);
235 DockPane(&m_wndLocatorBar);
236 DockPane(&m_wndLineDiffBar);
237 ShowPane(&m_wndLocatorBar, true, false, true);
238 ShowPane(&m_wndLineDiffBar, true, false, true);
240 m_wndLocatorBar.EnableGripper(FALSE);
241 m_wndLineDiffBar.EnableGripper(FALSE);
243 return 0;
246 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
248 if( !CFrameWndEx::PreCreateWindow(cs) )
249 return FALSE;
250 return TRUE;
253 void CMainFrame::OnApplicationLook(UINT id)
255 CWaitCursor wait;
257 theApp.m_nAppLook = id;
259 switch (theApp.m_nAppLook)
261 case ID_VIEW_APPLOOK_WIN_2000:
262 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManager));
263 m_wndRibbonBar.SetWindows7Look(FALSE);
264 break;
266 case ID_VIEW_APPLOOK_OFF_XP:
267 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOfficeXP));
268 m_wndRibbonBar.SetWindows7Look(FALSE);
269 break;
271 case ID_VIEW_APPLOOK_WIN_XP:
272 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
273 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
274 m_wndRibbonBar.SetWindows7Look(FALSE);
275 break;
277 case ID_VIEW_APPLOOK_OFF_2003:
278 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2003));
279 CDockingManager::SetDockingMode(DT_SMART);
280 m_wndRibbonBar.SetWindows7Look(FALSE);
281 break;
283 case ID_VIEW_APPLOOK_VS_2005:
284 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2005));
285 CDockingManager::SetDockingMode(DT_SMART);
286 m_wndRibbonBar.SetWindows7Look(FALSE);
287 break;
289 case ID_VIEW_APPLOOK_VS_2008:
290 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2008));
291 CDockingManager::SetDockingMode(DT_SMART);
292 m_wndRibbonBar.SetWindows7Look(FALSE);
293 break;
295 case ID_VIEW_APPLOOK_WIN7:
296 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows7));
297 CDockingManager::SetDockingMode(DT_SMART);
298 m_wndRibbonBar.SetWindows7Look(TRUE);
299 break;
301 default:
302 switch (theApp.m_nAppLook)
304 case ID_VIEW_APPLOOK_OFF_2007_BLUE:
305 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_LunaBlue);
306 break;
308 case ID_VIEW_APPLOOK_OFF_2007_BLACK:
309 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_ObsidianBlack);
310 break;
312 case ID_VIEW_APPLOOK_OFF_2007_SILVER:
313 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Silver);
314 break;
316 case ID_VIEW_APPLOOK_OFF_2007_AQUA:
317 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Aqua);
318 break;
321 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));
322 CDockingManager::SetDockingMode(DT_SMART);
323 m_wndRibbonBar.SetWindows7Look(FALSE);
326 RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_FRAME | RDW_ERASE);
328 theApp.WriteInt(_T("ApplicationLook"), theApp.m_nAppLook);
331 void CMainFrame::OnUpdateApplicationLook(CCmdUI* pCmdUI)
333 pCmdUI->Enable();
334 pCmdUI->SetRadio(theApp.m_nAppLook == pCmdUI->m_nID);
338 // CMainFrame diagnostics
340 #ifdef _DEBUG
341 void CMainFrame::AssertValid() const
343 CFrameWndEx::AssertValid();
346 void CMainFrame::Dump(CDumpContext& dc) const
348 CFrameWndEx::Dump(dc);
351 #endif //_DEBUG
354 // CMainFrame message handlers
357 BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)
359 CRect cr;
360 GetClientRect( &cr);
363 // split into three panes:
364 // -------------
365 // | | |
366 // | | |
367 // |------------
368 // | |
369 // | |
370 // |------------
372 // create a splitter with 2 rows, 1 column
373 if (!m_wndSplitter.CreateStatic(this, 2, 1))
375 TRACE0("Failed to CreateStaticSplitter\n");
376 return FALSE;
379 // add the second splitter pane - which is a nested splitter with 2 columns
380 if (!m_wndSplitter2.CreateStatic(
381 &m_wndSplitter, // our parent window is the first splitter
382 1, 2, // the new splitter is 1 row, 2 columns
383 WS_CHILD | WS_VISIBLE | WS_BORDER, // style, WS_BORDER is needed
384 m_wndSplitter.IdFromRowCol(0, 0)
385 // new splitter is in the first row, 1st column of first splitter
388 TRACE0("Failed to create nested splitter\n");
389 return FALSE;
391 // add the first splitter pane - the default view in row 0
392 if (!m_wndSplitter.CreateView(1, 0,
393 RUNTIME_CLASS(CBottomView), CSize(cr.Width(), cr.Height()), pContext))
395 TRACE0("Failed to create first pane\n");
396 return FALSE;
398 m_pwndBottomView = (CBottomView *)m_wndSplitter.GetPane(1,0);
399 m_pwndBottomView->m_pwndLocator = &m_wndLocatorBar;
400 m_pwndBottomView->m_pwndLineDiffBar = &m_wndLineDiffBar;
401 m_pwndBottomView->m_pwndStatusBar = &m_wndStatusBar;
402 m_pwndBottomView->m_pMainFrame = this;
404 // now create the two views inside the nested splitter
406 if (!m_wndSplitter2.CreateView(0, 0,
407 RUNTIME_CLASS(CLeftView), CSize(cr.Width()/2, cr.Height()/2), pContext))
409 TRACE0("Failed to create second pane\n");
410 return FALSE;
412 m_pwndLeftView = (CLeftView *)m_wndSplitter2.GetPane(0,0);
413 m_pwndLeftView->m_pwndLocator = &m_wndLocatorBar;
414 m_pwndLeftView->m_pwndLineDiffBar = &m_wndLineDiffBar;
415 m_pwndLeftView->m_pwndStatusBar = &m_wndStatusBar;
416 m_pwndLeftView->m_pMainFrame = this;
418 if (!m_wndSplitter2.CreateView(0, 1,
419 RUNTIME_CLASS(CRightView), CSize(cr.Width()/2, cr.Height()/2), pContext))
421 TRACE0("Failed to create third pane\n");
422 return FALSE;
424 m_pwndRightView = (CRightView *)m_wndSplitter2.GetPane(0,1);
425 m_pwndRightView->m_pwndLocator = &m_wndLocatorBar;
426 m_pwndRightView->m_pwndLineDiffBar = &m_wndLineDiffBar;
427 m_pwndRightView->m_pwndStatusBar = &m_wndStatusBar;
428 m_pwndRightView->m_pMainFrame = this;
429 m_bInitSplitter = TRUE;
431 m_dlgFilePatches.Create(IDD_FILEPATCHES, this);
432 UpdateLayout();
433 return TRUE;
436 // Callback function
437 BOOL CMainFrame::PatchFile(CString sFilePath, bool /*bContentMods*/, bool bPropMods, CString sVersion, BOOL bAutoPatch)
439 CString sDummy;
440 //"dry run" was successful, so save the patched file somewhere...
441 CString sTempFile = CTempFiles::Instance().GetTempFilePathString();
442 CString sRejectedFile;
443 if (m_Patch.GetPatchResult(sFilePath, sTempFile, sRejectedFile) < 0)
445 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
446 return FALSE;
448 sFilePath = m_Patch.GetTargetPath() + _T("\\") + sFilePath;
449 sFilePath.Replace('/', '\\');
450 if (m_bReversedPatch)
452 m_Data.m_baseFile.SetFileName(sTempFile);
453 CString temp;
454 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
455 m_Data.m_baseFile.SetDescriptiveName(temp);
456 m_Data.m_yourFile.SetFileName(sFilePath);
457 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchOriginal);
458 m_Data.m_yourFile.SetDescriptiveName(temp);
459 m_Data.m_theirFile.SetOutOfUse();
460 m_Data.m_mergedFile.SetOutOfUse();
462 else
464 if ((!PathFileExists(sFilePath))||(PathIsDirectory(sFilePath)))
466 m_Data.m_baseFile.SetFileName(CTempFiles::Instance().GetTempFilePathString());
467 m_Data.m_baseFile.CreateEmptyFile();
469 else
471 m_Data.m_baseFile.SetFileName(sFilePath);
473 CString sDescription;
474 sDescription.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchOriginal);
475 m_Data.m_baseFile.SetDescriptiveName(sDescription);
476 m_Data.m_yourFile.SetFileName(sTempFile);
477 CString temp;
478 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
479 m_Data.m_yourFile.SetDescriptiveName(temp);
480 m_Data.m_theirFile.SetOutOfUse();
481 m_Data.m_mergedFile.SetFileName(sFilePath);
482 m_Data.m_bPatchRequired = bPropMods;
484 TRACE(_T("comparing %s\nwith the patched result %s\n"), (LPCTSTR)sFilePath, (LPCTSTR)sTempFile);
486 LoadViews();
487 if (!sRejectedFile.IsEmpty())
489 #if 0 // TGIT TODO
490 // start TortoiseUDiff with the rejected hunks
491 CString sTitle;
492 sTitle.Format(IDS_TITLE_REJECTEDHUNKS, (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath));
493 CAppUtils::StartUnifiedDiffViewer(sRejectedFile, sTitle);
494 #endif
496 if (bAutoPatch)
498 PatchSave();
500 return TRUE;
503 // Callback function
504 BOOL CMainFrame::DiffFiles(CString sURL1, CString sRev1, CString sURL2, CString sRev2)
506 CString tempfile1 = CTempFiles::Instance().GetTempFilePathString();
507 CString tempfile2 = CTempFiles::Instance().GetTempFilePathString();
509 ASSERT(tempfile1.Compare(tempfile2));
511 CString sTemp;
512 CSysProgressDlg progDlg;
513 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev1);
514 progDlg.SetLine(1, sTemp, true);
515 progDlg.SetLine(2, sURL1, true);
516 sTemp.LoadString(IDS_GETVERSIONOFFILETITLE);
517 progDlg.SetTitle(sTemp);
518 progDlg.SetShowProgressBar(true);
519 progDlg.SetAnimation(IDR_DOWNLOAD);
520 progDlg.SetTime(FALSE);
521 progDlg.SetProgress(1,100);
522 progDlg.ShowModeless(this);
523 if (!CAppUtils::GetVersionedFile(sURL1, sRev1, tempfile1, &progDlg, m_hWnd))
525 progDlg.Stop();
526 CString sErrMsg;
527 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev1, (LPCTSTR)sURL1);
528 MessageBox(sErrMsg, NULL, MB_ICONERROR);
529 return FALSE;
531 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev2);
532 progDlg.SetLine(1, sTemp, true);
533 progDlg.SetLine(2, sURL2, true);
534 progDlg.SetProgress(50, 100);
535 if (!CAppUtils::GetVersionedFile(sURL2, sRev2, tempfile2, &progDlg, m_hWnd))
537 progDlg.Stop();
538 CString sErrMsg;
539 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev2, (LPCTSTR)sURL2);
540 MessageBox(sErrMsg, NULL, MB_ICONERROR);
541 return FALSE;
543 progDlg.SetProgress(100,100);
544 progDlg.Stop();
545 CString temp;
546 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL1), (LPCTSTR)sRev1);
547 m_Data.m_baseFile.SetFileName(tempfile1);
548 m_Data.m_baseFile.SetDescriptiveName(temp);
549 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL2), (LPCTSTR)sRev2);
550 m_Data.m_yourFile.SetFileName(tempfile2);
551 m_Data.m_yourFile.SetDescriptiveName(temp);
553 LoadViews();
555 return TRUE;
558 void CMainFrame::OnFileOpen()
560 if (CheckForSave()==IDCANCEL)
561 return;
562 COpenDlg dlg;
563 if (dlg.DoModal()!=IDOK)
565 return;
567 m_dlgFilePatches.ShowWindow(SW_HIDE);
568 m_dlgFilePatches.Init(NULL, NULL, CString(), NULL);
569 TRACE(_T("got the files:\n %s\n %s\n %s\n %s\n %s\n"), (LPCTSTR)dlg.m_sBaseFile, (LPCTSTR)dlg.m_sTheirFile, (LPCTSTR)dlg.m_sYourFile,
570 (LPCTSTR)dlg.m_sUnifiedDiffFile, (LPCTSTR)dlg.m_sPatchDirectory);
571 m_Data.m_baseFile.SetFileName(dlg.m_sBaseFile);
572 m_Data.m_theirFile.SetFileName(dlg.m_sTheirFile);
573 m_Data.m_yourFile.SetFileName(dlg.m_sYourFile);
574 m_Data.m_sDiffFile = dlg.m_sUnifiedDiffFile;
575 m_Data.m_sPatchPath = dlg.m_sPatchDirectory;
576 m_Data.m_mergedFile.SetOutOfUse();
577 CCrashReport::Instance().AddFile2(dlg.m_sBaseFile, NULL, _T("Basefile"), CR_AF_MAKE_FILE_COPY);
578 CCrashReport::Instance().AddFile2(dlg.m_sTheirFile, NULL, _T("Theirfile"), CR_AF_MAKE_FILE_COPY);
579 CCrashReport::Instance().AddFile2(dlg.m_sYourFile, NULL, _T("Yourfile"), CR_AF_MAKE_FILE_COPY);
580 CCrashReport::Instance().AddFile2(dlg.m_sUnifiedDiffFile, NULL, _T("Difffile"), CR_AF_MAKE_FILE_COPY);
582 if (!m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && m_Data.IsYourFileInUse())
584 // a diff between two files means "Yours" against "Base", not "Theirs" against "Yours"
585 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
587 if (m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && !m_Data.IsYourFileInUse())
589 // a diff between two files means "Yours" against "Base", not "Theirs" against "Base"
590 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
592 m_bSaveRequired = false;
594 LoadViews();
597 void CMainFrame::ClearViewNamesAndPaths()
599 m_pwndLeftView->m_sWindowName.Empty();
600 m_pwndLeftView->m_sFullFilePath.Empty();
601 m_pwndRightView->m_sWindowName.Empty();
602 m_pwndRightView->m_sFullFilePath.Empty();
603 m_pwndBottomView->m_sWindowName.Empty();
604 m_pwndBottomView->m_sFullFilePath.Empty();
607 bool CMainFrame::LoadViews(int line)
609 m_Data.SetBlame(m_bBlame);
610 m_Data.SetMovedBlocks(m_bViewMovedBlocks);
611 m_bHasConflicts = false;
612 CBaseView* pwndActiveView = m_pwndLeftView;
613 int nOldLine = m_pwndRightView ? m_pwndRightView->m_nTopLine : -1;
614 int nOldLineNumber =
615 m_pwndRightView && m_pwndRightView->m_pViewData ?
616 m_pwndRightView->m_pViewData->GetLineNumber(m_pwndRightView->m_nTopLine) : -1;
617 POINT ptOldCaretPos = {-1, -1};
618 if (m_pwndRightView && m_pwndRightView->IsTarget())
619 ptOldCaretPos = m_pwndRightView->GetCaretPosition();
620 if (m_pwndBottomView && m_pwndBottomView->IsTarget())
621 ptOldCaretPos = m_pwndBottomView->GetCaretPosition();
622 if (!m_Data.Load())
624 m_pwndLeftView->BuildAllScreen2ViewVector();
625 m_pwndLeftView->DocumentUpdated();
626 m_pwndRightView->DocumentUpdated();
627 m_pwndBottomView->DocumentUpdated();
628 m_wndLocatorBar.DocumentUpdated();
629 m_wndLineDiffBar.DocumentUpdated();
630 ::MessageBox(m_hWnd, m_Data.GetError(), _T("TortoiseGitMerge"), MB_ICONERROR);
631 m_Data.m_mergedFile.SetOutOfUse();
632 m_bSaveRequired = false;
633 return false;
635 SetWindowTitle();
636 m_pwndLeftView->BuildAllScreen2ViewVector();
637 m_pwndLeftView->DocumentUpdated();
638 m_pwndRightView->DocumentUpdated();
639 m_pwndBottomView->DocumentUpdated();
640 m_wndLocatorBar.DocumentUpdated();
641 m_wndLineDiffBar.DocumentUpdated();
643 m_pwndRightView->SetWritable(false);
644 m_pwndRightView->SetTarget(false);
645 m_pwndBottomView->SetWritable(false);
646 m_pwndBottomView->SetTarget(false);
648 if (!m_Data.IsBaseFileInUse())
650 CSysProgressDlg progDlg;
651 if (m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
653 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
655 else if ((!m_Data.m_sDiffFile.IsEmpty())&&(!m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg)))
657 progDlg.Stop();
658 ClearViewNamesAndPaths();
659 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
660 m_bSaveRequired = false;
661 return false;
663 progDlg.Stop();
664 if (m_Patch.GetNumberOfFiles() > 0)
666 CString betterpatchpath = m_Patch.CheckPatchPath(m_Data.m_sPatchPath);
667 if (betterpatchpath.CompareNoCase(m_Data.m_sPatchPath)!=0)
669 CString msg;
670 msg.Format(IDS_WARNBETTERPATCHPATHFOUND, (LPCTSTR)m_Data.m_sPatchPath, (LPCTSTR)betterpatchpath);
671 if (CMessageBox::Show(m_hWnd, msg, _T("TortoiseGitMerge"), MB_ICONQUESTION | MB_YESNO)==IDYES)
673 m_Data.m_sPatchPath = betterpatchpath;
674 m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg);
677 m_dlgFilePatches.Init(&m_Patch, this, m_Data.m_sPatchPath, this);
678 m_dlgFilePatches.ShowWindow(SW_SHOW);
679 ClearViewNamesAndPaths();
680 if (!m_wndSplitter.IsRowHidden(1))
681 m_wndSplitter.HideRow(1);
682 m_pwndLeftView->SetHidden(FALSE);
683 m_pwndRightView->SetHidden(FALSE);
684 m_pwndBottomView->SetHidden(TRUE);
687 if (m_Data.IsBaseFileInUse() && !m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
689 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
691 if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && !m_Data.IsTheirFileInUse())
693 //diff between YOUR and BASE
694 m_pwndRightView->SetWritable();
695 m_pwndRightView->SetTarget();
696 if (m_bOneWay)
698 if (!m_wndSplitter2.IsColumnHidden(1))
699 m_wndSplitter2.HideColumn(1);
701 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseBoth;
702 m_pwndLeftView->texttype = m_Data.m_arYourFile.GetUnicodeType();
703 m_pwndLeftView->lineendings = m_Data.m_arYourFile.GetLineEndings();
704 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName() + _T(" - ") + m_Data.m_yourFile.GetWindowName();
705 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename() + _T(" - ") + m_Data.m_yourFile.GetFilename();
707 m_pwndRightView->m_pViewData = NULL;
708 m_pwndBottomView->m_pViewData = NULL;
710 if (!m_wndSplitter.IsRowHidden(1))
711 m_wndSplitter.HideRow(1);
712 m_pwndLeftView->SetHidden(FALSE);
713 m_pwndRightView->SetHidden(TRUE);
714 m_pwndBottomView->SetHidden(TRUE);
715 ::SetWindowPos(m_pwndLeftView->m_hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
717 else
719 pwndActiveView = m_pwndRightView;
720 if (m_wndSplitter2.IsColumnHidden(1))
721 m_wndSplitter2.ShowColumn();
723 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseLeft;
724 m_pwndLeftView->texttype = m_Data.m_arBaseFile.GetUnicodeType();
725 m_pwndLeftView->lineendings = m_Data.m_arBaseFile.GetLineEndings();
726 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName();
727 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename();
729 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseRight;
730 m_pwndRightView->texttype = m_Data.m_arYourFile.GetUnicodeType();
731 m_pwndRightView->lineendings = m_Data.m_arYourFile.GetLineEndings();
732 m_pwndRightView->m_sWindowName = m_Data.m_yourFile.GetWindowName();
733 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
735 m_pwndBottomView->m_pViewData = NULL;
737 if (!m_wndSplitter.IsRowHidden(1))
738 m_wndSplitter.HideRow(1);
739 m_pwndLeftView->SetHidden(FALSE);
740 m_pwndRightView->SetHidden(FALSE);
741 m_pwndBottomView->SetHidden(TRUE);
744 else if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
746 //diff between THEIR, YOUR and BASE
747 m_pwndBottomView->SetWritable();
748 m_pwndBottomView->SetTarget();
749 pwndActiveView = m_pwndBottomView;
751 m_pwndLeftView->m_pViewData = &m_Data.m_TheirBaseBoth;
752 m_pwndLeftView->texttype = m_Data.m_arTheirFile.GetUnicodeType();
753 m_pwndLeftView->lineendings = m_Data.m_arTheirFile.GetLineEndings();
754 m_pwndLeftView->m_sWindowName.LoadString(IDS_VIEWTITLE_THEIRS);
755 m_pwndLeftView->m_sWindowName += _T(" - ") + m_Data.m_theirFile.GetWindowName();
756 m_pwndLeftView->m_sFullFilePath = m_Data.m_theirFile.GetFilename();
758 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseBoth;
759 m_pwndRightView->texttype = m_Data.m_arYourFile.GetUnicodeType();
760 m_pwndRightView->lineendings = m_Data.m_arYourFile.GetLineEndings();
761 m_pwndRightView->m_sWindowName.LoadString(IDS_VIEWTITLE_MINE);
762 m_pwndRightView->m_sWindowName += _T(" - ") + m_Data.m_yourFile.GetWindowName();
763 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
765 m_pwndBottomView->m_pViewData = &m_Data.m_Diff3;
766 m_pwndBottomView->texttype = m_Data.m_arTheirFile.GetUnicodeType();
767 m_pwndBottomView->lineendings = m_Data.m_arTheirFile.GetLineEndings();
768 m_pwndBottomView->m_sWindowName.LoadString(IDS_VIEWTITLE_MERGED);
769 m_pwndBottomView->m_sWindowName += _T(" - ") + m_Data.m_mergedFile.GetWindowName();
770 m_pwndBottomView->m_sFullFilePath = m_Data.m_mergedFile.GetFilename();
772 if (m_wndSplitter2.IsColumnHidden(1))
773 m_wndSplitter2.ShowColumn();
774 if (m_wndSplitter.IsRowHidden(1))
775 m_wndSplitter.ShowRow();
776 m_pwndLeftView->SetHidden(FALSE);
777 m_pwndRightView->SetHidden(FALSE);
778 m_pwndBottomView->SetHidden(FALSE);
779 // in three pane view, hide the line diff bar
780 m_wndLineDiffBar.ShowPane(false, false, true);
781 m_wndLineDiffBar.DocumentUpdated();
783 if (!m_Data.m_mergedFile.InUse())
785 m_Data.m_mergedFile.SetFileName(m_Data.m_yourFile.GetFilename());
787 m_pwndLeftView->BuildAllScreen2ViewVector();
788 m_pwndLeftView->DocumentUpdated();
789 m_pwndRightView->DocumentUpdated();
790 m_pwndBottomView->DocumentUpdated();
791 m_wndLocatorBar.DocumentUpdated();
792 m_wndLineDiffBar.DocumentUpdated();
793 UpdateLayout();
794 SetActiveView(pwndActiveView);
796 if ((line >= -1) && m_pwndRightView->m_pViewData)
798 int n = line == -1 ? min( nOldLineNumber, nOldLine ) : line;
799 if (n >= 0)
800 n = m_pwndRightView->m_pViewData->FindLineNumber(n);
801 if (n < 0)
802 n = nOldLine;
804 m_pwndRightView->ScrollAllToLine(n);
805 POINT p;
806 p.x = 0;
807 p.y = n;
808 if ((ptOldCaretPos.x >= 0) || (ptOldCaretPos.y >= 0))
809 p = ptOldCaretPos;
810 m_pwndLeftView->SetCaretPosition(p);
811 m_pwndRightView->SetCaretPosition(p);
812 m_pwndBottomView->SetCaretPosition(p);
813 m_pwndBottomView->ScrollToChar(0);
814 m_pwndLeftView->ScrollToChar(0);
815 m_pwndRightView->ScrollToChar(0);
817 else
819 CRegDWORD regFirstDiff = CRegDWORD(_T("Software\\TortoiseGitMerge\\FirstDiffOnLoad"), TRUE);
820 CRegDWORD regFirstConflict = CRegDWORD(_T("Software\\TortoiseGitMerge\\FirstConflictOnLoad"), TRUE);
821 bool bGoFirstDiff = (0 != (DWORD)regFirstDiff);
822 bool bGoFirstConflict = (0 != (DWORD)regFirstConflict);
823 if (bGoFirstConflict && (CheckResolved()>=0))
825 pwndActiveView->GoToFirstConflict();
826 // Ignore the first few Mouse Move messages, so that the line diff stays on
827 // the first diff line until the user actually moves the mouse
828 m_nMoveMovesToIgnore = MOVESTOIGNORE;
830 else if (bGoFirstDiff)
832 pwndActiveView->GoToFirstDifference();
833 // Ignore the first few Mouse Move messages, so that the line diff stays on
834 // the first diff line until the user actually moves the mouse
835 m_nMoveMovesToIgnore = MOVESTOIGNORE;
837 else
839 // Avoid incorrect rendering of active pane.
840 m_pwndBottomView->ScrollToChar(0);
841 m_pwndLeftView->ScrollToChar(0);
842 m_pwndRightView->ScrollToChar(0);
845 CheckResolved();
846 if (m_bHasConflicts)
847 m_bSaveRequired = false;
848 CUndo::GetInstance().Clear();
849 return true;
852 void CMainFrame::UpdateLayout()
854 if (m_bInitSplitter)
856 m_wndSplitter.CenterSplitter();
857 m_wndSplitter2.CenterSplitter();
861 void CMainFrame::OnSize(UINT nType, int cx, int cy)
863 CFrameWndEx::OnSize(nType, cx, cy);
864 if (m_bInitSplitter && nType != SIZE_MINIMIZED)
866 if (m_wndSplitter.GetSafeHwnd())
868 if (m_wndSplitter.HasOldRowSize() && (m_wndSplitter.GetOldRowCount() == 2))
870 int oldTotal = m_wndSplitter.GetOldRowSize(0) + m_wndSplitter.GetOldRowSize(1);
871 if (oldTotal)
873 int cxCur0, cxCur1, cxMin0, cxMin1;
874 m_wndSplitter.GetRowInfo(0, cxCur0, cxMin0);
875 m_wndSplitter.GetRowInfo(1, cxCur1, cxMin1);
876 cxCur0 = m_wndSplitter.GetOldRowSize(0) * (cxCur0 + cxCur1) / oldTotal;
877 cxCur1 = m_wndSplitter.GetOldRowSize(1) * (cxCur0 + cxCur1) / oldTotal;
878 m_wndSplitter.SetRowInfo(0, cxCur0, 0);
879 m_wndSplitter.SetRowInfo(1, cxCur1, 0);
880 m_wndSplitter.RecalcLayout();
884 if (m_wndSplitter2.HasOldColSize() && (m_wndSplitter2.GetOldColCount() == 2))
886 int oldTotal = m_wndSplitter2.GetOldColSize(0) + m_wndSplitter2.GetOldColSize(1);
887 if (oldTotal)
889 int cyCur0, cyCur1, cyMin0, cyMin1;
890 m_wndSplitter2.GetColumnInfo(0, cyCur0, cyMin0);
891 m_wndSplitter2.GetColumnInfo(1, cyCur1, cyMin1);
892 cyCur0 = m_wndSplitter2.GetOldColSize(0) * (cyCur0 + cyCur1) / oldTotal;
893 cyCur1 = m_wndSplitter2.GetOldColSize(1) * (cyCur0 + cyCur1) / oldTotal;
894 m_wndSplitter2.SetColumnInfo(0, cyCur0, 0);
895 m_wndSplitter2.SetColumnInfo(1, cyCur1, 0);
896 m_wndSplitter2.RecalcLayout();
901 if ((nType == SIZE_RESTORED)&&m_bCheckReload)
903 m_bCheckReload = false;
904 CheckForReload();
908 void CMainFrame::OnViewWhitespaces()
910 CRegDWORD regViewWhitespaces = CRegDWORD(_T("Software\\TortoiseGitMerge\\ViewWhitespaces"), 1);
911 BOOL bViewWhitespaces = regViewWhitespaces;
912 if (m_pwndLeftView)
913 bViewWhitespaces = m_pwndLeftView->m_bViewWhitespace;
915 bViewWhitespaces = !bViewWhitespaces;
916 regViewWhitespaces = bViewWhitespaces;
917 if (m_pwndLeftView)
919 m_pwndLeftView->m_bViewWhitespace = bViewWhitespaces;
920 m_pwndLeftView->Invalidate();
922 if (m_pwndRightView)
924 m_pwndRightView->m_bViewWhitespace = bViewWhitespaces;
925 m_pwndRightView->Invalidate();
927 if (m_pwndBottomView)
929 m_pwndBottomView->m_bViewWhitespace = bViewWhitespaces;
930 m_pwndBottomView->Invalidate();
934 void CMainFrame::OnUpdateViewWhitespaces(CCmdUI *pCmdUI)
936 if (m_pwndLeftView)
937 pCmdUI->SetCheck(m_pwndLeftView->m_bViewWhitespace);
940 void CMainFrame::OnViewCollapsed()
942 m_regCollapsed = !(DWORD)m_regCollapsed;
943 m_bCollapsed = !!(DWORD)m_regCollapsed;
945 OnViewTextFoldUnfold();
946 m_wndLocatorBar.Invalidate();
949 void CMainFrame::OnUpdateViewCollapsed(CCmdUI *pCmdUI)
951 pCmdUI->SetCheck(m_bCollapsed);
954 void CMainFrame::OnViewWraplonglines()
956 m_bWrapLines = !(DWORD)m_regWrapLines;
957 m_regWrapLines = m_bWrapLines;
959 if (m_pwndLeftView) m_pwndLeftView ->WrapChanged();
960 if (m_pwndRightView) m_pwndRightView ->WrapChanged();
961 if (m_pwndBottomView) m_pwndBottomView->WrapChanged();
962 OnViewTextFoldUnfold();
963 m_wndLocatorBar.DocumentUpdated();
966 void CMainFrame::OnViewTextFoldUnfold()
968 OnViewTextFoldUnfold(m_pwndLeftView);
969 OnViewTextFoldUnfold(m_pwndRightView);
970 OnViewTextFoldUnfold(m_pwndBottomView);
973 void CMainFrame::OnViewTextFoldUnfold(CBaseView* view)
975 if (view == 0)
976 return;
977 view->BuildAllScreen2ViewVector();
978 view->UpdateCaret();
979 view->Invalidate();
980 view->EnsureCaretVisible();
983 void CMainFrame::OnUpdateViewWraplonglines(CCmdUI *pCmdUI)
985 pCmdUI->SetCheck(m_bWrapLines);
988 void CMainFrame::OnViewOnewaydiff()
990 if (CheckForSave()==IDCANCEL)
991 return;
992 m_bOneWay = !m_bOneWay;
993 ShowDiffBar(!m_bOneWay);
994 LoadViews(-1);
997 void CMainFrame::ShowDiffBar(bool bShow)
999 if (bShow)
1001 // restore the line diff bar
1002 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
1003 m_wndLineDiffBar.DocumentUpdated();
1004 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
1005 m_wndLocatorBar.DocumentUpdated();
1007 else
1009 // in one way view, hide the line diff bar
1010 m_wndLineDiffBar.ShowPane(false, false, true);
1011 m_wndLineDiffBar.DocumentUpdated();
1015 int CMainFrame::CheckResolved()
1017 //only in three way diffs can be conflicts!
1018 m_bHasConflicts = true;
1019 if (m_pwndBottomView->IsWindowVisible())
1021 CViewData* viewdata = m_pwndBottomView->m_pViewData;
1022 if (viewdata)
1024 for (int i=0; i<viewdata->GetCount(); i++)
1026 const DiffStates state = viewdata->GetState(i);
1027 if ((DIFFSTATE_CONFLICTED == state)||(DIFFSTATE_CONFLICTED_IGNORED == state))
1028 return i;
1032 m_bHasConflicts = false;
1033 return -1;
1036 int CMainFrame::SaveFile(const CString& sFilePath)
1038 CViewData * pViewData = NULL;
1039 CFileTextLines * pOriginFile = &m_Data.m_arBaseFile;
1040 if (IsViewGood(m_pwndBottomView))
1042 pViewData = m_pwndBottomView->m_pViewData;
1043 Invalidate();
1045 else if (IsViewGood(m_pwndRightView))
1047 pViewData = m_pwndRightView->m_pViewData;
1048 if (m_Data.IsYourFileInUse())
1049 pOriginFile = &m_Data.m_arYourFile;
1050 else if (m_Data.IsTheirFileInUse())
1051 pOriginFile = &m_Data.m_arTheirFile;
1052 Invalidate();
1054 else
1056 // nothing to save!
1057 return 1;
1059 if ((pViewData)&&(pOriginFile))
1061 CFileTextLines file;
1062 pOriginFile->CopySettings(&file);
1063 for (int i=0; i<pViewData->GetCount(); i++)
1065 //only copy non-removed lines
1066 DiffStates state = pViewData->GetState(i);
1067 switch (state)
1069 case DIFFSTATE_CONFLICTED:
1070 case DIFFSTATE_CONFLICTED_IGNORED:
1072 int first = i;
1073 int last = i;
1076 last++;
1077 } while((last<pViewData->GetCount()) && ((pViewData->GetState(last)==DIFFSTATE_CONFLICTED)||(pViewData->GetState(last)==DIFFSTATE_CONFLICTED_IGNORED)));
1078 // TortoiseGitMerge changes here
1079 file.Add(_T("<<<<<<< .mine"), m_pwndRightView->lineendings);
1080 for (int j=first; j<last; j++)
1082 EOL lineending = m_pwndRightView->m_pViewData->GetLineEnding(j);
1083 if (lineending == EOL_NOENDING)
1084 lineending = m_pwndRightView->lineendings;
1085 file.Add(m_pwndRightView->m_pViewData->GetLine(j), lineending);
1087 file.Add(_T("======="), m_pwndRightView->lineendings);
1088 for (int j=first; j<last; j++)
1090 EOL lineending = m_pwndLeftView->m_pViewData->GetLineEnding(j);
1091 if (lineending == EOL_NOENDING)
1092 lineending = m_pwndLeftView->lineendings;
1093 file.Add(m_pwndLeftView->m_pViewData->GetLine(j), lineending);
1095 file.Add(_T(">>>>>>> .theirs"), m_pwndRightView->lineendings);
1096 i = last-1;
1098 break;
1099 case DIFFSTATE_EMPTY:
1100 case DIFFSTATE_CONFLICTEMPTY:
1101 case DIFFSTATE_IDENTICALREMOVED:
1102 case DIFFSTATE_REMOVED:
1103 case DIFFSTATE_THEIRSREMOVED:
1104 case DIFFSTATE_YOURSREMOVED:
1105 case DIFFSTATE_CONFLICTRESOLVEDEMPTY:
1106 // do not save removed lines
1107 break;
1108 default:
1109 file.Add(pViewData->GetLine(i), pViewData->GetLineEnding(i));
1110 break;
1113 if (!file.Save(sFilePath, false, false))
1115 CMessageBox::Show(m_hWnd, file.GetErrorString(), _T("TortoiseGitMerge"), MB_ICONERROR);
1116 return -1;
1118 if (sFilePath == m_Data.m_baseFile.GetFilename())
1120 m_Data.m_baseFile.StoreFileAttributes();
1122 if (sFilePath == m_Data.m_theirFile.GetFilename())
1124 m_Data.m_theirFile.StoreFileAttributes();
1126 if (sFilePath == m_Data.m_yourFile.GetFilename())
1128 m_Data.m_yourFile.StoreFileAttributes();
1130 /*if (sFilePath == m_Data.m_mergedFile.GetFilename())
1132 m_Data.m_mergedFile.StoreFileAttributes();
1133 }//*/
1134 m_dlgFilePatches.SetFileStatusAsPatched(sFilePath);
1135 if (m_pwndBottomView)
1136 m_pwndBottomView->SetModified(FALSE);
1137 if (m_pwndRightView)
1138 m_pwndRightView->SetModified(FALSE);
1139 CUndo::GetInstance().MarkAsOriginalState();
1140 if (file.GetCount() == 1 && file.GetLineEnding(0) == EOL_NOENDING)
1141 return 0;
1142 return file.GetCount();
1144 return 1;
1147 void CMainFrame::OnFileSave()
1149 FileSave();
1152 void CMainFrame::PatchSave()
1154 bool bDoesNotExist = !PathFileExists(m_Data.m_mergedFile.GetFilename());
1155 if (m_Data.m_bPatchRequired)
1157 m_Patch.PatchPath(m_Data.m_mergedFile.GetFilename());
1159 if (!PathIsDirectory(m_Data.m_mergedFile.GetFilename()))
1161 int saveret = SaveFile(m_Data.m_mergedFile.GetFilename());
1162 if (saveret==0)
1164 // file was saved with 0 lines, remove it.
1165 m_Patch.RemoveFile(m_Data.m_mergedFile.GetFilename());
1166 // just in case
1167 DeleteFile(m_Data.m_mergedFile.GetFilename());
1169 m_Data.m_mergedFile.StoreFileAttributes();
1170 if (m_Data.m_mergedFile.GetFilename() == m_Data.m_yourFile.GetFilename())
1171 m_Data.m_yourFile.StoreFileAttributes();
1172 if ((bDoesNotExist)&&(DWORD(CRegDWORD(_T("Software\\TortoiseGitMerge\\AutoAdd"), TRUE))))
1174 // call TortoiseProc to add the new file to version control
1175 CString cmd = _T("/command:add /noui /path:\"");
1176 cmd += m_Data.m_mergedFile.GetFilename() + _T("\"");
1177 CAppUtils::RunTortoiseGitProc(cmd);
1182 bool CMainFrame::FileSave(bool bCheckResolved /*=true*/)
1184 if (!m_Data.m_mergedFile.InUse())
1185 return FileSaveAs(bCheckResolved);
1186 // check if the file has the readonly attribute set
1187 bool bDoesNotExist = false;
1188 DWORD fAttribs = GetFileAttributes(m_Data.m_mergedFile.GetFilename());
1189 if ((fAttribs != INVALID_FILE_ATTRIBUTES)&&(fAttribs & FILE_ATTRIBUTE_READONLY))
1190 return FileSaveAs(bCheckResolved);
1191 if (fAttribs == INVALID_FILE_ATTRIBUTES)
1193 bDoesNotExist = (GetLastError() == ERROR_FILE_NOT_FOUND);
1195 if (bCheckResolved && HasConflictsWontKeep())
1196 return false;
1198 if (((DWORD)CRegDWORD(_T("Software\\TortoiseGitMerge\\Backup"))) != 0)
1200 MoveFileEx(m_Data.m_mergedFile.GetFilename(), m_Data.m_mergedFile.GetFilename() + _T(".bak"), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
1202 if (m_Data.m_bPatchRequired)
1204 m_Patch.PatchPath(m_Data.m_mergedFile.GetFilename());
1206 int saveret = SaveFile(m_Data.m_mergedFile.GetFilename());
1207 if (saveret==0)
1209 // file was saved with 0 lines!
1210 // ask the user if the file should be deleted
1211 CString sTemp;
1212 sTemp.Format(IDS_DELETEWHENEMPTY, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
1213 if (CMessageBox::ShowCheck(m_hWnd, sTemp, _T("TortoiseGitMerge"), MB_YESNO, _T("DeleteFileWhenEmpty")) == IDYES)
1215 m_Patch.RemoveFile(m_Data.m_mergedFile.GetFilename());
1216 DeleteFile(m_Data.m_mergedFile.GetFilename());
1219 else if (saveret < 0)
1221 // error while saving the file
1222 return false;
1225 // if we're in conflict resolve mode (three pane view), check if there are no more conflicts
1226 // and if there aren't, ask to mark the file as resolved
1227 if (IsViewGood(m_pwndBottomView) && !m_bHasConflicts)
1229 #if 0 // TGIT TODO
1230 CTGitPath svnpath = CTGitPath(m_Data.m_mergedFile.GetFilename());
1231 if (SVNHelper::IsVersioned(svnpath, true))
1233 SVNPool pool;
1234 svn_opt_revision_t rev;
1235 rev.kind = svn_opt_revision_unspecified;
1236 svn_wc_status_kind statuskind = svn_wc_status_none;
1237 svn_client_ctx_t * ctx = NULL;
1238 svn_error_clear(svn_client_create_context2(&ctx, SVNConfig::Instance().GetConfig(pool), pool));
1239 svn_error_t * err = svn_client_status5(NULL, ctx, svnpath.GetSVNApiPath(pool), &rev,
1240 svn_depth_empty,
1241 true,
1242 false,
1243 true,
1244 true,
1245 false,
1246 NULL,
1247 getallstatus,
1248 &statuskind,
1249 pool);
1250 if ((err == NULL) && (statuskind == svn_wc_status_conflicted))
1252 CString sTemp;
1253 sTemp.Format(IDS_MARKASRESOLVED, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1254 if (CMessageBox::Show(m_hWnd, sTemp, _T("TortoiseGitMerge"), MB_YESNO) == IDYES))
1255 MarkAsResolved();
1257 svn_error_clear(err);
1259 #endif
1262 m_bSaveRequired = false;
1263 m_Data.m_mergedFile.StoreFileAttributes();
1265 if ((bDoesNotExist)&&(DWORD(CRegDWORD(_T("Software\\TortoiseGitMerge\\AutoAdd"), TRUE))))
1267 // call TortoiseProc to add the new file to version control
1268 CString cmd = _T("/command:add /noui /path:\"");
1269 cmd += m_Data.m_mergedFile.GetFilename() + _T("\"");
1270 if(!CAppUtils::RunTortoiseGitProc(cmd))
1271 return false;
1273 return true;
1276 void CMainFrame::OnFileSaveAs()
1278 FileSaveAs();
1281 bool CMainFrame::FileSaveAs(bool bCheckResolved /*=true*/)
1283 if (bCheckResolved && HasConflictsWontKeep())
1284 return false;
1286 CString fileName;
1287 if(!TryGetFileName(fileName))
1288 return false;
1290 SaveFile(fileName);
1291 return true;
1294 void CMainFrame::OnUpdateFileSave(CCmdUI *pCmdUI)
1296 BOOL bEnable = FALSE;
1297 if (m_Data.m_mergedFile.InUse())
1299 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1300 bEnable = TRUE;
1301 else if ( (IsViewGood(m_pwndRightView)&&(m_pwndRightView->m_pViewData)) &&
1302 (m_pwndRightView->IsModified() || (m_Data.m_yourFile.GetWindowName().Right(9).Compare(_T(": patched"))==0)) )
1303 bEnable = TRUE;
1305 pCmdUI->Enable(bEnable);
1308 void CMainFrame::OnUpdateFileSaveAs(CCmdUI *pCmdUI)
1310 BOOL bEnable = FALSE;
1311 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1312 bEnable = TRUE;
1313 else if (IsViewGood(m_pwndRightView)&&(m_pwndRightView->m_pViewData))
1314 bEnable = TRUE;
1315 pCmdUI->Enable(bEnable);
1318 void CMainFrame::OnUpdateViewOnewaydiff(CCmdUI *pCmdUI)
1320 pCmdUI->SetCheck(!m_bOneWay);
1321 BOOL bEnable = TRUE;
1322 if (IsViewGood(m_pwndBottomView))
1324 bEnable = FALSE;
1326 pCmdUI->Enable(bEnable);
1329 void CMainFrame::OnViewOptions()
1331 CString sTemp;
1332 sTemp.LoadString(IDS_SETTINGSTITLE);
1333 CSettings dlg(sTemp);
1334 dlg.DoModal();
1335 if (dlg.IsReloadNeeded())
1337 if (CheckForSave()==IDCANCEL)
1338 return;
1339 CDiffColors::GetInstance().LoadRegistry();
1340 LoadViews();
1341 return;
1343 CDiffColors::GetInstance().LoadRegistry();
1344 if (m_pwndBottomView)
1345 m_pwndBottomView->Invalidate();
1346 if (m_pwndLeftView)
1347 m_pwndLeftView->Invalidate();
1348 if (m_pwndRightView)
1349 m_pwndRightView->Invalidate();
1352 void CMainFrame::OnClose()
1354 UINT ret = IDNO;
1355 if (HasUnsavedEdits())
1357 CString sTemp;
1358 sTemp.LoadString(IDS_ASKFORSAVE);
1359 ret = MessageBox(sTemp, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
1361 if (ret == IDYES)
1363 if (!FileSave())
1364 return;
1367 if ((ret == IDNO)||(ret == IDYES))
1369 WINDOWPLACEMENT wp;
1371 // before it is destroyed, save the position of the window
1372 wp.length = sizeof wp;
1374 if (GetWindowPlacement(&wp))
1377 if (IsIconic())
1378 // never restore to Iconic state
1379 wp.showCmd = SW_SHOW ;
1381 if ((wp.flags & WPF_RESTORETOMAXIMIZED) != 0)
1382 // if maximized and maybe iconic restore maximized state
1383 wp.showCmd = SW_SHOWMAXIMIZED ;
1385 // and write it to the .INI file
1386 WriteWindowPlacement(&wp);
1388 __super::OnClose();
1392 void CMainFrame::OnActivate(UINT nValue, CWnd* /*pwnd*/, BOOL /*bActivated?*/) {
1393 if (nValue != 0) // activated
1395 if (IsIconic())
1397 m_bCheckReload = TRUE;
1399 else
1400 CheckForReload();
1404 void CMainFrame::OnViewLinedown()
1406 OnViewLineUpDown(1);
1409 void CMainFrame::OnViewLineup()
1411 OnViewLineUpDown(-1);
1414 void CMainFrame::OnViewLineUpDown(int direction)
1416 if (m_pwndLeftView)
1417 m_pwndLeftView->ScrollToLine(m_pwndLeftView->m_nTopLine+direction);
1418 if (m_pwndRightView)
1419 m_pwndRightView->ScrollToLine(m_pwndRightView->m_nTopLine+direction);
1420 if (m_pwndBottomView)
1421 m_pwndBottomView->ScrollToLine(m_pwndBottomView->m_nTopLine+direction);
1422 m_wndLocatorBar.Invalidate();
1423 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1426 void CMainFrame::OnViewLineleft()
1428 OnViewLineLeftRight(-1);
1431 void CMainFrame::OnViewLineright()
1433 OnViewLineLeftRight(1);
1436 void CMainFrame::OnViewLineLeftRight(int direction)
1438 if (m_pwndLeftView)
1439 m_pwndLeftView->ScrollSide(direction);
1440 if (m_pwndRightView)
1441 m_pwndRightView->ScrollSide(direction);
1442 if (m_pwndBottomView)
1443 m_pwndBottomView->ScrollSide(direction);
1446 void CMainFrame::OnEditUseTheirs()
1448 if (m_pwndBottomView)
1449 m_pwndBottomView->UseTheirTextBlock();
1451 void CMainFrame::OnUpdateEditUsetheirblock(CCmdUI *pCmdUI)
1453 pCmdUI->Enable(m_pwndBottomView && m_pwndBottomView->HasSelection());
1456 void CMainFrame::OnEditUseMine()
1458 if (m_pwndBottomView)
1459 m_pwndBottomView->UseMyTextBlock();
1461 void CMainFrame::OnUpdateEditUsemyblock(CCmdUI *pCmdUI)
1463 OnUpdateEditUsetheirblock(pCmdUI);
1466 void CMainFrame::OnEditUseTheirsThenMine()
1468 if (m_pwndBottomView)
1469 m_pwndBottomView->UseTheirAndYourBlock();
1472 void CMainFrame::OnUpdateEditUsetheirthenmyblock(CCmdUI *pCmdUI)
1474 OnUpdateEditUsetheirblock(pCmdUI);
1477 void CMainFrame::OnEditUseMineThenTheirs()
1479 if (m_pwndBottomView)
1480 m_pwndBottomView->UseYourAndTheirBlock();
1483 void CMainFrame::OnUpdateEditUseminethentheirblock(CCmdUI *pCmdUI)
1485 OnUpdateEditUsetheirblock(pCmdUI);
1488 void CMainFrame::OnEditUseleftblock()
1490 if (m_pwndBottomView->IsWindowVisible())
1491 m_pwndBottomView->UseRightBlock();
1492 else
1493 m_pwndRightView->UseLeftBlock();
1496 void CMainFrame::OnUpdateEditUseleftblock(CCmdUI *pCmdUI)
1498 pCmdUI->Enable(IsViewGood(m_pwndRightView) && m_pwndRightView->IsTarget() && m_pwndRightView->HasSelection());
1501 void CMainFrame::OnUpdateUseBlock(CCmdUI *pCmdUI)
1503 pCmdUI->Enable(TRUE);
1506 void CMainFrame::OnEditUseleftfile()
1508 if (m_pwndBottomView->IsWindowVisible())
1509 m_pwndBottomView->UseRightFile();
1510 else
1511 m_pwndRightView->UseLeftFile();
1514 void CMainFrame::OnUpdateEditUseleftfile(CCmdUI *pCmdUI)
1516 pCmdUI->Enable(IsViewGood(m_pwndRightView) && m_pwndRightView->IsTarget());
1519 void CMainFrame::OnEditUseblockfromleftbeforeright()
1521 if (m_pwndRightView)
1522 m_pwndRightView->UseBothLeftFirst();
1525 void CMainFrame::OnUpdateEditUseblockfromleftbeforeright(CCmdUI *pCmdUI)
1527 OnUpdateEditUseleftblock(pCmdUI);
1530 void CMainFrame::OnEditUseblockfromrightbeforeleft()
1532 if (m_pwndRightView)
1533 m_pwndRightView->UseBothRightFirst();
1536 void CMainFrame::OnUpdateEditUseblockfromrightbeforeleft(CCmdUI *pCmdUI)
1538 OnUpdateEditUseleftblock(pCmdUI);
1541 void CMainFrame::OnFileReload()
1543 if (CheckForSave()==IDCANCEL)
1544 return;
1545 CDiffColors::GetInstance().LoadRegistry();
1546 LoadViews(-1);
1549 void CMainFrame::ActivateFrame(int nCmdShow)
1551 // nCmdShow is the normal show mode this frame should be in
1552 // translate default nCmdShow (-1)
1553 if (nCmdShow == -1)
1555 if (!IsWindowVisible())
1556 nCmdShow = SW_SHOWNORMAL;
1557 else if (IsIconic())
1558 nCmdShow = SW_RESTORE;
1561 // bring to top before showing
1562 BringToTop(nCmdShow);
1564 if (nCmdShow != -1)
1566 // show the window as specified
1567 WINDOWPLACEMENT wp;
1569 if ( !ReadWindowPlacement(&wp) )
1571 ShowWindow(nCmdShow);
1573 else
1575 if ( nCmdShow != SW_SHOWNORMAL )
1576 wp.showCmd = nCmdShow;
1578 SetWindowPlacement(&wp);
1581 // and finally, bring to top after showing
1582 BringToTop(nCmdShow);
1586 BOOL CMainFrame::ReadWindowPlacement(WINDOWPLACEMENT * pwp)
1588 CRegString placement = CRegString(_T("Software\\TortoiseGitMerge\\WindowPos"));
1589 CString sPlacement = placement;
1590 if (sPlacement.IsEmpty())
1591 return FALSE;
1592 int nRead = _stscanf_s(sPlacement, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
1593 &pwp->flags, &pwp->showCmd,
1594 &pwp->ptMinPosition.x, &pwp->ptMinPosition.y,
1595 &pwp->ptMaxPosition.x, &pwp->ptMaxPosition.y,
1596 &pwp->rcNormalPosition.left, &pwp->rcNormalPosition.top,
1597 &pwp->rcNormalPosition.right, &pwp->rcNormalPosition.bottom);
1598 if ( nRead != 10 )
1599 return FALSE;
1600 pwp->length = sizeof(WINDOWPLACEMENT);
1602 return TRUE;
1605 void CMainFrame::WriteWindowPlacement(WINDOWPLACEMENT * pwp)
1607 CRegString placement = CRegString(_T("Software\\TortoiseGitMerge\\WindowPos"));
1608 TCHAR szBuffer[_countof("-32767")*8 + sizeof("65535")*2];
1610 _stprintf_s(szBuffer, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
1611 pwp->flags, pwp->showCmd,
1612 pwp->ptMinPosition.x, pwp->ptMinPosition.y,
1613 pwp->ptMaxPosition.x, pwp->ptMaxPosition.y,
1614 pwp->rcNormalPosition.left, pwp->rcNormalPosition.top,
1615 pwp->rcNormalPosition.right, pwp->rcNormalPosition.bottom);
1616 placement = szBuffer;
1619 void CMainFrame::OnUpdateMergeMarkasresolved(CCmdUI *pCmdUI)
1621 if (pCmdUI == NULL)
1622 return;
1623 BOOL bEnable = FALSE;
1624 if ((!m_bReadOnly)&&(m_Data.m_mergedFile.InUse()))
1626 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1628 bEnable = TRUE;
1631 pCmdUI->Enable(bEnable);
1634 void CMainFrame::OnMergeMarkasresolved()
1636 if(HasConflictsWontKeep())
1637 return;
1639 // now check if the file has already been saved and if not, save it.
1640 if (m_Data.m_mergedFile.InUse())
1642 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1644 FileSave(false);
1645 m_bSaveRequired = false;
1648 MarkAsResolved();
1651 BOOL CMainFrame::MarkAsResolved()
1653 if (m_bReadOnly)
1654 return FALSE;
1655 if (!IsViewGood(m_pwndBottomView))
1656 return FALSE;
1658 CString cmd = _T("/command:resolve /path:\"");
1659 cmd += m_Data.m_mergedFile.GetFilename();
1660 cmd += _T("\" /closeonend:1 /noquestion /skipcheck /silent");
1661 if (resolveMsgWnd)
1663 CString s;
1664 s.Format(L" /resolvemsghwnd:%I64d /resolvemsgwparam:%I64d /resolvemsglparam:%I64d", (__int64)resolveMsgWnd, (__int64)resolveMsgWParam, (__int64)resolveMsgLParam);
1665 cmd += s;
1667 if(!CAppUtils::RunTortoiseGitProc(cmd))
1668 return FALSE;
1669 m_bSaveRequired = false;
1670 return TRUE;
1673 void CMainFrame::OnUpdateMergeNextconflict(CCmdUI *pCmdUI)
1675 BOOL bShow = FALSE;
1676 if (HasNextConflict(m_pwndBottomView))
1677 bShow = TRUE;
1678 else if (HasNextConflict(m_pwndRightView))
1679 bShow = TRUE;
1680 else if (HasNextConflict(m_pwndLeftView))
1681 bShow = TRUE;
1682 pCmdUI->Enable(bShow);
1685 bool CMainFrame::HasNextConflict(CBaseView* view)
1687 if (view == 0)
1688 return false;
1689 if (!view->IsTarget())
1690 return false;
1691 return view->HasNextConflict();
1694 void CMainFrame::OnUpdateMergePreviousconflict(CCmdUI *pCmdUI)
1696 BOOL bShow = FALSE;
1697 if (HasPrevConflict(m_pwndBottomView))
1698 bShow = TRUE;
1699 else if (HasPrevConflict(m_pwndRightView))
1700 bShow = TRUE;
1701 else if (HasPrevConflict(m_pwndLeftView))
1702 bShow = TRUE;
1703 pCmdUI->Enable(bShow);
1706 bool CMainFrame::HasPrevConflict(CBaseView* view)
1708 if (view == 0)
1709 return false;
1710 if (!view->IsTarget())
1711 return false;
1712 return view->HasPrevConflict();
1715 void CMainFrame::OnUpdateNavigateNextdifference(CCmdUI *pCmdUI)
1717 CBaseView* baseView = GetActiveBaseView();
1718 BOOL bShow = FALSE;
1719 if (baseView != 0)
1720 bShow = baseView->HasNextDiff();
1721 pCmdUI->Enable(bShow);
1724 void CMainFrame::OnUpdateNavigatePreviousdifference(CCmdUI *pCmdUI)
1726 CBaseView* baseView = GetActiveBaseView();
1727 BOOL bShow = FALSE;
1728 if (baseView != 0)
1729 bShow = baseView->HasPrevDiff();
1730 pCmdUI->Enable(bShow);
1733 void CMainFrame::OnUpdateNavigateNextinlinediff(CCmdUI *pCmdUI)
1735 BOOL bShow = FALSE;
1736 if (HasNextInlineDiff(m_pwndBottomView))
1737 bShow = TRUE;
1738 else if (HasNextInlineDiff(m_pwndRightView))
1739 bShow = TRUE;
1740 else if (HasNextInlineDiff(m_pwndLeftView))
1741 bShow = TRUE;
1742 pCmdUI->Enable(bShow);
1745 bool CMainFrame::HasNextInlineDiff(CBaseView* view)
1747 if (view == 0)
1748 return false;
1749 if (!view->IsTarget())
1750 return false;
1751 return view->HasNextInlineDiff();
1754 void CMainFrame::OnUpdateNavigatePrevinlinediff(CCmdUI *pCmdUI)
1756 BOOL bShow = FALSE;
1757 if (HasPrevInlineDiff(m_pwndBottomView))
1758 bShow = TRUE;
1759 else if (HasPrevInlineDiff(m_pwndRightView))
1760 bShow = TRUE;
1761 else if (HasPrevInlineDiff(m_pwndLeftView))
1762 bShow = TRUE;
1763 pCmdUI->Enable(bShow);
1766 bool CMainFrame::HasPrevInlineDiff(CBaseView* view)
1768 if (view == 0)
1769 return false;
1770 if (!view->IsTarget())
1771 return false;
1772 return view->HasPrevInlineDiff();
1775 void CMainFrame::OnMoving(UINT fwSide, LPRECT pRect)
1777 // if the pathfilelist dialog is attached to the mainframe,
1778 // move it along with the mainframe
1779 if (::IsWindow(m_dlgFilePatches.m_hWnd))
1781 RECT patchrect;
1782 m_dlgFilePatches.GetWindowRect(&patchrect);
1783 if (::IsWindow(m_hWnd))
1785 RECT thisrect;
1786 GetWindowRect(&thisrect);
1787 if (patchrect.right == thisrect.left)
1789 m_dlgFilePatches.SetWindowPos(NULL, patchrect.left - (thisrect.left - pRect->left), patchrect.top - (thisrect.top - pRect->top),
1790 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
1794 __super::OnMoving(fwSide, pRect);
1797 void CMainFrame::OnUpdateEditCopy(CCmdUI *pCmdUI)
1799 BOOL bShow = FALSE;
1800 if ((m_pwndBottomView)&&(m_pwndBottomView->HasSelection()))
1801 bShow = TRUE;
1802 else if ((m_pwndRightView)&&(m_pwndRightView->HasSelection()))
1803 bShow = TRUE;
1804 else if ((m_pwndLeftView)&&(m_pwndLeftView->HasSelection()))
1805 bShow = TRUE;
1806 pCmdUI->Enable(bShow);
1809 void CMainFrame::OnUpdateEditPaste(CCmdUI *pCmdUI)
1811 BOOL bWritable = FALSE;
1812 if ((m_pwndBottomView)&&(m_pwndBottomView->IsWritable()))
1813 bWritable = TRUE;
1814 else if ((m_pwndRightView)&&(m_pwndRightView->IsWritable()))
1815 bWritable = TRUE;
1816 else if ((m_pwndLeftView)&&(m_pwndLeftView->IsWritable()))
1817 bWritable = TRUE;
1818 pCmdUI->Enable(bWritable && ::IsClipboardFormatAvailable(CF_TEXT));
1821 void CMainFrame::OnViewSwitchleft()
1823 int ret = IDNO;
1824 if (HasUnsavedEdits())
1826 CString sTemp;
1827 sTemp.LoadString(IDS_ASKFORSAVE);
1828 ret = MessageBox(sTemp, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
1829 if (ret == IDYES)
1831 if (!FileSave())
1832 return;
1835 if ((ret == IDNO)||(ret == IDYES))
1837 CWorkingFile file = m_Data.m_baseFile;
1838 m_Data.m_baseFile = m_Data.m_yourFile;
1839 m_Data.m_yourFile = file;
1840 if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_yourFile.GetFilename())==0)
1842 m_Data.m_mergedFile = m_Data.m_baseFile;
1844 else if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_baseFile.GetFilename())==0)
1846 m_Data.m_mergedFile = m_Data.m_yourFile;
1848 LoadViews();
1852 void CMainFrame::OnUpdateViewSwitchleft(CCmdUI *pCmdUI)
1854 BOOL bEnable = !IsViewGood(m_pwndBottomView);
1855 pCmdUI->Enable(bEnable);
1858 void CMainFrame::OnUpdateViewShowfilelist(CCmdUI *pCmdUI)
1860 BOOL bEnable = m_dlgFilePatches.HasFiles();
1861 pCmdUI->Enable(bEnable);
1862 pCmdUI->SetCheck(m_dlgFilePatches.IsWindowVisible());
1865 void CMainFrame::OnViewShowfilelist()
1867 m_dlgFilePatches.ShowWindow(m_dlgFilePatches.IsWindowVisible() ? SW_HIDE : SW_SHOW);
1870 void CMainFrame::OnEditUndo()
1872 if (CUndo::GetInstance().CanUndo())
1874 CUndo::GetInstance().Undo(m_pwndLeftView, m_pwndRightView, m_pwndBottomView);
1878 void CMainFrame::OnUpdateEditUndo(CCmdUI *pCmdUI)
1880 pCmdUI->Enable(CUndo::GetInstance().CanUndo());
1883 int CMainFrame::CheckForReload()
1885 static bool bLock = false; //we don't want to check when activated after MessageBox we just created ... this is simple, but we don't need multithread lock
1886 if (bLock)
1888 return IDNO;
1890 bLock = true;
1891 bool bSourceChanged =
1892 m_Data.m_baseFile.HasSourceFileChanged()
1893 || m_Data.m_yourFile.HasSourceFileChanged()
1894 || m_Data.m_theirFile.HasSourceFileChanged()
1895 /*|| m_Data.m_mergedFile.HasSourceFileChanged()*/;
1896 if (!bSourceChanged)
1898 bLock = false;
1899 return IDNO;
1902 int idsMessage = HasUnsavedEdits() ? IDS_WARNMODIFIEDOUTSIDELOOSECHANGES : IDS_WARNMODIFIEDOUTSIDE;
1903 UINT ret = CMessageBox::Show(m_hWnd, idsMessage, IDS_APPNAME, MB_YESNO | MB_ICONQUESTION);
1905 if (ret == IDYES)
1907 CDiffColors::GetInstance().LoadRegistry();
1908 LoadViews(-1);
1910 else
1912 if (IsViewGood(m_pwndBottomView)) // three pane view
1914 /*if (m_Data.m_sourceFile.HasSourceFileChanged())
1915 m_pwndBottomView->SetModified();
1916 if (m_Data.m_mergedFile.HasSourceFileChanged())
1917 m_pwndBottomView->SetModified();//*/
1918 if (m_Data.m_yourFile.HasSourceFileChanged())
1919 m_pwndRightView->SetModified();
1920 if (m_Data.m_theirFile.HasSourceFileChanged())
1921 m_pwndLeftView->SetModified();
1923 else if (IsViewGood(m_pwndRightView)) // two pane view
1925 if (m_Data.m_baseFile.HasSourceFileChanged())
1926 m_pwndLeftView->SetModified();
1927 if (m_Data.m_yourFile.HasSourceFileChanged())
1928 m_pwndRightView->SetModified();
1930 else
1932 if (m_Data.m_yourFile.HasSourceFileChanged())
1933 m_pwndLeftView->SetModified();
1936 // no reload just store updated file time
1937 m_Data.m_baseFile.StoreFileAttributes();
1938 m_Data.m_theirFile.StoreFileAttributes();
1939 m_Data.m_yourFile.StoreFileAttributes();
1940 //m_Data.m_mergedFile.StoreFileAttributes();
1942 bLock = false;
1943 return ret;
1946 int CMainFrame::CheckForSave()
1948 UINT ret = IDNO;
1949 if (HasUnsavedEdits())
1951 CString sTemp;
1952 sTemp.LoadString(IDS_WARNMODIFIEDLOOSECHANGES);
1953 ret = MessageBox(sTemp, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
1955 if (ret == IDYES)
1957 if (!FileSave())
1958 ret = IDCANCEL;
1961 return ret;
1964 bool CMainFrame::HasUnsavedEdits() const
1966 return HasUnsavedEdits(m_pwndBottomView) || HasUnsavedEdits(m_pwndRightView) || m_bSaveRequired;
1969 bool CMainFrame::HasUnsavedEdits(const CBaseView* view)
1971 if(view == 0)
1972 return false;
1973 return view->IsModified();
1976 bool CMainFrame::IsViewGood(const CBaseView* view)
1978 return CBaseView::IsViewGood(view);
1981 void CMainFrame::OnViewInlinediffword()
1983 m_bInlineWordDiff = !m_bInlineWordDiff;
1984 if (m_pwndLeftView)
1986 m_pwndLeftView->SetInlineWordDiff(m_bInlineWordDiff);
1987 m_pwndLeftView->BuildAllScreen2ViewVector();
1988 m_pwndLeftView->DocumentUpdated();
1990 if (m_pwndRightView)
1992 m_pwndRightView->SetInlineWordDiff(m_bInlineWordDiff);
1993 m_pwndRightView->BuildAllScreen2ViewVector();
1994 m_pwndRightView->DocumentUpdated();
1996 if (m_pwndBottomView)
1998 m_pwndBottomView->SetInlineWordDiff(m_bInlineWordDiff);
1999 m_pwndBottomView->BuildAllScreen2ViewVector();
2000 m_pwndBottomView->DocumentUpdated();
2002 m_wndLineDiffBar.DocumentUpdated();
2005 void CMainFrame::OnUpdateViewInlinediffword(CCmdUI *pCmdUI)
2007 pCmdUI->Enable(m_bInlineDiff && IsViewGood(m_pwndLeftView) && IsViewGood(m_pwndRightView));
2008 pCmdUI->SetCheck(m_bInlineWordDiff);
2011 void CMainFrame::OnViewInlinediff()
2013 m_bInlineDiff = !m_bInlineDiff;
2014 if (m_pwndLeftView)
2016 m_pwndLeftView->SetInlineDiff(m_bInlineDiff);
2017 m_pwndLeftView->BuildAllScreen2ViewVector();
2018 m_pwndLeftView->DocumentUpdated();
2020 if (m_pwndRightView)
2022 m_pwndRightView->SetInlineDiff(m_bInlineDiff);
2023 m_pwndRightView->BuildAllScreen2ViewVector();
2024 m_pwndRightView->DocumentUpdated();
2026 if (m_pwndBottomView)
2028 m_pwndBottomView->SetInlineDiff(m_bInlineDiff);
2029 m_pwndBottomView->BuildAllScreen2ViewVector();
2030 m_pwndBottomView->DocumentUpdated();
2032 m_wndLineDiffBar.DocumentUpdated();
2035 void CMainFrame::OnUpdateViewInlinediff(CCmdUI *pCmdUI)
2037 pCmdUI->Enable(IsViewGood(m_pwndLeftView) && IsViewGood(m_pwndRightView));
2038 pCmdUI->SetCheck(m_bInlineDiff);
2041 void CMainFrame::OnUpdateEditCreateunifieddifffile(CCmdUI *pCmdUI)
2043 // "create unified diff file" is only available if two files
2044 // are diffed, not three.
2045 bool bEnabled = true;
2046 if (!IsViewGood(m_pwndLeftView))
2047 bEnabled = false;
2048 else if (!IsViewGood(m_pwndRightView))
2049 bEnabled = false;
2050 else if (IsViewGood(m_pwndBottomView)) //no negation here
2051 bEnabled = false;
2052 pCmdUI->Enable(bEnabled);
2055 void CMainFrame::OnEditCreateunifieddifffile()
2057 CString origFile, modifiedFile;
2058 // the original file is the one on the left
2059 if (m_pwndLeftView)
2060 origFile = m_pwndLeftView->m_sFullFilePath;
2061 if (m_pwndRightView)
2062 modifiedFile = m_pwndRightView->m_sFullFilePath;
2063 if (origFile.IsEmpty() || modifiedFile.IsEmpty())
2064 return;
2066 CString outputFile;
2067 if(!TryGetFileName(outputFile))
2068 return;
2070 CAppUtils::CreateUnifiedDiff(origFile, modifiedFile, outputFile, true);
2073 void CMainFrame::OnUpdateViewLinediffbar(CCmdUI *pCmdUI)
2075 pCmdUI->SetCheck(m_bLineDiff);
2076 pCmdUI->Enable();
2079 void CMainFrame::OnViewLinediffbar()
2081 m_bLineDiff = !m_bLineDiff;
2082 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2083 m_wndLineDiffBar.DocumentUpdated();
2084 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2085 m_wndLocatorBar.DocumentUpdated();
2088 void CMainFrame::OnUpdateViewLocatorbar(CCmdUI *pCmdUI)
2090 pCmdUI->SetCheck(m_bLocatorBar);
2091 pCmdUI->Enable();
2094 void CMainFrame::OnViewLocatorbar()
2096 m_bLocatorBar = !m_bLocatorBar;
2097 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2098 m_wndLocatorBar.DocumentUpdated();
2099 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2100 m_wndLineDiffBar.DocumentUpdated();
2103 void CMainFrame::OnViewComparewhitespaces()
2105 if (CheckForSave()==IDCANCEL)
2106 return;
2107 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2108 regIgnoreWS = 0;
2109 LoadViews(-1);
2112 void CMainFrame::OnUpdateViewComparewhitespaces(CCmdUI *pCmdUI)
2114 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2115 DWORD dwIgnoreWS = regIgnoreWS;
2116 pCmdUI->SetCheck(dwIgnoreWS == 0);
2119 void CMainFrame::OnViewIgnorewhitespacechanges()
2121 if (CheckForSave()==IDCANCEL)
2122 return;
2123 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2124 regIgnoreWS = 2;
2125 LoadViews(-1);
2128 void CMainFrame::OnUpdateViewIgnorewhitespacechanges(CCmdUI *pCmdUI)
2130 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2131 DWORD dwIgnoreWS = regIgnoreWS;
2132 pCmdUI->SetCheck(dwIgnoreWS == 2);
2135 void CMainFrame::OnViewIgnoreallwhitespacechanges()
2137 if (CheckForSave()==IDCANCEL)
2138 return;
2139 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2140 regIgnoreWS = 1;
2141 LoadViews(-1);
2144 void CMainFrame::OnUpdateViewIgnoreallwhitespacechanges(CCmdUI *pCmdUI)
2146 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2147 DWORD dwIgnoreWS = regIgnoreWS;
2148 pCmdUI->SetCheck(dwIgnoreWS == 1);
2151 void CMainFrame::OnViewMovedBlocks()
2153 m_bViewMovedBlocks = !(DWORD)m_regViewModedBlocks;
2154 m_regViewModedBlocks = m_bViewMovedBlocks;
2155 LoadViews(-1);
2158 void CMainFrame::OnUpdateViewMovedBlocks(CCmdUI *pCmdUI)
2160 pCmdUI->SetCheck(m_bViewMovedBlocks);
2161 BOOL bEnable = TRUE;
2162 if (IsViewGood(m_pwndBottomView))
2164 bEnable = FALSE;
2166 pCmdUI->Enable(bEnable);
2169 bool CMainFrame::HasConflictsWontKeep()
2171 const int nConflictLine = CheckResolved();
2172 if (nConflictLine < 0)
2173 return false;
2175 CString sTemp;
2176 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
2177 if (MessageBox(sTemp, 0, MB_ICONERROR | MB_YESNO)==IDYES)
2178 return false;
2180 if (m_pwndBottomView)
2181 m_pwndBottomView->GoToLine(nConflictLine);
2182 return true;
2185 bool CMainFrame::TryGetFileName(CString& result)
2187 return CCommonAppUtils::FileOpenSave(result, NULL, IDS_SAVEASTITLE, IDS_COMMONFILEFILTER, false, m_hWnd);
2190 CBaseView* CMainFrame::GetActiveBaseView() const
2192 CView* activeView = GetActiveView();
2193 CBaseView* activeBase = dynamic_cast<CBaseView*>( activeView );
2194 return activeBase;
2197 void CMainFrame::SetWindowTitle()
2199 // try to find a suitable window title
2200 CString sYour = m_Data.m_yourFile.GetDescriptiveName();
2201 if (sYour.Find(_T(" - "))>=0)
2202 sYour = sYour.Left(sYour.Find(_T(" - ")));
2203 if (sYour.Find(_T(" : "))>=0)
2204 sYour = sYour.Left(sYour.Find(_T(" : ")));
2205 CString sTheir = m_Data.m_theirFile.GetDescriptiveName();
2206 if (sTheir.IsEmpty())
2207 sTheir = m_Data.m_baseFile.GetDescriptiveName();
2208 if (sTheir.Find(_T(" - "))>=0)
2209 sTheir = sTheir.Left(sTheir.Find(_T(" - ")));
2210 if (sTheir.Find(_T(" : "))>=0)
2211 sTheir = sTheir.Left(sTheir.Find(_T(" : ")));
2213 if (!sYour.IsEmpty() && !sTheir.IsEmpty())
2215 if (sYour.CompareNoCase(sTheir)==0)
2216 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
2217 else if ((sYour.GetLength() < 10) &&
2218 (sTheir.GetLength() < 10))
2219 SetWindowText(sYour + _T(" - ") + sTheir + _T(" - TortoiseGitMerge"));
2220 else
2222 // we have two very long descriptive texts here, which
2223 // means we have to find a way to use them as a window
2224 // title in a shorter way.
2225 // for simplicity, we just use the one from "yourfile"
2226 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
2229 else if (!sYour.IsEmpty())
2230 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
2231 else if (!sTheir.IsEmpty())
2232 SetWindowText(sTheir + _T(" - TortoiseGitMerge"));
2233 else
2234 SetWindowText(L"TortoiseGitMerge");