aa2213bd200b71e05f9b91e35e7e14ee8353ea20
[TortoiseGit.git] / src / TortoiseMerge / MainFrm.cpp
blobaa2213bd200b71e05f9b91e35e7e14ee8353ea20
1 // TortoiseGitMerge - a Diff/Patch program
3 // Copyright (C) 2008-2013 - TortoiseGit
4 // Copyright (C) 2004-2012 - TortoiseSVN
5 // Copyright (C) 2012-2013 - 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"
38 #include "git2.h"
40 #ifdef _DEBUG
41 #define new DEBUG_NEW
42 #endif
44 // CMainFrame
45 const UINT TaskBarButtonCreated = RegisterWindowMessage(L"TaskbarButtonCreated");
47 IMPLEMENT_DYNCREATE(CMainFrame, CFrameWndEx)
49 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)
50 ON_WM_CREATE()
51 ON_COMMAND_RANGE(ID_VIEW_APPLOOK_WIN7, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnApplicationLook)
52 ON_UPDATE_COMMAND_UI_RANGE(IDC_STYLEBUTTON, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnUpdateApplicationLook)
53 // Global help commands
54 ON_COMMAND(ID_HELP_FINDER, CFrameWndEx::OnHelpFinder)
55 ON_COMMAND(ID_HELP, CFrameWndEx::OnHelp)
56 ON_COMMAND(ID_CONTEXT_HELP, CFrameWndEx::OnContextHelp)
57 ON_COMMAND(ID_DEFAULT_HELP, CFrameWndEx::OnHelpFinder)
58 ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
59 ON_COMMAND(ID_VIEW_WHITESPACES, OnViewWhitespaces)
60 ON_WM_SIZE()
61 ON_COMMAND(ID_FILE_SAVE, OnFileSave)
62 ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
63 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave)
64 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_AS, OnUpdateFileSaveAs)
65 ON_COMMAND(ID_VIEW_ONEWAYDIFF, OnViewOnewaydiff)
66 ON_UPDATE_COMMAND_UI(ID_VIEW_ONEWAYDIFF, OnUpdateViewOnewaydiff)
67 ON_UPDATE_COMMAND_UI(ID_VIEW_WHITESPACES, OnUpdateViewWhitespaces)
68 ON_COMMAND(ID_VIEW_OPTIONS, OnViewOptions)
69 ON_WM_CLOSE()
70 ON_WM_ACTIVATE()
71 ON_COMMAND(ID_FILE_RELOAD, OnFileReload)
72 ON_COMMAND(ID_VIEW_LINEDOWN, OnViewLinedown)
73 ON_COMMAND(ID_VIEW_LINEUP, OnViewLineup)
74 ON_COMMAND(ID_VIEW_MOVEDBLOCKS, OnViewMovedBlocks)
75 ON_UPDATE_COMMAND_UI(ID_VIEW_MOVEDBLOCKS, OnUpdateViewMovedBlocks)
76 ON_UPDATE_COMMAND_UI(ID_EDIT_MARKASRESOLVED, OnUpdateMergeMarkasresolved)
77 ON_COMMAND(ID_EDIT_MARKASRESOLVED, OnMergeMarkasresolved)
78 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTCONFLICT, OnUpdateMergeNextconflict)
79 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSCONFLICT, OnUpdateMergePreviousconflict)
80 ON_WM_MOVE()
81 ON_WM_MOVING()
82 ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
83 ON_COMMAND(ID_VIEW_SWITCHLEFT, OnViewSwitchleft)
84 ON_UPDATE_COMMAND_UI(ID_VIEW_SWITCHLEFT, OnUpdateViewSwitchleft)
85 ON_COMMAND(ID_VIEW_LINELEFT, &CMainFrame::OnViewLineleft)
86 ON_COMMAND(ID_VIEW_LINERIGHT, &CMainFrame::OnViewLineright)
87 ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWFILELIST, &CMainFrame::OnUpdateViewShowfilelist)
88 ON_COMMAND(ID_VIEW_SHOWFILELIST, &CMainFrame::OnViewShowfilelist)
89 ON_COMMAND(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnEditUseTheirs)
90 ON_COMMAND(ID_EDIT_USEMYBLOCK, &CMainFrame::OnEditUseMine)
91 ON_COMMAND(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnEditUseTheirsThenMine)
92 ON_COMMAND(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnEditUseMineThenTheirs)
93 ON_COMMAND(ID_EDIT_UNDO, &CMainFrame::OnEditUndo)
94 ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, &CMainFrame::OnUpdateEditUndo)
95 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnUpdateEditUseminethentheirblock)
96 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMYBLOCK, &CMainFrame::OnUpdateEditUsemyblock)
97 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnUpdateEditUsetheirblock)
98 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnUpdateEditUsetheirthenmyblock)
99 ON_COMMAND(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnViewInlinediffword)
100 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnUpdateViewInlinediffword)
101 ON_COMMAND(ID_VIEW_INLINEDIFF, &CMainFrame::OnViewInlinediff)
102 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFF, &CMainFrame::OnUpdateViewInlinediff)
103 ON_UPDATE_COMMAND_UI(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnUpdateEditCreateunifieddifffile)
104 ON_COMMAND(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnEditCreateunifieddifffile)
105 ON_UPDATE_COMMAND_UI(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnUpdateViewLinediffbar)
106 ON_COMMAND(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnViewLinediffbar)
107 ON_UPDATE_COMMAND_UI(ID_VIEW_LOCATORBAR, &CMainFrame::OnUpdateViewLocatorbar)
108 ON_COMMAND(ID_VIEW_LOCATORBAR, &CMainFrame::OnViewLocatorbar)
109 ON_COMMAND(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnEditUseleftblock)
110 ON_UPDATE_COMMAND_UI(ID_USEBLOCKS, &CMainFrame::OnUpdateUseBlock)
111 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnUpdateEditUseleftblock)
112 ON_COMMAND(ID_EDIT_USELEFTFILE, &CMainFrame::OnEditUseleftfile)
113 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTFILE, &CMainFrame::OnUpdateEditUseleftfile)
114 ON_COMMAND(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnEditUseblockfromleftbeforeright)
115 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnUpdateEditUseblockfromleftbeforeright)
116 ON_COMMAND(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnEditUseblockfromrightbeforeleft)
117 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnUpdateEditUseblockfromrightbeforeleft)
118 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTDIFFERENCE, &CMainFrame::OnUpdateNavigateNextdifference)
119 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSDIFFERENCE, &CMainFrame::OnUpdateNavigatePreviousdifference)
120 ON_COMMAND(ID_VIEW_COLLAPSED, &CMainFrame::OnViewCollapsed)
121 ON_UPDATE_COMMAND_UI(ID_VIEW_COLLAPSED, &CMainFrame::OnUpdateViewCollapsed)
122 ON_COMMAND(ID_VIEW_COMPAREWHITESPACES, &CMainFrame::OnViewComparewhitespaces)
123 ON_UPDATE_COMMAND_UI(ID_VIEW_COMPAREWHITESPACES, &CMainFrame::OnUpdateViewComparewhitespaces)
124 ON_COMMAND(ID_VIEW_IGNOREWHITESPACECHANGES, &CMainFrame::OnViewIgnorewhitespacechanges)
125 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREWHITESPACECHANGES, &CMainFrame::OnUpdateViewIgnorewhitespacechanges)
126 ON_COMMAND(ID_VIEW_IGNOREALLWHITESPACECHANGES, &CMainFrame::OnViewIgnoreallwhitespacechanges)
127 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREALLWHITESPACECHANGES, &CMainFrame::OnUpdateViewIgnoreallwhitespacechanges)
128 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTINLINEDIFF, &CMainFrame::OnUpdateNavigateNextinlinediff)
129 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVINLINEDIFF, &CMainFrame::OnUpdateNavigatePrevinlinediff)
130 ON_COMMAND(ID_VIEW_WRAPLONGLINES, &CMainFrame::OnViewWraplonglines)
131 ON_UPDATE_COMMAND_UI(ID_VIEW_WRAPLONGLINES, &CMainFrame::OnUpdateViewWraplonglines)
132 ON_REGISTERED_MESSAGE( TaskBarButtonCreated, CMainFrame::OnTaskbarButtonCreated )
133 ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, &CMainFrame::OnUpdateEditPaste)
134 END_MESSAGE_MAP()
136 static UINT indicators[] =
138 ID_SEPARATOR, // status line indicator
139 ID_INDICATOR_LEFTVIEW,
140 ID_INDICATOR_RIGHTVIEW,
141 ID_INDICATOR_BOTTOMVIEW,
142 ID_INDICATOR_CAPS,
143 ID_INDICATOR_NUM,
147 // CMainFrame construction/destruction
149 CMainFrame::CMainFrame()
150 : m_bInitSplitter(FALSE)
151 , m_bReversedPatch(FALSE)
152 , m_bHasConflicts(false)
153 , m_bInlineWordDiff(true)
154 , m_bLineDiff(true)
155 , m_bLocatorBar(true)
156 , m_nMoveMovesToIgnore(0)
157 , m_pwndLeftView(NULL)
158 , m_pwndRightView(NULL)
159 , m_pwndBottomView(NULL)
160 , m_bReadOnly(false)
161 , m_bBlame(false)
162 , m_bCheckReload(false)
163 , m_bSaveRequired(false)
164 , resolveMsgWnd(0)
165 , resolveMsgWParam(0)
166 , resolveMsgLParam(0)
167 , m_regWrapLines(L"Software\\TortoiseGitMerge\\WrapLines", 0)
168 , m_regViewModedBlocks(L"Software\\TortoiseGitMerge\\ViewMovedBlocks", 0)
169 , m_regOneWay(L"Software\\TortoiseGitMerge\\OnePane")
170 , m_regCollapsed(L"Software\\TortoiseGitMerge\\Collapsed", 0)
171 , m_regInlineDiff(L"Software\\TortoiseGitMerge\\DisplayBinDiff", TRUE)
173 m_bOneWay = (0 != ((DWORD)m_regOneWay));
174 theApp.m_nAppLook = theApp.GetInt(_T("ApplicationLook"), ID_VIEW_APPLOOK_VS_2005);
175 m_bCollapsed = !!(DWORD)m_regCollapsed;
176 m_bViewMovedBlocks = !!(DWORD)m_regViewModedBlocks;
177 m_bWrapLines = !!(DWORD)m_regWrapLines;
178 m_bInlineDiff = !!m_regInlineDiff;
179 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
182 CMainFrame::~CMainFrame()
186 LRESULT CMainFrame::OnTaskbarButtonCreated(WPARAM /*wParam*/, LPARAM /*lParam*/)
188 SetUUIDOverlayIcon(m_hWnd);
189 return 0;
193 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
195 if (CFrameWndEx::OnCreate(lpCreateStruct) == -1)
196 return -1;
198 OnApplicationLook(theApp.m_nAppLook);
200 m_wndRibbonBar.Create (this);
201 m_wndRibbonBar.LoadFromResource(IDR_RIBBON);
203 // enable the dialog launch button on the view panel
204 CMFCRibbonCategory * pMainCat = m_wndRibbonBar.GetCategory(1);
205 if (pMainCat)
207 CMFCRibbonPanel * pPanel = pMainCat->GetPanel(3);
208 if (pPanel)
209 pPanel->EnableLaunchButton(ID_VIEW_OPTIONS);
212 if (!m_wndStatusBar.Create(this) ||
213 !m_wndStatusBar.SetIndicators(indicators,
214 _countof(indicators)))
216 TRACE0("Failed to create status bar\n");
217 return -1; // fail to create
220 if (!m_wndLocatorBar.Create(this, IDD_DIFFLOCATOR,
221 CBRS_ALIGN_LEFT | CBRS_SIZE_FIXED, ID_VIEW_LOCATORBAR))
223 TRACE0("Failed to create dialogbar\n");
224 return -1; // fail to create
226 if (!m_wndLineDiffBar.Create(this, IDD_LINEDIFF,
227 CBRS_ALIGN_BOTTOM | CBRS_SIZE_FIXED, ID_VIEW_LINEDIFFBAR))
229 TRACE0("Failed to create dialogbar\n");
230 return -1; // fail to create
232 m_wndLocatorBar.m_pMainFrm = this;
233 m_wndLineDiffBar.m_pMainFrm = this;
235 EnableDocking(CBRS_ALIGN_ANY);
236 DockPane(&m_wndLocatorBar);
237 DockPane(&m_wndLineDiffBar);
238 ShowPane(&m_wndLocatorBar, true, false, true);
239 ShowPane(&m_wndLineDiffBar, true, false, true);
241 m_wndLocatorBar.EnableGripper(FALSE);
242 m_wndLineDiffBar.EnableGripper(FALSE);
244 return 0;
247 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
249 if( !CFrameWndEx::PreCreateWindow(cs) )
250 return FALSE;
251 return TRUE;
254 void CMainFrame::OnApplicationLook(UINT id)
256 CWaitCursor wait;
258 theApp.m_nAppLook = id;
260 switch (theApp.m_nAppLook)
262 case ID_VIEW_APPLOOK_WIN_2000:
263 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManager));
264 m_wndRibbonBar.SetWindows7Look(FALSE);
265 break;
267 case ID_VIEW_APPLOOK_OFF_XP:
268 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOfficeXP));
269 m_wndRibbonBar.SetWindows7Look(FALSE);
270 break;
272 case ID_VIEW_APPLOOK_WIN_XP:
273 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
274 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
275 m_wndRibbonBar.SetWindows7Look(FALSE);
276 break;
278 case ID_VIEW_APPLOOK_OFF_2003:
279 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2003));
280 CDockingManager::SetDockingMode(DT_SMART);
281 m_wndRibbonBar.SetWindows7Look(FALSE);
282 break;
284 case ID_VIEW_APPLOOK_VS_2005:
285 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2005));
286 CDockingManager::SetDockingMode(DT_SMART);
287 m_wndRibbonBar.SetWindows7Look(FALSE);
288 break;
290 case ID_VIEW_APPLOOK_VS_2008:
291 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2008));
292 CDockingManager::SetDockingMode(DT_SMART);
293 m_wndRibbonBar.SetWindows7Look(FALSE);
294 break;
296 case ID_VIEW_APPLOOK_WIN7:
297 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows7));
298 CDockingManager::SetDockingMode(DT_SMART);
299 m_wndRibbonBar.SetWindows7Look(TRUE);
300 break;
302 default:
303 switch (theApp.m_nAppLook)
305 case ID_VIEW_APPLOOK_OFF_2007_BLUE:
306 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_LunaBlue);
307 break;
309 case ID_VIEW_APPLOOK_OFF_2007_BLACK:
310 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_ObsidianBlack);
311 break;
313 case ID_VIEW_APPLOOK_OFF_2007_SILVER:
314 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Silver);
315 break;
317 case ID_VIEW_APPLOOK_OFF_2007_AQUA:
318 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Aqua);
319 break;
322 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));
323 CDockingManager::SetDockingMode(DT_SMART);
324 m_wndRibbonBar.SetWindows7Look(FALSE);
327 RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_FRAME | RDW_ERASE);
329 theApp.WriteInt(_T("ApplicationLook"), theApp.m_nAppLook);
332 void CMainFrame::OnUpdateApplicationLook(CCmdUI* pCmdUI)
334 pCmdUI->Enable();
335 pCmdUI->SetRadio(theApp.m_nAppLook == pCmdUI->m_nID);
339 // CMainFrame diagnostics
341 #ifdef _DEBUG
342 void CMainFrame::AssertValid() const
344 CFrameWndEx::AssertValid();
347 void CMainFrame::Dump(CDumpContext& dc) const
349 CFrameWndEx::Dump(dc);
352 #endif //_DEBUG
355 // CMainFrame message handlers
358 BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)
360 CRect cr;
361 GetClientRect( &cr);
364 // split into three panes:
365 // -------------
366 // | | |
367 // | | |
368 // |------------
369 // | |
370 // | |
371 // |------------
373 // create a splitter with 2 rows, 1 column
374 if (!m_wndSplitter.CreateStatic(this, 2, 1))
376 TRACE0("Failed to CreateStaticSplitter\n");
377 return FALSE;
380 // add the second splitter pane - which is a nested splitter with 2 columns
381 if (!m_wndSplitter2.CreateStatic(
382 &m_wndSplitter, // our parent window is the first splitter
383 1, 2, // the new splitter is 1 row, 2 columns
384 WS_CHILD | WS_VISIBLE | WS_BORDER, // style, WS_BORDER is needed
385 m_wndSplitter.IdFromRowCol(0, 0)
386 // new splitter is in the first row, 1st column of first splitter
389 TRACE0("Failed to create nested splitter\n");
390 return FALSE;
392 // add the first splitter pane - the default view in row 0
393 if (!m_wndSplitter.CreateView(1, 0,
394 RUNTIME_CLASS(CBottomView), CSize(cr.Width(), cr.Height()), pContext))
396 TRACE0("Failed to create first pane\n");
397 return FALSE;
399 m_pwndBottomView = (CBottomView *)m_wndSplitter.GetPane(1,0);
400 m_pwndBottomView->m_pwndLocator = &m_wndLocatorBar;
401 m_pwndBottomView->m_pwndLineDiffBar = &m_wndLineDiffBar;
402 m_pwndBottomView->m_pwndStatusBar = &m_wndStatusBar;
403 m_pwndBottomView->m_pMainFrame = this;
405 // now create the two views inside the nested splitter
407 if (!m_wndSplitter2.CreateView(0, 0,
408 RUNTIME_CLASS(CLeftView), CSize(cr.Width()/2, cr.Height()/2), pContext))
410 TRACE0("Failed to create second pane\n");
411 return FALSE;
413 m_pwndLeftView = (CLeftView *)m_wndSplitter2.GetPane(0,0);
414 m_pwndLeftView->m_pwndLocator = &m_wndLocatorBar;
415 m_pwndLeftView->m_pwndLineDiffBar = &m_wndLineDiffBar;
416 m_pwndLeftView->m_pwndStatusBar = &m_wndStatusBar;
417 m_pwndLeftView->m_pMainFrame = this;
419 if (!m_wndSplitter2.CreateView(0, 1,
420 RUNTIME_CLASS(CRightView), CSize(cr.Width()/2, cr.Height()/2), pContext))
422 TRACE0("Failed to create third pane\n");
423 return FALSE;
425 m_pwndRightView = (CRightView *)m_wndSplitter2.GetPane(0,1);
426 m_pwndRightView->m_pwndLocator = &m_wndLocatorBar;
427 m_pwndRightView->m_pwndLineDiffBar = &m_wndLineDiffBar;
428 m_pwndRightView->m_pwndStatusBar = &m_wndStatusBar;
429 m_pwndRightView->m_pMainFrame = this;
430 m_bInitSplitter = TRUE;
432 m_dlgFilePatches.Create(IDD_FILEPATCHES, this);
433 UpdateLayout();
434 return TRUE;
437 // Callback function
438 BOOL CMainFrame::PatchFile(CString sFilePath, bool /*bContentMods*/, bool bPropMods, CString sVersion, BOOL bAutoPatch)
440 CString sDummy;
441 //"dry run" was successful, so save the patched file somewhere...
442 CString sTempFile = CTempFiles::Instance().GetTempFilePathString();
443 CString sRejectedFile;
444 if (m_Patch.GetPatchResult(sFilePath, sTempFile, sRejectedFile) < 0)
446 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
447 return FALSE;
449 sFilePath = m_Patch.GetTargetPath() + _T("\\") + sFilePath;
450 sFilePath.Replace('/', '\\');
451 if (m_bReversedPatch)
453 m_Data.m_baseFile.SetFileName(sTempFile);
454 CString temp;
455 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
456 m_Data.m_baseFile.SetDescriptiveName(temp);
457 m_Data.m_yourFile.SetFileName(sFilePath);
458 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchOriginal);
459 m_Data.m_yourFile.SetDescriptiveName(temp);
460 m_Data.m_theirFile.SetOutOfUse();
461 m_Data.m_mergedFile.SetOutOfUse();
463 else
465 if ((!PathFileExists(sFilePath))||(PathIsDirectory(sFilePath)))
467 m_Data.m_baseFile.SetFileName(CTempFiles::Instance().GetTempFilePathString());
468 m_Data.m_baseFile.CreateEmptyFile();
470 else
472 m_Data.m_baseFile.SetFileName(sFilePath);
474 CString sDescription;
475 sDescription.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchOriginal);
476 m_Data.m_baseFile.SetDescriptiveName(sDescription);
477 m_Data.m_yourFile.SetFileName(sTempFile);
478 CString temp;
479 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
480 m_Data.m_yourFile.SetDescriptiveName(temp);
481 m_Data.m_theirFile.SetOutOfUse();
482 m_Data.m_mergedFile.SetFileName(sFilePath);
483 m_Data.m_bPatchRequired = bPropMods;
485 TRACE(_T("comparing %s\nwith the patched result %s\n"), (LPCTSTR)sFilePath, (LPCTSTR)sTempFile);
487 LoadViews();
488 if (!sRejectedFile.IsEmpty())
490 #if 0 // TGIT TODO
491 // start TortoiseUDiff with the rejected hunks
492 CString sTitle;
493 sTitle.Format(IDS_TITLE_REJECTEDHUNKS, (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath));
494 CAppUtils::StartUnifiedDiffViewer(sRejectedFile, sTitle);
495 #endif
497 if (bAutoPatch)
499 PatchSave();
501 return TRUE;
504 // Callback function
505 BOOL CMainFrame::DiffFiles(CString sURL1, CString sRev1, CString sURL2, CString sRev2)
507 CString tempfile1 = CTempFiles::Instance().GetTempFilePathString();
508 CString tempfile2 = CTempFiles::Instance().GetTempFilePathString();
510 ASSERT(tempfile1.Compare(tempfile2));
512 CString sTemp;
513 CSysProgressDlg progDlg;
514 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev1);
515 progDlg.SetLine(1, sTemp, true);
516 progDlg.SetLine(2, sURL1, true);
517 sTemp.LoadString(IDS_GETVERSIONOFFILETITLE);
518 progDlg.SetTitle(sTemp);
519 progDlg.SetShowProgressBar(true);
520 progDlg.SetAnimation(IDR_DOWNLOAD);
521 progDlg.SetTime(FALSE);
522 progDlg.SetProgress(1,100);
523 progDlg.ShowModeless(this);
524 if (!CAppUtils::GetVersionedFile(sURL1, sRev1, tempfile1, &progDlg, m_hWnd))
526 progDlg.Stop();
527 CString sErrMsg;
528 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev1, (LPCTSTR)sURL1);
529 MessageBox(sErrMsg, NULL, MB_ICONERROR);
530 return FALSE;
532 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev2);
533 progDlg.SetLine(1, sTemp, true);
534 progDlg.SetLine(2, sURL2, true);
535 progDlg.SetProgress(50, 100);
536 if (!CAppUtils::GetVersionedFile(sURL2, sRev2, tempfile2, &progDlg, m_hWnd))
538 progDlg.Stop();
539 CString sErrMsg;
540 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev2, (LPCTSTR)sURL2);
541 MessageBox(sErrMsg, NULL, MB_ICONERROR);
542 return FALSE;
544 progDlg.SetProgress(100,100);
545 progDlg.Stop();
546 CString temp;
547 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL1), (LPCTSTR)sRev1);
548 m_Data.m_baseFile.SetFileName(tempfile1);
549 m_Data.m_baseFile.SetDescriptiveName(temp);
550 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL2), (LPCTSTR)sRev2);
551 m_Data.m_yourFile.SetFileName(tempfile2);
552 m_Data.m_yourFile.SetDescriptiveName(temp);
554 LoadViews();
556 return TRUE;
559 void CMainFrame::OnFileOpen()
561 if (CheckForSave()==IDCANCEL)
562 return;
563 COpenDlg dlg;
564 if (dlg.DoModal()!=IDOK)
566 return;
568 m_dlgFilePatches.ShowWindow(SW_HIDE);
569 m_dlgFilePatches.Init(NULL, NULL, CString(), NULL);
570 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,
571 (LPCTSTR)dlg.m_sUnifiedDiffFile, (LPCTSTR)dlg.m_sPatchDirectory);
572 m_Data.m_baseFile.SetFileName(dlg.m_sBaseFile);
573 m_Data.m_theirFile.SetFileName(dlg.m_sTheirFile);
574 m_Data.m_yourFile.SetFileName(dlg.m_sYourFile);
575 m_Data.m_sDiffFile = dlg.m_sUnifiedDiffFile;
576 m_Data.m_sPatchPath = dlg.m_sPatchDirectory;
577 m_Data.m_mergedFile.SetOutOfUse();
578 CCrashReport::Instance().AddFile2(dlg.m_sBaseFile, NULL, _T("Basefile"), CR_AF_MAKE_FILE_COPY);
579 CCrashReport::Instance().AddFile2(dlg.m_sTheirFile, NULL, _T("Theirfile"), CR_AF_MAKE_FILE_COPY);
580 CCrashReport::Instance().AddFile2(dlg.m_sYourFile, NULL, _T("Yourfile"), CR_AF_MAKE_FILE_COPY);
581 CCrashReport::Instance().AddFile2(dlg.m_sUnifiedDiffFile, NULL, _T("Difffile"), CR_AF_MAKE_FILE_COPY);
583 if (!m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && m_Data.IsYourFileInUse())
585 // a diff between two files means "Yours" against "Base", not "Theirs" against "Yours"
586 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
588 if (m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && !m_Data.IsYourFileInUse())
590 // a diff between two files means "Yours" against "Base", not "Theirs" against "Base"
591 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
593 m_bSaveRequired = false;
595 LoadViews();
598 void CMainFrame::ClearViewNamesAndPaths()
600 m_pwndLeftView->m_sWindowName.Empty();
601 m_pwndLeftView->m_sFullFilePath.Empty();
602 m_pwndRightView->m_sWindowName.Empty();
603 m_pwndRightView->m_sFullFilePath.Empty();
604 m_pwndBottomView->m_sWindowName.Empty();
605 m_pwndBottomView->m_sFullFilePath.Empty();
608 bool CMainFrame::LoadViews(int line)
610 m_Data.SetBlame(m_bBlame);
611 m_Data.SetMovedBlocks(m_bViewMovedBlocks);
612 m_bHasConflicts = false;
613 CBaseView* pwndActiveView = m_pwndLeftView;
614 int nOldLine = m_pwndRightView ? m_pwndRightView->m_nTopLine : -1;
615 int nOldLineNumber =
616 m_pwndRightView && m_pwndRightView->m_pViewData ?
617 m_pwndRightView->m_pViewData->GetLineNumber(m_pwndRightView->m_nTopLine) : -1;
618 POINT ptOldCaretPos = {-1, -1};
619 if (m_pwndRightView && m_pwndRightView->IsTarget())
620 ptOldCaretPos = m_pwndRightView->GetCaretPosition();
621 if (m_pwndBottomView && m_pwndBottomView->IsTarget())
622 ptOldCaretPos = m_pwndBottomView->GetCaretPosition();
623 if (!m_Data.Load())
625 m_pwndLeftView->BuildAllScreen2ViewVector();
626 m_pwndLeftView->DocumentUpdated();
627 m_pwndRightView->DocumentUpdated();
628 m_pwndBottomView->DocumentUpdated();
629 m_wndLocatorBar.DocumentUpdated();
630 m_wndLineDiffBar.DocumentUpdated();
631 ::MessageBox(m_hWnd, m_Data.GetError(), _T("TortoiseGitMerge"), MB_ICONERROR);
632 m_Data.m_mergedFile.SetOutOfUse();
633 m_bSaveRequired = false;
634 return false;
636 SetWindowTitle();
637 m_pwndLeftView->BuildAllScreen2ViewVector();
638 m_pwndLeftView->DocumentUpdated();
639 m_pwndRightView->DocumentUpdated();
640 m_pwndBottomView->DocumentUpdated();
641 m_wndLocatorBar.DocumentUpdated();
642 m_wndLineDiffBar.DocumentUpdated();
644 m_pwndRightView->SetWritable(false);
645 m_pwndRightView->SetTarget(false);
646 m_pwndBottomView->SetWritable(false);
647 m_pwndBottomView->SetTarget(false);
649 if (!m_Data.IsBaseFileInUse())
651 CSysProgressDlg progDlg;
652 if (m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
654 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
656 else if ((!m_Data.m_sDiffFile.IsEmpty())&&(!m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg)))
658 progDlg.Stop();
659 ClearViewNamesAndPaths();
660 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
661 m_bSaveRequired = false;
662 return false;
664 progDlg.Stop();
665 if (m_Patch.GetNumberOfFiles() > 0)
667 CString betterpatchpath = m_Patch.CheckPatchPath(m_Data.m_sPatchPath);
668 if (betterpatchpath.CompareNoCase(m_Data.m_sPatchPath)!=0)
670 CString msg;
671 msg.Format(IDS_WARNBETTERPATCHPATHFOUND, (LPCTSTR)m_Data.m_sPatchPath, (LPCTSTR)betterpatchpath);
672 if (CMessageBox::Show(m_hWnd, msg, _T("TortoiseGitMerge"), MB_ICONQUESTION | MB_YESNO)==IDYES)
674 m_Data.m_sPatchPath = betterpatchpath;
675 m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg);
678 m_dlgFilePatches.Init(&m_Patch, this, m_Data.m_sPatchPath, this);
679 m_dlgFilePatches.ShowWindow(SW_SHOW);
680 ClearViewNamesAndPaths();
681 if (!m_wndSplitter.IsRowHidden(1))
682 m_wndSplitter.HideRow(1);
683 m_pwndLeftView->SetHidden(FALSE);
684 m_pwndRightView->SetHidden(FALSE);
685 m_pwndBottomView->SetHidden(TRUE);
688 if (m_Data.IsBaseFileInUse() && !m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
690 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
692 if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && !m_Data.IsTheirFileInUse())
694 //diff between YOUR and BASE
695 m_pwndRightView->SetWritable();
696 m_pwndRightView->SetTarget();
697 if (m_bOneWay)
699 if (!m_wndSplitter2.IsColumnHidden(1))
700 m_wndSplitter2.HideColumn(1);
702 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseBoth;
703 m_pwndLeftView->texttype = m_Data.m_arYourFile.GetUnicodeType();
704 m_pwndLeftView->lineendings = m_Data.m_arYourFile.GetLineEndings();
705 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName() + _T(" - ") + m_Data.m_yourFile.GetWindowName();
706 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename() + _T(" - ") + m_Data.m_yourFile.GetFilename();
708 m_pwndRightView->m_pViewData = NULL;
709 m_pwndBottomView->m_pViewData = NULL;
711 if (!m_wndSplitter.IsRowHidden(1))
712 m_wndSplitter.HideRow(1);
713 m_pwndLeftView->SetHidden(FALSE);
714 m_pwndRightView->SetHidden(TRUE);
715 m_pwndBottomView->SetHidden(TRUE);
716 ::SetWindowPos(m_pwndLeftView->m_hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
718 else
720 pwndActiveView = m_pwndRightView;
721 if (m_wndSplitter2.IsColumnHidden(1))
722 m_wndSplitter2.ShowColumn();
724 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseLeft;
725 m_pwndLeftView->texttype = m_Data.m_arBaseFile.GetUnicodeType();
726 m_pwndLeftView->lineendings = m_Data.m_arBaseFile.GetLineEndings();
727 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName();
728 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename();
730 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseRight;
731 m_pwndRightView->texttype = m_Data.m_arYourFile.GetUnicodeType();
732 m_pwndRightView->lineendings = m_Data.m_arYourFile.GetLineEndings();
733 m_pwndRightView->m_sWindowName = m_Data.m_yourFile.GetWindowName();
734 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
736 m_pwndBottomView->m_pViewData = NULL;
738 if (!m_wndSplitter.IsRowHidden(1))
739 m_wndSplitter.HideRow(1);
740 m_pwndLeftView->SetHidden(FALSE);
741 m_pwndRightView->SetHidden(FALSE);
742 m_pwndBottomView->SetHidden(TRUE);
745 else if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
747 //diff between THEIR, YOUR and BASE
748 m_pwndBottomView->SetWritable();
749 m_pwndBottomView->SetTarget();
750 pwndActiveView = m_pwndBottomView;
752 m_pwndLeftView->m_pViewData = &m_Data.m_TheirBaseBoth;
753 m_pwndLeftView->texttype = m_Data.m_arTheirFile.GetUnicodeType();
754 m_pwndLeftView->lineendings = m_Data.m_arTheirFile.GetLineEndings();
755 m_pwndLeftView->m_sWindowName.LoadString(IDS_VIEWTITLE_THEIRS);
756 m_pwndLeftView->m_sWindowName += _T(" - ") + m_Data.m_theirFile.GetWindowName();
757 m_pwndLeftView->m_sFullFilePath = m_Data.m_theirFile.GetFilename();
759 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseBoth;
760 m_pwndRightView->texttype = m_Data.m_arYourFile.GetUnicodeType();
761 m_pwndRightView->lineendings = m_Data.m_arYourFile.GetLineEndings();
762 m_pwndRightView->m_sWindowName.LoadString(IDS_VIEWTITLE_MINE);
763 m_pwndRightView->m_sWindowName += _T(" - ") + m_Data.m_yourFile.GetWindowName();
764 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
766 m_pwndBottomView->m_pViewData = &m_Data.m_Diff3;
767 m_pwndBottomView->texttype = m_Data.m_arTheirFile.GetUnicodeType();
768 m_pwndBottomView->lineendings = m_Data.m_arTheirFile.GetLineEndings();
769 m_pwndBottomView->m_sWindowName.LoadString(IDS_VIEWTITLE_MERGED);
770 m_pwndBottomView->m_sWindowName += _T(" - ") + m_Data.m_mergedFile.GetWindowName();
771 m_pwndBottomView->m_sFullFilePath = m_Data.m_mergedFile.GetFilename();
773 if (m_wndSplitter2.IsColumnHidden(1))
774 m_wndSplitter2.ShowColumn();
775 if (m_wndSplitter.IsRowHidden(1))
776 m_wndSplitter.ShowRow();
777 m_pwndLeftView->SetHidden(FALSE);
778 m_pwndRightView->SetHidden(FALSE);
779 m_pwndBottomView->SetHidden(FALSE);
780 // in three pane view, hide the line diff bar
781 m_wndLineDiffBar.ShowPane(false, false, true);
782 m_wndLineDiffBar.DocumentUpdated();
784 if (!m_Data.m_mergedFile.InUse())
786 m_Data.m_mergedFile.SetFileName(m_Data.m_yourFile.GetFilename());
788 m_pwndLeftView->BuildAllScreen2ViewVector();
789 m_pwndLeftView->DocumentUpdated();
790 m_pwndRightView->DocumentUpdated();
791 m_pwndBottomView->DocumentUpdated();
792 m_wndLocatorBar.DocumentUpdated();
793 m_wndLineDiffBar.DocumentUpdated();
794 UpdateLayout();
795 SetActiveView(pwndActiveView);
797 if ((line >= -1) && m_pwndRightView->m_pViewData)
799 int n = line == -1 ? min( nOldLineNumber, nOldLine ) : line;
800 if (n >= 0)
801 n = m_pwndRightView->m_pViewData->FindLineNumber(n);
802 if (n < 0)
803 n = nOldLine;
805 m_pwndRightView->ScrollAllToLine(n);
806 POINT p;
807 p.x = 0;
808 p.y = n;
809 if ((ptOldCaretPos.x >= 0) || (ptOldCaretPos.y >= 0))
810 p = ptOldCaretPos;
811 m_pwndLeftView->SetCaretPosition(p);
812 m_pwndRightView->SetCaretPosition(p);
813 m_pwndBottomView->SetCaretPosition(p);
814 m_pwndBottomView->ScrollToChar(0);
815 m_pwndLeftView->ScrollToChar(0);
816 m_pwndRightView->ScrollToChar(0);
818 else
820 CRegDWORD regFirstDiff = CRegDWORD(_T("Software\\TortoiseGitMerge\\FirstDiffOnLoad"), TRUE);
821 CRegDWORD regFirstConflict = CRegDWORD(_T("Software\\TortoiseGitMerge\\FirstConflictOnLoad"), TRUE);
822 bool bGoFirstDiff = (0 != (DWORD)regFirstDiff);
823 bool bGoFirstConflict = (0 != (DWORD)regFirstConflict);
824 if (bGoFirstConflict && (CheckResolved()>=0))
826 pwndActiveView->GoToFirstConflict();
827 // Ignore the first few Mouse Move messages, so that the line diff stays on
828 // the first diff line until the user actually moves the mouse
829 m_nMoveMovesToIgnore = MOVESTOIGNORE;
831 else if (bGoFirstDiff)
833 pwndActiveView->GoToFirstDifference();
834 // Ignore the first few Mouse Move messages, so that the line diff stays on
835 // the first diff line until the user actually moves the mouse
836 m_nMoveMovesToIgnore = MOVESTOIGNORE;
838 else
840 // Avoid incorrect rendering of active pane.
841 m_pwndBottomView->ScrollToChar(0);
842 m_pwndLeftView->ScrollToChar(0);
843 m_pwndRightView->ScrollToChar(0);
846 CheckResolved();
847 if (m_bHasConflicts)
848 m_bSaveRequired = false;
849 CUndo::GetInstance().Clear();
850 return true;
853 void CMainFrame::UpdateLayout()
855 if (m_bInitSplitter)
857 m_wndSplitter.CenterSplitter();
858 m_wndSplitter2.CenterSplitter();
862 void CMainFrame::OnSize(UINT nType, int cx, int cy)
864 CFrameWndEx::OnSize(nType, cx, cy);
865 if (m_bInitSplitter && nType != SIZE_MINIMIZED)
867 if (m_wndSplitter.GetSafeHwnd())
869 if (m_wndSplitter.HasOldRowSize() && (m_wndSplitter.GetOldRowCount() == 2))
871 int oldTotal = m_wndSplitter.GetOldRowSize(0) + m_wndSplitter.GetOldRowSize(1);
872 if (oldTotal)
874 int cxCur0, cxCur1, cxMin0, cxMin1;
875 m_wndSplitter.GetRowInfo(0, cxCur0, cxMin0);
876 m_wndSplitter.GetRowInfo(1, cxCur1, cxMin1);
877 cxCur0 = m_wndSplitter.GetOldRowSize(0) * (cxCur0 + cxCur1) / oldTotal;
878 cxCur1 = m_wndSplitter.GetOldRowSize(1) * (cxCur0 + cxCur1) / oldTotal;
879 m_wndSplitter.SetRowInfo(0, cxCur0, 0);
880 m_wndSplitter.SetRowInfo(1, cxCur1, 0);
881 m_wndSplitter.RecalcLayout();
885 if (m_wndSplitter2.HasOldColSize() && (m_wndSplitter2.GetOldColCount() == 2))
887 int oldTotal = m_wndSplitter2.GetOldColSize(0) + m_wndSplitter2.GetOldColSize(1);
888 if (oldTotal)
890 int cyCur0, cyCur1, cyMin0, cyMin1;
891 m_wndSplitter2.GetColumnInfo(0, cyCur0, cyMin0);
892 m_wndSplitter2.GetColumnInfo(1, cyCur1, cyMin1);
893 cyCur0 = m_wndSplitter2.GetOldColSize(0) * (cyCur0 + cyCur1) / oldTotal;
894 cyCur1 = m_wndSplitter2.GetOldColSize(1) * (cyCur0 + cyCur1) / oldTotal;
895 m_wndSplitter2.SetColumnInfo(0, cyCur0, 0);
896 m_wndSplitter2.SetColumnInfo(1, cyCur1, 0);
897 m_wndSplitter2.RecalcLayout();
902 if ((nType == SIZE_RESTORED)&&m_bCheckReload)
904 m_bCheckReload = false;
905 CheckForReload();
909 void CMainFrame::OnViewWhitespaces()
911 CRegDWORD regViewWhitespaces = CRegDWORD(_T("Software\\TortoiseGitMerge\\ViewWhitespaces"), 1);
912 BOOL bViewWhitespaces = regViewWhitespaces;
913 if (m_pwndLeftView)
914 bViewWhitespaces = m_pwndLeftView->m_bViewWhitespace;
916 bViewWhitespaces = !bViewWhitespaces;
917 regViewWhitespaces = bViewWhitespaces;
918 if (m_pwndLeftView)
920 m_pwndLeftView->m_bViewWhitespace = bViewWhitespaces;
921 m_pwndLeftView->Invalidate();
923 if (m_pwndRightView)
925 m_pwndRightView->m_bViewWhitespace = bViewWhitespaces;
926 m_pwndRightView->Invalidate();
928 if (m_pwndBottomView)
930 m_pwndBottomView->m_bViewWhitespace = bViewWhitespaces;
931 m_pwndBottomView->Invalidate();
935 void CMainFrame::OnUpdateViewWhitespaces(CCmdUI *pCmdUI)
937 if (m_pwndLeftView)
938 pCmdUI->SetCheck(m_pwndLeftView->m_bViewWhitespace);
941 void CMainFrame::OnViewCollapsed()
943 m_regCollapsed = !(DWORD)m_regCollapsed;
944 m_bCollapsed = !!(DWORD)m_regCollapsed;
946 OnViewTextFoldUnfold();
947 m_wndLocatorBar.Invalidate();
950 void CMainFrame::OnUpdateViewCollapsed(CCmdUI *pCmdUI)
952 pCmdUI->SetCheck(m_bCollapsed);
955 void CMainFrame::OnViewWraplonglines()
957 m_bWrapLines = !(DWORD)m_regWrapLines;
958 m_regWrapLines = m_bWrapLines;
960 if (m_pwndLeftView) m_pwndLeftView ->WrapChanged();
961 if (m_pwndRightView) m_pwndRightView ->WrapChanged();
962 if (m_pwndBottomView) m_pwndBottomView->WrapChanged();
963 OnViewTextFoldUnfold();
964 m_wndLocatorBar.DocumentUpdated();
967 void CMainFrame::OnViewTextFoldUnfold()
969 OnViewTextFoldUnfold(m_pwndLeftView);
970 OnViewTextFoldUnfold(m_pwndRightView);
971 OnViewTextFoldUnfold(m_pwndBottomView);
974 void CMainFrame::OnViewTextFoldUnfold(CBaseView* view)
976 if (view == 0)
977 return;
978 view->BuildAllScreen2ViewVector();
979 view->UpdateCaret();
980 view->Invalidate();
981 view->EnsureCaretVisible();
984 void CMainFrame::OnUpdateViewWraplonglines(CCmdUI *pCmdUI)
986 pCmdUI->SetCheck(m_bWrapLines);
989 void CMainFrame::OnViewOnewaydiff()
991 if (CheckForSave()==IDCANCEL)
992 return;
993 m_bOneWay = !m_bOneWay;
994 ShowDiffBar(!m_bOneWay);
995 LoadViews(-1);
998 void CMainFrame::ShowDiffBar(bool bShow)
1000 if (bShow)
1002 // restore the line diff bar
1003 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
1004 m_wndLineDiffBar.DocumentUpdated();
1005 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
1006 m_wndLocatorBar.DocumentUpdated();
1008 else
1010 // in one way view, hide the line diff bar
1011 m_wndLineDiffBar.ShowPane(false, false, true);
1012 m_wndLineDiffBar.DocumentUpdated();
1016 int CMainFrame::CheckResolved()
1018 //only in three way diffs can be conflicts!
1019 m_bHasConflicts = true;
1020 if (m_pwndBottomView->IsWindowVisible())
1022 CViewData* viewdata = m_pwndBottomView->m_pViewData;
1023 if (viewdata)
1025 for (int i=0; i<viewdata->GetCount(); i++)
1027 const DiffStates state = viewdata->GetState(i);
1028 if ((DIFFSTATE_CONFLICTED == state)||(DIFFSTATE_CONFLICTED_IGNORED == state))
1029 return i;
1033 m_bHasConflicts = false;
1034 return -1;
1037 int CMainFrame::SaveFile(const CString& sFilePath)
1039 CViewData * pViewData = NULL;
1040 CFileTextLines * pOriginFile = &m_Data.m_arBaseFile;
1041 if (IsViewGood(m_pwndBottomView))
1043 pViewData = m_pwndBottomView->m_pViewData;
1044 Invalidate();
1046 else if (IsViewGood(m_pwndRightView))
1048 pViewData = m_pwndRightView->m_pViewData;
1049 if (m_Data.IsYourFileInUse())
1050 pOriginFile = &m_Data.m_arYourFile;
1051 else if (m_Data.IsTheirFileInUse())
1052 pOriginFile = &m_Data.m_arTheirFile;
1053 Invalidate();
1055 else
1057 // nothing to save!
1058 return 1;
1060 if ((pViewData)&&(pOriginFile))
1062 CFileTextLines file;
1063 pOriginFile->CopySettings(&file);
1064 for (int i=0; i<pViewData->GetCount(); i++)
1066 //only copy non-removed lines
1067 DiffStates state = pViewData->GetState(i);
1068 switch (state)
1070 case DIFFSTATE_CONFLICTED:
1071 case DIFFSTATE_CONFLICTED_IGNORED:
1073 int first = i;
1074 int last = i;
1077 last++;
1078 } while((last<pViewData->GetCount()) && ((pViewData->GetState(last)==DIFFSTATE_CONFLICTED)||(pViewData->GetState(last)==DIFFSTATE_CONFLICTED_IGNORED)));
1079 // TortoiseGitMerge changes here
1080 file.Add(_T("<<<<<<< .mine"), m_pwndRightView->lineendings);
1081 for (int j=first; j<last; j++)
1083 EOL lineending = m_pwndRightView->m_pViewData->GetLineEnding(j);
1084 if (lineending == EOL_NOENDING)
1085 lineending = m_pwndRightView->lineendings;
1086 file.Add(m_pwndRightView->m_pViewData->GetLine(j), lineending);
1088 file.Add(_T("======="), m_pwndRightView->lineendings);
1089 for (int j=first; j<last; j++)
1091 EOL lineending = m_pwndLeftView->m_pViewData->GetLineEnding(j);
1092 if (lineending == EOL_NOENDING)
1093 lineending = m_pwndLeftView->lineendings;
1094 file.Add(m_pwndLeftView->m_pViewData->GetLine(j), lineending);
1096 file.Add(_T(">>>>>>> .theirs"), m_pwndRightView->lineendings);
1097 i = last-1;
1099 break;
1100 case DIFFSTATE_EMPTY:
1101 case DIFFSTATE_CONFLICTEMPTY:
1102 case DIFFSTATE_IDENTICALREMOVED:
1103 case DIFFSTATE_REMOVED:
1104 case DIFFSTATE_THEIRSREMOVED:
1105 case DIFFSTATE_YOURSREMOVED:
1106 case DIFFSTATE_CONFLICTRESOLVEDEMPTY:
1107 // do not save removed lines
1108 break;
1109 default:
1110 file.Add(pViewData->GetLine(i), pViewData->GetLineEnding(i));
1111 break;
1114 if (!file.Save(sFilePath, false, false))
1116 CMessageBox::Show(m_hWnd, file.GetErrorString(), _T("TortoiseGitMerge"), MB_ICONERROR);
1117 return -1;
1119 if (sFilePath == m_Data.m_baseFile.GetFilename())
1121 m_Data.m_baseFile.StoreFileAttributes();
1123 if (sFilePath == m_Data.m_theirFile.GetFilename())
1125 m_Data.m_theirFile.StoreFileAttributes();
1127 if (sFilePath == m_Data.m_yourFile.GetFilename())
1129 m_Data.m_yourFile.StoreFileAttributes();
1131 /*if (sFilePath == m_Data.m_mergedFile.GetFilename())
1133 m_Data.m_mergedFile.StoreFileAttributes();
1134 }//*/
1135 m_dlgFilePatches.SetFileStatusAsPatched(sFilePath);
1136 if (m_pwndBottomView)
1137 m_pwndBottomView->SetModified(FALSE);
1138 if (m_pwndRightView)
1139 m_pwndRightView->SetModified(FALSE);
1140 CUndo::GetInstance().MarkAsOriginalState();
1141 if (file.GetCount() == 1 && file.GetLineEnding(0) == EOL_NOENDING)
1142 return 0;
1143 return file.GetCount();
1145 return 1;
1148 void CMainFrame::OnFileSave()
1150 FileSave();
1153 void CMainFrame::PatchSave()
1155 bool bDoesNotExist = !PathFileExists(m_Data.m_mergedFile.GetFilename());
1156 if (m_Data.m_bPatchRequired)
1158 m_Patch.PatchPath(m_Data.m_mergedFile.GetFilename());
1160 if (!PathIsDirectory(m_Data.m_mergedFile.GetFilename()))
1162 int saveret = SaveFile(m_Data.m_mergedFile.GetFilename());
1163 if (saveret==0)
1165 // file was saved with 0 lines, remove it.
1166 m_Patch.RemoveFile(m_Data.m_mergedFile.GetFilename());
1167 // just in case
1168 DeleteFile(m_Data.m_mergedFile.GetFilename());
1170 m_Data.m_mergedFile.StoreFileAttributes();
1171 if (m_Data.m_mergedFile.GetFilename() == m_Data.m_yourFile.GetFilename())
1172 m_Data.m_yourFile.StoreFileAttributes();
1173 if ((bDoesNotExist)&&(DWORD(CRegDWORD(_T("Software\\TortoiseGitMerge\\AutoAdd"), TRUE))))
1175 // call TortoiseProc to add the new file to version control
1176 CString cmd = _T("/command:add /noui /path:\"");
1177 cmd += m_Data.m_mergedFile.GetFilename() + _T("\"");
1178 CAppUtils::RunTortoiseGitProc(cmd);
1183 bool CMainFrame::FileSave(bool bCheckResolved /*=true*/)
1185 if (!m_Data.m_mergedFile.InUse())
1186 return FileSaveAs(bCheckResolved);
1187 // check if the file has the readonly attribute set
1188 bool bDoesNotExist = false;
1189 DWORD fAttribs = GetFileAttributes(m_Data.m_mergedFile.GetFilename());
1190 if ((fAttribs != INVALID_FILE_ATTRIBUTES)&&(fAttribs & FILE_ATTRIBUTE_READONLY))
1191 return FileSaveAs(bCheckResolved);
1192 if (fAttribs == INVALID_FILE_ATTRIBUTES)
1194 bDoesNotExist = (GetLastError() == ERROR_FILE_NOT_FOUND);
1196 if (bCheckResolved && HasConflictsWontKeep())
1197 return false;
1199 if (((DWORD)CRegDWORD(_T("Software\\TortoiseGitMerge\\Backup"))) != 0)
1201 MoveFileEx(m_Data.m_mergedFile.GetFilename(), m_Data.m_mergedFile.GetFilename() + _T(".bak"), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
1203 if (m_Data.m_bPatchRequired)
1205 m_Patch.PatchPath(m_Data.m_mergedFile.GetFilename());
1207 int saveret = SaveFile(m_Data.m_mergedFile.GetFilename());
1208 if (saveret==0)
1210 // file was saved with 0 lines!
1211 // ask the user if the file should be deleted
1212 CString sTemp;
1213 sTemp.Format(IDS_DELETEWHENEMPTY, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
1214 if (CMessageBox::ShowCheck(m_hWnd, sTemp, _T("TortoiseGitMerge"), MB_YESNO, _T("DeleteFileWhenEmpty")) == IDYES)
1216 m_Patch.RemoveFile(m_Data.m_mergedFile.GetFilename());
1217 DeleteFile(m_Data.m_mergedFile.GetFilename());
1220 else if (saveret < 0)
1222 // error while saving the file
1223 return false;
1226 // if we're in conflict resolve mode (three pane view), check if there are no more conflicts
1227 // and if there aren't, ask to mark the file as resolved
1228 if (IsViewGood(m_pwndBottomView) && !m_bHasConflicts)
1230 CString projectRoot;
1231 if (g_GitAdminDir.HasAdminDir(m_Data.m_mergedFile.GetFilename(), false, &projectRoot))
1233 CString subpath = m_Data.m_mergedFile.GetFilename();
1234 subpath.Replace(_T('\\'), _T('/'));
1235 if (subpath.GetLength() >= projectRoot.GetLength())
1237 if (subpath[projectRoot.GetLength()] == _T('/'))
1238 subpath = subpath.Right(subpath.GetLength() - projectRoot.GetLength() - 1);
1239 else
1240 subpath = subpath.Right(subpath.GetLength() - projectRoot.GetLength());
1243 CStringA gitdir = CUnicodeUtils::GetMulti(projectRoot, CP_UTF8);
1244 git_repository *repository = NULL;
1245 git_index *index = NULL;
1246 bool hasConflictInIndex = false;
1249 if (git_repository_open(&repository, gitdir.GetBuffer()))
1251 gitdir.ReleaseBuffer();
1252 break;
1254 gitdir.ReleaseBuffer();
1256 if (git_repository_index(&index, repository))
1257 break;
1259 CStringA path = CUnicodeUtils::GetMulti(subpath, CP_UTF8);
1260 const git_index_entry * entry = git_index_get_bypath(index, path.GetBuffer(), 1);
1261 path.ReleaseBuffer();
1262 hasConflictInIndex = entry != nullptr;
1263 } while(0);
1265 if (index)
1266 git_index_free(index);
1268 if (repository)
1269 git_repository_free(repository);
1271 if (hasConflictInIndex)
1273 CString sTemp;
1274 sTemp.Format(IDS_MARKASRESOLVED, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1275 if (CMessageBox::Show(m_hWnd, sTemp, _T("TortoiseGitMerge"), MB_YESNO | MB_ICONQUESTION) == IDYES)
1276 MarkAsResolved();
1281 m_bSaveRequired = false;
1282 m_Data.m_mergedFile.StoreFileAttributes();
1284 if ((bDoesNotExist)&&(DWORD(CRegDWORD(_T("Software\\TortoiseGitMerge\\AutoAdd"), TRUE))))
1286 // call TortoiseProc to add the new file to version control
1287 CString cmd = _T("/command:add /noui /path:\"");
1288 cmd += m_Data.m_mergedFile.GetFilename() + _T("\"");
1289 if(!CAppUtils::RunTortoiseGitProc(cmd))
1290 return false;
1292 return true;
1295 void CMainFrame::OnFileSaveAs()
1297 FileSaveAs();
1300 bool CMainFrame::FileSaveAs(bool bCheckResolved /*=true*/)
1302 if (bCheckResolved && HasConflictsWontKeep())
1303 return false;
1305 CString fileName;
1306 if(!TryGetFileName(fileName))
1307 return false;
1309 SaveFile(fileName);
1310 return true;
1313 void CMainFrame::OnUpdateFileSave(CCmdUI *pCmdUI)
1315 BOOL bEnable = FALSE;
1316 if (m_Data.m_mergedFile.InUse())
1318 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1319 bEnable = TRUE;
1320 else if ( (IsViewGood(m_pwndRightView)&&(m_pwndRightView->m_pViewData)) &&
1321 (m_pwndRightView->IsModified() || (m_Data.m_yourFile.GetWindowName().Right(9).Compare(_T(": patched"))==0)) )
1322 bEnable = TRUE;
1324 pCmdUI->Enable(bEnable);
1327 void CMainFrame::OnUpdateFileSaveAs(CCmdUI *pCmdUI)
1329 BOOL bEnable = FALSE;
1330 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1331 bEnable = TRUE;
1332 else if (IsViewGood(m_pwndRightView)&&(m_pwndRightView->m_pViewData))
1333 bEnable = TRUE;
1334 pCmdUI->Enable(bEnable);
1337 void CMainFrame::OnUpdateViewOnewaydiff(CCmdUI *pCmdUI)
1339 pCmdUI->SetCheck(!m_bOneWay);
1340 BOOL bEnable = TRUE;
1341 if (IsViewGood(m_pwndBottomView))
1343 bEnable = FALSE;
1345 pCmdUI->Enable(bEnable);
1348 void CMainFrame::OnViewOptions()
1350 CString sTemp;
1351 sTemp.LoadString(IDS_SETTINGSTITLE);
1352 CSettings dlg(sTemp);
1353 dlg.DoModal();
1354 if (dlg.IsReloadNeeded())
1356 if (CheckForSave()==IDCANCEL)
1357 return;
1358 CDiffColors::GetInstance().LoadRegistry();
1359 LoadViews();
1360 return;
1362 CDiffColors::GetInstance().LoadRegistry();
1363 if (m_pwndBottomView)
1364 m_pwndBottomView->Invalidate();
1365 if (m_pwndLeftView)
1366 m_pwndLeftView->Invalidate();
1367 if (m_pwndRightView)
1368 m_pwndRightView->Invalidate();
1371 void CMainFrame::OnClose()
1373 UINT ret = IDNO;
1374 if (HasUnsavedEdits())
1376 CString sTemp;
1377 sTemp.LoadString(IDS_ASKFORSAVE);
1378 ret = MessageBox(sTemp, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
1380 if (ret == IDYES)
1382 if (!FileSave())
1383 return;
1386 if ((ret == IDNO)||(ret == IDYES))
1388 WINDOWPLACEMENT wp;
1390 // before it is destroyed, save the position of the window
1391 wp.length = sizeof wp;
1393 if (GetWindowPlacement(&wp))
1396 if (IsIconic())
1397 // never restore to Iconic state
1398 wp.showCmd = SW_SHOW ;
1400 if ((wp.flags & WPF_RESTORETOMAXIMIZED) != 0)
1401 // if maximized and maybe iconic restore maximized state
1402 wp.showCmd = SW_SHOWMAXIMIZED ;
1404 // and write it to the .INI file
1405 WriteWindowPlacement(&wp);
1407 __super::OnClose();
1411 void CMainFrame::OnActivate(UINT nValue, CWnd* /*pwnd*/, BOOL /*bActivated?*/) {
1412 if (nValue != 0) // activated
1414 if (IsIconic())
1416 m_bCheckReload = TRUE;
1418 else
1419 CheckForReload();
1423 void CMainFrame::OnViewLinedown()
1425 OnViewLineUpDown(1);
1428 void CMainFrame::OnViewLineup()
1430 OnViewLineUpDown(-1);
1433 void CMainFrame::OnViewLineUpDown(int direction)
1435 if (m_pwndLeftView)
1436 m_pwndLeftView->ScrollToLine(m_pwndLeftView->m_nTopLine+direction);
1437 if (m_pwndRightView)
1438 m_pwndRightView->ScrollToLine(m_pwndRightView->m_nTopLine+direction);
1439 if (m_pwndBottomView)
1440 m_pwndBottomView->ScrollToLine(m_pwndBottomView->m_nTopLine+direction);
1441 m_wndLocatorBar.Invalidate();
1442 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1445 void CMainFrame::OnViewLineleft()
1447 OnViewLineLeftRight(-1);
1450 void CMainFrame::OnViewLineright()
1452 OnViewLineLeftRight(1);
1455 void CMainFrame::OnViewLineLeftRight(int direction)
1457 if (m_pwndLeftView)
1458 m_pwndLeftView->ScrollSide(direction);
1459 if (m_pwndRightView)
1460 m_pwndRightView->ScrollSide(direction);
1461 if (m_pwndBottomView)
1462 m_pwndBottomView->ScrollSide(direction);
1465 void CMainFrame::OnEditUseTheirs()
1467 if (m_pwndBottomView)
1468 m_pwndBottomView->UseTheirTextBlock();
1470 void CMainFrame::OnUpdateEditUsetheirblock(CCmdUI *pCmdUI)
1472 pCmdUI->Enable(m_pwndBottomView && m_pwndBottomView->HasSelection());
1475 void CMainFrame::OnEditUseMine()
1477 if (m_pwndBottomView)
1478 m_pwndBottomView->UseMyTextBlock();
1480 void CMainFrame::OnUpdateEditUsemyblock(CCmdUI *pCmdUI)
1482 OnUpdateEditUsetheirblock(pCmdUI);
1485 void CMainFrame::OnEditUseTheirsThenMine()
1487 if (m_pwndBottomView)
1488 m_pwndBottomView->UseTheirAndYourBlock();
1491 void CMainFrame::OnUpdateEditUsetheirthenmyblock(CCmdUI *pCmdUI)
1493 OnUpdateEditUsetheirblock(pCmdUI);
1496 void CMainFrame::OnEditUseMineThenTheirs()
1498 if (m_pwndBottomView)
1499 m_pwndBottomView->UseYourAndTheirBlock();
1502 void CMainFrame::OnUpdateEditUseminethentheirblock(CCmdUI *pCmdUI)
1504 OnUpdateEditUsetheirblock(pCmdUI);
1507 void CMainFrame::OnEditUseleftblock()
1509 if (m_pwndBottomView->IsWindowVisible())
1510 m_pwndBottomView->UseRightBlock();
1511 else
1512 m_pwndRightView->UseLeftBlock();
1515 void CMainFrame::OnUpdateEditUseleftblock(CCmdUI *pCmdUI)
1517 pCmdUI->Enable(IsViewGood(m_pwndRightView) && m_pwndRightView->IsTarget() && m_pwndRightView->HasSelection());
1520 void CMainFrame::OnUpdateUseBlock(CCmdUI *pCmdUI)
1522 pCmdUI->Enable(TRUE);
1525 void CMainFrame::OnEditUseleftfile()
1527 if (m_pwndBottomView->IsWindowVisible())
1528 m_pwndBottomView->UseRightFile();
1529 else
1530 m_pwndRightView->UseLeftFile();
1533 void CMainFrame::OnUpdateEditUseleftfile(CCmdUI *pCmdUI)
1535 pCmdUI->Enable(IsViewGood(m_pwndRightView) && m_pwndRightView->IsTarget());
1538 void CMainFrame::OnEditUseblockfromleftbeforeright()
1540 if (m_pwndRightView)
1541 m_pwndRightView->UseBothLeftFirst();
1544 void CMainFrame::OnUpdateEditUseblockfromleftbeforeright(CCmdUI *pCmdUI)
1546 OnUpdateEditUseleftblock(pCmdUI);
1549 void CMainFrame::OnEditUseblockfromrightbeforeleft()
1551 if (m_pwndRightView)
1552 m_pwndRightView->UseBothRightFirst();
1555 void CMainFrame::OnUpdateEditUseblockfromrightbeforeleft(CCmdUI *pCmdUI)
1557 OnUpdateEditUseleftblock(pCmdUI);
1560 void CMainFrame::OnFileReload()
1562 if (CheckForSave()==IDCANCEL)
1563 return;
1564 CDiffColors::GetInstance().LoadRegistry();
1565 LoadViews(-1);
1568 void CMainFrame::ActivateFrame(int nCmdShow)
1570 // nCmdShow is the normal show mode this frame should be in
1571 // translate default nCmdShow (-1)
1572 if (nCmdShow == -1)
1574 if (!IsWindowVisible())
1575 nCmdShow = SW_SHOWNORMAL;
1576 else if (IsIconic())
1577 nCmdShow = SW_RESTORE;
1580 // bring to top before showing
1581 BringToTop(nCmdShow);
1583 if (nCmdShow != -1)
1585 // show the window as specified
1586 WINDOWPLACEMENT wp;
1588 if ( !ReadWindowPlacement(&wp) )
1590 ShowWindow(nCmdShow);
1592 else
1594 if ( nCmdShow != SW_SHOWNORMAL )
1595 wp.showCmd = nCmdShow;
1597 SetWindowPlacement(&wp);
1600 // and finally, bring to top after showing
1601 BringToTop(nCmdShow);
1605 BOOL CMainFrame::ReadWindowPlacement(WINDOWPLACEMENT * pwp)
1607 CRegString placement = CRegString(_T("Software\\TortoiseGitMerge\\WindowPos"));
1608 CString sPlacement = placement;
1609 if (sPlacement.IsEmpty())
1610 return FALSE;
1611 int nRead = _stscanf_s(sPlacement, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
1612 &pwp->flags, &pwp->showCmd,
1613 &pwp->ptMinPosition.x, &pwp->ptMinPosition.y,
1614 &pwp->ptMaxPosition.x, &pwp->ptMaxPosition.y,
1615 &pwp->rcNormalPosition.left, &pwp->rcNormalPosition.top,
1616 &pwp->rcNormalPosition.right, &pwp->rcNormalPosition.bottom);
1617 if ( nRead != 10 )
1618 return FALSE;
1619 pwp->length = sizeof(WINDOWPLACEMENT);
1621 return TRUE;
1624 void CMainFrame::WriteWindowPlacement(WINDOWPLACEMENT * pwp)
1626 CRegString placement = CRegString(_T("Software\\TortoiseGitMerge\\WindowPos"));
1627 TCHAR szBuffer[_countof("-32767")*8 + sizeof("65535")*2];
1629 _stprintf_s(szBuffer, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
1630 pwp->flags, pwp->showCmd,
1631 pwp->ptMinPosition.x, pwp->ptMinPosition.y,
1632 pwp->ptMaxPosition.x, pwp->ptMaxPosition.y,
1633 pwp->rcNormalPosition.left, pwp->rcNormalPosition.top,
1634 pwp->rcNormalPosition.right, pwp->rcNormalPosition.bottom);
1635 placement = szBuffer;
1638 void CMainFrame::OnUpdateMergeMarkasresolved(CCmdUI *pCmdUI)
1640 if (pCmdUI == NULL)
1641 return;
1642 BOOL bEnable = FALSE;
1643 if ((!m_bReadOnly)&&(m_Data.m_mergedFile.InUse()))
1645 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1647 bEnable = TRUE;
1650 pCmdUI->Enable(bEnable);
1653 void CMainFrame::OnMergeMarkasresolved()
1655 if(HasConflictsWontKeep())
1656 return;
1658 // now check if the file has already been saved and if not, save it.
1659 if (m_Data.m_mergedFile.InUse())
1661 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1663 FileSave(false);
1664 m_bSaveRequired = false;
1667 MarkAsResolved();
1670 BOOL CMainFrame::MarkAsResolved()
1672 if (m_bReadOnly)
1673 return FALSE;
1674 if (!IsViewGood(m_pwndBottomView))
1675 return FALSE;
1677 CString cmd = _T("/command:resolve /path:\"");
1678 cmd += m_Data.m_mergedFile.GetFilename();
1679 cmd += _T("\" /closeonend:1 /noquestion /skipcheck /silent");
1680 if (resolveMsgWnd)
1682 CString s;
1683 s.Format(L" /resolvemsghwnd:%I64d /resolvemsgwparam:%I64d /resolvemsglparam:%I64d", (__int64)resolveMsgWnd, (__int64)resolveMsgWParam, (__int64)resolveMsgLParam);
1684 cmd += s;
1686 if(!CAppUtils::RunTortoiseGitProc(cmd))
1687 return FALSE;
1688 m_bSaveRequired = false;
1689 return TRUE;
1692 void CMainFrame::OnUpdateMergeNextconflict(CCmdUI *pCmdUI)
1694 BOOL bShow = FALSE;
1695 if (HasNextConflict(m_pwndBottomView))
1696 bShow = TRUE;
1697 else if (HasNextConflict(m_pwndRightView))
1698 bShow = TRUE;
1699 else if (HasNextConflict(m_pwndLeftView))
1700 bShow = TRUE;
1701 pCmdUI->Enable(bShow);
1704 bool CMainFrame::HasNextConflict(CBaseView* view)
1706 if (view == 0)
1707 return false;
1708 if (!view->IsTarget())
1709 return false;
1710 return view->HasNextConflict();
1713 void CMainFrame::OnUpdateMergePreviousconflict(CCmdUI *pCmdUI)
1715 BOOL bShow = FALSE;
1716 if (HasPrevConflict(m_pwndBottomView))
1717 bShow = TRUE;
1718 else if (HasPrevConflict(m_pwndRightView))
1719 bShow = TRUE;
1720 else if (HasPrevConflict(m_pwndLeftView))
1721 bShow = TRUE;
1722 pCmdUI->Enable(bShow);
1725 bool CMainFrame::HasPrevConflict(CBaseView* view)
1727 if (view == 0)
1728 return false;
1729 if (!view->IsTarget())
1730 return false;
1731 return view->HasPrevConflict();
1734 void CMainFrame::OnUpdateNavigateNextdifference(CCmdUI *pCmdUI)
1736 CBaseView* baseView = GetActiveBaseView();
1737 BOOL bShow = FALSE;
1738 if (baseView != 0)
1739 bShow = baseView->HasNextDiff();
1740 pCmdUI->Enable(bShow);
1743 void CMainFrame::OnUpdateNavigatePreviousdifference(CCmdUI *pCmdUI)
1745 CBaseView* baseView = GetActiveBaseView();
1746 BOOL bShow = FALSE;
1747 if (baseView != 0)
1748 bShow = baseView->HasPrevDiff();
1749 pCmdUI->Enable(bShow);
1752 void CMainFrame::OnUpdateNavigateNextinlinediff(CCmdUI *pCmdUI)
1754 BOOL bShow = FALSE;
1755 if (HasNextInlineDiff(m_pwndBottomView))
1756 bShow = TRUE;
1757 else if (HasNextInlineDiff(m_pwndRightView))
1758 bShow = TRUE;
1759 else if (HasNextInlineDiff(m_pwndLeftView))
1760 bShow = TRUE;
1761 pCmdUI->Enable(bShow);
1764 bool CMainFrame::HasNextInlineDiff(CBaseView* view)
1766 if (view == 0)
1767 return false;
1768 if (!view->IsTarget())
1769 return false;
1770 return view->HasNextInlineDiff();
1773 void CMainFrame::OnUpdateNavigatePrevinlinediff(CCmdUI *pCmdUI)
1775 BOOL bShow = FALSE;
1776 if (HasPrevInlineDiff(m_pwndBottomView))
1777 bShow = TRUE;
1778 else if (HasPrevInlineDiff(m_pwndRightView))
1779 bShow = TRUE;
1780 else if (HasPrevInlineDiff(m_pwndLeftView))
1781 bShow = TRUE;
1782 pCmdUI->Enable(bShow);
1785 bool CMainFrame::HasPrevInlineDiff(CBaseView* view)
1787 if (view == 0)
1788 return false;
1789 if (!view->IsTarget())
1790 return false;
1791 return view->HasPrevInlineDiff();
1794 void CMainFrame::OnMoving(UINT fwSide, LPRECT pRect)
1796 // if the pathfilelist dialog is attached to the mainframe,
1797 // move it along with the mainframe
1798 if (::IsWindow(m_dlgFilePatches.m_hWnd))
1800 RECT patchrect;
1801 m_dlgFilePatches.GetWindowRect(&patchrect);
1802 if (::IsWindow(m_hWnd))
1804 RECT thisrect;
1805 GetWindowRect(&thisrect);
1806 if (patchrect.right == thisrect.left)
1808 m_dlgFilePatches.SetWindowPos(NULL, patchrect.left - (thisrect.left - pRect->left), patchrect.top - (thisrect.top - pRect->top),
1809 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
1813 __super::OnMoving(fwSide, pRect);
1816 void CMainFrame::OnUpdateEditCopy(CCmdUI *pCmdUI)
1818 BOOL bShow = FALSE;
1819 if ((m_pwndBottomView)&&(m_pwndBottomView->HasSelection()))
1820 bShow = TRUE;
1821 else if ((m_pwndRightView)&&(m_pwndRightView->HasSelection()))
1822 bShow = TRUE;
1823 else if ((m_pwndLeftView)&&(m_pwndLeftView->HasSelection()))
1824 bShow = TRUE;
1825 pCmdUI->Enable(bShow);
1828 void CMainFrame::OnUpdateEditPaste(CCmdUI *pCmdUI)
1830 BOOL bWritable = FALSE;
1831 if ((m_pwndBottomView)&&(m_pwndBottomView->IsWritable()))
1832 bWritable = TRUE;
1833 else if ((m_pwndRightView)&&(m_pwndRightView->IsWritable()))
1834 bWritable = TRUE;
1835 else if ((m_pwndLeftView)&&(m_pwndLeftView->IsWritable()))
1836 bWritable = TRUE;
1837 pCmdUI->Enable(bWritable && ::IsClipboardFormatAvailable(CF_TEXT));
1840 void CMainFrame::OnViewSwitchleft()
1842 int ret = IDNO;
1843 if (HasUnsavedEdits())
1845 CString sTemp;
1846 sTemp.LoadString(IDS_ASKFORSAVE);
1847 ret = MessageBox(sTemp, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
1848 if (ret == IDYES)
1850 if (!FileSave())
1851 return;
1854 if ((ret == IDNO)||(ret == IDYES))
1856 CWorkingFile file = m_Data.m_baseFile;
1857 m_Data.m_baseFile = m_Data.m_yourFile;
1858 m_Data.m_yourFile = file;
1859 if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_yourFile.GetFilename())==0)
1861 m_Data.m_mergedFile = m_Data.m_baseFile;
1863 else if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_baseFile.GetFilename())==0)
1865 m_Data.m_mergedFile = m_Data.m_yourFile;
1867 LoadViews();
1871 void CMainFrame::OnUpdateViewSwitchleft(CCmdUI *pCmdUI)
1873 BOOL bEnable = !IsViewGood(m_pwndBottomView);
1874 pCmdUI->Enable(bEnable);
1877 void CMainFrame::OnUpdateViewShowfilelist(CCmdUI *pCmdUI)
1879 BOOL bEnable = m_dlgFilePatches.HasFiles();
1880 pCmdUI->Enable(bEnable);
1881 pCmdUI->SetCheck(m_dlgFilePatches.IsWindowVisible());
1884 void CMainFrame::OnViewShowfilelist()
1886 m_dlgFilePatches.ShowWindow(m_dlgFilePatches.IsWindowVisible() ? SW_HIDE : SW_SHOW);
1889 void CMainFrame::OnEditUndo()
1891 if (CUndo::GetInstance().CanUndo())
1893 CUndo::GetInstance().Undo(m_pwndLeftView, m_pwndRightView, m_pwndBottomView);
1897 void CMainFrame::OnUpdateEditUndo(CCmdUI *pCmdUI)
1899 pCmdUI->Enable(CUndo::GetInstance().CanUndo());
1902 int CMainFrame::CheckForReload()
1904 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
1905 if (bLock)
1907 return IDNO;
1909 bLock = true;
1910 bool bSourceChanged =
1911 m_Data.m_baseFile.HasSourceFileChanged()
1912 || m_Data.m_yourFile.HasSourceFileChanged()
1913 || m_Data.m_theirFile.HasSourceFileChanged()
1914 /*|| m_Data.m_mergedFile.HasSourceFileChanged()*/;
1915 if (!bSourceChanged)
1917 bLock = false;
1918 return IDNO;
1921 int idsMessage = HasUnsavedEdits() ? IDS_WARNMODIFIEDOUTSIDELOOSECHANGES : IDS_WARNMODIFIEDOUTSIDE;
1922 UINT ret = CMessageBox::Show(m_hWnd, idsMessage, IDS_APPNAME, MB_YESNO | MB_ICONQUESTION);
1924 if (ret == IDYES)
1926 CDiffColors::GetInstance().LoadRegistry();
1927 LoadViews(-1);
1929 else
1931 if (IsViewGood(m_pwndBottomView)) // three pane view
1933 /*if (m_Data.m_sourceFile.HasSourceFileChanged())
1934 m_pwndBottomView->SetModified();
1935 if (m_Data.m_mergedFile.HasSourceFileChanged())
1936 m_pwndBottomView->SetModified();//*/
1937 if (m_Data.m_yourFile.HasSourceFileChanged())
1938 m_pwndRightView->SetModified();
1939 if (m_Data.m_theirFile.HasSourceFileChanged())
1940 m_pwndLeftView->SetModified();
1942 else if (IsViewGood(m_pwndRightView)) // two pane view
1944 if (m_Data.m_baseFile.HasSourceFileChanged())
1945 m_pwndLeftView->SetModified();
1946 if (m_Data.m_yourFile.HasSourceFileChanged())
1947 m_pwndRightView->SetModified();
1949 else
1951 if (m_Data.m_yourFile.HasSourceFileChanged())
1952 m_pwndLeftView->SetModified();
1955 // no reload just store updated file time
1956 m_Data.m_baseFile.StoreFileAttributes();
1957 m_Data.m_theirFile.StoreFileAttributes();
1958 m_Data.m_yourFile.StoreFileAttributes();
1959 //m_Data.m_mergedFile.StoreFileAttributes();
1961 bLock = false;
1962 return ret;
1965 int CMainFrame::CheckForSave()
1967 UINT ret = IDNO;
1968 if (HasUnsavedEdits())
1970 CString sTemp;
1971 sTemp.LoadString(IDS_WARNMODIFIEDLOOSECHANGES);
1972 ret = MessageBox(sTemp, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
1974 if (ret == IDYES)
1976 if (!FileSave())
1977 ret = IDCANCEL;
1980 return ret;
1983 bool CMainFrame::HasUnsavedEdits() const
1985 return HasUnsavedEdits(m_pwndBottomView) || HasUnsavedEdits(m_pwndRightView) || m_bSaveRequired;
1988 bool CMainFrame::HasUnsavedEdits(const CBaseView* view)
1990 if(view == 0)
1991 return false;
1992 return view->IsModified();
1995 bool CMainFrame::IsViewGood(const CBaseView* view)
1997 return CBaseView::IsViewGood(view);
2000 void CMainFrame::OnViewInlinediffword()
2002 m_bInlineWordDiff = !m_bInlineWordDiff;
2003 if (m_pwndLeftView)
2005 m_pwndLeftView->SetInlineWordDiff(m_bInlineWordDiff);
2006 m_pwndLeftView->BuildAllScreen2ViewVector();
2007 m_pwndLeftView->DocumentUpdated();
2009 if (m_pwndRightView)
2011 m_pwndRightView->SetInlineWordDiff(m_bInlineWordDiff);
2012 m_pwndRightView->BuildAllScreen2ViewVector();
2013 m_pwndRightView->DocumentUpdated();
2015 if (m_pwndBottomView)
2017 m_pwndBottomView->SetInlineWordDiff(m_bInlineWordDiff);
2018 m_pwndBottomView->BuildAllScreen2ViewVector();
2019 m_pwndBottomView->DocumentUpdated();
2021 m_wndLineDiffBar.DocumentUpdated();
2024 void CMainFrame::OnUpdateViewInlinediffword(CCmdUI *pCmdUI)
2026 pCmdUI->Enable(m_bInlineDiff && IsViewGood(m_pwndLeftView) && IsViewGood(m_pwndRightView));
2027 pCmdUI->SetCheck(m_bInlineWordDiff);
2030 void CMainFrame::OnViewInlinediff()
2032 m_bInlineDiff = !m_bInlineDiff;
2033 if (m_pwndLeftView)
2035 m_pwndLeftView->SetInlineDiff(m_bInlineDiff);
2036 m_pwndLeftView->BuildAllScreen2ViewVector();
2037 m_pwndLeftView->DocumentUpdated();
2039 if (m_pwndRightView)
2041 m_pwndRightView->SetInlineDiff(m_bInlineDiff);
2042 m_pwndRightView->BuildAllScreen2ViewVector();
2043 m_pwndRightView->DocumentUpdated();
2045 if (m_pwndBottomView)
2047 m_pwndBottomView->SetInlineDiff(m_bInlineDiff);
2048 m_pwndBottomView->BuildAllScreen2ViewVector();
2049 m_pwndBottomView->DocumentUpdated();
2051 m_wndLineDiffBar.DocumentUpdated();
2054 void CMainFrame::OnUpdateViewInlinediff(CCmdUI *pCmdUI)
2056 pCmdUI->Enable(IsViewGood(m_pwndLeftView) && IsViewGood(m_pwndRightView));
2057 pCmdUI->SetCheck(m_bInlineDiff);
2060 void CMainFrame::OnUpdateEditCreateunifieddifffile(CCmdUI *pCmdUI)
2062 // "create unified diff file" is only available if two files
2063 // are diffed, not three.
2064 bool bEnabled = true;
2065 if (!IsViewGood(m_pwndLeftView))
2066 bEnabled = false;
2067 else if (!IsViewGood(m_pwndRightView))
2068 bEnabled = false;
2069 else if (IsViewGood(m_pwndBottomView)) //no negation here
2070 bEnabled = false;
2071 pCmdUI->Enable(bEnabled);
2074 void CMainFrame::OnEditCreateunifieddifffile()
2076 CString origFile, modifiedFile;
2077 // the original file is the one on the left
2078 if (m_pwndLeftView)
2079 origFile = m_pwndLeftView->m_sFullFilePath;
2080 if (m_pwndRightView)
2081 modifiedFile = m_pwndRightView->m_sFullFilePath;
2082 if (origFile.IsEmpty() || modifiedFile.IsEmpty())
2083 return;
2085 CString outputFile;
2086 if(!TryGetFileName(outputFile))
2087 return;
2089 CAppUtils::CreateUnifiedDiff(origFile, modifiedFile, outputFile, true);
2092 void CMainFrame::OnUpdateViewLinediffbar(CCmdUI *pCmdUI)
2094 pCmdUI->SetCheck(m_bLineDiff);
2095 pCmdUI->Enable();
2098 void CMainFrame::OnViewLinediffbar()
2100 m_bLineDiff = !m_bLineDiff;
2101 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2102 m_wndLineDiffBar.DocumentUpdated();
2103 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2104 m_wndLocatorBar.DocumentUpdated();
2107 void CMainFrame::OnUpdateViewLocatorbar(CCmdUI *pCmdUI)
2109 pCmdUI->SetCheck(m_bLocatorBar);
2110 pCmdUI->Enable();
2113 void CMainFrame::OnViewLocatorbar()
2115 m_bLocatorBar = !m_bLocatorBar;
2116 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2117 m_wndLocatorBar.DocumentUpdated();
2118 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2119 m_wndLineDiffBar.DocumentUpdated();
2122 void CMainFrame::OnViewComparewhitespaces()
2124 if (CheckForSave()==IDCANCEL)
2125 return;
2126 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2127 regIgnoreWS = 0;
2128 LoadViews(-1);
2131 void CMainFrame::OnUpdateViewComparewhitespaces(CCmdUI *pCmdUI)
2133 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2134 DWORD dwIgnoreWS = regIgnoreWS;
2135 pCmdUI->SetCheck(dwIgnoreWS == 0);
2138 void CMainFrame::OnViewIgnorewhitespacechanges()
2140 if (CheckForSave()==IDCANCEL)
2141 return;
2142 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2143 regIgnoreWS = 2;
2144 LoadViews(-1);
2147 void CMainFrame::OnUpdateViewIgnorewhitespacechanges(CCmdUI *pCmdUI)
2149 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2150 DWORD dwIgnoreWS = regIgnoreWS;
2151 pCmdUI->SetCheck(dwIgnoreWS == 2);
2154 void CMainFrame::OnViewIgnoreallwhitespacechanges()
2156 if (CheckForSave()==IDCANCEL)
2157 return;
2158 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2159 regIgnoreWS = 1;
2160 LoadViews(-1);
2163 void CMainFrame::OnUpdateViewIgnoreallwhitespacechanges(CCmdUI *pCmdUI)
2165 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2166 DWORD dwIgnoreWS = regIgnoreWS;
2167 pCmdUI->SetCheck(dwIgnoreWS == 1);
2170 void CMainFrame::OnViewMovedBlocks()
2172 m_bViewMovedBlocks = !(DWORD)m_regViewModedBlocks;
2173 m_regViewModedBlocks = m_bViewMovedBlocks;
2174 LoadViews(-1);
2177 void CMainFrame::OnUpdateViewMovedBlocks(CCmdUI *pCmdUI)
2179 pCmdUI->SetCheck(m_bViewMovedBlocks);
2180 BOOL bEnable = TRUE;
2181 if (IsViewGood(m_pwndBottomView))
2183 bEnable = FALSE;
2185 pCmdUI->Enable(bEnable);
2188 bool CMainFrame::HasConflictsWontKeep()
2190 const int nConflictLine = CheckResolved();
2191 if (nConflictLine < 0)
2192 return false;
2194 CString sTemp;
2195 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
2196 if (MessageBox(sTemp, 0, MB_ICONERROR | MB_YESNO)==IDYES)
2197 return false;
2199 if (m_pwndBottomView)
2200 m_pwndBottomView->GoToLine(nConflictLine);
2201 return true;
2204 bool CMainFrame::TryGetFileName(CString& result)
2206 return CCommonAppUtils::FileOpenSave(result, NULL, IDS_SAVEASTITLE, IDS_COMMONFILEFILTER, false, m_hWnd);
2209 CBaseView* CMainFrame::GetActiveBaseView() const
2211 CView* activeView = GetActiveView();
2212 CBaseView* activeBase = dynamic_cast<CBaseView*>( activeView );
2213 return activeBase;
2216 void CMainFrame::SetWindowTitle()
2218 // try to find a suitable window title
2219 CString sYour = m_Data.m_yourFile.GetDescriptiveName();
2220 if (sYour.Find(_T(" - "))>=0)
2221 sYour = sYour.Left(sYour.Find(_T(" - ")));
2222 if (sYour.Find(_T(" : "))>=0)
2223 sYour = sYour.Left(sYour.Find(_T(" : ")));
2224 CString sTheir = m_Data.m_theirFile.GetDescriptiveName();
2225 if (sTheir.IsEmpty())
2226 sTheir = m_Data.m_baseFile.GetDescriptiveName();
2227 if (sTheir.Find(_T(" - "))>=0)
2228 sTheir = sTheir.Left(sTheir.Find(_T(" - ")));
2229 if (sTheir.Find(_T(" : "))>=0)
2230 sTheir = sTheir.Left(sTheir.Find(_T(" : ")));
2232 if (!sYour.IsEmpty() && !sTheir.IsEmpty())
2234 if (sYour.CompareNoCase(sTheir)==0)
2235 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
2236 else if ((sYour.GetLength() < 10) &&
2237 (sTheir.GetLength() < 10))
2238 SetWindowText(sYour + _T(" - ") + sTheir + _T(" - TortoiseGitMerge"));
2239 else
2241 // we have two very long descriptive texts here, which
2242 // means we have to find a way to use them as a window
2243 // title in a shorter way.
2244 // for simplicity, we just use the one from "yourfile"
2245 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
2248 else if (!sYour.IsEmpty())
2249 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
2250 else if (!sTheir.IsEmpty())
2251 SetWindowText(sTheir + _T(" - TortoiseGitMerge"));
2252 else
2253 SetWindowText(L"TortoiseGitMerge");