Success build TortoiseMerge.
[TortoiseGit.git] / src / TortoiseMerge / MainFrm.cpp
blob0f95fb22d55beaab46de27ad4be96b1ac0a10bef
1 // TortoiseMerge - a Diff/Patch program
3 // Copyright (C) 2004-2009 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "stdafx.h"
20 #include "TortoiseMerge.h"
21 #include "OpenDlg.h"
22 #include "Patch.h"
23 #include "SysProgressDlg.h"
24 #include "Settings.h"
25 #include "MessageBox.h"
26 #include "AppUtils.h"
27 #include "PathUtils.h"
28 #include "MainFrm.h"
29 #include "LeftView.h"
30 #include "RightView.h"
31 #include "BottomView.h"
32 #include "DiffColors.h"
33 #include ".\mainfrm.h"
35 #ifdef _DEBUG
36 #define new DEBUG_NEW
37 #endif
40 // CMainFrame
41 const UINT CMainFrame::m_FindDialogMessage = RegisterWindowMessage(FINDMSGSTRING);
43 IMPLEMENT_DYNCREATE(CMainFrame, CFrameWndEx)
45 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)
46 ON_WM_CREATE()
47 ON_COMMAND_RANGE(ID_VIEW_APPLOOK_WIN_2000, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnApplicationLook)
48 ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_APPLOOK_WIN_2000, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnUpdateApplicationLook)
49 // Global help commands
50 ON_COMMAND(ID_HELP_FINDER, CFrameWndEx::OnHelpFinder)
51 ON_COMMAND(ID_HELP, CFrameWndEx::OnHelp)
52 ON_COMMAND(ID_CONTEXT_HELP, CFrameWndEx::OnContextHelp)
53 ON_COMMAND(ID_DEFAULT_HELP, CFrameWndEx::OnHelpFinder)
54 ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
55 ON_COMMAND(ID_VIEW_WHITESPACES, OnViewWhitespaces)
56 ON_WM_SIZE()
57 ON_COMMAND(ID_FILE_SAVE, OnFileSave)
58 ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
59 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave)
60 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_AS, OnUpdateFileSaveAs)
61 ON_COMMAND(ID_VIEW_ONEWAYDIFF, OnViewOnewaydiff)
62 ON_UPDATE_COMMAND_UI(ID_VIEW_ONEWAYDIFF, OnUpdateViewOnewaydiff)
63 ON_UPDATE_COMMAND_UI(ID_VIEW_WHITESPACES, OnUpdateViewWhitespaces)
64 ON_COMMAND(ID_VIEW_OPTIONS, OnViewOptions)
65 ON_WM_CLOSE()
66 ON_COMMAND(ID_EDIT_FIND, OnEditFind)
67 ON_REGISTERED_MESSAGE(m_FindDialogMessage, OnFindDialogMessage)
68 ON_COMMAND(ID_EDIT_FINDNEXT, OnEditFindnext)
69 ON_COMMAND(ID_EDIT_FINDPREV, OnEditFindprev)
70 ON_COMMAND(ID_FILE_RELOAD, OnFileReload)
71 ON_COMMAND(ID_VIEW_LINEDOWN, OnViewLinedown)
72 ON_COMMAND(ID_VIEW_LINEUP, OnViewLineup)
73 ON_UPDATE_COMMAND_UI(ID_EDIT_MARKASRESOLVED, OnUpdateMergeMarkasresolved)
74 ON_COMMAND(ID_EDIT_MARKASRESOLVED, OnMergeMarkasresolved)
75 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTCONFLICT, OnUpdateMergeNextconflict)
76 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSCONFLICT, OnUpdateMergePreviousconflict)
77 ON_WM_MOVE()
78 ON_WM_MOVING()
79 ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
80 ON_COMMAND(ID_VIEW_SWITCHLEFT, OnViewSwitchleft)
81 ON_UPDATE_COMMAND_UI(ID_VIEW_SWITCHLEFT, OnUpdateViewSwitchleft)
82 ON_COMMAND(ID_VIEW_LINELEFT, &CMainFrame::OnViewLineleft)
83 ON_COMMAND(ID_VIEW_LINERIGHT, &CMainFrame::OnViewLineright)
84 ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWFILELIST, &CMainFrame::OnUpdateViewShowfilelist)
85 ON_COMMAND(ID_VIEW_SHOWFILELIST, &CMainFrame::OnViewShowfilelist)
86 ON_COMMAND(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnEditUseTheirs)
87 ON_COMMAND(ID_EDIT_USEMYBLOCK, &CMainFrame::OnEditUseMine)
88 ON_COMMAND(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnEditUseTheirsThenMine)
89 ON_COMMAND(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnEditUseMineThenTheirs)
90 ON_COMMAND(ID_EDIT_UNDO, &CMainFrame::OnEditUndo)
91 ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, &CMainFrame::OnUpdateEditUndo)
92 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnUpdateEditUseminethentheirblock)
93 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMYBLOCK, &CMainFrame::OnUpdateEditUsemyblock)
94 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnUpdateEditUsetheirblock)
95 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnUpdateEditUsetheirthenmyblock)
96 ON_COMMAND(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnViewInlinediffword)
97 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnUpdateViewInlinediffword)
98 ON_UPDATE_COMMAND_UI(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnUpdateEditCreateunifieddifffile)
99 ON_COMMAND(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnEditCreateunifieddifffile)
100 ON_UPDATE_COMMAND_UI(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnUpdateViewLinediffbar)
101 ON_COMMAND(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnViewLinediffbar)
102 ON_UPDATE_COMMAND_UI(ID_VIEW_LOCATORBAR, &CMainFrame::OnUpdateViewLocatorbar)
103 ON_COMMAND(ID_VIEW_LOCATORBAR, &CMainFrame::OnViewLocatorbar)
104 ON_COMMAND(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnEditUseleftblock)
105 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnUpdateEditUseleftblock)
106 ON_COMMAND(ID_EDIT_USELEFTFILE, &CMainFrame::OnEditUseleftfile)
107 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTFILE, &CMainFrame::OnUpdateEditUseleftfile)
108 ON_COMMAND(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnEditUseblockfromleftbeforeright)
109 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnUpdateEditUseblockfromleftbeforeright)
110 ON_COMMAND(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnEditUseblockfromrightbeforeleft)
111 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnUpdateEditUseblockfromrightbeforeleft)
112 END_MESSAGE_MAP()
114 static UINT indicators[] =
116 ID_SEPARATOR, // status line indicator
117 ID_INDICATOR_LEFTVIEW,
118 ID_INDICATOR_RIGHTVIEW,
119 ID_INDICATOR_BOTTOMVIEW,
120 ID_INDICATOR_CAPS,
121 ID_INDICATOR_NUM,
122 ID_INDICATOR_SCRL
126 // CMainFrame construction/destruction
128 CMainFrame::CMainFrame()
130 m_pFindDialog = NULL;
131 m_nSearchIndex = 0;
132 m_bInitSplitter = FALSE;
133 m_bOneWay = (0 != ((DWORD)CRegDWORD(_T("Software\\TortoiseMerge\\OnePane"))));
134 m_bReversedPatch = FALSE;
135 m_bHasConflicts = false;
136 m_bInlineWordDiff = true;
137 m_bLineDiff = true;
138 m_bLocatorBar = true;
139 m_nMoveMovesToIgnore = 0;
140 theApp.m_nAppLook = theApp.GetInt(_T("ApplicationLook"), ID_VIEW_APPLOOK_VS_2005);
143 CMainFrame::~CMainFrame()
147 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
149 if (CFrameWndEx::OnCreate(lpCreateStruct) == -1)
150 return -1;
152 OnApplicationLook(theApp.m_nAppLook);
154 if (!m_wndMenuBar.Create(this))
156 TRACE0("Failed to create menubar\n");
157 return -1; // fail to create
160 m_wndMenuBar.SetPaneStyle(m_wndMenuBar.GetPaneStyle() | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY);
162 // prevent the menu bar from taking the focus on activation
163 CMFCPopupMenu::SetForceMenuFocus(FALSE);
165 if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY) ||
166 !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
168 TRACE0("Failed to create toolbar\n");
169 return -1; // fail to create
171 m_wndToolBar.SetWindowText(_T("Main"));
173 if (!m_wndStatusBar.Create(this) ||
174 !m_wndStatusBar.SetIndicators(indicators,
175 sizeof(indicators)/sizeof(UINT)))
177 TRACE0("Failed to create status bar\n");
178 return -1; // fail to create
181 if (!m_wndLocatorBar.Create(this, IDD_DIFFLOCATOR,
182 CBRS_ALIGN_LEFT | CBRS_SIZE_FIXED, ID_VIEW_LOCATORBAR))
184 TRACE0("Failed to create dialogbar\n");
185 return -1; // fail to create
187 if (!m_wndLineDiffBar.Create(this, IDD_LINEDIFF,
188 CBRS_ALIGN_BOTTOM | CBRS_SIZE_FIXED, ID_VIEW_LINEDIFFBAR))
190 TRACE0("Failed to create dialogbar\n");
191 return -1; // fail to create
193 m_wndLocatorBar.m_pMainFrm = this;
194 m_wndLineDiffBar.m_pMainFrm = this;
196 EnableDocking(CBRS_ALIGN_ANY);
197 m_wndMenuBar.EnableDocking(CBRS_ALIGN_TOP);
198 m_wndToolBar.EnableDocking(CBRS_ALIGN_TOP);
199 DockPane(&m_wndMenuBar);
200 DockPane(&m_wndToolBar);
201 DockPane(&m_wndLocatorBar);
202 DockPane(&m_wndLineDiffBar);
203 ShowPane(&m_wndLocatorBar, true, false, true);
204 ShowPane(&m_wndLineDiffBar, true, false, true);
206 m_wndLocatorBar.EnableGripper(FALSE);
207 m_wndLineDiffBar.EnableGripper(FALSE);
209 return 0;
212 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
214 if( !CFrameWndEx::PreCreateWindow(cs) )
215 return FALSE;
216 return TRUE;
219 void CMainFrame::OnApplicationLook(UINT id)
221 CWaitCursor wait;
223 theApp.m_nAppLook = id;
225 switch (theApp.m_nAppLook)
227 case ID_VIEW_APPLOOK_WIN_2000:
228 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManager));
229 break;
231 case ID_VIEW_APPLOOK_OFF_XP:
232 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOfficeXP));
233 break;
235 case ID_VIEW_APPLOOK_WIN_XP:
236 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
237 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
238 break;
240 case ID_VIEW_APPLOOK_OFF_2003:
241 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2003));
242 CDockingManager::SetDockingMode(DT_SMART);
243 break;
245 case ID_VIEW_APPLOOK_VS_2005:
246 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2005));
247 CDockingManager::SetDockingMode(DT_SMART);
248 break;
250 default:
251 switch (theApp.m_nAppLook)
253 case ID_VIEW_APPLOOK_OFF_2007_BLUE:
254 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_LunaBlue);
255 break;
257 case ID_VIEW_APPLOOK_OFF_2007_BLACK:
258 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_ObsidianBlack);
259 break;
261 case ID_VIEW_APPLOOK_OFF_2007_SILVER:
262 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Silver);
263 break;
265 case ID_VIEW_APPLOOK_OFF_2007_AQUA:
266 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Aqua);
267 break;
270 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));
271 CDockingManager::SetDockingMode(DT_SMART);
274 RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_FRAME | RDW_ERASE);
276 theApp.WriteInt(_T("ApplicationLook"), theApp.m_nAppLook);
279 void CMainFrame::OnUpdateApplicationLook(CCmdUI* pCmdUI)
281 pCmdUI->SetRadio(theApp.m_nAppLook == pCmdUI->m_nID);
285 // CMainFrame diagnostics
287 #ifdef _DEBUG
288 void CMainFrame::AssertValid() const
290 CFrameWndEx::AssertValid();
293 void CMainFrame::Dump(CDumpContext& dc) const
295 CFrameWndEx::Dump(dc);
298 #endif //_DEBUG
301 // CMainFrame message handlers
304 BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)
306 CRect cr;
307 GetClientRect( &cr);
310 // split into three panes:
311 // -------------
312 // | | |
313 // | | |
314 // |------------
315 // | |
316 // | |
317 // |------------
319 // create a splitter with 2 rows, 1 column
320 if (!m_wndSplitter.CreateStatic(this, 2, 1))
322 TRACE0("Failed to CreateStaticSplitter\n");
323 return FALSE;
326 // add the second splitter pane - which is a nested splitter with 2 columns
327 if (!m_wndSplitter2.CreateStatic(
328 &m_wndSplitter, // our parent window is the first splitter
329 1, 2, // the new splitter is 1 row, 2 columns
330 WS_CHILD | WS_VISIBLE | WS_BORDER, // style, WS_BORDER is needed
331 m_wndSplitter.IdFromRowCol(0, 0)
332 // new splitter is in the first row, 1st column of first splitter
335 TRACE0("Failed to create nested splitter\n");
336 return FALSE;
338 // add the first splitter pane - the default view in row 0
339 if (!m_wndSplitter.CreateView(1, 0,
340 RUNTIME_CLASS(CBottomView), CSize(cr.Width(), cr.Height()), pContext))
342 TRACE0("Failed to create first pane\n");
343 return FALSE;
345 m_pwndBottomView = (CBottomView *)m_wndSplitter.GetPane(1,0);
346 m_pwndBottomView->m_pwndLocator = &m_wndLocatorBar;
347 m_pwndBottomView->m_pwndLineDiffBar = &m_wndLineDiffBar;
348 m_pwndBottomView->m_pwndStatusBar = &m_wndStatusBar;
349 m_pwndBottomView->m_pMainFrame = this;
351 // now create the two views inside the nested splitter
353 if (!m_wndSplitter2.CreateView(0, 0,
354 RUNTIME_CLASS(CLeftView), CSize(cr.Width()/2, cr.Height()/2), pContext))
356 TRACE0("Failed to create second pane\n");
357 return FALSE;
359 m_pwndLeftView = (CLeftView *)m_wndSplitter2.GetPane(0,0);
360 m_pwndLeftView->m_pwndLocator = &m_wndLocatorBar;
361 m_pwndLeftView->m_pwndLineDiffBar = &m_wndLineDiffBar;
362 m_pwndLeftView->m_pwndStatusBar = &m_wndStatusBar;
363 m_pwndLeftView->m_pMainFrame = this;
365 if (!m_wndSplitter2.CreateView(0, 1,
366 RUNTIME_CLASS(CRightView), CSize(cr.Width()/2, cr.Height()/2), pContext))
368 TRACE0("Failed to create third pane\n");
369 return FALSE;
371 m_pwndRightView = (CRightView *)m_wndSplitter2.GetPane(0,1);
372 m_pwndRightView->m_pwndLocator = &m_wndLocatorBar;
373 m_pwndRightView->m_pwndLineDiffBar = &m_wndLineDiffBar;
374 m_pwndRightView->m_pwndStatusBar = &m_wndStatusBar;
375 m_pwndRightView->m_pMainFrame = this;
376 m_bInitSplitter = TRUE;
378 m_dlgFilePatches.Create(IDD_FILEPATCHES, this);
379 UpdateLayout();
380 return TRUE;
383 // Callback function
384 BOOL CMainFrame::PatchFile(CString sFilePath, CString sVersion, BOOL bAutoPatch)
386 //first, do a "dry run" of patching...
387 if (!m_Patch.PatchFile(sFilePath))
389 //patching not successful, so retrieve the
390 //base file from version control and try
391 //again...
392 CString sTemp;
393 CSysProgressDlg progDlg;
394 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sVersion);
395 progDlg.SetLine(1, sTemp, true);
396 progDlg.SetLine(2, sFilePath, true);
397 sTemp.LoadString(IDS_GETVERSIONOFFILETITLE);
398 progDlg.SetTitle(sTemp);
399 progDlg.SetShowProgressBar(false);
400 progDlg.SetAnimation(IDR_DOWNLOAD);
401 progDlg.SetTime(FALSE);
402 progDlg.ShowModeless(this);
403 CString sBaseFile = m_TempFiles.GetTempFilePath();
404 if (!CAppUtils::GetVersionedFile(sFilePath, sVersion, sBaseFile, &progDlg, m_hWnd))
406 progDlg.Stop();
407 CString sErrMsg;
408 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sVersion, (LPCTSTR)sFilePath);
409 MessageBox(sErrMsg, NULL, MB_ICONERROR);
410 return FALSE;
412 progDlg.Stop();
413 CString sTempFile = m_TempFiles.GetTempFilePath();
414 if (!m_Patch.PatchFile(sFilePath, sTempFile, sBaseFile))
416 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
417 return FALSE;
419 CString temp;
420 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)sVersion);
421 m_Data.m_baseFile.SetFileName(sBaseFile);
422 m_Data.m_baseFile.SetDescriptiveName(temp);
423 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
424 m_Data.m_theirFile.SetFileName(sTempFile);
425 m_Data.m_theirFile.SetDescriptiveName(temp);
426 m_Data.m_yourFile.SetFileName(sFilePath);
427 m_Data.m_yourFile.SetDescriptiveName(CPathUtils::GetFileNameFromPath(sFilePath));
428 m_Data.m_mergedFile.SetFileName(sFilePath);
429 m_Data.m_mergedFile.SetDescriptiveName(CPathUtils::GetFileNameFromPath(sFilePath));
430 TRACE(_T("comparing %s and %s\nagainst the base file %s\n"), (LPCTSTR)sTempFile, (LPCTSTR)sFilePath, (LPCTSTR)sBaseFile);
432 else
434 //"dry run" was successful, so save the patched file somewhere...
435 CString sTempFile = m_TempFiles.GetTempFilePath();
436 if (!m_Patch.PatchFile(sFilePath, sTempFile))
438 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
439 return FALSE;
441 if (m_bReversedPatch)
443 m_Data.m_baseFile.SetFileName(sTempFile);
444 CString temp;
445 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
446 m_Data.m_baseFile.SetDescriptiveName(temp);
447 m_Data.m_yourFile.SetFileName(sFilePath);
448 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchOriginal);
449 m_Data.m_yourFile.SetDescriptiveName(temp);
450 m_Data.m_theirFile.SetOutOfUse();
451 m_Data.m_mergedFile.SetOutOfUse();
453 else
455 if (!PathFileExists(sFilePath))
457 m_Data.m_baseFile.SetFileName(m_TempFiles.GetTempFilePath());
458 m_Data.m_baseFile.CreateEmptyFile();
460 else
462 m_Data.m_baseFile.SetFileName(sFilePath);
464 CString sDescription;
465 sDescription.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchOriginal);
466 m_Data.m_baseFile.SetDescriptiveName(sDescription);
467 m_Data.m_yourFile.SetFileName(sTempFile);
468 CString temp;
469 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
470 m_Data.m_yourFile.SetDescriptiveName(temp);
471 m_Data.m_theirFile.SetOutOfUse();
472 m_Data.m_mergedFile.SetFileName(sFilePath);
474 TRACE(_T("comparing %s\nwith the patched result %s\n"), (LPCTSTR)sFilePath, (LPCTSTR)sTempFile);
476 LoadViews();
477 if (bAutoPatch)
479 OnFileSave();
481 return TRUE;
484 // Callback function
485 BOOL CMainFrame::DiffFiles(CString sURL1, CString sRev1, CString sURL2, CString sRev2)
487 CString tempfile1 = m_TempFiles.GetTempFilePath();
488 CString tempfile2 = m_TempFiles.GetTempFilePath();
490 ASSERT(tempfile1.Compare(tempfile2));
492 CString sTemp;
493 CSysProgressDlg progDlg;
494 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev1);
495 progDlg.SetLine(1, sTemp, true);
496 progDlg.SetLine(2, sURL1, true);
497 sTemp.LoadString(IDS_GETVERSIONOFFILETITLE);
498 progDlg.SetTitle(sTemp);
499 progDlg.SetShowProgressBar(true);
500 progDlg.SetAnimation(IDR_DOWNLOAD);
501 progDlg.SetTime(FALSE);
502 progDlg.SetProgress(1,100);
503 progDlg.ShowModeless(this);
504 if (!CAppUtils::GetVersionedFile(sURL1, sRev1, tempfile1, &progDlg, m_hWnd))
506 progDlg.Stop();
507 CString sErrMsg;
508 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev1, (LPCTSTR)sURL1);
509 MessageBox(sErrMsg, NULL, MB_ICONERROR);
510 return FALSE;
512 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev2);
513 progDlg.SetLine(1, sTemp, true);
514 progDlg.SetLine(2, sURL2, true);
515 progDlg.SetProgress(50, 100);
516 if (!CAppUtils::GetVersionedFile(sURL2, sRev2, tempfile2, &progDlg, m_hWnd))
518 progDlg.Stop();
519 CString sErrMsg;
520 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev2, (LPCTSTR)sURL2);
521 MessageBox(sErrMsg, NULL, MB_ICONERROR);
522 return FALSE;
524 progDlg.SetProgress(100,100);
525 progDlg.Stop();
526 CString temp;
527 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL1), (LPCTSTR)sRev1);
528 m_Data.m_baseFile.SetFileName(tempfile1);
529 m_Data.m_baseFile.SetDescriptiveName(temp);
530 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL2), (LPCTSTR)sRev2);
531 m_Data.m_yourFile.SetFileName(tempfile2);
532 m_Data.m_yourFile.SetDescriptiveName(temp);
534 LoadViews();
536 return TRUE;
539 void CMainFrame::OnFileOpen()
541 if (CheckForSave()==IDCANCEL)
542 return;
543 COpenDlg dlg;
544 if (dlg.DoModal()!=IDOK)
546 return;
548 m_dlgFilePatches.ShowWindow(SW_HIDE);
549 m_dlgFilePatches.Init(NULL, NULL, CString(), NULL);
550 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,
551 (LPCTSTR)dlg.m_sUnifiedDiffFile, (LPCTSTR)dlg.m_sPatchDirectory);
552 m_Data.m_baseFile.SetFileName(dlg.m_sBaseFile);
553 m_Data.m_theirFile.SetFileName(dlg.m_sTheirFile);
554 m_Data.m_yourFile.SetFileName(dlg.m_sYourFile);
555 m_Data.m_sDiffFile = dlg.m_sUnifiedDiffFile;
556 m_Data.m_sPatchPath = dlg.m_sPatchDirectory;
557 m_Data.m_mergedFile.SetOutOfUse();
558 g_crasher.AddFile((LPCSTR)(LPCTSTR)dlg.m_sBaseFile, (LPCSTR)(LPCTSTR)_T("Basefile"));
559 g_crasher.AddFile((LPCSTR)(LPCTSTR)dlg.m_sTheirFile, (LPCSTR)(LPCTSTR)_T("Theirfile"));
560 g_crasher.AddFile((LPCSTR)(LPCTSTR)dlg.m_sYourFile, (LPCSTR)(LPCTSTR)_T("Yourfile"));
561 g_crasher.AddFile((LPCSTR)(LPCTSTR)dlg.m_sUnifiedDiffFile, (LPCSTR)(LPCTSTR)_T("Difffile"));
563 if (!m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && m_Data.IsYourFileInUse())
565 // a diff between two files means "Yours" against "Base", not "Theirs" against "Yours"
566 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
568 if (m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && !m_Data.IsYourFileInUse())
570 // a diff between two files means "Yours" against "Base", not "Theirs" against "Base"
571 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
574 LoadViews();
577 void CMainFrame::ClearViewNamesAndPaths() {
578 m_pwndLeftView->m_sWindowName.Empty();
579 m_pwndLeftView->m_sFullFilePath.Empty();
580 m_pwndRightView->m_sWindowName.Empty();
581 m_pwndRightView->m_sFullFilePath.Empty();
582 m_pwndBottomView->m_sWindowName.Empty();
583 m_pwndBottomView->m_sFullFilePath.Empty();
586 bool CMainFrame::LoadViews(bool bRetainPosition)
588 m_Data.SetBlame(m_bBlame);
589 m_bHasConflicts = false;
590 CBaseView* pwndActiveView = m_pwndLeftView;
591 int nOldLine = m_pwndLeftView ? m_pwndLeftView->m_nTopLine : -1;
592 int nOldLineNumber =
593 m_pwndLeftView && m_pwndLeftView->m_pViewData ?
594 m_pwndLeftView->m_pViewData->GetLineNumber(m_pwndLeftView->m_nTopLine) : -1;
595 if (!m_Data.Load())
597 ::MessageBox(NULL, m_Data.GetError(), _T("TortoiseMerge"), MB_ICONERROR);
598 m_Data.m_mergedFile.SetOutOfUse();
599 return false;
602 m_pwndRightView->UseCaret(false);
603 m_pwndBottomView->UseCaret(false);
605 if (!m_Data.IsBaseFileInUse())
607 if (m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
609 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
611 else if ((!m_Data.m_sDiffFile.IsEmpty())&&(!m_Patch.OpenUnifiedDiffFile(m_Data.m_sDiffFile)))
613 ClearViewNamesAndPaths();
614 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
615 return false;
617 if (m_Patch.GetNumberOfFiles() > 0)
619 CString firstpath = m_Patch.GetFilename(0);
620 CString path=firstpath;
621 path.Replace('/','\\');
622 if ( !PathIsRelative(path) && !PathFileExists(path) )
624 // The absolute path mentioned in the patch does not exist. Lets
625 // try to find the correct relative path by stripping prefixes.
626 BOOL bFound = m_Patch.StripPrefixes(m_Data.m_sPatchPath);
627 CString strippedpath = m_Patch.GetFilename(0);
628 if (bFound)
630 CString msg;
631 msg.Format(IDS_WARNABSOLUTEPATHFOUND, (LPCTSTR)firstpath, (LPCTSTR)strippedpath);
632 if (CMessageBox::Show(m_hWnd, msg, _T("TortoiseMerge"), MB_ICONQUESTION | MB_YESNO)==IDNO)
633 return false;
635 else
637 CString msg;
638 msg.Format(IDS_WARNABSOLUTEPATHNOTFOUND, (LPCTSTR)firstpath);
639 CMessageBox::Show(m_hWnd, msg, _T("TortoiseMerge"), MB_ICONEXCLAMATION);
640 return false;
643 CString betterpatchpath = m_Patch.CheckPatchPath(m_Data.m_sPatchPath);
644 if (betterpatchpath.CompareNoCase(m_Data.m_sPatchPath)!=0)
646 CString msg;
647 msg.Format(IDS_WARNBETTERPATCHPATHFOUND, (LPCTSTR)m_Data.m_sPatchPath, (LPCTSTR)betterpatchpath);
648 if (CMessageBox::Show(m_hWnd, msg, _T("TortoiseMerge"), MB_ICONQUESTION | MB_YESNO)==IDYES)
649 m_Data.m_sPatchPath = betterpatchpath;
651 m_dlgFilePatches.Init(&m_Patch, this, m_Data.m_sPatchPath, this);
652 m_dlgFilePatches.ShowWindow(SW_SHOW);
653 ClearViewNamesAndPaths();
654 if (!m_wndSplitter.IsRowHidden(1))
655 m_wndSplitter.HideRow(1);
656 m_pwndLeftView->SetHidden(FALSE);
657 m_pwndRightView->SetHidden(FALSE);
658 m_pwndBottomView->SetHidden(TRUE);
661 if (m_Data.IsBaseFileInUse() && !m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
663 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
665 if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && !m_Data.IsTheirFileInUse())
667 //diff between YOUR and BASE
668 m_pwndRightView->UseCaret();
669 if (m_bOneWay)
671 if (!m_wndSplitter2.IsColumnHidden(1))
672 m_wndSplitter2.HideColumn(1);
674 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseBoth;
675 m_pwndLeftView->texttype = m_Data.m_arYourFile.GetUnicodeType();
676 m_pwndLeftView->lineendings = m_Data.m_arYourFile.GetLineEndings();
677 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName() + _T(" - ") + m_Data.m_yourFile.GetWindowName();
678 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename() + _T(" - ") + m_Data.m_yourFile.GetFilename();
680 m_pwndRightView->m_pViewData = NULL;
681 m_pwndBottomView->m_pViewData = NULL;
683 if (!m_wndSplitter.IsRowHidden(1))
684 m_wndSplitter.HideRow(1);
685 m_pwndLeftView->SetHidden(FALSE);
686 m_pwndRightView->SetHidden(TRUE);
687 m_pwndBottomView->SetHidden(TRUE);
688 ::SetWindowPos(m_pwndLeftView->m_hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
690 else
692 pwndActiveView = m_pwndRightView;
693 if (m_wndSplitter2.IsColumnHidden(1))
694 m_wndSplitter2.ShowColumn();
696 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseLeft;
697 m_pwndLeftView->texttype = m_Data.m_arBaseFile.GetUnicodeType();
698 m_pwndLeftView->lineendings = m_Data.m_arBaseFile.GetLineEndings();
699 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName();
700 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename();
702 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseRight;
703 m_pwndRightView->texttype = m_Data.m_arYourFile.GetUnicodeType();
704 m_pwndRightView->lineendings = m_Data.m_arYourFile.GetLineEndings();
705 m_pwndRightView->m_sWindowName = m_Data.m_yourFile.GetWindowName();
706 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
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(FALSE);
714 m_pwndBottomView->SetHidden(TRUE);
717 else if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
719 //diff between THEIR, YOUR and BASE
720 m_pwndBottomView->UseCaret();
721 pwndActiveView = m_pwndBottomView;
723 m_pwndLeftView->m_pViewData = &m_Data.m_TheirBaseBoth;
724 m_pwndLeftView->texttype = m_Data.m_arTheirFile.GetUnicodeType();
725 m_pwndLeftView->lineendings = m_Data.m_arTheirFile.GetLineEndings();
726 m_pwndLeftView->m_sWindowName.LoadString(IDS_VIEWTITLE_THEIRS);
727 m_pwndLeftView->m_sWindowName += _T(" - ") + m_Data.m_theirFile.GetWindowName();
728 m_pwndLeftView->m_sFullFilePath = m_Data.m_theirFile.GetFilename();
730 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseBoth;
731 m_pwndRightView->texttype = m_Data.m_arYourFile.GetUnicodeType();
732 m_pwndRightView->lineendings = m_Data.m_arYourFile.GetLineEndings();
733 m_pwndRightView->m_sWindowName.LoadString(IDS_VIEWTITLE_MINE);
734 m_pwndRightView->m_sWindowName += _T(" - ") + m_Data.m_yourFile.GetWindowName();
735 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
737 m_pwndBottomView->m_pViewData = &m_Data.m_Diff3;
738 m_pwndBottomView->texttype = m_Data.m_arTheirFile.GetUnicodeType();
739 m_pwndBottomView->lineendings = m_Data.m_arTheirFile.GetLineEndings();
740 m_pwndBottomView->m_sWindowName.LoadString(IDS_VIEWTITLE_MERGED);
741 m_pwndBottomView->m_sWindowName += _T(" - ") + m_Data.m_mergedFile.GetWindowName();
742 m_pwndBottomView->m_sFullFilePath = m_Data.m_mergedFile.GetFilename();
744 if (m_wndSplitter2.IsColumnHidden(1))
745 m_wndSplitter2.ShowColumn();
746 if (m_wndSplitter.IsRowHidden(1))
747 m_wndSplitter.ShowRow();
748 m_pwndLeftView->SetHidden(FALSE);
749 m_pwndRightView->SetHidden(FALSE);
750 m_pwndBottomView->SetHidden(FALSE);
751 // in three pane view, hide the line diff bar
752 m_wndLineDiffBar.ShowPane(false, false, true);
753 m_wndLineDiffBar.DocumentUpdated();
755 if (!m_Data.m_mergedFile.InUse())
757 m_Data.m_mergedFile.SetFileName(m_Data.m_yourFile.GetFilename());
759 m_pwndLeftView->DocumentUpdated();
760 m_pwndRightView->DocumentUpdated();
761 m_pwndBottomView->DocumentUpdated();
762 m_wndLocatorBar.DocumentUpdated();
763 m_wndLineDiffBar.DocumentUpdated();
764 UpdateLayout();
765 SetActiveView(pwndActiveView);
767 if (bRetainPosition && m_pwndLeftView->m_pViewData)
769 int n = nOldLineNumber;
770 if (n >= 0)
771 n = m_pwndLeftView->m_pViewData->FindLineNumber(n);
772 if (n < 0)
773 n = nOldLine;
775 m_pwndLeftView->ScrollAllToLine(n);
776 POINT p;
777 p.x = 0;
778 p.y = n;
779 m_pwndLeftView->SetCaretPosition(p);
781 else
783 bool bGoFirstDiff = (0 != (DWORD)CRegDWORD(_T("Software\\TortoiseMerge\\FirstDiffOnLoad"), TRUE));
784 if (bGoFirstDiff) {
785 pwndActiveView->GoToFirstDifference();
786 // Ignore the first few Mouse Move messages, so that the line diff stays on
787 // the first diff line until the user actually moves the mouse
788 m_nMoveMovesToIgnore = 3;
792 // Avoid incorrect rendering of active pane.
793 m_pwndBottomView->ScrollToChar(0);
794 m_pwndLeftView->ScrollToChar(0);
795 m_pwndRightView->ScrollToChar(0);
796 CheckResolved();
797 CUndo::GetInstance().Clear();
798 return true;
801 void CMainFrame::UpdateLayout()
803 if (m_bInitSplitter)
805 CRect cr, rclocbar;
806 GetWindowRect(&cr);
807 int width = cr.Width();
808 if (::IsWindow(m_wndLocatorBar) && m_wndLocatorBar.IsWindowVisible())
810 m_wndLocatorBar.GetWindowRect(&rclocbar);
811 width -= rclocbar.Width();
813 m_wndSplitter.SetRowInfo(0, cr.Height()/2, 0);
814 m_wndSplitter.SetRowInfo(1, cr.Height()/2, 0);
815 m_wndSplitter.SetColumnInfo(0, width / 2, 50);
816 m_wndSplitter2.SetRowInfo(0, cr.Height()/2, 0);
817 m_wndSplitter2.SetColumnInfo(0, width / 2, 50);
818 m_wndSplitter2.SetColumnInfo(1, width / 2, 50);
820 m_wndSplitter.RecalcLayout();
824 void CMainFrame::OnSize(UINT nType, int cx, int cy)
826 if (m_bInitSplitter && nType != SIZE_MINIMIZED)
828 UpdateLayout();
830 CFrameWndEx::OnSize(nType, cx, cy);
833 void CMainFrame::OnViewWhitespaces()
835 CRegDWORD regViewWhitespaces = CRegDWORD(_T("Software\\TortoiseMerge\\ViewWhitespaces"), 1);
836 BOOL bViewWhitespaces = regViewWhitespaces;
837 if (m_pwndLeftView)
838 bViewWhitespaces = m_pwndLeftView->m_bViewWhitespace;
840 bViewWhitespaces = !bViewWhitespaces;
841 regViewWhitespaces = bViewWhitespaces;
842 if (m_pwndLeftView)
844 m_pwndLeftView->m_bViewWhitespace = bViewWhitespaces;
845 m_pwndLeftView->Invalidate();
847 if (m_pwndRightView)
849 m_pwndRightView->m_bViewWhitespace = bViewWhitespaces;
850 m_pwndRightView->Invalidate();
852 if (m_pwndBottomView)
854 m_pwndBottomView->m_bViewWhitespace = bViewWhitespaces;
855 m_pwndBottomView->Invalidate();
859 void CMainFrame::OnUpdateViewWhitespaces(CCmdUI *pCmdUI)
861 if (m_pwndLeftView)
862 pCmdUI->SetCheck(m_pwndLeftView->m_bViewWhitespace);
865 void CMainFrame::OnViewOnewaydiff()
867 if (CheckForSave()==IDCANCEL)
868 return;
869 m_bOneWay = !m_bOneWay;
870 if (m_bOneWay)
872 // in one way view, hide the line diff bar
873 m_wndLineDiffBar.ShowPane(false, false, true);
874 m_wndLineDiffBar.DocumentUpdated();
876 else
878 // restore the line diff bar
879 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
880 m_wndLineDiffBar.DocumentUpdated();
881 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
882 m_wndLocatorBar.DocumentUpdated();
884 LoadViews(true);
887 void CMainFrame::ShowDiffBar(bool bShow)
889 if (bShow)
891 // restore the line diff bar
892 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
893 m_wndLineDiffBar.DocumentUpdated();
894 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
895 m_wndLocatorBar.DocumentUpdated();
897 else
899 // in one way view, hide the line diff bar
900 m_wndLineDiffBar.ShowPane(false, false, true);
901 m_wndLineDiffBar.DocumentUpdated();
905 int CMainFrame::CheckResolved()
907 //only in three way diffs can be conflicts!
908 m_bHasConflicts = true;
909 if (m_pwndBottomView->IsWindowVisible())
911 if (m_pwndBottomView->m_pViewData)
913 for (int i=0; i<m_pwndBottomView->m_pViewData->GetCount(); i++)
915 if ((DIFFSTATE_CONFLICTED == m_pwndBottomView->m_pViewData->GetState(i))||
916 (DIFFSTATE_CONFLICTED_IGNORED == m_pwndBottomView->m_pViewData->GetState(i)))
917 return i;
921 m_bHasConflicts = false;
922 return -1;
925 int CMainFrame::SaveFile(const CString& sFilePath)
927 CViewData * pViewData = NULL;
928 CFileTextLines * pOriginFile = &m_Data.m_arBaseFile;
929 if ((m_pwndBottomView)&&(m_pwndBottomView->IsWindowVisible()))
931 pViewData = m_pwndBottomView->m_pViewData;
932 Invalidate();
934 else if ((m_pwndRightView)&&(m_pwndRightView->IsWindowVisible()))
936 pViewData = m_pwndRightView->m_pViewData;
937 if (m_Data.IsYourFileInUse())
938 pOriginFile = &m_Data.m_arYourFile;
939 else if (m_Data.IsTheirFileInUse())
940 pOriginFile = &m_Data.m_arTheirFile;
941 Invalidate();
943 else
945 // nothing to save!
946 return -1;
948 if ((pViewData)&&(pOriginFile))
950 CFileTextLines file;
951 pOriginFile->CopySettings(&file);
952 for (int i=0; i<pViewData->GetCount(); i++)
954 //only copy non-removed lines
955 DiffStates state = pViewData->GetState(i);
956 switch (state)
958 case DIFFSTATE_CONFLICTED:
959 case DIFFSTATE_CONFLICTED_IGNORED:
961 int first = i;
962 int last = i;
965 last++;
966 } while((last<pViewData->GetCount()) && ((pViewData->GetState(last)==DIFFSTATE_CONFLICTED)||(pViewData->GetState(last)==DIFFSTATE_CONFLICTED_IGNORED)));
967 file.Add(_T("<<<<<<< .mine"), EOL_NOENDING);
968 for (int j=first; j<last; j++)
970 file.Add(m_pwndRightView->m_pViewData->GetLine(j), m_pwndRightView->m_pViewData->GetLineEnding(j));
972 file.Add(_T("======="), EOL_NOENDING);
973 for (int j=first; j<last; j++)
975 file.Add(m_pwndLeftView->m_pViewData->GetLine(j), m_pwndLeftView->m_pViewData->GetLineEnding(j));
977 file.Add(_T(">>>>>>> .theirs"), EOL_NOENDING);
978 i = last-1;
980 break;
981 case DIFFSTATE_EMPTY:
982 case DIFFSTATE_CONFLICTEMPTY:
983 case DIFFSTATE_IDENTICALREMOVED:
984 case DIFFSTATE_REMOVED:
985 case DIFFSTATE_THEIRSREMOVED:
986 case DIFFSTATE_YOURSREMOVED:
987 case DIFFSTATE_CONFLICTRESOLVEDEMPTY:
988 // do not save removed lines
989 break;
990 default:
991 file.Add(pViewData->GetLine(i), pViewData->GetLineEnding(i));
992 break;
995 if (!file.Save(sFilePath, false))
997 CMessageBox::Show(m_hWnd, file.GetErrorString(), _T("TortoiseMerge"), MB_ICONERROR);
998 return -1;
1000 m_dlgFilePatches.SetFileStatusAsPatched(sFilePath);
1001 if (m_pwndBottomView)
1002 m_pwndBottomView->SetModified(FALSE);
1003 if (m_pwndRightView)
1004 m_pwndRightView->SetModified(FALSE);
1005 CUndo::GetInstance().MarkAsOriginalState();
1006 return file.GetCount();
1008 return -1;
1011 void CMainFrame::OnFileSave()
1013 FileSave();
1016 bool CMainFrame::FileSave(bool bCheckResolved /*=true*/)
1018 if (!m_Data.m_mergedFile.InUse())
1019 return FileSaveAs(bCheckResolved);
1020 // check if the file has the readonly attribute set
1021 bool bDoesNotExist = false;
1022 DWORD fAttribs = GetFileAttributes(m_Data.m_mergedFile.GetFilename());
1023 if ((fAttribs != INVALID_FILE_ATTRIBUTES)&&(fAttribs & FILE_ATTRIBUTE_READONLY))
1024 return FileSaveAs(bCheckResolved);
1025 if (fAttribs == INVALID_FILE_ATTRIBUTES)
1027 bDoesNotExist = (GetLastError() == ERROR_FILE_NOT_FOUND);
1029 if (bCheckResolved)
1031 int nConflictLine = CheckResolved();
1032 if (nConflictLine >= 0)
1034 CString sTemp;
1035 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
1036 if (MessageBox(sTemp, 0, MB_ICONERROR | MB_YESNO)!=IDYES)
1038 if (m_pwndBottomView)
1039 m_pwndBottomView->GoToLine(nConflictLine);
1040 return false;
1044 if (((DWORD)CRegDWORD(_T("Software\\TortoiseMerge\\Backup"))) != 0)
1046 MoveFileEx(m_Data.m_mergedFile.GetFilename(), m_Data.m_mergedFile.GetFilename() + _T(".bak"), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
1048 if (SaveFile(m_Data.m_mergedFile.GetFilename())==0)
1050 // file was saved with 0 lines!
1051 // ask the user if the file should be deleted
1052 CString sTemp;
1053 sTemp.Format(IDS_DELETEWHENEMPTY, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
1054 if (CMessageBox::ShowCheck(m_hWnd, sTemp, _T("TortoiseMerge"), MB_YESNO, _T("DeleteFileWhenEmpty")) == IDYES)
1056 DeleteFile(m_Data.m_mergedFile.GetFilename());
1060 if (bDoesNotExist)
1062 // call TortoiseProc to add the new file to version control
1063 CString cmd = _T("\"") + CPathUtils::GetAppDirectory();
1064 cmd += _T("TortoiseProc.exe\" /command:add /noui /path:\"");
1065 cmd += m_Data.m_mergedFile.GetFilename() + _T("\"");
1066 TCHAR * buf = new TCHAR[cmd.GetLength()+1];
1067 _tcscpy_s(buf, cmd.GetLength()+1, cmd);
1068 STARTUPINFO startup;
1069 PROCESS_INFORMATION process;
1070 memset(&startup, 0, sizeof(startup));
1071 startup.cb = sizeof(startup);
1072 memset(&process, 0, sizeof(process));
1073 if (CreateProcess(NULL, buf, NULL, NULL, FALSE, 0, 0, 0, &startup, &process)==0)
1075 delete [] buf;
1076 LPVOID lpMsgBuf;
1077 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1078 FORMAT_MESSAGE_FROM_SYSTEM |
1079 FORMAT_MESSAGE_IGNORE_INSERTS,
1080 NULL,
1081 GetLastError(),
1082 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
1083 (LPTSTR) &lpMsgBuf,
1085 NULL
1087 MessageBox((LPCTSTR)lpMsgBuf, _T("TortoiseMerge"), MB_OK | MB_ICONINFORMATION);
1088 LocalFree( lpMsgBuf );
1089 return FALSE;
1091 delete [] buf;
1092 CloseHandle(process.hThread);
1093 CloseHandle(process.hProcess);
1095 return true;
1098 void CMainFrame::OnFileSaveAs()
1100 FileSaveAs();
1103 bool CMainFrame::FileSaveAs(bool bCheckResolved /*=true*/)
1105 if (bCheckResolved)
1107 int nConflictLine = CheckResolved();
1108 if (nConflictLine >= 0)
1110 CString sTemp;
1111 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
1112 if (MessageBox(sTemp, 0, MB_ICONERROR | MB_YESNO)!=IDYES)
1114 if (m_pwndBottomView)
1115 m_pwndBottomView->GoToLine(nConflictLine);
1116 return false;
1120 OPENFILENAME ofn = {0}; // common dialog box structure
1121 TCHAR szFile[MAX_PATH] = {0}; // buffer for file name
1122 ofn.lStructSize = sizeof(OPENFILENAME);
1123 ofn.hwndOwner = m_hWnd;
1124 ofn.lpstrFile = szFile;
1125 ofn.nMaxFile = sizeof(szFile)/sizeof(TCHAR);
1126 CString temp;
1127 temp.LoadString(IDS_SAVEASTITLE);
1128 if (!temp.IsEmpty())
1129 ofn.lpstrTitle = temp;
1130 ofn.Flags = OFN_OVERWRITEPROMPT;
1131 CString sFilter;
1132 sFilter.LoadString(IDS_COMMONFILEFILTER);
1133 TCHAR * pszFilters = new TCHAR[sFilter.GetLength()+4];
1134 _tcscpy_s (pszFilters, sFilter.GetLength()+4, sFilter);
1135 // Replace '|' delimiters with '\0's
1136 TCHAR *ptr = pszFilters + _tcslen(pszFilters); //set ptr at the NULL
1137 while (ptr != pszFilters)
1139 if (*ptr == '|')
1140 *ptr = '\0';
1141 ptr--;
1143 ofn.lpstrFilter = pszFilters;
1144 ofn.nFilterIndex = 1;
1146 // Display the Open dialog box.
1147 CString sFile;
1148 if (GetSaveFileName(&ofn)==TRUE)
1150 sFile = CString(ofn.lpstrFile);
1151 SaveFile(sFile);
1152 delete [] pszFilters;
1153 return true;
1155 delete [] pszFilters;
1156 return false;
1159 void CMainFrame::OnUpdateFileSave(CCmdUI *pCmdUI)
1161 BOOL bEnable = FALSE;
1162 if (m_Data.m_mergedFile.InUse())
1164 if (m_pwndBottomView)
1166 if ((m_pwndBottomView->IsWindowVisible())&&(m_pwndBottomView->m_pViewData))
1168 bEnable = TRUE;
1171 if (m_pwndRightView)
1173 if ((m_pwndRightView->IsWindowVisible())&&(m_pwndRightView->m_pViewData))
1175 if (m_pwndRightView->IsModified() || (m_Data.m_yourFile.GetWindowName().Right(9).Compare(_T(": patched"))==0))
1176 bEnable = TRUE;
1180 pCmdUI->Enable(bEnable);
1183 void CMainFrame::OnUpdateFileSaveAs(CCmdUI *pCmdUI)
1185 BOOL bEnable = FALSE;
1186 if (m_pwndBottomView)
1188 if ((m_pwndBottomView->IsWindowVisible())&&(m_pwndBottomView->m_pViewData))
1190 bEnable = TRUE;
1193 if (m_pwndRightView)
1195 if ((m_pwndRightView->IsWindowVisible())&&(m_pwndRightView->m_pViewData))
1197 bEnable = TRUE;
1200 pCmdUI->Enable(bEnable);
1204 void CMainFrame::OnUpdateViewOnewaydiff(CCmdUI *pCmdUI)
1206 pCmdUI->SetCheck(!m_bOneWay);
1207 BOOL bEnable = TRUE;
1208 if (m_pwndBottomView)
1210 if (m_pwndBottomView->IsWindowVisible())
1211 bEnable = FALSE;
1213 pCmdUI->Enable(bEnable);
1216 void CMainFrame::OnViewOptions()
1218 CString sTemp;
1219 sTemp.LoadString(IDS_SETTINGSTITLE);
1220 CSettings dlg(sTemp);
1221 dlg.DoModal();
1222 if (dlg.IsReloadNeeded())
1224 if (CheckForSave()==IDCANCEL)
1225 return;
1226 CDiffColors::GetInstance().LoadRegistry();
1227 LoadViews();
1228 return;
1230 CDiffColors::GetInstance().LoadRegistry();
1231 if (m_pwndBottomView)
1232 m_pwndBottomView->Invalidate();
1233 if (m_pwndLeftView)
1234 m_pwndLeftView->Invalidate();
1235 if (m_pwndRightView)
1236 m_pwndRightView->Invalidate();
1239 void CMainFrame::OnClose()
1241 if ((m_pFindDialog)&&(!m_pFindDialog->IsTerminating()))
1243 m_pFindDialog->SendMessage(WM_CLOSE);
1244 return;
1246 int ret = IDNO;
1247 if (((m_pwndBottomView)&&(m_pwndBottomView->IsModified())) ||
1248 ((m_pwndRightView)&&(m_pwndRightView->IsModified())))
1250 CString sTemp;
1251 sTemp.LoadString(IDS_ASKFORSAVE);
1252 ret = MessageBox(sTemp, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
1253 if (ret == IDYES)
1255 if (!FileSave())
1256 return;
1259 if ((ret == IDNO)||(ret == IDYES))
1261 WINDOWPLACEMENT wp;
1263 // before it is destroyed, save the position of the window
1264 wp.length = sizeof wp;
1266 if (GetWindowPlacement(&wp))
1269 if (IsIconic())
1270 // never restore to Iconic state
1271 wp.showCmd = SW_SHOW ;
1273 if ((wp.flags & WPF_RESTORETOMAXIMIZED) != 0)
1274 // if maximized and maybe iconic restore maximized state
1275 wp.showCmd = SW_SHOWMAXIMIZED ;
1277 // and write it to the .INI file
1278 WriteWindowPlacement(&wp);
1280 __super::OnClose();
1284 void CMainFrame::OnEditFind()
1286 if (m_pFindDialog)
1288 return;
1290 else
1292 // start searching from the start again
1293 // if no line is selected, otherwise start from
1294 // the selected line
1295 m_nSearchIndex = FindSearchStart(0);
1296 m_pFindDialog = new CFindDlg();
1297 m_pFindDialog->Create(this);
1301 LRESULT CMainFrame::OnFindDialogMessage(WPARAM /*wParam*/, LPARAM /*lParam*/)
1303 ASSERT(m_pFindDialog != NULL);
1305 if (m_pFindDialog->IsTerminating())
1307 // invalidate the handle identifying the dialog box.
1308 m_pFindDialog = NULL;
1309 return 0;
1312 if(m_pFindDialog->FindNext())
1314 //read data from dialog
1315 m_sFindText = m_pFindDialog->GetFindString();
1316 m_bMatchCase = (m_pFindDialog->MatchCase() == TRUE);
1317 m_bLimitToDiff = m_pFindDialog->LimitToDiffs();
1318 m_bWholeWord = m_pFindDialog->WholeWord();
1320 OnEditFindnext();
1323 return 0;
1326 bool CharIsDelimiter(const CString& ch)
1328 CString delimiters(_T(" .,:;=+-*/\\\n\t()[]<>@"));
1329 return delimiters.Find(ch) >= 0;
1332 bool CMainFrame::StringFound(const CString& str)const
1334 int nSubStringStartIdx = str.Find(m_sFindText);
1335 bool bStringFound = (nSubStringStartIdx >= 0);
1336 if (bStringFound && m_bWholeWord)
1338 if (nSubStringStartIdx)
1339 bStringFound = CharIsDelimiter(str.Mid(nSubStringStartIdx-1,1));
1341 if (bStringFound)
1343 int nEndIndex = nSubStringStartIdx + m_sFindText.GetLength();
1344 if (str.GetLength() > nEndIndex)
1345 bStringFound = CharIsDelimiter(str.Mid(nEndIndex, 1));
1348 return bStringFound;
1351 void CMainFrame::OnEditFindprev()
1353 Search(SearchPrevious);
1356 void CMainFrame::OnEditFindnext()
1358 Search(SearchNext);
1361 void CMainFrame::Search(SearchDirection srchDir)
1363 if (m_sFindText.IsEmpty())
1364 return;
1366 if ((m_pwndLeftView)&&(m_pwndLeftView->m_pViewData))
1368 bool bFound = FALSE;
1370 CString left;
1371 CString right;
1372 CString bottom;
1373 DiffStates leftstate = DIFFSTATE_NORMAL;
1374 DiffStates rightstate = DIFFSTATE_NORMAL;
1375 DiffStates bottomstate = DIFFSTATE_NORMAL;
1376 int i = 0;
1378 m_nSearchIndex = FindSearchStart(m_nSearchIndex);
1379 m_nSearchIndex++;
1380 if (m_nSearchIndex >= m_pwndLeftView->m_pViewData->GetCount())
1381 m_nSearchIndex = 0;
1382 if (srchDir == SearchPrevious)
1384 // SearchIndex points 1 past where we found the last match,
1385 // so if we are searching backwards we need to adjust accordingly
1386 m_nSearchIndex -= 2;
1387 // if at the top, start again from the end
1388 if (m_nSearchIndex < 0)
1389 m_nSearchIndex += m_pwndLeftView->m_pViewData->GetCount();
1391 const int idxLimits[2][2][2]={{{m_nSearchIndex, m_pwndLeftView->m_pViewData->GetCount()},
1392 {0, m_nSearchIndex}},
1393 {{m_nSearchIndex, -1},
1394 {m_pwndLeftView->m_pViewData->GetCount()-1, m_nSearchIndex}}};
1395 const int offsets[2]={+1, -1};
1397 for (int j=0; j != 2 && !bFound; ++j)
1399 for (i=idxLimits[srchDir][j][0]; i != idxLimits[srchDir][j][1]; i += offsets[srchDir])
1401 left = m_pwndLeftView->m_pViewData->GetLine(i);
1402 leftstate = m_pwndLeftView->m_pViewData->GetState(i);
1403 if ((!m_bOneWay)&&(m_pwndRightView->m_pViewData))
1405 right = m_pwndRightView->m_pViewData->GetLine(i);
1406 rightstate = m_pwndRightView->m_pViewData->GetState(i);
1408 if ((m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1410 bottom = m_pwndBottomView->m_pViewData->GetLine(i);
1411 bottomstate = m_pwndBottomView->m_pViewData->GetState(i);
1414 if (!m_bMatchCase)
1416 left = left.MakeLower();
1417 right = right.MakeLower();
1418 bottom = bottom.MakeLower();
1419 m_sFindText = m_sFindText.MakeLower();
1421 if (StringFound(left))
1423 if ((!m_bLimitToDiff)||(leftstate != DIFFSTATE_NORMAL))
1425 bFound = TRUE;
1426 break;
1429 else if (StringFound(right))
1431 if ((!m_bLimitToDiff)||(rightstate != DIFFSTATE_NORMAL))
1433 bFound = TRUE;
1434 break;
1437 else if (StringFound(bottom))
1439 if ((!m_bLimitToDiff)||(bottomstate != DIFFSTATE_NORMAL))
1441 bFound = TRUE;
1442 break;
1447 if (bFound)
1449 m_nSearchIndex = i;
1450 m_pwndLeftView->GoToLine(m_nSearchIndex);
1451 if (StringFound(left))
1453 m_pwndLeftView->SetFocus();
1454 m_pwndLeftView->HiglightLines(m_nSearchIndex);
1456 else if (StringFound(right))
1458 m_pwndRightView->SetFocus();
1459 m_pwndRightView->HiglightLines(m_nSearchIndex);
1461 else if (StringFound(bottom))
1463 m_pwndBottomView->SetFocus();
1464 m_pwndBottomView->HiglightLines(m_nSearchIndex);
1467 else
1469 m_nSearchIndex = 0;
1474 int CMainFrame::FindSearchStart(int nDefault)
1476 // TortoiseMerge doesn't have a cursor which we could use to
1477 // anchor the search on.
1478 // Instead we use a line that is selected.
1479 // If however no line is selected, use the default line (which could
1480 // be the top of the document for a new search, or the line where the
1481 // search was successful on)
1482 int nLine = nDefault;
1483 int nSelStart = 0;
1484 int nSelEnd = 0;
1485 if (m_pwndLeftView)
1487 if (m_pwndLeftView->GetSelection(nSelStart, nSelEnd))
1489 if (nSelStart == nSelEnd)
1490 nLine = nSelStart;
1493 else if ((nLine == nDefault)&&(m_pwndRightView))
1495 if (m_pwndRightView->GetSelection(nSelStart, nSelEnd))
1497 if (nSelStart == nSelEnd)
1498 nLine = nSelStart;
1501 else if ((nLine == nDefault)&&(m_pwndBottomView))
1503 if (m_pwndBottomView->GetSelection(nSelStart, nSelEnd))
1505 if (nSelStart == nSelEnd)
1506 nLine = nSelStart;
1509 return nLine;
1512 void CMainFrame::OnViewLinedown()
1514 if (m_pwndLeftView)
1515 m_pwndLeftView->ScrollToLine(m_pwndLeftView->m_nTopLine+1);
1516 if (m_pwndRightView)
1517 m_pwndRightView->ScrollToLine(m_pwndRightView->m_nTopLine+1);
1518 if (m_pwndBottomView)
1519 m_pwndBottomView->ScrollToLine(m_pwndBottomView->m_nTopLine+1);
1520 m_wndLocatorBar.Invalidate();
1523 void CMainFrame::OnViewLineup()
1525 if (m_pwndLeftView)
1526 m_pwndLeftView->ScrollToLine(m_pwndLeftView->m_nTopLine-1);
1527 if (m_pwndRightView)
1528 m_pwndRightView->ScrollToLine(m_pwndRightView->m_nTopLine-1);
1529 if (m_pwndBottomView)
1530 m_pwndBottomView->ScrollToLine(m_pwndBottomView->m_nTopLine-1);
1531 m_wndLocatorBar.Invalidate();
1534 void CMainFrame::OnViewLineleft()
1536 if (m_pwndLeftView)
1537 m_pwndLeftView->ScrollSide(-1);
1538 if (m_pwndRightView)
1539 m_pwndRightView->ScrollSide(-1);
1540 if (m_pwndBottomView)
1541 m_pwndBottomView->ScrollSide(-1);
1544 void CMainFrame::OnViewLineright()
1546 if (m_pwndLeftView)
1547 m_pwndLeftView->ScrollSide(1);
1548 if (m_pwndRightView)
1549 m_pwndRightView->ScrollSide(1);
1550 if (m_pwndBottomView)
1551 m_pwndBottomView->ScrollSide(1);
1554 void CMainFrame::OnEditUseTheirs()
1556 if (m_pwndBottomView)
1557 m_pwndBottomView->UseTheirTextBlock();
1559 void CMainFrame::OnUpdateEditUsetheirblock(CCmdUI *pCmdUI)
1561 int nSelBlockStart = -1;
1562 int nSelBlockEnd = -1;
1563 if (m_pwndBottomView)
1564 m_pwndBottomView->GetSelection(nSelBlockStart, nSelBlockEnd);
1565 pCmdUI->Enable((nSelBlockStart >= 0)&&(nSelBlockEnd >= 0));
1569 void CMainFrame::OnEditUseMine()
1571 if (m_pwndBottomView)
1572 m_pwndBottomView->UseMyTextBlock();
1574 void CMainFrame::OnUpdateEditUsemyblock(CCmdUI *pCmdUI)
1576 int nSelBlockStart = -1;
1577 int nSelBlockEnd = -1;
1578 if (m_pwndBottomView)
1579 m_pwndBottomView->GetSelection(nSelBlockStart, nSelBlockEnd);
1580 pCmdUI->Enable((nSelBlockStart >= 0)&&(nSelBlockEnd >= 0));
1584 void CMainFrame::OnEditUseTheirsThenMine()
1586 if (m_pwndBottomView)
1587 m_pwndBottomView->UseTheirThenMyTextBlock();
1589 void CMainFrame::OnUpdateEditUsetheirthenmyblock(CCmdUI *pCmdUI)
1591 int nSelBlockStart = -1;
1592 int nSelBlockEnd = -1;
1593 if (m_pwndBottomView)
1594 m_pwndBottomView->GetSelection(nSelBlockStart, nSelBlockEnd);
1595 pCmdUI->Enable((nSelBlockStart >= 0)&&(nSelBlockEnd >= 0));
1599 void CMainFrame::OnEditUseMineThenTheirs()
1601 if (m_pwndBottomView)
1602 m_pwndBottomView->UseMyThenTheirTextBlock();
1604 void CMainFrame::OnUpdateEditUseminethentheirblock(CCmdUI *pCmdUI)
1606 int nSelBlockStart = -1;
1607 int nSelBlockEnd = -1;
1608 if (m_pwndBottomView)
1609 m_pwndBottomView->GetSelection(nSelBlockStart, nSelBlockEnd);
1610 pCmdUI->Enable((nSelBlockStart >= 0)&&(nSelBlockEnd >= 0));
1613 void CMainFrame::OnEditUseleftblock()
1615 if (m_pwndRightView)
1616 m_pwndRightView->UseBlock();
1619 void CMainFrame::OnUpdateEditUseleftblock(CCmdUI *pCmdUI)
1621 pCmdUI->Enable(m_pwndRightView && m_pwndRightView->IsWindowVisible() && m_pwndRightView->HasCaret() && m_pwndRightView->HasSelection());
1624 void CMainFrame::OnEditUseleftfile()
1626 if (m_pwndRightView)
1627 m_pwndRightView->UseFile();
1630 void CMainFrame::OnUpdateEditUseleftfile(CCmdUI *pCmdUI)
1632 pCmdUI->Enable(m_pwndRightView && m_pwndRightView->IsWindowVisible() && m_pwndRightView->HasCaret());
1635 void CMainFrame::OnEditUseblockfromleftbeforeright()
1637 if (m_pwndRightView)
1638 m_pwndRightView->UseLeftBeforeRight();
1641 void CMainFrame::OnUpdateEditUseblockfromleftbeforeright(CCmdUI *pCmdUI)
1643 pCmdUI->Enable(m_pwndRightView && m_pwndRightView->IsWindowVisible() && m_pwndRightView->HasCaret() && m_pwndRightView->HasSelection());
1646 void CMainFrame::OnEditUseblockfromrightbeforeleft()
1648 if (m_pwndRightView)
1649 m_pwndRightView->UseRightBeforeLeft();
1652 void CMainFrame::OnUpdateEditUseblockfromrightbeforeleft(CCmdUI *pCmdUI)
1654 pCmdUI->Enable(m_pwndRightView && m_pwndRightView->IsWindowVisible() && m_pwndRightView->HasCaret() && m_pwndRightView->HasSelection());
1658 void CMainFrame::OnFileReload()
1660 if (CheckForSave()==IDCANCEL)
1661 return;
1662 CDiffColors::GetInstance().LoadRegistry();
1663 LoadViews(true);
1666 void CMainFrame::ActivateFrame(int nCmdShow)
1668 // nCmdShow is the normal show mode this frame should be in
1669 // translate default nCmdShow (-1)
1670 if (nCmdShow == -1)
1672 if (!IsWindowVisible())
1673 nCmdShow = SW_SHOWNORMAL;
1674 else if (IsIconic())
1675 nCmdShow = SW_RESTORE;
1678 // bring to top before showing
1679 BringToTop(nCmdShow);
1681 if (nCmdShow != -1)
1683 // show the window as specified
1684 WINDOWPLACEMENT wp;
1686 if ( !ReadWindowPlacement(&wp) )
1688 ShowWindow(nCmdShow);
1690 else
1692 if ( nCmdShow != SW_SHOWNORMAL )
1693 wp.showCmd = nCmdShow;
1695 SetWindowPlacement(&wp);
1698 // and finally, bring to top after showing
1699 BringToTop(nCmdShow);
1701 return;
1704 BOOL CMainFrame::ReadWindowPlacement(WINDOWPLACEMENT * pwp)
1706 CRegString placement = CRegString(_T("Software\\TortoiseMerge\\WindowPos"));
1707 CString sPlacement = placement;
1708 if (sPlacement.IsEmpty())
1709 return FALSE;
1710 int nRead = _stscanf_s(sPlacement, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
1711 &pwp->flags, &pwp->showCmd,
1712 &pwp->ptMinPosition.x, &pwp->ptMinPosition.y,
1713 &pwp->ptMaxPosition.x, &pwp->ptMaxPosition.y,
1714 &pwp->rcNormalPosition.left, &pwp->rcNormalPosition.top,
1715 &pwp->rcNormalPosition.right, &pwp->rcNormalPosition.bottom);
1716 if ( nRead != 10 )
1717 return FALSE;
1718 pwp->length = sizeof(WINDOWPLACEMENT);
1720 return TRUE;
1723 void CMainFrame::WriteWindowPlacement(WINDOWPLACEMENT * pwp)
1725 CRegString placement = CRegString(_T("Software\\TortoiseMerge\\WindowPos"));
1726 TCHAR szBuffer[sizeof("-32767")*8 + sizeof("65535")*2];
1727 CString s;
1729 _stprintf_s(szBuffer, sizeof("-32767")*8 + sizeof("65535")*2, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
1730 pwp->flags, pwp->showCmd,
1731 pwp->ptMinPosition.x, pwp->ptMinPosition.y,
1732 pwp->ptMaxPosition.x, pwp->ptMaxPosition.y,
1733 pwp->rcNormalPosition.left, pwp->rcNormalPosition.top,
1734 pwp->rcNormalPosition.right, pwp->rcNormalPosition.bottom);
1735 placement = szBuffer;
1738 void CMainFrame::OnUpdateMergeMarkasresolved(CCmdUI *pCmdUI)
1740 if (pCmdUI == NULL)
1741 return;
1742 BOOL bEnable = FALSE;
1743 if ((!m_bReadOnly)&&(m_Data.m_mergedFile.InUse()))
1745 if (m_pwndBottomView)
1747 if ((m_pwndBottomView->IsWindowVisible())&&(m_pwndBottomView->m_pViewData))
1749 bEnable = TRUE;
1753 pCmdUI->Enable(bEnable);
1756 void CMainFrame::OnMergeMarkasresolved()
1758 int nConflictLine = CheckResolved();
1759 if (nConflictLine >= 0)
1761 CString sTemp;
1762 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
1763 if (MessageBox(sTemp, 0, MB_ICONERROR | MB_YESNO)!=IDYES)
1765 if (m_pwndBottomView)
1766 m_pwndBottomView->GoToLine(nConflictLine);
1767 return;
1770 // now check if the file has already been saved and if not, save it.
1771 if (m_Data.m_mergedFile.InUse())
1773 if (m_pwndBottomView)
1775 if ((m_pwndBottomView->IsWindowVisible())&&(m_pwndBottomView->m_pViewData))
1777 FileSave(false);
1781 MarkAsResolved();
1784 BOOL CMainFrame::MarkAsResolved()
1786 if (m_bReadOnly)
1787 return FALSE;
1788 if ((m_pwndBottomView)&&(m_pwndBottomView->IsWindowVisible()))
1790 TCHAR buf[MAX_PATH*3];
1791 GetModuleFileName(NULL, buf, MAX_PATH);
1792 TCHAR * end = _tcsrchr(buf, '\\');
1793 end++;
1794 (*end) = 0;
1795 _tcscat_s(buf, MAX_PATH*3, _T("TortoiseProc.exe /command:resolve /path:\""));
1796 _tcscat_s(buf, MAX_PATH*3, m_Data.m_mergedFile.GetFilename());
1797 _tcscat_s(buf, MAX_PATH*3, _T("\" /closeonend:1 /noquestion /skipcheck"));
1798 STARTUPINFO startup;
1799 PROCESS_INFORMATION process;
1800 memset(&startup, 0, sizeof(startup));
1801 startup.cb = sizeof(startup);
1802 memset(&process, 0, sizeof(process));
1803 if (CreateProcess(NULL, buf, NULL, NULL, FALSE, 0, 0, 0, &startup, &process)==0)
1805 LPVOID lpMsgBuf;
1806 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1807 FORMAT_MESSAGE_FROM_SYSTEM |
1808 FORMAT_MESSAGE_IGNORE_INSERTS,
1809 NULL,
1810 GetLastError(),
1811 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
1812 (LPTSTR) &lpMsgBuf,
1814 NULL
1816 MessageBox((LPCTSTR)lpMsgBuf, _T("TortoiseMerge"), MB_OK | MB_ICONINFORMATION);
1817 LocalFree( lpMsgBuf );
1818 return FALSE;
1820 CloseHandle(process.hThread);
1821 CloseHandle(process.hProcess);
1823 else
1824 return FALSE;
1825 return TRUE;
1828 void CMainFrame::OnUpdateMergeNextconflict(CCmdUI *pCmdUI)
1830 pCmdUI->Enable(m_bHasConflicts);
1833 void CMainFrame::OnUpdateMergePreviousconflict(CCmdUI *pCmdUI)
1835 pCmdUI->Enable(m_bHasConflicts);
1838 void CMainFrame::OnMoving(UINT fwSide, LPRECT pRect)
1840 // if the pathfilelist dialog is attached to the mainframe,
1841 // move it along with the mainframe
1842 if (::IsWindow(m_dlgFilePatches.m_hWnd))
1844 RECT patchrect;
1845 m_dlgFilePatches.GetWindowRect(&patchrect);
1846 if (::IsWindow(m_hWnd))
1848 RECT thisrect;
1849 GetWindowRect(&thisrect);
1850 if (patchrect.right == thisrect.left)
1852 m_dlgFilePatches.SetWindowPos(NULL, patchrect.left - (thisrect.left - pRect->left), patchrect.top - (thisrect.top - pRect->top),
1853 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
1857 __super::OnMoving(fwSide, pRect);
1860 void CMainFrame::OnUpdateEditCopy(CCmdUI *pCmdUI)
1862 BOOL bShow = FALSE;
1863 if ((m_pwndBottomView)&&(m_pwndBottomView->HasSelection()))
1864 bShow = TRUE;
1865 if ((m_pwndRightView)&&(m_pwndRightView->HasSelection()))
1866 bShow = TRUE;
1867 if ((m_pwndLeftView)&&(m_pwndLeftView->HasSelection()))
1868 bShow = TRUE;
1869 pCmdUI->Enable(bShow);
1872 void CMainFrame::OnViewSwitchleft()
1874 int ret = IDNO;
1875 if (((m_pwndBottomView)&&(m_pwndBottomView->IsModified())) ||
1876 ((m_pwndRightView)&&(m_pwndRightView->IsModified())))
1878 CString sTemp;
1879 sTemp.LoadString(IDS_ASKFORSAVE);
1880 ret = MessageBox(sTemp, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
1881 if (ret == IDYES)
1883 if (!FileSave())
1884 return;
1887 if ((ret == IDNO)||(ret == IDYES))
1889 CWorkingFile file = m_Data.m_baseFile;
1890 m_Data.m_baseFile = m_Data.m_yourFile;
1891 m_Data.m_yourFile = file;
1892 if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_yourFile.GetFilename())==0)
1894 m_Data.m_mergedFile = m_Data.m_baseFile;
1896 else if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_baseFile.GetFilename())==0)
1898 m_Data.m_mergedFile = m_Data.m_yourFile;
1900 LoadViews();
1904 void CMainFrame::OnUpdateViewSwitchleft(CCmdUI *pCmdUI)
1906 BOOL bEnable = TRUE;
1907 if (m_pwndBottomView)
1909 if (m_pwndBottomView->IsWindowVisible())
1910 bEnable = FALSE;
1912 pCmdUI->Enable(bEnable);
1916 void CMainFrame::OnUpdateViewShowfilelist(CCmdUI *pCmdUI)
1918 if (m_dlgFilePatches.HasFiles())
1920 pCmdUI->Enable(true);
1922 else
1923 pCmdUI->Enable(false);
1924 pCmdUI->SetCheck(m_dlgFilePatches.IsWindowVisible());
1927 void CMainFrame::OnViewShowfilelist()
1929 m_dlgFilePatches.ShowWindow(m_dlgFilePatches.IsWindowVisible() ? SW_HIDE : SW_SHOW);
1932 void CMainFrame::OnEditUndo()
1934 if (CUndo::GetInstance().CanUndo())
1936 CUndo::GetInstance().Undo(m_pwndLeftView, m_pwndRightView, m_pwndBottomView);
1941 void CMainFrame::OnUpdateEditUndo(CCmdUI *pCmdUI)
1943 pCmdUI->Enable(CUndo::GetInstance().CanUndo());
1946 int CMainFrame::CheckForSave()
1948 int ret = IDNO;
1949 if (((m_pwndBottomView)&&(m_pwndBottomView->IsModified())) ||
1950 ((m_pwndRightView)&&(m_pwndRightView->IsModified())))
1952 CString sTemp;
1953 sTemp.LoadString(IDS_WARNMODIFIEDLOOSECHANGES);
1954 ret = MessageBox(sTemp, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
1956 if (ret == IDYES)
1958 FileSave();
1961 return ret;
1964 void CMainFrame::OnViewInlinediffword()
1966 m_bInlineWordDiff = !m_bInlineWordDiff;
1967 if (m_pwndLeftView)
1969 m_pwndLeftView->SetInlineWordDiff(m_bInlineWordDiff);
1970 m_pwndLeftView->Invalidate();
1972 if (m_pwndRightView)
1974 m_pwndRightView->SetInlineWordDiff(m_bInlineWordDiff);
1975 m_pwndRightView->Invalidate();
1977 if (m_pwndBottomView)
1979 m_pwndBottomView->SetInlineWordDiff(m_bInlineWordDiff);
1980 m_pwndBottomView->Invalidate();
1982 m_wndLineDiffBar.Invalidate();
1985 void CMainFrame::OnUpdateViewInlinediffword(CCmdUI *pCmdUI)
1987 pCmdUI->Enable(m_pwndLeftView && m_pwndLeftView->IsWindowVisible() &&
1988 m_pwndRightView && m_pwndRightView->IsWindowVisible());
1989 pCmdUI->SetCheck(m_bInlineWordDiff);
1992 void CMainFrame::OnUpdateEditCreateunifieddifffile(CCmdUI *pCmdUI)
1994 // "create unified diff file" is only available if two files
1995 // are diffed, not three.
1996 bool bEnabled = true;
1997 if ((m_pwndLeftView == NULL)||(!m_pwndLeftView->IsWindowVisible()))
1998 bEnabled = false;
1999 if ((m_pwndRightView == NULL)||(!m_pwndRightView->IsWindowVisible()))
2000 bEnabled = false;
2001 if ((m_pwndBottomView)&&(m_pwndBottomView->IsWindowVisible()))
2002 bEnabled = false;
2003 pCmdUI->Enable(bEnabled);
2006 void CMainFrame::OnEditCreateunifieddifffile()
2008 CString origFile, modifiedFile, outputFile;
2009 // the original file is the one on the left
2010 if (m_pwndLeftView)
2011 origFile = m_pwndLeftView->m_sFullFilePath;
2012 if (m_pwndRightView)
2013 modifiedFile = m_pwndRightView->m_sFullFilePath;
2014 if (!origFile.IsEmpty() && !modifiedFile.IsEmpty())
2016 // ask for the path to save the unified diff file to
2017 OPENFILENAME ofn = {0}; // common dialog box structure
2018 TCHAR szFile[MAX_PATH] = {0}; // buffer for file name
2019 ofn.lStructSize = sizeof(OPENFILENAME);
2020 ofn.lpstrFile = szFile;
2021 ofn.nMaxFile = sizeof(szFile)/sizeof(TCHAR);
2022 CString temp;
2023 temp.LoadString(IDS_SAVEASTITLE);
2024 if (!temp.IsEmpty())
2025 ofn.lpstrTitle = temp;
2026 ofn.Flags = OFN_OVERWRITEPROMPT;
2027 CString sFilter;
2028 sFilter.LoadString(IDS_COMMONFILEFILTER);
2029 TCHAR * pszFilters = new TCHAR[sFilter.GetLength()+4];
2030 _tcscpy_s (pszFilters, sFilter.GetLength()+4, sFilter);
2031 // Replace '|' delimiters with '\0's
2032 TCHAR *ptr = pszFilters + _tcslen(pszFilters); //set ptr at the NULL
2033 while (ptr != pszFilters)
2035 if (*ptr == '|')
2036 *ptr = '\0';
2037 ptr--;
2039 ofn.lpstrFilter = pszFilters;
2040 ofn.nFilterIndex = 1;
2042 // Display the Save dialog box.
2043 CString sFile;
2044 if (GetSaveFileName(&ofn)==TRUE)
2046 outputFile = CString(ofn.lpstrFile);
2047 CAppUtils::CreateUnifiedDiff(origFile, modifiedFile, outputFile, true);
2049 delete [] pszFilters;
2053 void CMainFrame::OnUpdateViewLinediffbar(CCmdUI *pCmdUI)
2055 pCmdUI->SetCheck(m_bLineDiff);
2056 pCmdUI->Enable();
2059 void CMainFrame::OnViewLinediffbar()
2061 m_bLineDiff = !m_bLineDiff;
2062 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2063 m_wndLineDiffBar.DocumentUpdated();
2064 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2065 m_wndLocatorBar.DocumentUpdated();
2068 void CMainFrame::OnUpdateViewLocatorbar(CCmdUI *pCmdUI)
2070 pCmdUI->SetCheck(m_bLocatorBar);
2071 pCmdUI->Enable();
2074 void CMainFrame::OnViewLocatorbar()
2076 m_bLocatorBar = !m_bLocatorBar;
2077 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2078 m_wndLocatorBar.DocumentUpdated();
2079 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2080 m_wndLineDiffBar.DocumentUpdated();