Fixed issue #1507: Submodule Diff Dialog should show dirty state only on working...
[TortoiseGit.git] / src / TortoiseMerge / MainFrm.cpp
blobacc035d6db0db3ae5a9f95cd501eea328987d1e1
1 // TortoiseMerge - a Diff/Patch program
3 // Copyright (C) 2008-2012 - TortoiseGit
4 // Copyright (C) 2012 - Sven Strickroth <email@cs-ware.de>
5 // Copyright (C) 2004-2009 - TortoiseSVN
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 "Patch.h"
25 #include "SysProgressDlg.h"
26 #include "Settings.h"
27 #include "MessageBox.h"
28 #include "AppUtils.h"
29 #include "PathUtils.h"
30 #include "MainFrm.h"
31 #include "LeftView.h"
32 #include "RightView.h"
33 #include "BottomView.h"
34 #include "DiffColors.h"
35 #include ".\mainfrm.h"
36 #include "FormatMessageWrapper.h"
37 #include "EditGotoDlg.h"
39 #ifdef _DEBUG
40 #define new DEBUG_NEW
41 #endif
44 // CMainFrame
45 const UINT CMainFrame::m_FindDialogMessage = RegisterWindowMessage(FINDMSGSTRING);
47 IMPLEMENT_DYNCREATE(CMainFrame, CFrameWndEx)
49 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)
50 ON_WM_CREATE()
51 ON_COMMAND_RANGE(ID_VIEW_APPLOOK_WIN_2000, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnApplicationLook)
52 ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_APPLOOK_WIN_2000, 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_COMMAND(ID_EDIT_FIND, OnEditFind)
71 ON_REGISTERED_MESSAGE(m_FindDialogMessage, OnFindDialogMessage)
72 ON_COMMAND(ID_EDIT_FINDNEXT, OnEditFindnext)
73 ON_COMMAND(ID_EDIT_FINDPREV, OnEditFindprev)
74 ON_COMMAND(ID_EDIT_GOTO, OnEditGoto)
75 ON_COMMAND(ID_FILE_RELOAD, OnFileReload)
76 ON_COMMAND(ID_VIEW_LINEDOWN, OnViewLinedown)
77 ON_COMMAND(ID_VIEW_LINEUP, OnViewLineup)
78 ON_UPDATE_COMMAND_UI(ID_EDIT_MARKASRESOLVED, OnUpdateMergeMarkasresolved)
79 ON_COMMAND(ID_EDIT_MARKASRESOLVED, OnMergeMarkasresolved)
80 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTCONFLICT, OnUpdateMergeNextconflict)
81 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSCONFLICT, OnUpdateMergePreviousconflict)
82 ON_WM_MOVE()
83 ON_WM_MOVING()
84 ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
85 ON_COMMAND(ID_VIEW_SWITCHLEFT, OnViewSwitchleft)
86 ON_UPDATE_COMMAND_UI(ID_VIEW_SWITCHLEFT, OnUpdateViewSwitchleft)
87 ON_COMMAND(ID_VIEW_LINELEFT, &CMainFrame::OnViewLineleft)
88 ON_COMMAND(ID_VIEW_LINERIGHT, &CMainFrame::OnViewLineright)
89 ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWFILELIST, &CMainFrame::OnUpdateViewShowfilelist)
90 ON_COMMAND(ID_VIEW_SHOWFILELIST, &CMainFrame::OnViewShowfilelist)
91 ON_COMMAND(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnEditUseTheirs)
92 ON_COMMAND(ID_EDIT_USEMYBLOCK, &CMainFrame::OnEditUseMine)
93 ON_COMMAND(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnEditUseTheirsThenMine)
94 ON_COMMAND(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnEditUseMineThenTheirs)
95 ON_COMMAND(ID_EDIT_UNDO, &CMainFrame::OnEditUndo)
96 ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, &CMainFrame::OnUpdateEditUndo)
97 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnUpdateEditUseminethentheirblock)
98 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMYBLOCK, &CMainFrame::OnUpdateEditUsemyblock)
99 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnUpdateEditUsetheirblock)
100 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnUpdateEditUsetheirthenmyblock)
101 ON_COMMAND(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnViewInlinediffword)
102 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnUpdateViewInlinediffword)
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_EDIT_USELEFTBLOCK, &CMainFrame::OnUpdateEditUseleftblock)
111 ON_COMMAND(ID_EDIT_USELEFTFILE, &CMainFrame::OnEditUseleftfile)
112 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTFILE, &CMainFrame::OnUpdateEditUseleftfile)
113 ON_COMMAND(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnEditUseblockfromleftbeforeright)
114 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnUpdateEditUseblockfromleftbeforeright)
115 ON_COMMAND(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnEditUseblockfromrightbeforeleft)
116 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnUpdateEditUseblockfromrightbeforeleft)
117 END_MESSAGE_MAP()
119 static UINT indicators[] =
121 ID_SEPARATOR, // status line indicator
122 ID_INDICATOR_LEFTVIEW,
123 ID_INDICATOR_RIGHTVIEW,
124 ID_INDICATOR_BOTTOMVIEW,
125 ID_INDICATOR_CAPS,
126 ID_INDICATOR_NUM,
127 ID_INDICATOR_SCRL
131 // CMainFrame construction/destruction
133 CMainFrame::CMainFrame()
134 : m_pFindDialog(NULL)
135 , m_nSearchIndex(0)
136 , m_bInitSplitter(FALSE)
137 , m_bReversedPatch(FALSE)
138 , m_bHasConflicts(false)
139 , m_bInlineWordDiff(true)
140 , m_bLineDiff(true)
141 , m_bLocatorBar(true)
142 , m_nMoveMovesToIgnore(0)
143 , m_bLimitToDiff(false)
144 , m_bWholeWord(false)
145 , m_pwndLeftView(NULL)
146 , m_pwndRightView(NULL)
147 , m_pwndBottomView(NULL)
148 , m_bReadOnly(false)
149 , m_bBlame(false)
151 m_bOneWay = (0 != ((DWORD)CRegDWORD(_T("Software\\TortoiseMerge\\OnePane"))));
152 theApp.m_nAppLook = theApp.GetInt(_T("ApplicationLook"), ID_VIEW_APPLOOK_VS_2005);
155 CMainFrame::~CMainFrame()
159 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
161 if (CFrameWndEx::OnCreate(lpCreateStruct) == -1)
162 return -1;
164 OnApplicationLook(theApp.m_nAppLook);
166 if (!m_wndMenuBar.Create(this))
168 TRACE0("Failed to create menubar\n");
169 return -1; // fail to create
172 m_wndMenuBar.SetPaneStyle(m_wndMenuBar.GetPaneStyle() | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY);
174 // prevent the menu bar from taking the focus on activation
175 CMFCPopupMenu::SetForceMenuFocus(FALSE);
177 if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY) ||
178 !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
180 TRACE0("Failed to create toolbar\n");
181 return -1; // fail to create
183 m_wndToolBar.SetWindowText(_T("Main"));
185 if (!m_wndStatusBar.Create(this) ||
186 !m_wndStatusBar.SetIndicators(indicators,
187 _countof(indicators)))
189 TRACE0("Failed to create status bar\n");
190 return -1; // fail to create
193 if (!m_wndLocatorBar.Create(this, IDD_DIFFLOCATOR,
194 CBRS_ALIGN_LEFT | CBRS_SIZE_FIXED, ID_VIEW_LOCATORBAR))
196 TRACE0("Failed to create dialogbar\n");
197 return -1; // fail to create
199 if (!m_wndLineDiffBar.Create(this, IDD_LINEDIFF,
200 CBRS_ALIGN_BOTTOM | CBRS_SIZE_FIXED, ID_VIEW_LINEDIFFBAR))
202 TRACE0("Failed to create dialogbar\n");
203 return -1; // fail to create
205 m_wndLocatorBar.m_pMainFrm = this;
206 m_wndLineDiffBar.m_pMainFrm = this;
208 EnableDocking(CBRS_ALIGN_ANY);
209 m_wndMenuBar.EnableDocking(CBRS_ALIGN_TOP);
210 m_wndToolBar.EnableDocking(CBRS_ALIGN_TOP);
211 DockPane(&m_wndMenuBar);
212 DockPane(&m_wndToolBar);
213 DockPane(&m_wndLocatorBar);
214 DockPane(&m_wndLineDiffBar);
215 ShowPane(&m_wndLocatorBar, true, false, true);
216 ShowPane(&m_wndLineDiffBar, true, false, true);
218 m_wndLocatorBar.EnableGripper(FALSE);
219 m_wndLineDiffBar.EnableGripper(FALSE);
221 return 0;
224 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
226 if( !CFrameWndEx::PreCreateWindow(cs) )
227 return FALSE;
228 return TRUE;
231 void CMainFrame::OnApplicationLook(UINT id)
233 CWaitCursor wait;
235 theApp.m_nAppLook = id;
237 switch (theApp.m_nAppLook)
239 case ID_VIEW_APPLOOK_WIN_2000:
240 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManager));
241 break;
243 case ID_VIEW_APPLOOK_OFF_XP:
244 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOfficeXP));
245 break;
247 case ID_VIEW_APPLOOK_WIN_XP:
248 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
249 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
250 break;
252 case ID_VIEW_APPLOOK_OFF_2003:
253 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2003));
254 CDockingManager::SetDockingMode(DT_SMART);
255 break;
257 case ID_VIEW_APPLOOK_VS_2005:
258 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2005));
259 CDockingManager::SetDockingMode(DT_SMART);
260 break;
262 default:
263 switch (theApp.m_nAppLook)
265 case ID_VIEW_APPLOOK_OFF_2007_BLUE:
266 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_LunaBlue);
267 break;
269 case ID_VIEW_APPLOOK_OFF_2007_BLACK:
270 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_ObsidianBlack);
271 break;
273 case ID_VIEW_APPLOOK_OFF_2007_SILVER:
274 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Silver);
275 break;
277 case ID_VIEW_APPLOOK_OFF_2007_AQUA:
278 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Aqua);
279 break;
282 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));
283 CDockingManager::SetDockingMode(DT_SMART);
286 RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_FRAME | RDW_ERASE);
288 theApp.WriteInt(_T("ApplicationLook"), theApp.m_nAppLook);
291 void CMainFrame::OnUpdateApplicationLook(CCmdUI* pCmdUI)
293 pCmdUI->SetRadio(theApp.m_nAppLook == pCmdUI->m_nID);
297 // CMainFrame diagnostics
299 #ifdef _DEBUG
300 void CMainFrame::AssertValid() const
302 CFrameWndEx::AssertValid();
305 void CMainFrame::Dump(CDumpContext& dc) const
307 CFrameWndEx::Dump(dc);
310 #endif //_DEBUG
313 // CMainFrame message handlers
316 BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)
318 CRect cr;
319 GetClientRect( &cr);
322 // split into three panes:
323 // -------------
324 // | | |
325 // | | |
326 // |------------
327 // | |
328 // | |
329 // |------------
331 // create a splitter with 2 rows, 1 column
332 if (!m_wndSplitter.CreateStatic(this, 2, 1))
334 TRACE0("Failed to CreateStaticSplitter\n");
335 return FALSE;
338 // add the second splitter pane - which is a nested splitter with 2 columns
339 if (!m_wndSplitter2.CreateStatic(
340 &m_wndSplitter, // our parent window is the first splitter
341 1, 2, // the new splitter is 1 row, 2 columns
342 WS_CHILD | WS_VISIBLE | WS_BORDER, // style, WS_BORDER is needed
343 m_wndSplitter.IdFromRowCol(0, 0)
344 // new splitter is in the first row, 1st column of first splitter
347 TRACE0("Failed to create nested splitter\n");
348 return FALSE;
350 // add the first splitter pane - the default view in row 0
351 if (!m_wndSplitter.CreateView(1, 0,
352 RUNTIME_CLASS(CBottomView), CSize(cr.Width(), cr.Height()), pContext))
354 TRACE0("Failed to create first pane\n");
355 return FALSE;
357 m_pwndBottomView = (CBottomView *)m_wndSplitter.GetPane(1,0);
358 m_pwndBottomView->m_pwndLocator = &m_wndLocatorBar;
359 m_pwndBottomView->m_pwndLineDiffBar = &m_wndLineDiffBar;
360 m_pwndBottomView->m_pwndStatusBar = &m_wndStatusBar;
361 m_pwndBottomView->m_pMainFrame = this;
363 // now create the two views inside the nested splitter
365 if (!m_wndSplitter2.CreateView(0, 0,
366 RUNTIME_CLASS(CLeftView), CSize(cr.Width()/2, cr.Height()/2), pContext))
368 TRACE0("Failed to create second pane\n");
369 return FALSE;
371 m_pwndLeftView = (CLeftView *)m_wndSplitter2.GetPane(0,0);
372 m_pwndLeftView->m_pwndLocator = &m_wndLocatorBar;
373 m_pwndLeftView->m_pwndLineDiffBar = &m_wndLineDiffBar;
374 m_pwndLeftView->m_pwndStatusBar = &m_wndStatusBar;
375 m_pwndLeftView->m_pMainFrame = this;
377 if (!m_wndSplitter2.CreateView(0, 1,
378 RUNTIME_CLASS(CRightView), CSize(cr.Width()/2, cr.Height()/2), pContext))
380 TRACE0("Failed to create third pane\n");
381 return FALSE;
383 m_pwndRightView = (CRightView *)m_wndSplitter2.GetPane(0,1);
384 m_pwndRightView->m_pwndLocator = &m_wndLocatorBar;
385 m_pwndRightView->m_pwndLineDiffBar = &m_wndLineDiffBar;
386 m_pwndRightView->m_pwndStatusBar = &m_wndStatusBar;
387 m_pwndRightView->m_pMainFrame = this;
388 m_bInitSplitter = TRUE;
390 m_dlgFilePatches.Create(IDD_FILEPATCHES, this);
391 UpdateLayout();
392 return TRUE;
395 // Callback function
396 BOOL CMainFrame::PatchFile(int nIndex, bool bAutoPatch, bool bIsReview)
398 CString Path2 = m_Patch.GetFullPath(m_Data.m_sPatchPath, nIndex, 1);
399 CString sFilePath = m_Patch.GetFullPath(m_Data.m_sPatchPath, nIndex);
400 //first, do a "dry run" of patching...
401 if (!m_Patch.PatchFile(nIndex, m_Data.m_sPatchPath))
403 //patching not successful, so retrieve the
404 //base file from version control and try
405 //again...
406 CString sVersion = m_Patch.GetRevision(nIndex);
408 CString sBaseFile;
409 if (sVersion == _T("0000000") || sFilePath == _T("NUL"))
410 sBaseFile = m_TempFiles.GetTempFilePath();
411 else
413 CSysProgressDlg progDlg;
414 CString sTemp;
415 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sVersion);
416 progDlg.SetLine(1, sTemp, true);
417 progDlg.SetLine(2, sFilePath, true);
418 sTemp.LoadString(IDS_GETVERSIONOFFILETITLE);
419 progDlg.SetTitle(sTemp);
420 progDlg.SetShowProgressBar(false);
421 progDlg.SetAnimation(IDR_DOWNLOAD);
422 progDlg.SetTime(FALSE);
424 if(!m_Patch.m_IsGitPatch)
425 progDlg.ShowModeless(this);
427 sBaseFile = m_TempFiles.GetTempFilePath();
428 if (!CAppUtils::GetVersionedFile(sFilePath, sVersion, sBaseFile, &progDlg, m_hWnd))
430 progDlg.Stop();
431 CString sErrMsg;
432 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sVersion, (LPCTSTR)sFilePath);
433 MessageBox(sErrMsg, NULL, MB_ICONERROR);
434 return FALSE;
437 progDlg.Stop();
440 CString sTempFile = m_TempFiles.GetTempFilePath();
441 if (!m_Patch.PatchFile(nIndex, m_Data.m_sPatchPath, sTempFile, sBaseFile, true))
443 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
444 return FALSE;
447 CString temp;
448 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)sVersion);
449 m_Data.m_baseFile.SetFileName(sBaseFile);
450 m_Data.m_baseFile.SetDescriptiveName(temp);
451 if(!Path2.IsEmpty() && Path2 != _T("NUL"))
452 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(Path2), (LPCTSTR)m_Data.m_sPatchPatched);
453 else
454 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
456 if (sVersion == _T("0000000") || sFilePath == _T("NUL"))
458 m_Data.m_baseFile.SetFileName(Path2);
459 m_Data.m_yourFile.SetFileName(Path2);
460 m_Data.m_theirFile.SetFileName(sTempFile);
461 m_Data.m_theirFile.SetDescriptiveName(CPathUtils::GetFileNameFromPath(Path2));
462 m_Data.m_mergedFile.SetFileName(Path2);
463 if (!bIsReview)
465 LoadViews();
466 return FALSE;
469 else if (bIsReview)
471 m_Data.m_yourFile.SetFileName(sTempFile);
472 m_Data.m_yourFile.SetDescriptiveName(temp);
473 m_Data.m_theirFile.SetOutOfUse();
474 m_Data.m_mergedFile.SetOutOfUse();
476 else
478 m_Data.m_theirFile.SetFileName(sTempFile);
479 m_Data.m_theirFile.SetDescriptiveName(temp);
480 m_Data.m_yourFile.SetFileName(sFilePath);
481 m_Data.m_yourFile.SetDescriptiveName(CPathUtils::GetFileNameFromPath(sFilePath));
482 m_Data.m_mergedFile.SetFileName(sFilePath);
483 m_Data.m_mergedFile.SetDescriptiveName(CPathUtils::GetFileNameFromPath(sFilePath));
485 TRACE(_T("comparing %s and %s\nagainst the base file %s\n"), (LPCTSTR)sTempFile, (LPCTSTR)sFilePath, (LPCTSTR)sBaseFile);
489 else
491 //"dry run" was successful, so save the patched file somewhere...
492 CString sTempFile = m_TempFiles.GetTempFilePath();
493 if (!m_Patch.PatchFile(nIndex, m_Data.m_sPatchPath, sTempFile))
495 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
496 return FALSE;
498 if (m_bReversedPatch)
500 m_Data.m_baseFile.SetFileName(sTempFile);
501 CString temp;
502 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
503 m_Data.m_baseFile.SetDescriptiveName(temp);
504 m_Data.m_yourFile.SetFileName(sFilePath);
505 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchOriginal);
506 m_Data.m_yourFile.SetDescriptiveName(temp);
507 m_Data.m_theirFile.SetOutOfUse();
508 m_Data.m_mergedFile.SetOutOfUse();
510 else
512 if (!PathFileExists(sFilePath))
514 m_Data.m_baseFile.SetFileName(m_TempFiles.GetTempFilePath());
515 m_Data.m_baseFile.CreateEmptyFile();
517 else
519 m_Data.m_baseFile.SetFileName(sFilePath);
521 CString sDescription;
522 sDescription.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchOriginal);
523 m_Data.m_baseFile.SetDescriptiveName(sDescription);
524 m_Data.m_yourFile.SetFileName(sTempFile);
525 CString temp;
526 if (!Path2.IsEmpty() && Path2 != _T("NUL"))
528 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(Path2), (LPCTSTR)m_Data.m_sPatchPatched);
529 m_Data.m_mergedFile.SetFileName(Path2);
531 else
533 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
534 m_Data.m_mergedFile.SetFileName(sFilePath);
537 m_Data.m_yourFile.SetDescriptiveName(temp);
538 m_Data.m_theirFile.SetOutOfUse();
540 TRACE(_T("comparing %s\nwith the patched result %s\n"), (LPCTSTR)sFilePath, (LPCTSTR)sTempFile);
542 LoadViews();
543 if (bAutoPatch)
545 OnFileSave();
547 return TRUE;
550 // Callback function
551 BOOL CMainFrame::DiffFiles(CString sURL1, CString sRev1, CString sURL2, CString sRev2)
553 CString tempfile1 = m_TempFiles.GetTempFilePath();
554 CString tempfile2 = m_TempFiles.GetTempFilePath();
556 ASSERT(tempfile1.Compare(tempfile2));
558 CString sTemp;
559 CSysProgressDlg progDlg;
560 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev1);
561 progDlg.SetLine(1, sTemp, true);
562 progDlg.SetLine(2, sURL1, true);
563 sTemp.LoadString(IDS_GETVERSIONOFFILETITLE);
564 progDlg.SetTitle(sTemp);
565 progDlg.SetShowProgressBar(true);
566 progDlg.SetAnimation(IDR_DOWNLOAD);
567 progDlg.SetTime(FALSE);
568 progDlg.SetProgress(1,100);
569 progDlg.ShowModeless(this);
570 if (!CAppUtils::GetVersionedFile(sURL1, sRev1, tempfile1, &progDlg, m_hWnd))
572 progDlg.Stop();
573 CString sErrMsg;
574 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev1, (LPCTSTR)sURL1);
575 MessageBox(sErrMsg, NULL, MB_ICONERROR);
576 return FALSE;
578 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev2);
579 progDlg.SetLine(1, sTemp, true);
580 progDlg.SetLine(2, sURL2, true);
581 progDlg.SetProgress(50, 100);
582 if (!CAppUtils::GetVersionedFile(sURL2, sRev2, tempfile2, &progDlg, m_hWnd))
584 progDlg.Stop();
585 CString sErrMsg;
586 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev2, (LPCTSTR)sURL2);
587 MessageBox(sErrMsg, NULL, MB_ICONERROR);
588 return FALSE;
590 progDlg.SetProgress(100,100);
591 progDlg.Stop();
592 CString temp;
593 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL1), (LPCTSTR)sRev1);
594 m_Data.m_baseFile.SetFileName(tempfile1);
595 m_Data.m_baseFile.SetDescriptiveName(temp);
596 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL2), (LPCTSTR)sRev2);
597 m_Data.m_yourFile.SetFileName(tempfile2);
598 m_Data.m_yourFile.SetDescriptiveName(temp);
600 LoadViews();
602 return TRUE;
605 void CMainFrame::OnFileOpen()
607 if (CheckForSave()==IDCANCEL)
608 return;
609 COpenDlg dlg;
610 if (dlg.DoModal()!=IDOK)
612 return;
614 m_dlgFilePatches.ShowWindow(SW_HIDE);
615 m_dlgFilePatches.Init(NULL, NULL, CString(), NULL);
616 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,
617 (LPCTSTR)dlg.m_sUnifiedDiffFile, (LPCTSTR)dlg.m_sPatchDirectory);
618 m_Data.m_baseFile.SetFileName(dlg.m_sBaseFile);
619 m_Data.m_theirFile.SetFileName(dlg.m_sTheirFile);
620 m_Data.m_yourFile.SetFileName(dlg.m_sYourFile);
621 m_Data.m_sDiffFile = dlg.m_sUnifiedDiffFile;
622 m_Data.m_sPatchPath = dlg.m_sPatchDirectory;
623 m_Data.m_mergedFile.SetOutOfUse();
624 CCrashReport::Instance().AddFile2(dlg.m_sBaseFile, NULL, _T("Basefile"), CR_AF_MAKE_FILE_COPY);
625 CCrashReport::Instance().AddFile2(dlg.m_sTheirFile, NULL, _T("Theirfile"), CR_AF_MAKE_FILE_COPY);
626 CCrashReport::Instance().AddFile2(dlg.m_sYourFile, NULL, _T("Yourfile"), CR_AF_MAKE_FILE_COPY);
627 CCrashReport::Instance().AddFile2(dlg.m_sUnifiedDiffFile, NULL, _T("Difffile"), CR_AF_MAKE_FILE_COPY);
629 if (!m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && m_Data.IsYourFileInUse())
631 // a diff between two files means "Yours" against "Base", not "Theirs" against "Yours"
632 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
634 if (m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && !m_Data.IsYourFileInUse())
636 // a diff between two files means "Yours" against "Base", not "Theirs" against "Base"
637 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
640 LoadViews();
643 void CMainFrame::ClearViewNamesAndPaths() {
644 m_pwndLeftView->m_sWindowName.Empty();
645 m_pwndLeftView->m_sFullFilePath.Empty();
646 m_pwndRightView->m_sWindowName.Empty();
647 m_pwndRightView->m_sFullFilePath.Empty();
648 m_pwndBottomView->m_sWindowName.Empty();
649 m_pwndBottomView->m_sFullFilePath.Empty();
652 bool CMainFrame::LoadViews(bool bRetainPosition)
654 m_Data.SetBlame(m_bBlame);
655 m_bHasConflicts = false;
656 CBaseView* pwndActiveView = m_pwndLeftView;
657 int nOldLine = m_pwndLeftView ? m_pwndLeftView->m_nTopLine : -1;
658 int nOldLineNumber =
659 m_pwndLeftView && m_pwndLeftView->m_pViewData ?
660 m_pwndLeftView->m_pViewData->GetLineNumber(m_pwndLeftView->m_nTopLine) : -1;
661 if (!m_Data.Load())
663 ::MessageBox(NULL, m_Data.GetError(), _T("TortoiseMerge"), MB_ICONERROR);
664 m_Data.m_mergedFile.SetOutOfUse();
665 return false;
668 m_pwndRightView->UseCaret(false);
669 m_pwndBottomView->UseCaret(false);
671 if (!m_Data.IsBaseFileInUse())
673 if (m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
675 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
677 else if ((!m_Data.m_sDiffFile.IsEmpty())&&(!m_Patch.OpenUnifiedDiffFile(m_Data.m_sDiffFile)))
679 ClearViewNamesAndPaths();
680 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
681 return false;
683 if (m_Patch.GetNumberOfFiles() > 0)
685 CString firstpath = m_Patch.GetFilename(0);
686 CString path=firstpath;
687 path.Replace('/','\\');
688 if ( !PathIsRelative(path) && !PathFileExists(path) )
690 // The absolute path mentioned in the patch does not exist. Lets
691 // try to find the correct relative path by stripping prefixes.
692 BOOL bFound = m_Patch.StripPrefixes(m_Data.m_sPatchPath);
693 CString strippedpath = m_Patch.GetFilename(0);
694 if (bFound)
696 CString msg;
697 msg.Format(IDS_WARNABSOLUTEPATHFOUND, (LPCTSTR)firstpath, (LPCTSTR)strippedpath);
698 if (CMessageBox::Show(m_hWnd, msg, _T("TortoiseMerge"), MB_ICONQUESTION | MB_YESNO)==IDNO)
699 return false;
701 else
703 CString msg;
704 msg.Format(IDS_WARNABSOLUTEPATHNOTFOUND, (LPCTSTR)firstpath);
705 CMessageBox::Show(m_hWnd, msg, _T("TortoiseMerge"), MB_ICONEXCLAMATION);
706 return false;
709 CString betterpatchpath = m_Patch.CheckPatchPath(m_Data.m_sPatchPath);
710 if (betterpatchpath.CompareNoCase(m_Data.m_sPatchPath)!=0)
712 CString msg;
713 msg.Format(IDS_WARNBETTERPATCHPATHFOUND, (LPCTSTR)m_Data.m_sPatchPath, (LPCTSTR)betterpatchpath);
714 if (CMessageBox::Show(m_hWnd, msg, _T("TortoiseMerge"), MB_ICONQUESTION | MB_YESNO)==IDYES)
715 m_Data.m_sPatchPath = betterpatchpath;
717 m_dlgFilePatches.Init(&m_Patch, this, m_Data.m_sPatchPath, this);
718 m_dlgFilePatches.ShowWindow(SW_SHOW);
719 ClearViewNamesAndPaths();
720 if (!m_wndSplitter.IsRowHidden(1))
721 m_wndSplitter.HideRow(1);
722 m_pwndLeftView->SetHidden(FALSE);
723 m_pwndRightView->SetHidden(FALSE);
724 m_pwndBottomView->SetHidden(TRUE);
727 if (m_Data.IsBaseFileInUse() && !m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
729 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
731 if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && !m_Data.IsTheirFileInUse())
733 //diff between YOUR and BASE
734 m_pwndRightView->UseCaret();
735 if (m_bOneWay)
737 if (!m_wndSplitter2.IsColumnHidden(1))
738 m_wndSplitter2.HideColumn(1);
740 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseBoth;
741 m_pwndLeftView->texttype = m_Data.m_arYourFile.GetUnicodeType();
742 m_pwndLeftView->lineendings = m_Data.m_arYourFile.GetLineEndings();
743 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName() + _T(" - ") + m_Data.m_yourFile.GetWindowName();
744 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename() + _T(" - ") + m_Data.m_yourFile.GetFilename();
746 m_pwndRightView->m_pViewData = NULL;
747 m_pwndBottomView->m_pViewData = NULL;
749 if (!m_wndSplitter.IsRowHidden(1))
750 m_wndSplitter.HideRow(1);
751 m_pwndLeftView->SetHidden(FALSE);
752 m_pwndRightView->SetHidden(TRUE);
753 m_pwndBottomView->SetHidden(TRUE);
754 ::SetWindowPos(m_pwndLeftView->m_hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
756 else
758 pwndActiveView = m_pwndRightView;
759 if (m_wndSplitter2.IsColumnHidden(1))
760 m_wndSplitter2.ShowColumn();
762 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseLeft;
763 m_pwndLeftView->texttype = m_Data.m_arBaseFile.GetUnicodeType();
764 m_pwndLeftView->lineendings = m_Data.m_arBaseFile.GetLineEndings();
765 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName();
766 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename();
768 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseRight;
769 m_pwndRightView->texttype = m_Data.m_arYourFile.GetUnicodeType();
770 m_pwndRightView->lineendings = m_Data.m_arYourFile.GetLineEndings();
771 m_pwndRightView->m_sWindowName = m_Data.m_yourFile.GetWindowName();
772 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
774 m_pwndBottomView->m_pViewData = NULL;
776 if (!m_wndSplitter.IsRowHidden(1))
777 m_wndSplitter.HideRow(1);
778 m_pwndLeftView->SetHidden(FALSE);
779 m_pwndRightView->SetHidden(FALSE);
780 m_pwndBottomView->SetHidden(TRUE);
783 else if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
785 //diff between THEIR, YOUR and BASE
786 m_pwndBottomView->UseCaret();
787 pwndActiveView = m_pwndBottomView;
789 m_pwndLeftView->m_pViewData = &m_Data.m_TheirBaseBoth;
790 m_pwndLeftView->texttype = m_Data.m_arTheirFile.GetUnicodeType();
791 m_pwndLeftView->lineendings = m_Data.m_arTheirFile.GetLineEndings();
792 m_pwndLeftView->m_sWindowName.LoadString(IDS_VIEWTITLE_THEIRS);
793 m_pwndLeftView->m_sWindowName += _T(" - ") + m_Data.m_theirFile.GetWindowName();
794 m_pwndLeftView->m_sFullFilePath = m_Data.m_theirFile.GetFilename();
796 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseBoth;
797 m_pwndRightView->texttype = m_Data.m_arYourFile.GetUnicodeType();
798 m_pwndRightView->lineendings = m_Data.m_arYourFile.GetLineEndings();
799 m_pwndRightView->m_sWindowName.LoadString(IDS_VIEWTITLE_MINE);
800 m_pwndRightView->m_sWindowName += _T(" - ") + m_Data.m_yourFile.GetWindowName();
801 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
803 m_pwndBottomView->m_pViewData = &m_Data.m_Diff3;
804 m_pwndBottomView->texttype = m_Data.m_arTheirFile.GetUnicodeType();
805 m_pwndBottomView->lineendings = m_Data.m_arTheirFile.GetLineEndings();
806 m_pwndBottomView->m_sWindowName.LoadString(IDS_VIEWTITLE_MERGED);
807 m_pwndBottomView->m_sWindowName += _T(" - ") + m_Data.m_mergedFile.GetWindowName();
808 m_pwndBottomView->m_sFullFilePath = m_Data.m_mergedFile.GetFilename();
810 if (m_wndSplitter2.IsColumnHidden(1))
811 m_wndSplitter2.ShowColumn();
812 if (m_wndSplitter.IsRowHidden(1))
813 m_wndSplitter.ShowRow();
814 m_pwndLeftView->SetHidden(FALSE);
815 m_pwndRightView->SetHidden(FALSE);
816 m_pwndBottomView->SetHidden(FALSE);
817 // in three pane view, hide the line diff bar
818 m_wndLineDiffBar.ShowPane(false, false, true);
819 m_wndLineDiffBar.DocumentUpdated();
821 if (!m_Data.m_mergedFile.InUse())
823 m_Data.m_mergedFile.SetFileName(m_Data.m_yourFile.GetFilename());
825 m_pwndLeftView->DocumentUpdated();
826 m_pwndRightView->DocumentUpdated();
827 m_pwndBottomView->DocumentUpdated();
828 m_wndLocatorBar.DocumentUpdated();
829 m_wndLineDiffBar.DocumentUpdated();
830 UpdateLayout();
831 SetActiveView(pwndActiveView);
833 if (bRetainPosition && m_pwndLeftView->m_pViewData)
835 int n = nOldLineNumber;
836 if (n >= 0)
837 n = m_pwndLeftView->m_pViewData->FindLineNumber(n);
838 if (n < 0)
839 n = nOldLine;
841 m_pwndLeftView->ScrollAllToLine(n);
842 POINT p;
843 p.x = 0;
844 p.y = n;
845 m_pwndLeftView->SetCaretPosition(p);
847 else
849 bool bGoFirstDiff = (0 != (DWORD)CRegDWORD(_T("Software\\TortoiseMerge\\FirstDiffOnLoad"), TRUE));
850 if (bGoFirstDiff) {
851 pwndActiveView->GoToFirstDifference();
852 // Ignore the first few Mouse Move messages, so that the line diff stays on
853 // the first diff line until the user actually moves the mouse
854 m_nMoveMovesToIgnore = 3;
858 // Avoid incorrect rendering of active pane.
859 m_pwndBottomView->ScrollToChar(0);
860 m_pwndLeftView->ScrollToChar(0);
861 m_pwndRightView->ScrollToChar(0);
862 CheckResolved();
863 CUndo::GetInstance().Clear();
864 return true;
867 void CMainFrame::UpdateLayout()
869 if (m_bInitSplitter)
871 CRect cr, rclocbar;
872 GetWindowRect(&cr);
873 int width = cr.Width();
874 if (::IsWindow(m_wndLocatorBar) && m_wndLocatorBar.IsWindowVisible())
876 m_wndLocatorBar.GetWindowRect(&rclocbar);
877 width -= rclocbar.Width();
879 m_wndSplitter.SetRowInfo(0, cr.Height()/2, 0);
880 m_wndSplitter.SetRowInfo(1, cr.Height()/2, 0);
881 m_wndSplitter.SetColumnInfo(0, width / 2, 50);
882 m_wndSplitter2.SetRowInfo(0, cr.Height()/2, 0);
883 m_wndSplitter2.SetColumnInfo(0, width / 2, 50);
884 m_wndSplitter2.SetColumnInfo(1, width / 2, 50);
886 m_wndSplitter.RecalcLayout();
890 void CMainFrame::OnSize(UINT nType, int cx, int cy)
892 if (m_bInitSplitter && nType != SIZE_MINIMIZED)
894 UpdateLayout();
896 CFrameWndEx::OnSize(nType, cx, cy);
899 void CMainFrame::OnViewWhitespaces()
901 CRegDWORD regViewWhitespaces = CRegDWORD(_T("Software\\TortoiseMerge\\ViewWhitespaces"), 1);
902 BOOL bViewWhitespaces = regViewWhitespaces;
903 if (m_pwndLeftView)
904 bViewWhitespaces = m_pwndLeftView->m_bViewWhitespace;
906 bViewWhitespaces = !bViewWhitespaces;
907 regViewWhitespaces = bViewWhitespaces;
908 if (m_pwndLeftView)
910 m_pwndLeftView->m_bViewWhitespace = bViewWhitespaces;
911 m_pwndLeftView->Invalidate();
913 if (m_pwndRightView)
915 m_pwndRightView->m_bViewWhitespace = bViewWhitespaces;
916 m_pwndRightView->Invalidate();
918 if (m_pwndBottomView)
920 m_pwndBottomView->m_bViewWhitespace = bViewWhitespaces;
921 m_pwndBottomView->Invalidate();
925 void CMainFrame::OnUpdateViewWhitespaces(CCmdUI *pCmdUI)
927 if (m_pwndLeftView)
928 pCmdUI->SetCheck(m_pwndLeftView->m_bViewWhitespace);
931 void CMainFrame::OnViewOnewaydiff()
933 if (CheckForSave()==IDCANCEL)
934 return;
935 m_bOneWay = !m_bOneWay;
936 if (m_bOneWay)
938 // in one way view, hide the line diff bar
939 m_wndLineDiffBar.ShowPane(false, false, true);
940 m_wndLineDiffBar.DocumentUpdated();
942 else
944 // restore the line diff bar
945 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
946 m_wndLineDiffBar.DocumentUpdated();
947 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
948 m_wndLocatorBar.DocumentUpdated();
950 LoadViews(true);
953 void CMainFrame::ShowDiffBar(bool bShow)
955 if (bShow)
957 // restore the line diff bar
958 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
959 m_wndLineDiffBar.DocumentUpdated();
960 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
961 m_wndLocatorBar.DocumentUpdated();
963 else
965 // in one way view, hide the line diff bar
966 m_wndLineDiffBar.ShowPane(false, false, true);
967 m_wndLineDiffBar.DocumentUpdated();
971 int CMainFrame::CheckResolved()
973 //only in three way diffs can be conflicts!
974 m_bHasConflicts = true;
975 if (m_pwndBottomView->IsWindowVisible())
977 if (m_pwndBottomView->m_pViewData)
979 for (int i=0; i<m_pwndBottomView->m_pViewData->GetCount(); i++)
981 if ((DIFFSTATE_CONFLICTED == m_pwndBottomView->m_pViewData->GetState(i))||
982 (DIFFSTATE_CONFLICTED_IGNORED == m_pwndBottomView->m_pViewData->GetState(i)))
983 return i;
987 m_bHasConflicts = false;
988 return -1;
991 int CMainFrame::SaveFile(const CString& sFilePath)
993 CViewData * pViewData = NULL;
994 CFileTextLines * pOriginFile = &m_Data.m_arBaseFile;
995 if ((m_pwndBottomView)&&(m_pwndBottomView->IsWindowVisible()))
997 pViewData = m_pwndBottomView->m_pViewData;
998 Invalidate();
1000 else if ((m_pwndRightView)&&(m_pwndRightView->IsWindowVisible()))
1002 pViewData = m_pwndRightView->m_pViewData;
1003 if (m_Data.IsYourFileInUse())
1004 pOriginFile = &m_Data.m_arYourFile;
1005 else if (m_Data.IsTheirFileInUse())
1006 pOriginFile = &m_Data.m_arTheirFile;
1007 Invalidate();
1009 else
1011 // nothing to save!
1012 return -1;
1014 if ((pViewData)&&(pOriginFile))
1016 CFileTextLines file;
1017 pOriginFile->CopySettings(&file);
1018 for (int i=0; i<pViewData->GetCount(); i++)
1020 //only copy non-removed lines
1021 DiffStates state = pViewData->GetState(i);
1022 switch (state)
1024 case DIFFSTATE_CONFLICTED:
1025 case DIFFSTATE_CONFLICTED_IGNORED:
1027 int first = i;
1028 int last = i;
1031 last++;
1032 } while((last<pViewData->GetCount()) && ((pViewData->GetState(last)==DIFFSTATE_CONFLICTED)||(pViewData->GetState(last)==DIFFSTATE_CONFLICTED_IGNORED)));
1033 file.Add(_T("<<<<<<< .mine"), m_pwndRightView->lineendings);
1034 for (int j=first; j<last; j++)
1036 EOL lineending = m_pwndRightView->m_pViewData->GetLineEnding(j);
1037 if (lineending == EOL_NOENDING)
1038 lineending = m_pwndRightView->lineendings;
1039 file.Add(m_pwndRightView->m_pViewData->GetLine(j), lineending);
1041 file.Add(_T("======="), m_pwndRightView->lineendings);
1042 for (int j=first; j<last; j++)
1044 EOL lineending = m_pwndLeftView->m_pViewData->GetLineEnding(j);
1045 if (lineending == EOL_NOENDING)
1046 lineending = m_pwndLeftView->lineendings;
1047 file.Add(m_pwndLeftView->m_pViewData->GetLine(j), lineending);
1049 file.Add(_T(">>>>>>> .theirs"), m_pwndRightView->lineendings);
1050 i = last-1;
1052 break;
1053 case DIFFSTATE_EMPTY:
1054 case DIFFSTATE_CONFLICTEMPTY:
1055 case DIFFSTATE_IDENTICALREMOVED:
1056 case DIFFSTATE_REMOVED:
1057 case DIFFSTATE_THEIRSREMOVED:
1058 case DIFFSTATE_YOURSREMOVED:
1059 case DIFFSTATE_CONFLICTRESOLVEDEMPTY:
1060 // do not save removed lines
1061 break;
1062 default:
1063 file.Add(pViewData->GetLine(i), pViewData->GetLineEnding(i));
1064 break;
1067 if (!file.Save(sFilePath, false))
1069 CMessageBox::Show(m_hWnd, file.GetErrorString(), _T("TortoiseMerge"), MB_ICONERROR);
1070 return -1;
1072 m_dlgFilePatches.SetFileStatusAsPatched(sFilePath);
1073 if (m_pwndBottomView)
1074 m_pwndBottomView->SetModified(FALSE);
1075 if (m_pwndRightView)
1076 m_pwndRightView->SetModified(FALSE);
1077 CUndo::GetInstance().MarkAsOriginalState();
1078 return file.GetCount();
1080 return -1;
1083 void CMainFrame::OnFileSave()
1085 FileSave();
1088 bool CMainFrame::FileSave(bool bCheckResolved /*=true*/)
1090 if (!m_Data.m_mergedFile.InUse())
1091 return FileSaveAs(bCheckResolved);
1092 // check if the file has the readonly attribute set
1093 bool bDoesNotExist = false;
1094 DWORD fAttribs = GetFileAttributes(m_Data.m_mergedFile.GetFilename());
1095 if ((fAttribs != INVALID_FILE_ATTRIBUTES)&&(fAttribs & FILE_ATTRIBUTE_READONLY))
1096 return FileSaveAs(bCheckResolved);
1097 if (fAttribs == INVALID_FILE_ATTRIBUTES)
1099 bDoesNotExist = (GetLastError() == ERROR_FILE_NOT_FOUND);
1101 if (bCheckResolved)
1103 int nConflictLine = CheckResolved();
1104 if (nConflictLine >= 0)
1106 CString sTemp;
1107 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
1108 if (MessageBox(sTemp, 0, MB_ICONERROR | MB_YESNO)!=IDYES)
1110 if (m_pwndBottomView)
1111 m_pwndBottomView->GoToLine(nConflictLine);
1112 return false;
1116 if (((DWORD)CRegDWORD(_T("Software\\TortoiseMerge\\Backup"))) != 0)
1118 MoveFileEx(m_Data.m_mergedFile.GetFilename(), m_Data.m_mergedFile.GetFilename() + _T(".bak"), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
1120 if (SaveFile(m_Data.m_mergedFile.GetFilename())==0)
1122 // file was saved with 0 lines!
1123 // ask the user if the file should be deleted
1124 CString sTemp;
1125 sTemp.Format(IDS_DELETEWHENEMPTY, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
1126 if (CMessageBox::ShowCheck(m_hWnd, sTemp, _T("TortoiseMerge"), MB_YESNO, _T("DeleteFileWhenEmpty")) == IDYES)
1128 DeleteFile(m_Data.m_mergedFile.GetFilename());
1132 if (bDoesNotExist)
1134 // call TortoiseProc to add the new file to version control
1135 CString cmd = _T("/command:add /noui /path:\"");
1136 cmd += m_Data.m_mergedFile.GetFilename() + _T("\"");
1137 CAppUtils::RunTortoiseProc(cmd);
1139 return true;
1142 void CMainFrame::OnFileSaveAs()
1144 FileSaveAs();
1147 bool CMainFrame::FileSaveAs(bool bCheckResolved /*=true*/)
1149 if (bCheckResolved)
1151 int nConflictLine = CheckResolved();
1152 if (nConflictLine >= 0)
1154 CString sTemp;
1155 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
1156 if (MessageBox(sTemp, 0, MB_ICONERROR | MB_YESNO)!=IDYES)
1158 if (m_pwndBottomView)
1159 m_pwndBottomView->GoToLine(nConflictLine);
1160 return false;
1164 OPENFILENAME ofn = {0}; // common dialog box structure
1165 TCHAR szFile[MAX_PATH] = {0}; // buffer for file name
1166 ofn.lStructSize = sizeof(OPENFILENAME);
1167 ofn.hwndOwner = m_hWnd;
1168 ofn.lpstrFile = szFile;
1169 ofn.nMaxFile = _countof(szFile);
1170 CString temp;
1171 temp.LoadString(IDS_SAVEASTITLE);
1172 if (!temp.IsEmpty())
1173 ofn.lpstrTitle = temp;
1174 ofn.Flags = OFN_OVERWRITEPROMPT;
1175 CString sFilter;
1176 sFilter.LoadString(IDS_COMMONFILEFILTER);
1177 TCHAR * pszFilters = new TCHAR[sFilter.GetLength()+4];
1178 _tcscpy_s (pszFilters, sFilter.GetLength()+4, sFilter);
1179 // Replace '|' delimiters with '\0's
1180 TCHAR *ptr = pszFilters + _tcslen(pszFilters); //set ptr at the NULL
1181 while (ptr != pszFilters)
1183 if (*ptr == '|')
1184 *ptr = '\0';
1185 ptr--;
1187 ofn.lpstrFilter = pszFilters;
1188 ofn.nFilterIndex = 1;
1190 // Display the Open dialog box.
1191 CString sFile;
1192 if (GetSaveFileName(&ofn)==TRUE)
1194 sFile = CString(ofn.lpstrFile);
1195 SaveFile(sFile);
1196 delete [] pszFilters;
1197 return true;
1199 delete [] pszFilters;
1200 return false;
1203 void CMainFrame::OnUpdateFileSave(CCmdUI *pCmdUI)
1205 BOOL bEnable = FALSE;
1206 if (m_Data.m_mergedFile.InUse())
1208 if (m_pwndBottomView)
1210 if ((m_pwndBottomView->IsWindowVisible())&&(m_pwndBottomView->m_pViewData))
1212 bEnable = TRUE;
1215 if (m_pwndRightView)
1217 if ((m_pwndRightView->IsWindowVisible())&&(m_pwndRightView->m_pViewData))
1219 if (m_pwndRightView->IsModified() || (m_Data.m_yourFile.GetWindowName().Right(9).Compare(_T(": patched"))==0))
1220 bEnable = TRUE;
1224 pCmdUI->Enable(bEnable);
1227 void CMainFrame::OnUpdateFileSaveAs(CCmdUI *pCmdUI)
1229 BOOL bEnable = FALSE;
1230 if (m_pwndBottomView)
1232 if ((m_pwndBottomView->IsWindowVisible())&&(m_pwndBottomView->m_pViewData))
1234 bEnable = TRUE;
1237 if (m_pwndRightView)
1239 if ((m_pwndRightView->IsWindowVisible())&&(m_pwndRightView->m_pViewData))
1241 bEnable = TRUE;
1244 pCmdUI->Enable(bEnable);
1248 void CMainFrame::OnUpdateViewOnewaydiff(CCmdUI *pCmdUI)
1250 pCmdUI->SetCheck(!m_bOneWay);
1251 BOOL bEnable = TRUE;
1252 if (m_pwndBottomView)
1254 if (m_pwndBottomView->IsWindowVisible())
1255 bEnable = FALSE;
1257 pCmdUI->Enable(bEnable);
1260 void CMainFrame::OnViewOptions()
1262 CString sTemp;
1263 sTemp.LoadString(IDS_SETTINGSTITLE);
1264 CSettings dlg(sTemp);
1265 dlg.DoModal();
1266 if (dlg.IsReloadNeeded())
1268 if (CheckForSave()==IDCANCEL)
1269 return;
1270 CDiffColors::GetInstance().LoadRegistry();
1271 LoadViews();
1272 return;
1274 CDiffColors::GetInstance().LoadRegistry();
1275 if (m_pwndBottomView)
1276 m_pwndBottomView->Invalidate();
1277 if (m_pwndLeftView)
1278 m_pwndLeftView->Invalidate();
1279 if (m_pwndRightView)
1280 m_pwndRightView->Invalidate();
1283 void CMainFrame::OnClose()
1285 if ((m_pFindDialog)&&(!m_pFindDialog->IsTerminating()))
1287 m_pFindDialog->SendMessage(WM_CLOSE);
1288 return;
1290 int ret = IDNO;
1291 if (((m_pwndBottomView)&&(m_pwndBottomView->IsModified())) ||
1292 ((m_pwndRightView)&&(m_pwndRightView->IsModified())))
1294 CString sTemp;
1295 sTemp.LoadString(IDS_ASKFORSAVE);
1296 ret = MessageBox(sTemp, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
1297 if (ret == IDYES)
1299 if (!FileSave())
1300 return;
1303 if ((ret == IDNO)||(ret == IDYES))
1305 WINDOWPLACEMENT wp;
1307 // before it is destroyed, save the position of the window
1308 wp.length = sizeof wp;
1310 if (GetWindowPlacement(&wp))
1313 if (IsIconic())
1314 // never restore to Iconic state
1315 wp.showCmd = SW_SHOW ;
1317 if ((wp.flags & WPF_RESTORETOMAXIMIZED) != 0)
1318 // if maximized and maybe iconic restore maximized state
1319 wp.showCmd = SW_SHOWMAXIMIZED ;
1321 // and write it to the .INI file
1322 WriteWindowPlacement(&wp);
1324 __super::OnClose();
1328 void CMainFrame::OnEditFind()
1330 if (m_pFindDialog)
1332 return;
1334 else
1336 // start searching from the start again
1337 // if no line is selected, otherwise start from
1338 // the selected line
1339 m_nSearchIndex = FindSearchStart(0);
1340 m_pFindDialog = new CFindDlg();
1341 m_pFindDialog->Create(this);
1345 LRESULT CMainFrame::OnFindDialogMessage(WPARAM /*wParam*/, LPARAM /*lParam*/)
1347 ASSERT(m_pFindDialog != NULL);
1349 if (m_pFindDialog->IsTerminating())
1351 // invalidate the handle identifying the dialog box.
1352 m_pFindDialog = NULL;
1353 return 0;
1356 if(m_pFindDialog->FindNext())
1358 //read data from dialog
1359 m_sFindText = m_pFindDialog->GetFindString();
1360 m_bMatchCase = (m_pFindDialog->MatchCase() == TRUE);
1361 m_bLimitToDiff = m_pFindDialog->LimitToDiffs();
1362 m_bWholeWord = m_pFindDialog->WholeWord();
1364 OnEditFindnext();
1367 return 0;
1370 bool CharIsDelimiter(const CString& ch)
1372 CString delimiters(_T(" .,:;=+-*/\\\n\t()[]<>@"));
1373 return delimiters.Find(ch) >= 0;
1376 bool CMainFrame::StringFound(const CString& str)const
1378 int nSubStringStartIdx = str.Find(m_sFindText);
1379 bool bStringFound = (nSubStringStartIdx >= 0);
1380 if (bStringFound && m_bWholeWord)
1382 if (nSubStringStartIdx)
1383 bStringFound = CharIsDelimiter(str.Mid(nSubStringStartIdx-1,1));
1385 if (bStringFound)
1387 int nEndIndex = nSubStringStartIdx + m_sFindText.GetLength();
1388 if (str.GetLength() > nEndIndex)
1389 bStringFound = CharIsDelimiter(str.Mid(nEndIndex, 1));
1392 return bStringFound;
1395 void CMainFrame::OnEditFindprev()
1397 Search(SearchPrevious);
1400 void CMainFrame::OnEditFindnext()
1402 Search(SearchNext);
1405 void CMainFrame::Search(SearchDirection srchDir)
1407 if (m_sFindText.IsEmpty())
1408 return;
1410 if ((m_pwndLeftView)&&(m_pwndLeftView->m_pViewData))
1412 bool bFound = FALSE;
1414 CString left;
1415 CString right;
1416 CString bottom;
1417 DiffStates leftstate = DIFFSTATE_NORMAL;
1418 DiffStates rightstate = DIFFSTATE_NORMAL;
1419 DiffStates bottomstate = DIFFSTATE_NORMAL;
1420 int i = 0;
1422 m_nSearchIndex = FindSearchStart(m_nSearchIndex);
1423 m_nSearchIndex++;
1424 if (m_nSearchIndex >= m_pwndLeftView->m_pViewData->GetCount())
1425 m_nSearchIndex = 0;
1426 if (srchDir == SearchPrevious)
1428 // SearchIndex points 1 past where we found the last match,
1429 // so if we are searching backwards we need to adjust accordingly
1430 m_nSearchIndex -= 2;
1431 // if at the top, start again from the end
1432 if (m_nSearchIndex < 0)
1433 m_nSearchIndex += m_pwndLeftView->m_pViewData->GetCount();
1435 const int idxLimits[2][2][2]={{{m_nSearchIndex, m_pwndLeftView->m_pViewData->GetCount()},
1436 {0, m_nSearchIndex}},
1437 {{m_nSearchIndex, -1},
1438 {m_pwndLeftView->m_pViewData->GetCount()-1, m_nSearchIndex}}};
1439 const int offsets[2]={+1, -1};
1441 for (int j=0; j != 2 && !bFound; ++j)
1443 for (i=idxLimits[srchDir][j][0]; i != idxLimits[srchDir][j][1]; i += offsets[srchDir])
1445 left = m_pwndLeftView->m_pViewData->GetLine(i);
1446 leftstate = m_pwndLeftView->m_pViewData->GetState(i);
1447 if ((!m_bOneWay)&&(m_pwndRightView->m_pViewData))
1449 right = m_pwndRightView->m_pViewData->GetLine(i);
1450 rightstate = m_pwndRightView->m_pViewData->GetState(i);
1452 if ((m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1454 bottom = m_pwndBottomView->m_pViewData->GetLine(i);
1455 bottomstate = m_pwndBottomView->m_pViewData->GetState(i);
1458 if (!m_bMatchCase)
1460 left = left.MakeLower();
1461 right = right.MakeLower();
1462 bottom = bottom.MakeLower();
1463 m_sFindText = m_sFindText.MakeLower();
1465 if (StringFound(left))
1467 if ((!m_bLimitToDiff)||(leftstate != DIFFSTATE_NORMAL))
1469 bFound = TRUE;
1470 break;
1473 else if (StringFound(right))
1475 if ((!m_bLimitToDiff)||(rightstate != DIFFSTATE_NORMAL))
1477 bFound = TRUE;
1478 break;
1481 else if (StringFound(bottom))
1483 if ((!m_bLimitToDiff)||(bottomstate != DIFFSTATE_NORMAL))
1485 bFound = TRUE;
1486 break;
1491 if (bFound)
1493 m_nSearchIndex = i;
1494 m_pwndLeftView->GoToLine(m_nSearchIndex);
1495 if (StringFound(left))
1497 m_pwndLeftView->SetFocus();
1498 m_pwndLeftView->HiglightLines(m_nSearchIndex);
1500 else if (StringFound(right))
1502 m_pwndRightView->SetFocus();
1503 m_pwndRightView->HiglightLines(m_nSearchIndex);
1505 else if (StringFound(bottom))
1507 m_pwndBottomView->SetFocus();
1508 m_pwndBottomView->HiglightLines(m_nSearchIndex);
1511 else
1513 m_nSearchIndex = 0;
1518 int CMainFrame::FindSearchStart(int nDefault)
1520 // TortoiseMerge doesn't have a cursor which we could use to
1521 // anchor the search on.
1522 // Instead we use a line that is selected.
1523 // If however no line is selected, use the default line (which could
1524 // be the top of the document for a new search, or the line where the
1525 // search was successful on)
1526 int nLine = nDefault;
1527 int nSelStart = 0;
1528 int nSelEnd = 0;
1529 if (m_pwndLeftView)
1531 if (m_pwndLeftView->GetSelection(nSelStart, nSelEnd))
1533 if (nSelStart == nSelEnd)
1534 nLine = nSelStart;
1537 else if ((nLine == nDefault)&&(m_pwndRightView))
1539 if (m_pwndRightView->GetSelection(nSelStart, nSelEnd))
1541 if (nSelStart == nSelEnd)
1542 nLine = nSelStart;
1545 else if ((nLine == nDefault)&&(m_pwndBottomView))
1547 if (m_pwndBottomView->GetSelection(nSelStart, nSelEnd))
1549 if (nSelStart == nSelEnd)
1550 nLine = nSelStart;
1553 return nLine;
1556 void CMainFrame::OnEditGoto()
1558 CWnd *wnd = this->GetFocus();
1559 if (wnd != m_pwndLeftView && wnd != m_pwndRightView && wnd != m_pwndBottomView)
1560 return;
1562 CBaseView *view = (CBaseView *)wnd;
1563 CBaseView *view2 = view == m_pwndBottomView || view == m_pwndRightView ? (CBaseView *)m_pwndLeftView : m_pwndRightView;
1564 CBaseView *view3 = view == m_pwndBottomView || view == m_pwndLeftView ? (CBaseView *)m_pwndRightView : m_Data.IsTheirFileInUse() ? m_pwndBottomView : NULL;
1567 CEditGotoDlg dlg;
1568 int start, end;
1569 int count = view->m_pViewData->GetCount();
1570 if (view->GetSelection(start, end))
1572 int line = DIFF_EMPTYLINENUMBER;
1573 for (int i = start; i < count; i++)
1575 line = view->m_pViewData->GetLineNumber(i);
1576 if (line != DIFF_EMPTYLINENUMBER)
1577 break;
1579 dlg.m_LineNumber = line == DIFF_EMPTYLINENUMBER ? 1 : (line + 1);
1582 if (dlg.DoModal() == IDOK)
1584 int index = view->m_pViewData->FindLineNumber(dlg.m_LineNumber - 1);
1585 if (index < 0)
1586 index = 0;
1587 view->HiglightLines(index);
1588 view->GoToLine(index, FALSE);
1589 view2->GoToLine(index, FALSE);
1590 if (view3)
1591 view3->GoToLine(index, FALSE);
1595 void CMainFrame::OnViewLinedown()
1597 if (m_pwndLeftView)
1598 m_pwndLeftView->ScrollToLine(m_pwndLeftView->m_nTopLine+1);
1599 if (m_pwndRightView)
1600 m_pwndRightView->ScrollToLine(m_pwndRightView->m_nTopLine+1);
1601 if (m_pwndBottomView)
1602 m_pwndBottomView->ScrollToLine(m_pwndBottomView->m_nTopLine+1);
1603 m_wndLocatorBar.Invalidate();
1606 void CMainFrame::OnViewLineup()
1608 if (m_pwndLeftView)
1609 m_pwndLeftView->ScrollToLine(m_pwndLeftView->m_nTopLine-1);
1610 if (m_pwndRightView)
1611 m_pwndRightView->ScrollToLine(m_pwndRightView->m_nTopLine-1);
1612 if (m_pwndBottomView)
1613 m_pwndBottomView->ScrollToLine(m_pwndBottomView->m_nTopLine-1);
1614 m_wndLocatorBar.Invalidate();
1617 void CMainFrame::OnViewLineleft()
1619 if (m_pwndLeftView)
1620 m_pwndLeftView->ScrollSide(-1);
1621 if (m_pwndRightView)
1622 m_pwndRightView->ScrollSide(-1);
1623 if (m_pwndBottomView)
1624 m_pwndBottomView->ScrollSide(-1);
1627 void CMainFrame::OnViewLineright()
1629 if (m_pwndLeftView)
1630 m_pwndLeftView->ScrollSide(1);
1631 if (m_pwndRightView)
1632 m_pwndRightView->ScrollSide(1);
1633 if (m_pwndBottomView)
1634 m_pwndBottomView->ScrollSide(1);
1637 void CMainFrame::OnEditUseTheirs()
1639 if (m_pwndBottomView)
1640 m_pwndBottomView->UseTheirTextBlock();
1642 void CMainFrame::OnUpdateEditUsetheirblock(CCmdUI *pCmdUI)
1644 int nSelBlockStart = -1;
1645 int nSelBlockEnd = -1;
1646 if (m_pwndBottomView)
1647 m_pwndBottomView->GetSelection(nSelBlockStart, nSelBlockEnd);
1648 pCmdUI->Enable((nSelBlockStart >= 0)&&(nSelBlockEnd >= 0));
1652 void CMainFrame::OnEditUseMine()
1654 if (m_pwndBottomView)
1655 m_pwndBottomView->UseMyTextBlock();
1657 void CMainFrame::OnUpdateEditUsemyblock(CCmdUI *pCmdUI)
1659 int nSelBlockStart = -1;
1660 int nSelBlockEnd = -1;
1661 if (m_pwndBottomView)
1662 m_pwndBottomView->GetSelection(nSelBlockStart, nSelBlockEnd);
1663 pCmdUI->Enable((nSelBlockStart >= 0)&&(nSelBlockEnd >= 0));
1667 void CMainFrame::OnEditUseTheirsThenMine()
1669 if (m_pwndBottomView)
1670 m_pwndBottomView->UseTheirThenMyTextBlock();
1672 void CMainFrame::OnUpdateEditUsetheirthenmyblock(CCmdUI *pCmdUI)
1674 int nSelBlockStart = -1;
1675 int nSelBlockEnd = -1;
1676 if (m_pwndBottomView)
1677 m_pwndBottomView->GetSelection(nSelBlockStart, nSelBlockEnd);
1678 pCmdUI->Enable((nSelBlockStart >= 0)&&(nSelBlockEnd >= 0));
1682 void CMainFrame::OnEditUseMineThenTheirs()
1684 if (m_pwndBottomView)
1685 m_pwndBottomView->UseMyThenTheirTextBlock();
1687 void CMainFrame::OnUpdateEditUseminethentheirblock(CCmdUI *pCmdUI)
1689 int nSelBlockStart = -1;
1690 int nSelBlockEnd = -1;
1691 if (m_pwndBottomView)
1692 m_pwndBottomView->GetSelection(nSelBlockStart, nSelBlockEnd);
1693 pCmdUI->Enable((nSelBlockStart >= 0)&&(nSelBlockEnd >= 0));
1696 void CMainFrame::OnEditUseleftblock()
1698 if (m_pwndRightView)
1699 m_pwndRightView->UseBlock();
1702 void CMainFrame::OnUpdateEditUseleftblock(CCmdUI *pCmdUI)
1704 pCmdUI->Enable(m_pwndRightView && m_pwndRightView->IsWindowVisible() && m_pwndRightView->HasCaret() && m_pwndRightView->HasSelection());
1707 void CMainFrame::OnEditUseleftfile()
1709 if (m_pwndRightView)
1710 m_pwndRightView->UseFile();
1713 void CMainFrame::OnUpdateEditUseleftfile(CCmdUI *pCmdUI)
1715 pCmdUI->Enable(m_pwndRightView && m_pwndRightView->IsWindowVisible() && m_pwndRightView->HasCaret());
1718 void CMainFrame::OnEditUseblockfromleftbeforeright()
1720 if (m_pwndRightView)
1721 m_pwndRightView->UseLeftBeforeRight();
1724 void CMainFrame::OnUpdateEditUseblockfromleftbeforeright(CCmdUI *pCmdUI)
1726 pCmdUI->Enable(m_pwndRightView && m_pwndRightView->IsWindowVisible() && m_pwndRightView->HasCaret() && m_pwndRightView->HasSelection());
1729 void CMainFrame::OnEditUseblockfromrightbeforeleft()
1731 if (m_pwndRightView)
1732 m_pwndRightView->UseRightBeforeLeft();
1735 void CMainFrame::OnUpdateEditUseblockfromrightbeforeleft(CCmdUI *pCmdUI)
1737 pCmdUI->Enable(m_pwndRightView && m_pwndRightView->IsWindowVisible() && m_pwndRightView->HasCaret() && m_pwndRightView->HasSelection());
1741 void CMainFrame::OnFileReload()
1743 if (CheckForSave()==IDCANCEL)
1744 return;
1745 CDiffColors::GetInstance().LoadRegistry();
1746 LoadViews(true);
1749 void CMainFrame::ActivateFrame(int nCmdShow)
1751 // nCmdShow is the normal show mode this frame should be in
1752 // translate default nCmdShow (-1)
1753 if (nCmdShow == -1)
1755 if (!IsWindowVisible())
1756 nCmdShow = SW_SHOWNORMAL;
1757 else if (IsIconic())
1758 nCmdShow = SW_RESTORE;
1761 // bring to top before showing
1762 BringToTop(nCmdShow);
1764 if (nCmdShow != -1)
1766 // show the window as specified
1767 WINDOWPLACEMENT wp;
1769 if ( !ReadWindowPlacement(&wp) )
1771 ShowWindow(nCmdShow);
1773 else
1775 if ( nCmdShow != SW_SHOWNORMAL )
1776 wp.showCmd = nCmdShow;
1778 SetWindowPlacement(&wp);
1781 // and finally, bring to top after showing
1782 BringToTop(nCmdShow);
1784 return;
1787 BOOL CMainFrame::ReadWindowPlacement(WINDOWPLACEMENT * pwp)
1789 CRegString placement = CRegString(_T("Software\\TortoiseMerge\\WindowPos"));
1790 CString sPlacement = placement;
1791 if (sPlacement.IsEmpty())
1792 return FALSE;
1793 int nRead = _stscanf_s(sPlacement, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
1794 &pwp->flags, &pwp->showCmd,
1795 &pwp->ptMinPosition.x, &pwp->ptMinPosition.y,
1796 &pwp->ptMaxPosition.x, &pwp->ptMaxPosition.y,
1797 &pwp->rcNormalPosition.left, &pwp->rcNormalPosition.top,
1798 &pwp->rcNormalPosition.right, &pwp->rcNormalPosition.bottom);
1799 if ( nRead != 10 )
1800 return FALSE;
1801 pwp->length = sizeof(WINDOWPLACEMENT);
1803 return TRUE;
1806 void CMainFrame::WriteWindowPlacement(WINDOWPLACEMENT * pwp)
1808 CRegString placement = CRegString(_T("Software\\TortoiseMerge\\WindowPos"));
1809 TCHAR szBuffer[_countof("-32767")*8 + sizeof("65535")*2];
1810 CString s;
1812 _stprintf_s(szBuffer, _countof("-32767")*8 + sizeof("65535")*2, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
1813 pwp->flags, pwp->showCmd,
1814 pwp->ptMinPosition.x, pwp->ptMinPosition.y,
1815 pwp->ptMaxPosition.x, pwp->ptMaxPosition.y,
1816 pwp->rcNormalPosition.left, pwp->rcNormalPosition.top,
1817 pwp->rcNormalPosition.right, pwp->rcNormalPosition.bottom);
1818 placement = szBuffer;
1821 void CMainFrame::OnUpdateMergeMarkasresolved(CCmdUI *pCmdUI)
1823 if (pCmdUI == NULL)
1824 return;
1825 BOOL bEnable = FALSE;
1826 if ((!m_bReadOnly)&&(m_Data.m_mergedFile.InUse()))
1828 if (m_pwndBottomView)
1830 if ((m_pwndBottomView->IsWindowVisible())&&(m_pwndBottomView->m_pViewData))
1832 bEnable = TRUE;
1836 pCmdUI->Enable(bEnable);
1839 void CMainFrame::OnMergeMarkasresolved()
1841 int nConflictLine = CheckResolved();
1842 if (nConflictLine >= 0)
1844 CString sTemp;
1845 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
1846 if (MessageBox(sTemp, 0, MB_ICONERROR | MB_YESNO)!=IDYES)
1848 if (m_pwndBottomView)
1849 m_pwndBottomView->GoToLine(nConflictLine);
1850 return;
1853 // now check if the file has already been saved and if not, save it.
1854 if (m_Data.m_mergedFile.InUse())
1856 if (m_pwndBottomView)
1858 if ((m_pwndBottomView->IsWindowVisible())&&(m_pwndBottomView->m_pViewData))
1860 FileSave(false);
1864 MarkAsResolved();
1867 BOOL CMainFrame::MarkAsResolved()
1869 if (m_bReadOnly)
1870 return FALSE;
1871 if (!((m_pwndBottomView) && (m_pwndBottomView->IsWindowVisible())))
1872 return FALSE;
1874 CString cmd = _T("/command:resolve /path:\"");
1875 cmd += m_Data.m_mergedFile.GetFilename();
1876 cmd += _T("\" /closeonend:1 /noquestion /skipcheck /silent");
1877 if (!CAppUtils::RunTortoiseProc(cmd))
1878 return FALSE;
1880 return TRUE;
1883 void CMainFrame::OnUpdateMergeNextconflict(CCmdUI *pCmdUI)
1885 pCmdUI->Enable(m_bHasConflicts);
1888 void CMainFrame::OnUpdateMergePreviousconflict(CCmdUI *pCmdUI)
1890 pCmdUI->Enable(m_bHasConflicts);
1893 void CMainFrame::OnMoving(UINT fwSide, LPRECT pRect)
1895 // if the pathfilelist dialog is attached to the mainframe,
1896 // move it along with the mainframe
1897 if (::IsWindow(m_dlgFilePatches.m_hWnd))
1899 RECT patchrect;
1900 m_dlgFilePatches.GetWindowRect(&patchrect);
1901 if (::IsWindow(m_hWnd))
1903 RECT thisrect;
1904 GetWindowRect(&thisrect);
1905 if (patchrect.right == thisrect.left)
1907 m_dlgFilePatches.SetWindowPos(NULL, patchrect.left - (thisrect.left - pRect->left), patchrect.top - (thisrect.top - pRect->top),
1908 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
1912 __super::OnMoving(fwSide, pRect);
1915 void CMainFrame::OnUpdateEditCopy(CCmdUI *pCmdUI)
1917 BOOL bShow = FALSE;
1918 if ((m_pwndBottomView)&&(m_pwndBottomView->HasSelection()))
1919 bShow = TRUE;
1920 if ((m_pwndRightView)&&(m_pwndRightView->HasSelection()))
1921 bShow = TRUE;
1922 if ((m_pwndLeftView)&&(m_pwndLeftView->HasSelection()))
1923 bShow = TRUE;
1924 pCmdUI->Enable(bShow);
1927 void CMainFrame::OnViewSwitchleft()
1929 int ret = IDNO;
1930 if (((m_pwndBottomView)&&(m_pwndBottomView->IsModified())) ||
1931 ((m_pwndRightView)&&(m_pwndRightView->IsModified())))
1933 CString sTemp;
1934 sTemp.LoadString(IDS_ASKFORSAVE);
1935 ret = MessageBox(sTemp, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
1936 if (ret == IDYES)
1938 if (!FileSave())
1939 return;
1942 if ((ret == IDNO)||(ret == IDYES))
1944 CWorkingFile file = m_Data.m_baseFile;
1945 m_Data.m_baseFile = m_Data.m_yourFile;
1946 m_Data.m_yourFile = file;
1947 if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_yourFile.GetFilename())==0)
1949 m_Data.m_mergedFile = m_Data.m_baseFile;
1951 else if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_baseFile.GetFilename())==0)
1953 m_Data.m_mergedFile = m_Data.m_yourFile;
1955 LoadViews();
1959 void CMainFrame::OnUpdateViewSwitchleft(CCmdUI *pCmdUI)
1961 BOOL bEnable = TRUE;
1962 if (m_pwndBottomView)
1964 if (m_pwndBottomView->IsWindowVisible())
1965 bEnable = FALSE;
1967 pCmdUI->Enable(bEnable);
1971 void CMainFrame::OnUpdateViewShowfilelist(CCmdUI *pCmdUI)
1973 if (m_dlgFilePatches.HasFiles())
1975 pCmdUI->Enable(true);
1977 else
1978 pCmdUI->Enable(false);
1979 pCmdUI->SetCheck(m_dlgFilePatches.IsWindowVisible());
1982 void CMainFrame::OnViewShowfilelist()
1984 m_dlgFilePatches.ShowWindow(m_dlgFilePatches.IsWindowVisible() ? SW_HIDE : SW_SHOW);
1987 void CMainFrame::OnEditUndo()
1989 if (CUndo::GetInstance().CanUndo())
1991 CUndo::GetInstance().Undo(m_pwndLeftView, m_pwndRightView, m_pwndBottomView);
1996 void CMainFrame::OnUpdateEditUndo(CCmdUI *pCmdUI)
1998 pCmdUI->Enable(CUndo::GetInstance().CanUndo());
2001 int CMainFrame::CheckForSave()
2003 int ret = IDNO;
2004 if (((m_pwndBottomView)&&(m_pwndBottomView->IsModified())) ||
2005 ((m_pwndRightView)&&(m_pwndRightView->IsModified())))
2007 CString sTemp;
2008 sTemp.LoadString(IDS_WARNMODIFIEDLOOSECHANGES);
2009 ret = MessageBox(sTemp, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
2011 if (ret == IDYES)
2013 FileSave();
2016 return ret;
2019 void CMainFrame::OnViewInlinediffword()
2021 m_bInlineWordDiff = !m_bInlineWordDiff;
2022 if (m_pwndLeftView)
2024 m_pwndLeftView->SetInlineWordDiff(m_bInlineWordDiff);
2025 m_pwndLeftView->Invalidate();
2027 if (m_pwndRightView)
2029 m_pwndRightView->SetInlineWordDiff(m_bInlineWordDiff);
2030 m_pwndRightView->Invalidate();
2032 if (m_pwndBottomView)
2034 m_pwndBottomView->SetInlineWordDiff(m_bInlineWordDiff);
2035 m_pwndBottomView->Invalidate();
2037 m_wndLineDiffBar.Invalidate();
2040 void CMainFrame::OnUpdateViewInlinediffword(CCmdUI *pCmdUI)
2042 pCmdUI->Enable(m_pwndLeftView && m_pwndLeftView->IsWindowVisible() &&
2043 m_pwndRightView && m_pwndRightView->IsWindowVisible());
2044 pCmdUI->SetCheck(m_bInlineWordDiff);
2047 void CMainFrame::OnUpdateEditCreateunifieddifffile(CCmdUI *pCmdUI)
2049 // "create unified diff file" is only available if two files
2050 // are diffed, not three.
2051 bool bEnabled = true;
2052 if ((m_pwndLeftView == NULL)||(!m_pwndLeftView->IsWindowVisible()))
2053 bEnabled = false;
2054 if ((m_pwndRightView == NULL)||(!m_pwndRightView->IsWindowVisible()))
2055 bEnabled = false;
2056 if ((m_pwndBottomView)&&(m_pwndBottomView->IsWindowVisible()))
2057 bEnabled = false;
2058 pCmdUI->Enable(bEnabled);
2061 void CMainFrame::OnEditCreateunifieddifffile()
2063 CString origFile, modifiedFile, outputFile;
2064 // the original file is the one on the left
2065 if (m_pwndLeftView)
2066 origFile = m_pwndLeftView->m_sFullFilePath;
2067 if (m_pwndRightView)
2068 modifiedFile = m_pwndRightView->m_sFullFilePath;
2069 if (!origFile.IsEmpty() && !modifiedFile.IsEmpty())
2071 // ask for the path to save the unified diff file to
2072 OPENFILENAME ofn = {0}; // common dialog box structure
2073 TCHAR szFile[MAX_PATH] = {0}; // buffer for file name
2074 ofn.lStructSize = sizeof(OPENFILENAME);
2075 ofn.lpstrFile = szFile;
2076 ofn.nMaxFile = _countof(szFile);
2077 CString temp;
2078 temp.LoadString(IDS_SAVEASTITLE);
2079 if (!temp.IsEmpty())
2080 ofn.lpstrTitle = temp;
2081 ofn.Flags = OFN_OVERWRITEPROMPT;
2082 CString sFilter;
2083 sFilter.LoadString(IDS_COMMONFILEFILTER);
2084 TCHAR * pszFilters = new TCHAR[sFilter.GetLength()+4];
2085 _tcscpy_s (pszFilters, sFilter.GetLength()+4, sFilter);
2086 // Replace '|' delimiters with '\0's
2087 TCHAR *ptr = pszFilters + _tcslen(pszFilters); //set ptr at the NULL
2088 while (ptr != pszFilters)
2090 if (*ptr == '|')
2091 *ptr = '\0';
2092 ptr--;
2094 ofn.lpstrFilter = pszFilters;
2095 ofn.nFilterIndex = 1;
2097 // Display the Save dialog box.
2098 CString sFile;
2099 if (GetSaveFileName(&ofn)==TRUE)
2101 outputFile = CString(ofn.lpstrFile);
2102 CAppUtils::CreateUnifiedDiff(origFile, modifiedFile, outputFile, true);
2104 delete [] pszFilters;
2108 void CMainFrame::OnUpdateViewLinediffbar(CCmdUI *pCmdUI)
2110 pCmdUI->SetCheck(m_bLineDiff);
2111 pCmdUI->Enable();
2114 void CMainFrame::OnViewLinediffbar()
2116 m_bLineDiff = !m_bLineDiff;
2117 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2118 m_wndLineDiffBar.DocumentUpdated();
2119 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2120 m_wndLocatorBar.DocumentUpdated();
2123 void CMainFrame::OnUpdateViewLocatorbar(CCmdUI *pCmdUI)
2125 pCmdUI->SetCheck(m_bLocatorBar);
2126 pCmdUI->Enable();
2129 void CMainFrame::OnViewLocatorbar()
2131 m_bLocatorBar = !m_bLocatorBar;
2132 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2133 m_wndLocatorBar.DocumentUpdated();
2134 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2135 m_wndLineDiffBar.DocumentUpdated();