TortoiseMerge: correctly detect and allow to resolve "added file" exists on apply...
[TortoiseGit.git] / src / TortoiseMerge / MainFrm.cpp
blob933ee364191c79780552d90027c6dda39cff71b7
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"
38 #ifdef _DEBUG
39 #define new DEBUG_NEW
40 #endif
43 // CMainFrame
44 const UINT CMainFrame::m_FindDialogMessage = RegisterWindowMessage(FINDMSGSTRING);
46 IMPLEMENT_DYNCREATE(CMainFrame, CFrameWndEx)
48 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)
49 ON_WM_CREATE()
50 ON_COMMAND_RANGE(ID_VIEW_APPLOOK_WIN_2000, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnApplicationLook)
51 ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_APPLOOK_WIN_2000, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnUpdateApplicationLook)
52 // Global help commands
53 ON_COMMAND(ID_HELP_FINDER, CFrameWndEx::OnHelpFinder)
54 ON_COMMAND(ID_HELP, CFrameWndEx::OnHelp)
55 ON_COMMAND(ID_CONTEXT_HELP, CFrameWndEx::OnContextHelp)
56 ON_COMMAND(ID_DEFAULT_HELP, CFrameWndEx::OnHelpFinder)
57 ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
58 ON_COMMAND(ID_VIEW_WHITESPACES, OnViewWhitespaces)
59 ON_WM_SIZE()
60 ON_COMMAND(ID_FILE_SAVE, OnFileSave)
61 ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
62 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave)
63 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_AS, OnUpdateFileSaveAs)
64 ON_COMMAND(ID_VIEW_ONEWAYDIFF, OnViewOnewaydiff)
65 ON_UPDATE_COMMAND_UI(ID_VIEW_ONEWAYDIFF, OnUpdateViewOnewaydiff)
66 ON_UPDATE_COMMAND_UI(ID_VIEW_WHITESPACES, OnUpdateViewWhitespaces)
67 ON_COMMAND(ID_VIEW_OPTIONS, OnViewOptions)
68 ON_WM_CLOSE()
69 ON_COMMAND(ID_EDIT_FIND, OnEditFind)
70 ON_REGISTERED_MESSAGE(m_FindDialogMessage, OnFindDialogMessage)
71 ON_COMMAND(ID_EDIT_FINDNEXT, OnEditFindnext)
72 ON_COMMAND(ID_EDIT_FINDPREV, OnEditFindprev)
73 ON_COMMAND(ID_FILE_RELOAD, OnFileReload)
74 ON_COMMAND(ID_VIEW_LINEDOWN, OnViewLinedown)
75 ON_COMMAND(ID_VIEW_LINEUP, OnViewLineup)
76 ON_UPDATE_COMMAND_UI(ID_EDIT_MARKASRESOLVED, OnUpdateMergeMarkasresolved)
77 ON_COMMAND(ID_EDIT_MARKASRESOLVED, OnMergeMarkasresolved)
78 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTCONFLICT, OnUpdateMergeNextconflict)
79 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSCONFLICT, OnUpdateMergePreviousconflict)
80 ON_WM_MOVE()
81 ON_WM_MOVING()
82 ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
83 ON_COMMAND(ID_VIEW_SWITCHLEFT, OnViewSwitchleft)
84 ON_UPDATE_COMMAND_UI(ID_VIEW_SWITCHLEFT, OnUpdateViewSwitchleft)
85 ON_COMMAND(ID_VIEW_LINELEFT, &CMainFrame::OnViewLineleft)
86 ON_COMMAND(ID_VIEW_LINERIGHT, &CMainFrame::OnViewLineright)
87 ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWFILELIST, &CMainFrame::OnUpdateViewShowfilelist)
88 ON_COMMAND(ID_VIEW_SHOWFILELIST, &CMainFrame::OnViewShowfilelist)
89 ON_COMMAND(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnEditUseTheirs)
90 ON_COMMAND(ID_EDIT_USEMYBLOCK, &CMainFrame::OnEditUseMine)
91 ON_COMMAND(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnEditUseTheirsThenMine)
92 ON_COMMAND(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnEditUseMineThenTheirs)
93 ON_COMMAND(ID_EDIT_UNDO, &CMainFrame::OnEditUndo)
94 ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, &CMainFrame::OnUpdateEditUndo)
95 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnUpdateEditUseminethentheirblock)
96 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMYBLOCK, &CMainFrame::OnUpdateEditUsemyblock)
97 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnUpdateEditUsetheirblock)
98 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnUpdateEditUsetheirthenmyblock)
99 ON_COMMAND(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnViewInlinediffword)
100 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnUpdateViewInlinediffword)
101 ON_UPDATE_COMMAND_UI(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnUpdateEditCreateunifieddifffile)
102 ON_COMMAND(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnEditCreateunifieddifffile)
103 ON_UPDATE_COMMAND_UI(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnUpdateViewLinediffbar)
104 ON_COMMAND(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnViewLinediffbar)
105 ON_UPDATE_COMMAND_UI(ID_VIEW_LOCATORBAR, &CMainFrame::OnUpdateViewLocatorbar)
106 ON_COMMAND(ID_VIEW_LOCATORBAR, &CMainFrame::OnViewLocatorbar)
107 ON_COMMAND(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnEditUseleftblock)
108 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnUpdateEditUseleftblock)
109 ON_COMMAND(ID_EDIT_USELEFTFILE, &CMainFrame::OnEditUseleftfile)
110 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTFILE, &CMainFrame::OnUpdateEditUseleftfile)
111 ON_COMMAND(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnEditUseblockfromleftbeforeright)
112 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnUpdateEditUseblockfromleftbeforeright)
113 ON_COMMAND(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnEditUseblockfromrightbeforeleft)
114 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnUpdateEditUseblockfromrightbeforeleft)
115 END_MESSAGE_MAP()
117 static UINT indicators[] =
119 ID_SEPARATOR, // status line indicator
120 ID_INDICATOR_LEFTVIEW,
121 ID_INDICATOR_RIGHTVIEW,
122 ID_INDICATOR_BOTTOMVIEW,
123 ID_INDICATOR_CAPS,
124 ID_INDICATOR_NUM,
125 ID_INDICATOR_SCRL
129 // CMainFrame construction/destruction
131 CMainFrame::CMainFrame()
132 : m_pFindDialog(NULL)
133 , m_nSearchIndex(0)
134 , m_bInitSplitter(FALSE)
135 , m_bReversedPatch(FALSE)
136 , m_bHasConflicts(false)
137 , m_bInlineWordDiff(true)
138 , m_bLineDiff(true)
139 , m_bLocatorBar(true)
140 , m_nMoveMovesToIgnore(0)
141 , m_bLimitToDiff(false)
142 , m_bWholeWord(false)
143 , m_pwndLeftView(NULL)
144 , m_pwndRightView(NULL)
145 , m_pwndBottomView(NULL)
146 , m_bReadOnly(false)
147 , m_bBlame(false)
149 m_bOneWay = (0 != ((DWORD)CRegDWORD(_T("Software\\TortoiseMerge\\OnePane"))));
150 theApp.m_nAppLook = theApp.GetInt(_T("ApplicationLook"), ID_VIEW_APPLOOK_VS_2005);
153 CMainFrame::~CMainFrame()
157 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
159 if (CFrameWndEx::OnCreate(lpCreateStruct) == -1)
160 return -1;
162 OnApplicationLook(theApp.m_nAppLook);
164 if (!m_wndMenuBar.Create(this))
166 TRACE0("Failed to create menubar\n");
167 return -1; // fail to create
170 m_wndMenuBar.SetPaneStyle(m_wndMenuBar.GetPaneStyle() | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY);
172 // prevent the menu bar from taking the focus on activation
173 CMFCPopupMenu::SetForceMenuFocus(FALSE);
175 if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY) ||
176 !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
178 TRACE0("Failed to create toolbar\n");
179 return -1; // fail to create
181 m_wndToolBar.SetWindowText(_T("Main"));
183 if (!m_wndStatusBar.Create(this) ||
184 !m_wndStatusBar.SetIndicators(indicators,
185 _countof(indicators)))
187 TRACE0("Failed to create status bar\n");
188 return -1; // fail to create
191 if (!m_wndLocatorBar.Create(this, IDD_DIFFLOCATOR,
192 CBRS_ALIGN_LEFT | CBRS_SIZE_FIXED, ID_VIEW_LOCATORBAR))
194 TRACE0("Failed to create dialogbar\n");
195 return -1; // fail to create
197 if (!m_wndLineDiffBar.Create(this, IDD_LINEDIFF,
198 CBRS_ALIGN_BOTTOM | CBRS_SIZE_FIXED, ID_VIEW_LINEDIFFBAR))
200 TRACE0("Failed to create dialogbar\n");
201 return -1; // fail to create
203 m_wndLocatorBar.m_pMainFrm = this;
204 m_wndLineDiffBar.m_pMainFrm = this;
206 EnableDocking(CBRS_ALIGN_ANY);
207 m_wndMenuBar.EnableDocking(CBRS_ALIGN_TOP);
208 m_wndToolBar.EnableDocking(CBRS_ALIGN_TOP);
209 DockPane(&m_wndMenuBar);
210 DockPane(&m_wndToolBar);
211 DockPane(&m_wndLocatorBar);
212 DockPane(&m_wndLineDiffBar);
213 ShowPane(&m_wndLocatorBar, true, false, true);
214 ShowPane(&m_wndLineDiffBar, true, false, true);
216 m_wndLocatorBar.EnableGripper(FALSE);
217 m_wndLineDiffBar.EnableGripper(FALSE);
219 return 0;
222 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
224 if( !CFrameWndEx::PreCreateWindow(cs) )
225 return FALSE;
226 return TRUE;
229 void CMainFrame::OnApplicationLook(UINT id)
231 CWaitCursor wait;
233 theApp.m_nAppLook = id;
235 switch (theApp.m_nAppLook)
237 case ID_VIEW_APPLOOK_WIN_2000:
238 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManager));
239 break;
241 case ID_VIEW_APPLOOK_OFF_XP:
242 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOfficeXP));
243 break;
245 case ID_VIEW_APPLOOK_WIN_XP:
246 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
247 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
248 break;
250 case ID_VIEW_APPLOOK_OFF_2003:
251 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2003));
252 CDockingManager::SetDockingMode(DT_SMART);
253 break;
255 case ID_VIEW_APPLOOK_VS_2005:
256 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2005));
257 CDockingManager::SetDockingMode(DT_SMART);
258 break;
260 default:
261 switch (theApp.m_nAppLook)
263 case ID_VIEW_APPLOOK_OFF_2007_BLUE:
264 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_LunaBlue);
265 break;
267 case ID_VIEW_APPLOOK_OFF_2007_BLACK:
268 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_ObsidianBlack);
269 break;
271 case ID_VIEW_APPLOOK_OFF_2007_SILVER:
272 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Silver);
273 break;
275 case ID_VIEW_APPLOOK_OFF_2007_AQUA:
276 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Aqua);
277 break;
280 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));
281 CDockingManager::SetDockingMode(DT_SMART);
284 RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_FRAME | RDW_ERASE);
286 theApp.WriteInt(_T("ApplicationLook"), theApp.m_nAppLook);
289 void CMainFrame::OnUpdateApplicationLook(CCmdUI* pCmdUI)
291 pCmdUI->SetRadio(theApp.m_nAppLook == pCmdUI->m_nID);
295 // CMainFrame diagnostics
297 #ifdef _DEBUG
298 void CMainFrame::AssertValid() const
300 CFrameWndEx::AssertValid();
303 void CMainFrame::Dump(CDumpContext& dc) const
305 CFrameWndEx::Dump(dc);
308 #endif //_DEBUG
311 // CMainFrame message handlers
314 BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)
316 CRect cr;
317 GetClientRect( &cr);
320 // split into three panes:
321 // -------------
322 // | | |
323 // | | |
324 // |------------
325 // | |
326 // | |
327 // |------------
329 // create a splitter with 2 rows, 1 column
330 if (!m_wndSplitter.CreateStatic(this, 2, 1))
332 TRACE0("Failed to CreateStaticSplitter\n");
333 return FALSE;
336 // add the second splitter pane - which is a nested splitter with 2 columns
337 if (!m_wndSplitter2.CreateStatic(
338 &m_wndSplitter, // our parent window is the first splitter
339 1, 2, // the new splitter is 1 row, 2 columns
340 WS_CHILD | WS_VISIBLE | WS_BORDER, // style, WS_BORDER is needed
341 m_wndSplitter.IdFromRowCol(0, 0)
342 // new splitter is in the first row, 1st column of first splitter
345 TRACE0("Failed to create nested splitter\n");
346 return FALSE;
348 // add the first splitter pane - the default view in row 0
349 if (!m_wndSplitter.CreateView(1, 0,
350 RUNTIME_CLASS(CBottomView), CSize(cr.Width(), cr.Height()), pContext))
352 TRACE0("Failed to create first pane\n");
353 return FALSE;
355 m_pwndBottomView = (CBottomView *)m_wndSplitter.GetPane(1,0);
356 m_pwndBottomView->m_pwndLocator = &m_wndLocatorBar;
357 m_pwndBottomView->m_pwndLineDiffBar = &m_wndLineDiffBar;
358 m_pwndBottomView->m_pwndStatusBar = &m_wndStatusBar;
359 m_pwndBottomView->m_pMainFrame = this;
361 // now create the two views inside the nested splitter
363 if (!m_wndSplitter2.CreateView(0, 0,
364 RUNTIME_CLASS(CLeftView), CSize(cr.Width()/2, cr.Height()/2), pContext))
366 TRACE0("Failed to create second pane\n");
367 return FALSE;
369 m_pwndLeftView = (CLeftView *)m_wndSplitter2.GetPane(0,0);
370 m_pwndLeftView->m_pwndLocator = &m_wndLocatorBar;
371 m_pwndLeftView->m_pwndLineDiffBar = &m_wndLineDiffBar;
372 m_pwndLeftView->m_pwndStatusBar = &m_wndStatusBar;
373 m_pwndLeftView->m_pMainFrame = this;
375 if (!m_wndSplitter2.CreateView(0, 1,
376 RUNTIME_CLASS(CRightView), CSize(cr.Width()/2, cr.Height()/2), pContext))
378 TRACE0("Failed to create third pane\n");
379 return FALSE;
381 m_pwndRightView = (CRightView *)m_wndSplitter2.GetPane(0,1);
382 m_pwndRightView->m_pwndLocator = &m_wndLocatorBar;
383 m_pwndRightView->m_pwndLineDiffBar = &m_wndLineDiffBar;
384 m_pwndRightView->m_pwndStatusBar = &m_wndStatusBar;
385 m_pwndRightView->m_pMainFrame = this;
386 m_bInitSplitter = TRUE;
388 m_dlgFilePatches.Create(IDD_FILEPATCHES, this);
389 UpdateLayout();
390 return TRUE;
393 // Callback function
394 BOOL CMainFrame::PatchFile(int nIndex, bool bAutoPatch, bool bIsReview)
396 CString Path2 = m_Patch.GetFullPath(m_Data.m_sPatchPath, nIndex, 1);
397 CString sFilePath = m_Patch.GetFullPath(m_Data.m_sPatchPath, nIndex);
398 //first, do a "dry run" of patching...
399 if (!m_Patch.PatchFile(nIndex, m_Data.m_sPatchPath))
401 //patching not successful, so retrieve the
402 //base file from version control and try
403 //again...
404 CString sVersion = m_Patch.GetRevision(nIndex);
406 CString sBaseFile;
407 if (sVersion == _T("0000000") || sFilePath == _T("NUL"))
408 sBaseFile = m_TempFiles.GetTempFilePath();
409 else
411 CSysProgressDlg progDlg;
412 CString sTemp;
413 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sVersion);
414 progDlg.SetLine(1, sTemp, true);
415 progDlg.SetLine(2, sFilePath, true);
416 sTemp.LoadString(IDS_GETVERSIONOFFILETITLE);
417 progDlg.SetTitle(sTemp);
418 progDlg.SetShowProgressBar(false);
419 progDlg.SetAnimation(IDR_DOWNLOAD);
420 progDlg.SetTime(FALSE);
422 if(!m_Patch.m_IsGitPatch)
423 progDlg.ShowModeless(this);
425 sBaseFile = m_TempFiles.GetTempFilePath();
426 if (!CAppUtils::GetVersionedFile(sFilePath, sVersion, sBaseFile, &progDlg, m_hWnd))
428 progDlg.Stop();
429 CString sErrMsg;
430 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sVersion, (LPCTSTR)sFilePath);
431 MessageBox(sErrMsg, NULL, MB_ICONERROR);
432 return FALSE;
435 progDlg.Stop();
438 CString sTempFile = m_TempFiles.GetTempFilePath();
439 if (!m_Patch.PatchFile(nIndex, m_Data.m_sPatchPath, sTempFile, sBaseFile, true))
441 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
442 return FALSE;
445 CString temp;
446 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)sVersion);
447 m_Data.m_baseFile.SetFileName(sBaseFile);
448 m_Data.m_baseFile.SetDescriptiveName(temp);
449 if(!Path2.IsEmpty() && Path2 != _T("NUL"))
450 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(Path2), (LPCTSTR)m_Data.m_sPatchPatched);
451 else
452 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
454 if (sVersion == _T("0000000") || sFilePath == _T("NUL"))
456 m_Data.m_baseFile.SetFileName(Path2);
457 m_Data.m_yourFile.SetFileName(Path2);
458 m_Data.m_theirFile.SetFileName(sTempFile);
459 m_Data.m_theirFile.SetDescriptiveName(CPathUtils::GetFileNameFromPath(Path2));
460 m_Data.m_mergedFile.SetFileName(Path2);
461 if (!bIsReview)
463 LoadViews();
464 return FALSE;
467 else if (bIsReview)
469 m_Data.m_yourFile.SetFileName(sTempFile);
470 m_Data.m_yourFile.SetDescriptiveName(temp);
471 m_Data.m_theirFile.SetOutOfUse();
472 m_Data.m_mergedFile.SetOutOfUse();
474 else
476 m_Data.m_theirFile.SetFileName(sTempFile);
477 m_Data.m_theirFile.SetDescriptiveName(temp);
478 m_Data.m_yourFile.SetFileName(sFilePath);
479 m_Data.m_yourFile.SetDescriptiveName(CPathUtils::GetFileNameFromPath(sFilePath));
480 m_Data.m_mergedFile.SetFileName(sFilePath);
481 m_Data.m_mergedFile.SetDescriptiveName(CPathUtils::GetFileNameFromPath(sFilePath));
483 TRACE(_T("comparing %s and %s\nagainst the base file %s\n"), (LPCTSTR)sTempFile, (LPCTSTR)sFilePath, (LPCTSTR)sBaseFile);
487 else
489 //"dry run" was successful, so save the patched file somewhere...
490 CString sTempFile = m_TempFiles.GetTempFilePath();
491 if (!m_Patch.PatchFile(nIndex, m_Data.m_sPatchPath, sTempFile))
493 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
494 return FALSE;
496 if (m_bReversedPatch)
498 m_Data.m_baseFile.SetFileName(sTempFile);
499 CString temp;
500 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
501 m_Data.m_baseFile.SetDescriptiveName(temp);
502 m_Data.m_yourFile.SetFileName(sFilePath);
503 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchOriginal);
504 m_Data.m_yourFile.SetDescriptiveName(temp);
505 m_Data.m_theirFile.SetOutOfUse();
506 m_Data.m_mergedFile.SetOutOfUse();
508 else
510 if (!PathFileExists(sFilePath))
512 m_Data.m_baseFile.SetFileName(m_TempFiles.GetTempFilePath());
513 m_Data.m_baseFile.CreateEmptyFile();
515 else
517 m_Data.m_baseFile.SetFileName(sFilePath);
519 CString sDescription;
520 sDescription.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchOriginal);
521 m_Data.m_baseFile.SetDescriptiveName(sDescription);
522 m_Data.m_yourFile.SetFileName(sTempFile);
523 CString temp;
524 if (!Path2.IsEmpty() && Path2 != _T("NUL"))
526 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(Path2), (LPCTSTR)m_Data.m_sPatchPatched);
527 m_Data.m_mergedFile.SetFileName(Path2);
529 else
531 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
532 m_Data.m_mergedFile.SetFileName(sFilePath);
535 m_Data.m_yourFile.SetDescriptiveName(temp);
536 m_Data.m_theirFile.SetOutOfUse();
538 TRACE(_T("comparing %s\nwith the patched result %s\n"), (LPCTSTR)sFilePath, (LPCTSTR)sTempFile);
540 LoadViews();
541 if (bAutoPatch)
543 OnFileSave();
545 return TRUE;
548 // Callback function
549 BOOL CMainFrame::DiffFiles(CString sURL1, CString sRev1, CString sURL2, CString sRev2)
551 CString tempfile1 = m_TempFiles.GetTempFilePath();
552 CString tempfile2 = m_TempFiles.GetTempFilePath();
554 ASSERT(tempfile1.Compare(tempfile2));
556 CString sTemp;
557 CSysProgressDlg progDlg;
558 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev1);
559 progDlg.SetLine(1, sTemp, true);
560 progDlg.SetLine(2, sURL1, true);
561 sTemp.LoadString(IDS_GETVERSIONOFFILETITLE);
562 progDlg.SetTitle(sTemp);
563 progDlg.SetShowProgressBar(true);
564 progDlg.SetAnimation(IDR_DOWNLOAD);
565 progDlg.SetTime(FALSE);
566 progDlg.SetProgress(1,100);
567 progDlg.ShowModeless(this);
568 if (!CAppUtils::GetVersionedFile(sURL1, sRev1, tempfile1, &progDlg, m_hWnd))
570 progDlg.Stop();
571 CString sErrMsg;
572 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev1, (LPCTSTR)sURL1);
573 MessageBox(sErrMsg, NULL, MB_ICONERROR);
574 return FALSE;
576 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev2);
577 progDlg.SetLine(1, sTemp, true);
578 progDlg.SetLine(2, sURL2, true);
579 progDlg.SetProgress(50, 100);
580 if (!CAppUtils::GetVersionedFile(sURL2, sRev2, tempfile2, &progDlg, m_hWnd))
582 progDlg.Stop();
583 CString sErrMsg;
584 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev2, (LPCTSTR)sURL2);
585 MessageBox(sErrMsg, NULL, MB_ICONERROR);
586 return FALSE;
588 progDlg.SetProgress(100,100);
589 progDlg.Stop();
590 CString temp;
591 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL1), (LPCTSTR)sRev1);
592 m_Data.m_baseFile.SetFileName(tempfile1);
593 m_Data.m_baseFile.SetDescriptiveName(temp);
594 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL2), (LPCTSTR)sRev2);
595 m_Data.m_yourFile.SetFileName(tempfile2);
596 m_Data.m_yourFile.SetDescriptiveName(temp);
598 LoadViews();
600 return TRUE;
603 void CMainFrame::OnFileOpen()
605 if (CheckForSave()==IDCANCEL)
606 return;
607 COpenDlg dlg;
608 if (dlg.DoModal()!=IDOK)
610 return;
612 m_dlgFilePatches.ShowWindow(SW_HIDE);
613 m_dlgFilePatches.Init(NULL, NULL, CString(), NULL);
614 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,
615 (LPCTSTR)dlg.m_sUnifiedDiffFile, (LPCTSTR)dlg.m_sPatchDirectory);
616 m_Data.m_baseFile.SetFileName(dlg.m_sBaseFile);
617 m_Data.m_theirFile.SetFileName(dlg.m_sTheirFile);
618 m_Data.m_yourFile.SetFileName(dlg.m_sYourFile);
619 m_Data.m_sDiffFile = dlg.m_sUnifiedDiffFile;
620 m_Data.m_sPatchPath = dlg.m_sPatchDirectory;
621 m_Data.m_mergedFile.SetOutOfUse();
622 g_crasher.AddFile((LPCSTR)(LPCTSTR)dlg.m_sBaseFile, (LPCSTR)(LPCTSTR)_T("Basefile"));
623 g_crasher.AddFile((LPCSTR)(LPCTSTR)dlg.m_sTheirFile, (LPCSTR)(LPCTSTR)_T("Theirfile"));
624 g_crasher.AddFile((LPCSTR)(LPCTSTR)dlg.m_sYourFile, (LPCSTR)(LPCTSTR)_T("Yourfile"));
625 g_crasher.AddFile((LPCSTR)(LPCTSTR)dlg.m_sUnifiedDiffFile, (LPCSTR)(LPCTSTR)_T("Difffile"));
627 if (!m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && m_Data.IsYourFileInUse())
629 // a diff between two files means "Yours" against "Base", not "Theirs" against "Yours"
630 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
632 if (m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && !m_Data.IsYourFileInUse())
634 // a diff between two files means "Yours" against "Base", not "Theirs" against "Base"
635 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
638 LoadViews();
641 void CMainFrame::ClearViewNamesAndPaths() {
642 m_pwndLeftView->m_sWindowName.Empty();
643 m_pwndLeftView->m_sFullFilePath.Empty();
644 m_pwndRightView->m_sWindowName.Empty();
645 m_pwndRightView->m_sFullFilePath.Empty();
646 m_pwndBottomView->m_sWindowName.Empty();
647 m_pwndBottomView->m_sFullFilePath.Empty();
650 bool CMainFrame::LoadViews(bool bRetainPosition)
652 m_Data.SetBlame(m_bBlame);
653 m_bHasConflicts = false;
654 CBaseView* pwndActiveView = m_pwndLeftView;
655 int nOldLine = m_pwndLeftView ? m_pwndLeftView->m_nTopLine : -1;
656 int nOldLineNumber =
657 m_pwndLeftView && m_pwndLeftView->m_pViewData ?
658 m_pwndLeftView->m_pViewData->GetLineNumber(m_pwndLeftView->m_nTopLine) : -1;
659 if (!m_Data.Load())
661 ::MessageBox(NULL, m_Data.GetError(), _T("TortoiseMerge"), MB_ICONERROR);
662 m_Data.m_mergedFile.SetOutOfUse();
663 return false;
666 m_pwndRightView->UseCaret(false);
667 m_pwndBottomView->UseCaret(false);
669 if (!m_Data.IsBaseFileInUse())
671 if (m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
673 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
675 else if ((!m_Data.m_sDiffFile.IsEmpty())&&(!m_Patch.OpenUnifiedDiffFile(m_Data.m_sDiffFile)))
677 ClearViewNamesAndPaths();
678 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
679 return false;
681 if (m_Patch.GetNumberOfFiles() > 0)
683 CString firstpath = m_Patch.GetFilename(0);
684 CString path=firstpath;
685 path.Replace('/','\\');
686 if ( !PathIsRelative(path) && !PathFileExists(path) )
688 // The absolute path mentioned in the patch does not exist. Lets
689 // try to find the correct relative path by stripping prefixes.
690 BOOL bFound = m_Patch.StripPrefixes(m_Data.m_sPatchPath);
691 CString strippedpath = m_Patch.GetFilename(0);
692 if (bFound)
694 CString msg;
695 msg.Format(IDS_WARNABSOLUTEPATHFOUND, (LPCTSTR)firstpath, (LPCTSTR)strippedpath);
696 if (CMessageBox::Show(m_hWnd, msg, _T("TortoiseMerge"), MB_ICONQUESTION | MB_YESNO)==IDNO)
697 return false;
699 else
701 CString msg;
702 msg.Format(IDS_WARNABSOLUTEPATHNOTFOUND, (LPCTSTR)firstpath);
703 CMessageBox::Show(m_hWnd, msg, _T("TortoiseMerge"), MB_ICONEXCLAMATION);
704 return false;
707 CString betterpatchpath = m_Patch.CheckPatchPath(m_Data.m_sPatchPath);
708 if (betterpatchpath.CompareNoCase(m_Data.m_sPatchPath)!=0)
710 CString msg;
711 msg.Format(IDS_WARNBETTERPATCHPATHFOUND, (LPCTSTR)m_Data.m_sPatchPath, (LPCTSTR)betterpatchpath);
712 if (CMessageBox::Show(m_hWnd, msg, _T("TortoiseMerge"), MB_ICONQUESTION | MB_YESNO)==IDYES)
713 m_Data.m_sPatchPath = betterpatchpath;
715 m_dlgFilePatches.Init(&m_Patch, this, m_Data.m_sPatchPath, this);
716 m_dlgFilePatches.ShowWindow(SW_SHOW);
717 ClearViewNamesAndPaths();
718 if (!m_wndSplitter.IsRowHidden(1))
719 m_wndSplitter.HideRow(1);
720 m_pwndLeftView->SetHidden(FALSE);
721 m_pwndRightView->SetHidden(FALSE);
722 m_pwndBottomView->SetHidden(TRUE);
725 if (m_Data.IsBaseFileInUse() && !m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
727 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
729 if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && !m_Data.IsTheirFileInUse())
731 //diff between YOUR and BASE
732 m_pwndRightView->UseCaret();
733 if (m_bOneWay)
735 if (!m_wndSplitter2.IsColumnHidden(1))
736 m_wndSplitter2.HideColumn(1);
738 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseBoth;
739 m_pwndLeftView->texttype = m_Data.m_arYourFile.GetUnicodeType();
740 m_pwndLeftView->lineendings = m_Data.m_arYourFile.GetLineEndings();
741 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName() + _T(" - ") + m_Data.m_yourFile.GetWindowName();
742 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename() + _T(" - ") + m_Data.m_yourFile.GetFilename();
744 m_pwndRightView->m_pViewData = NULL;
745 m_pwndBottomView->m_pViewData = NULL;
747 if (!m_wndSplitter.IsRowHidden(1))
748 m_wndSplitter.HideRow(1);
749 m_pwndLeftView->SetHidden(FALSE);
750 m_pwndRightView->SetHidden(TRUE);
751 m_pwndBottomView->SetHidden(TRUE);
752 ::SetWindowPos(m_pwndLeftView->m_hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
754 else
756 pwndActiveView = m_pwndRightView;
757 if (m_wndSplitter2.IsColumnHidden(1))
758 m_wndSplitter2.ShowColumn();
760 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseLeft;
761 m_pwndLeftView->texttype = m_Data.m_arBaseFile.GetUnicodeType();
762 m_pwndLeftView->lineendings = m_Data.m_arBaseFile.GetLineEndings();
763 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName();
764 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename();
766 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseRight;
767 m_pwndRightView->texttype = m_Data.m_arYourFile.GetUnicodeType();
768 m_pwndRightView->lineendings = m_Data.m_arYourFile.GetLineEndings();
769 m_pwndRightView->m_sWindowName = m_Data.m_yourFile.GetWindowName();
770 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
772 m_pwndBottomView->m_pViewData = NULL;
774 if (!m_wndSplitter.IsRowHidden(1))
775 m_wndSplitter.HideRow(1);
776 m_pwndLeftView->SetHidden(FALSE);
777 m_pwndRightView->SetHidden(FALSE);
778 m_pwndBottomView->SetHidden(TRUE);
781 else if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
783 //diff between THEIR, YOUR and BASE
784 m_pwndBottomView->UseCaret();
785 pwndActiveView = m_pwndBottomView;
787 m_pwndLeftView->m_pViewData = &m_Data.m_TheirBaseBoth;
788 m_pwndLeftView->texttype = m_Data.m_arTheirFile.GetUnicodeType();
789 m_pwndLeftView->lineendings = m_Data.m_arTheirFile.GetLineEndings();
790 m_pwndLeftView->m_sWindowName.LoadString(IDS_VIEWTITLE_THEIRS);
791 m_pwndLeftView->m_sWindowName += _T(" - ") + m_Data.m_theirFile.GetWindowName();
792 m_pwndLeftView->m_sFullFilePath = m_Data.m_theirFile.GetFilename();
794 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseBoth;
795 m_pwndRightView->texttype = m_Data.m_arYourFile.GetUnicodeType();
796 m_pwndRightView->lineendings = m_Data.m_arYourFile.GetLineEndings();
797 m_pwndRightView->m_sWindowName.LoadString(IDS_VIEWTITLE_MINE);
798 m_pwndRightView->m_sWindowName += _T(" - ") + m_Data.m_yourFile.GetWindowName();
799 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
801 m_pwndBottomView->m_pViewData = &m_Data.m_Diff3;
802 m_pwndBottomView->texttype = m_Data.m_arTheirFile.GetUnicodeType();
803 m_pwndBottomView->lineendings = m_Data.m_arTheirFile.GetLineEndings();
804 m_pwndBottomView->m_sWindowName.LoadString(IDS_VIEWTITLE_MERGED);
805 m_pwndBottomView->m_sWindowName += _T(" - ") + m_Data.m_mergedFile.GetWindowName();
806 m_pwndBottomView->m_sFullFilePath = m_Data.m_mergedFile.GetFilename();
808 if (m_wndSplitter2.IsColumnHidden(1))
809 m_wndSplitter2.ShowColumn();
810 if (m_wndSplitter.IsRowHidden(1))
811 m_wndSplitter.ShowRow();
812 m_pwndLeftView->SetHidden(FALSE);
813 m_pwndRightView->SetHidden(FALSE);
814 m_pwndBottomView->SetHidden(FALSE);
815 // in three pane view, hide the line diff bar
816 m_wndLineDiffBar.ShowPane(false, false, true);
817 m_wndLineDiffBar.DocumentUpdated();
819 if (!m_Data.m_mergedFile.InUse())
821 m_Data.m_mergedFile.SetFileName(m_Data.m_yourFile.GetFilename());
823 m_pwndLeftView->DocumentUpdated();
824 m_pwndRightView->DocumentUpdated();
825 m_pwndBottomView->DocumentUpdated();
826 m_wndLocatorBar.DocumentUpdated();
827 m_wndLineDiffBar.DocumentUpdated();
828 UpdateLayout();
829 SetActiveView(pwndActiveView);
831 if (bRetainPosition && m_pwndLeftView->m_pViewData)
833 int n = nOldLineNumber;
834 if (n >= 0)
835 n = m_pwndLeftView->m_pViewData->FindLineNumber(n);
836 if (n < 0)
837 n = nOldLine;
839 m_pwndLeftView->ScrollAllToLine(n);
840 POINT p;
841 p.x = 0;
842 p.y = n;
843 m_pwndLeftView->SetCaretPosition(p);
845 else
847 bool bGoFirstDiff = (0 != (DWORD)CRegDWORD(_T("Software\\TortoiseMerge\\FirstDiffOnLoad"), TRUE));
848 if (bGoFirstDiff) {
849 pwndActiveView->GoToFirstDifference();
850 // Ignore the first few Mouse Move messages, so that the line diff stays on
851 // the first diff line until the user actually moves the mouse
852 m_nMoveMovesToIgnore = 3;
856 // Avoid incorrect rendering of active pane.
857 m_pwndBottomView->ScrollToChar(0);
858 m_pwndLeftView->ScrollToChar(0);
859 m_pwndRightView->ScrollToChar(0);
860 CheckResolved();
861 CUndo::GetInstance().Clear();
862 return true;
865 void CMainFrame::UpdateLayout()
867 if (m_bInitSplitter)
869 CRect cr, rclocbar;
870 GetWindowRect(&cr);
871 int width = cr.Width();
872 if (::IsWindow(m_wndLocatorBar) && m_wndLocatorBar.IsWindowVisible())
874 m_wndLocatorBar.GetWindowRect(&rclocbar);
875 width -= rclocbar.Width();
877 m_wndSplitter.SetRowInfo(0, cr.Height()/2, 0);
878 m_wndSplitter.SetRowInfo(1, cr.Height()/2, 0);
879 m_wndSplitter.SetColumnInfo(0, width / 2, 50);
880 m_wndSplitter2.SetRowInfo(0, cr.Height()/2, 0);
881 m_wndSplitter2.SetColumnInfo(0, width / 2, 50);
882 m_wndSplitter2.SetColumnInfo(1, width / 2, 50);
884 m_wndSplitter.RecalcLayout();
888 void CMainFrame::OnSize(UINT nType, int cx, int cy)
890 if (m_bInitSplitter && nType != SIZE_MINIMIZED)
892 UpdateLayout();
894 CFrameWndEx::OnSize(nType, cx, cy);
897 void CMainFrame::OnViewWhitespaces()
899 CRegDWORD regViewWhitespaces = CRegDWORD(_T("Software\\TortoiseMerge\\ViewWhitespaces"), 1);
900 BOOL bViewWhitespaces = regViewWhitespaces;
901 if (m_pwndLeftView)
902 bViewWhitespaces = m_pwndLeftView->m_bViewWhitespace;
904 bViewWhitespaces = !bViewWhitespaces;
905 regViewWhitespaces = bViewWhitespaces;
906 if (m_pwndLeftView)
908 m_pwndLeftView->m_bViewWhitespace = bViewWhitespaces;
909 m_pwndLeftView->Invalidate();
911 if (m_pwndRightView)
913 m_pwndRightView->m_bViewWhitespace = bViewWhitespaces;
914 m_pwndRightView->Invalidate();
916 if (m_pwndBottomView)
918 m_pwndBottomView->m_bViewWhitespace = bViewWhitespaces;
919 m_pwndBottomView->Invalidate();
923 void CMainFrame::OnUpdateViewWhitespaces(CCmdUI *pCmdUI)
925 if (m_pwndLeftView)
926 pCmdUI->SetCheck(m_pwndLeftView->m_bViewWhitespace);
929 void CMainFrame::OnViewOnewaydiff()
931 if (CheckForSave()==IDCANCEL)
932 return;
933 m_bOneWay = !m_bOneWay;
934 if (m_bOneWay)
936 // in one way view, hide the line diff bar
937 m_wndLineDiffBar.ShowPane(false, false, true);
938 m_wndLineDiffBar.DocumentUpdated();
940 else
942 // restore the line diff bar
943 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
944 m_wndLineDiffBar.DocumentUpdated();
945 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
946 m_wndLocatorBar.DocumentUpdated();
948 LoadViews(true);
951 void CMainFrame::ShowDiffBar(bool bShow)
953 if (bShow)
955 // restore the line diff bar
956 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
957 m_wndLineDiffBar.DocumentUpdated();
958 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
959 m_wndLocatorBar.DocumentUpdated();
961 else
963 // in one way view, hide the line diff bar
964 m_wndLineDiffBar.ShowPane(false, false, true);
965 m_wndLineDiffBar.DocumentUpdated();
969 int CMainFrame::CheckResolved()
971 //only in three way diffs can be conflicts!
972 m_bHasConflicts = true;
973 if (m_pwndBottomView->IsWindowVisible())
975 if (m_pwndBottomView->m_pViewData)
977 for (int i=0; i<m_pwndBottomView->m_pViewData->GetCount(); i++)
979 if ((DIFFSTATE_CONFLICTED == m_pwndBottomView->m_pViewData->GetState(i))||
980 (DIFFSTATE_CONFLICTED_IGNORED == m_pwndBottomView->m_pViewData->GetState(i)))
981 return i;
985 m_bHasConflicts = false;
986 return -1;
989 int CMainFrame::SaveFile(const CString& sFilePath)
991 CViewData * pViewData = NULL;
992 CFileTextLines * pOriginFile = &m_Data.m_arBaseFile;
993 if ((m_pwndBottomView)&&(m_pwndBottomView->IsWindowVisible()))
995 pViewData = m_pwndBottomView->m_pViewData;
996 Invalidate();
998 else if ((m_pwndRightView)&&(m_pwndRightView->IsWindowVisible()))
1000 pViewData = m_pwndRightView->m_pViewData;
1001 if (m_Data.IsYourFileInUse())
1002 pOriginFile = &m_Data.m_arYourFile;
1003 else if (m_Data.IsTheirFileInUse())
1004 pOriginFile = &m_Data.m_arTheirFile;
1005 Invalidate();
1007 else
1009 // nothing to save!
1010 return -1;
1012 if ((pViewData)&&(pOriginFile))
1014 CFileTextLines file;
1015 pOriginFile->CopySettings(&file);
1016 for (int i=0; i<pViewData->GetCount(); i++)
1018 //only copy non-removed lines
1019 DiffStates state = pViewData->GetState(i);
1020 switch (state)
1022 case DIFFSTATE_CONFLICTED:
1023 case DIFFSTATE_CONFLICTED_IGNORED:
1025 int first = i;
1026 int last = i;
1029 last++;
1030 } while((last<pViewData->GetCount()) && ((pViewData->GetState(last)==DIFFSTATE_CONFLICTED)||(pViewData->GetState(last)==DIFFSTATE_CONFLICTED_IGNORED)));
1031 file.Add(_T("<<<<<<< .mine"), EOL_NOENDING);
1032 for (int j=first; j<last; j++)
1034 file.Add(m_pwndRightView->m_pViewData->GetLine(j), m_pwndRightView->m_pViewData->GetLineEnding(j));
1036 file.Add(_T("======="), EOL_NOENDING);
1037 for (int j=first; j<last; j++)
1039 file.Add(m_pwndLeftView->m_pViewData->GetLine(j), m_pwndLeftView->m_pViewData->GetLineEnding(j));
1041 file.Add(_T(">>>>>>> .theirs"), EOL_NOENDING);
1042 i = last-1;
1044 break;
1045 case DIFFSTATE_EMPTY:
1046 case DIFFSTATE_CONFLICTEMPTY:
1047 case DIFFSTATE_IDENTICALREMOVED:
1048 case DIFFSTATE_REMOVED:
1049 case DIFFSTATE_THEIRSREMOVED:
1050 case DIFFSTATE_YOURSREMOVED:
1051 case DIFFSTATE_CONFLICTRESOLVEDEMPTY:
1052 // do not save removed lines
1053 break;
1054 default:
1055 file.Add(pViewData->GetLine(i), pViewData->GetLineEnding(i));
1056 break;
1059 if (!file.Save(sFilePath, false))
1061 CMessageBox::Show(m_hWnd, file.GetErrorString(), _T("TortoiseMerge"), MB_ICONERROR);
1062 return -1;
1064 m_dlgFilePatches.SetFileStatusAsPatched(sFilePath);
1065 if (m_pwndBottomView)
1066 m_pwndBottomView->SetModified(FALSE);
1067 if (m_pwndRightView)
1068 m_pwndRightView->SetModified(FALSE);
1069 CUndo::GetInstance().MarkAsOriginalState();
1070 return file.GetCount();
1072 return -1;
1075 void CMainFrame::OnFileSave()
1077 FileSave();
1080 bool CMainFrame::FileSave(bool bCheckResolved /*=true*/)
1082 if (!m_Data.m_mergedFile.InUse())
1083 return FileSaveAs(bCheckResolved);
1084 // check if the file has the readonly attribute set
1085 bool bDoesNotExist = false;
1086 DWORD fAttribs = GetFileAttributes(m_Data.m_mergedFile.GetFilename());
1087 if ((fAttribs != INVALID_FILE_ATTRIBUTES)&&(fAttribs & FILE_ATTRIBUTE_READONLY))
1088 return FileSaveAs(bCheckResolved);
1089 if (fAttribs == INVALID_FILE_ATTRIBUTES)
1091 bDoesNotExist = (GetLastError() == ERROR_FILE_NOT_FOUND);
1093 if (bCheckResolved)
1095 int nConflictLine = CheckResolved();
1096 if (nConflictLine >= 0)
1098 CString sTemp;
1099 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
1100 if (MessageBox(sTemp, 0, MB_ICONERROR | MB_YESNO)!=IDYES)
1102 if (m_pwndBottomView)
1103 m_pwndBottomView->GoToLine(nConflictLine);
1104 return false;
1108 if (((DWORD)CRegDWORD(_T("Software\\TortoiseMerge\\Backup"))) != 0)
1110 MoveFileEx(m_Data.m_mergedFile.GetFilename(), m_Data.m_mergedFile.GetFilename() + _T(".bak"), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
1112 if (SaveFile(m_Data.m_mergedFile.GetFilename())==0)
1114 // file was saved with 0 lines!
1115 // ask the user if the file should be deleted
1116 CString sTemp;
1117 sTemp.Format(IDS_DELETEWHENEMPTY, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
1118 if (CMessageBox::ShowCheck(m_hWnd, sTemp, _T("TortoiseMerge"), MB_YESNO, _T("DeleteFileWhenEmpty")) == IDYES)
1120 DeleteFile(m_Data.m_mergedFile.GetFilename());
1124 if (bDoesNotExist)
1126 // call TortoiseProc to add the new file to version control
1127 CString cmd = _T("/command:add /noui /path:\"");
1128 cmd += m_Data.m_mergedFile.GetFilename() + _T("\"");
1129 CAppUtils::RunTortoiseProc(cmd);
1131 return true;
1134 void CMainFrame::OnFileSaveAs()
1136 FileSaveAs();
1139 bool CMainFrame::FileSaveAs(bool bCheckResolved /*=true*/)
1141 if (bCheckResolved)
1143 int nConflictLine = CheckResolved();
1144 if (nConflictLine >= 0)
1146 CString sTemp;
1147 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
1148 if (MessageBox(sTemp, 0, MB_ICONERROR | MB_YESNO)!=IDYES)
1150 if (m_pwndBottomView)
1151 m_pwndBottomView->GoToLine(nConflictLine);
1152 return false;
1156 OPENFILENAME ofn = {0}; // common dialog box structure
1157 TCHAR szFile[MAX_PATH] = {0}; // buffer for file name
1158 ofn.lStructSize = sizeof(OPENFILENAME);
1159 ofn.hwndOwner = m_hWnd;
1160 ofn.lpstrFile = szFile;
1161 ofn.nMaxFile = _countof(szFile);
1162 CString temp;
1163 temp.LoadString(IDS_SAVEASTITLE);
1164 if (!temp.IsEmpty())
1165 ofn.lpstrTitle = temp;
1166 ofn.Flags = OFN_OVERWRITEPROMPT;
1167 CString sFilter;
1168 sFilter.LoadString(IDS_COMMONFILEFILTER);
1169 TCHAR * pszFilters = new TCHAR[sFilter.GetLength()+4];
1170 _tcscpy_s (pszFilters, sFilter.GetLength()+4, sFilter);
1171 // Replace '|' delimiters with '\0's
1172 TCHAR *ptr = pszFilters + _tcslen(pszFilters); //set ptr at the NULL
1173 while (ptr != pszFilters)
1175 if (*ptr == '|')
1176 *ptr = '\0';
1177 ptr--;
1179 ofn.lpstrFilter = pszFilters;
1180 ofn.nFilterIndex = 1;
1182 // Display the Open dialog box.
1183 CString sFile;
1184 if (GetSaveFileName(&ofn)==TRUE)
1186 sFile = CString(ofn.lpstrFile);
1187 SaveFile(sFile);
1188 delete [] pszFilters;
1189 return true;
1191 delete [] pszFilters;
1192 return false;
1195 void CMainFrame::OnUpdateFileSave(CCmdUI *pCmdUI)
1197 BOOL bEnable = FALSE;
1198 if (m_Data.m_mergedFile.InUse())
1200 if (m_pwndBottomView)
1202 if ((m_pwndBottomView->IsWindowVisible())&&(m_pwndBottomView->m_pViewData))
1204 bEnable = TRUE;
1207 if (m_pwndRightView)
1209 if ((m_pwndRightView->IsWindowVisible())&&(m_pwndRightView->m_pViewData))
1211 if (m_pwndRightView->IsModified() || (m_Data.m_yourFile.GetWindowName().Right(9).Compare(_T(": patched"))==0))
1212 bEnable = TRUE;
1216 pCmdUI->Enable(bEnable);
1219 void CMainFrame::OnUpdateFileSaveAs(CCmdUI *pCmdUI)
1221 BOOL bEnable = FALSE;
1222 if (m_pwndBottomView)
1224 if ((m_pwndBottomView->IsWindowVisible())&&(m_pwndBottomView->m_pViewData))
1226 bEnable = TRUE;
1229 if (m_pwndRightView)
1231 if ((m_pwndRightView->IsWindowVisible())&&(m_pwndRightView->m_pViewData))
1233 bEnable = TRUE;
1236 pCmdUI->Enable(bEnable);
1240 void CMainFrame::OnUpdateViewOnewaydiff(CCmdUI *pCmdUI)
1242 pCmdUI->SetCheck(!m_bOneWay);
1243 BOOL bEnable = TRUE;
1244 if (m_pwndBottomView)
1246 if (m_pwndBottomView->IsWindowVisible())
1247 bEnable = FALSE;
1249 pCmdUI->Enable(bEnable);
1252 void CMainFrame::OnViewOptions()
1254 CString sTemp;
1255 sTemp.LoadString(IDS_SETTINGSTITLE);
1256 CSettings dlg(sTemp);
1257 dlg.DoModal();
1258 if (dlg.IsReloadNeeded())
1260 if (CheckForSave()==IDCANCEL)
1261 return;
1262 CDiffColors::GetInstance().LoadRegistry();
1263 LoadViews();
1264 return;
1266 CDiffColors::GetInstance().LoadRegistry();
1267 if (m_pwndBottomView)
1268 m_pwndBottomView->Invalidate();
1269 if (m_pwndLeftView)
1270 m_pwndLeftView->Invalidate();
1271 if (m_pwndRightView)
1272 m_pwndRightView->Invalidate();
1275 void CMainFrame::OnClose()
1277 if ((m_pFindDialog)&&(!m_pFindDialog->IsTerminating()))
1279 m_pFindDialog->SendMessage(WM_CLOSE);
1280 return;
1282 int ret = IDNO;
1283 if (((m_pwndBottomView)&&(m_pwndBottomView->IsModified())) ||
1284 ((m_pwndRightView)&&(m_pwndRightView->IsModified())))
1286 CString sTemp;
1287 sTemp.LoadString(IDS_ASKFORSAVE);
1288 ret = MessageBox(sTemp, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
1289 if (ret == IDYES)
1291 if (!FileSave())
1292 return;
1295 if ((ret == IDNO)||(ret == IDYES))
1297 WINDOWPLACEMENT wp;
1299 // before it is destroyed, save the position of the window
1300 wp.length = sizeof wp;
1302 if (GetWindowPlacement(&wp))
1305 if (IsIconic())
1306 // never restore to Iconic state
1307 wp.showCmd = SW_SHOW ;
1309 if ((wp.flags & WPF_RESTORETOMAXIMIZED) != 0)
1310 // if maximized and maybe iconic restore maximized state
1311 wp.showCmd = SW_SHOWMAXIMIZED ;
1313 // and write it to the .INI file
1314 WriteWindowPlacement(&wp);
1316 __super::OnClose();
1320 void CMainFrame::OnEditFind()
1322 if (m_pFindDialog)
1324 return;
1326 else
1328 // start searching from the start again
1329 // if no line is selected, otherwise start from
1330 // the selected line
1331 m_nSearchIndex = FindSearchStart(0);
1332 m_pFindDialog = new CFindDlg();
1333 m_pFindDialog->Create(this);
1337 LRESULT CMainFrame::OnFindDialogMessage(WPARAM /*wParam*/, LPARAM /*lParam*/)
1339 ASSERT(m_pFindDialog != NULL);
1341 if (m_pFindDialog->IsTerminating())
1343 // invalidate the handle identifying the dialog box.
1344 m_pFindDialog = NULL;
1345 return 0;
1348 if(m_pFindDialog->FindNext())
1350 //read data from dialog
1351 m_sFindText = m_pFindDialog->GetFindString();
1352 m_bMatchCase = (m_pFindDialog->MatchCase() == TRUE);
1353 m_bLimitToDiff = m_pFindDialog->LimitToDiffs();
1354 m_bWholeWord = m_pFindDialog->WholeWord();
1356 OnEditFindnext();
1359 return 0;
1362 bool CharIsDelimiter(const CString& ch)
1364 CString delimiters(_T(" .,:;=+-*/\\\n\t()[]<>@"));
1365 return delimiters.Find(ch) >= 0;
1368 bool CMainFrame::StringFound(const CString& str)const
1370 int nSubStringStartIdx = str.Find(m_sFindText);
1371 bool bStringFound = (nSubStringStartIdx >= 0);
1372 if (bStringFound && m_bWholeWord)
1374 if (nSubStringStartIdx)
1375 bStringFound = CharIsDelimiter(str.Mid(nSubStringStartIdx-1,1));
1377 if (bStringFound)
1379 int nEndIndex = nSubStringStartIdx + m_sFindText.GetLength();
1380 if (str.GetLength() > nEndIndex)
1381 bStringFound = CharIsDelimiter(str.Mid(nEndIndex, 1));
1384 return bStringFound;
1387 void CMainFrame::OnEditFindprev()
1389 Search(SearchPrevious);
1392 void CMainFrame::OnEditFindnext()
1394 Search(SearchNext);
1397 void CMainFrame::Search(SearchDirection srchDir)
1399 if (m_sFindText.IsEmpty())
1400 return;
1402 if ((m_pwndLeftView)&&(m_pwndLeftView->m_pViewData))
1404 bool bFound = FALSE;
1406 CString left;
1407 CString right;
1408 CString bottom;
1409 DiffStates leftstate = DIFFSTATE_NORMAL;
1410 DiffStates rightstate = DIFFSTATE_NORMAL;
1411 DiffStates bottomstate = DIFFSTATE_NORMAL;
1412 int i = 0;
1414 m_nSearchIndex = FindSearchStart(m_nSearchIndex);
1415 m_nSearchIndex++;
1416 if (m_nSearchIndex >= m_pwndLeftView->m_pViewData->GetCount())
1417 m_nSearchIndex = 0;
1418 if (srchDir == SearchPrevious)
1420 // SearchIndex points 1 past where we found the last match,
1421 // so if we are searching backwards we need to adjust accordingly
1422 m_nSearchIndex -= 2;
1423 // if at the top, start again from the end
1424 if (m_nSearchIndex < 0)
1425 m_nSearchIndex += m_pwndLeftView->m_pViewData->GetCount();
1427 const int idxLimits[2][2][2]={{{m_nSearchIndex, m_pwndLeftView->m_pViewData->GetCount()},
1428 {0, m_nSearchIndex}},
1429 {{m_nSearchIndex, -1},
1430 {m_pwndLeftView->m_pViewData->GetCount()-1, m_nSearchIndex}}};
1431 const int offsets[2]={+1, -1};
1433 for (int j=0; j != 2 && !bFound; ++j)
1435 for (i=idxLimits[srchDir][j][0]; i != idxLimits[srchDir][j][1]; i += offsets[srchDir])
1437 left = m_pwndLeftView->m_pViewData->GetLine(i);
1438 leftstate = m_pwndLeftView->m_pViewData->GetState(i);
1439 if ((!m_bOneWay)&&(m_pwndRightView->m_pViewData))
1441 right = m_pwndRightView->m_pViewData->GetLine(i);
1442 rightstate = m_pwndRightView->m_pViewData->GetState(i);
1444 if ((m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1446 bottom = m_pwndBottomView->m_pViewData->GetLine(i);
1447 bottomstate = m_pwndBottomView->m_pViewData->GetState(i);
1450 if (!m_bMatchCase)
1452 left = left.MakeLower();
1453 right = right.MakeLower();
1454 bottom = bottom.MakeLower();
1455 m_sFindText = m_sFindText.MakeLower();
1457 if (StringFound(left))
1459 if ((!m_bLimitToDiff)||(leftstate != DIFFSTATE_NORMAL))
1461 bFound = TRUE;
1462 break;
1465 else if (StringFound(right))
1467 if ((!m_bLimitToDiff)||(rightstate != DIFFSTATE_NORMAL))
1469 bFound = TRUE;
1470 break;
1473 else if (StringFound(bottom))
1475 if ((!m_bLimitToDiff)||(bottomstate != DIFFSTATE_NORMAL))
1477 bFound = TRUE;
1478 break;
1483 if (bFound)
1485 m_nSearchIndex = i;
1486 m_pwndLeftView->GoToLine(m_nSearchIndex);
1487 if (StringFound(left))
1489 m_pwndLeftView->SetFocus();
1490 m_pwndLeftView->HiglightLines(m_nSearchIndex);
1492 else if (StringFound(right))
1494 m_pwndRightView->SetFocus();
1495 m_pwndRightView->HiglightLines(m_nSearchIndex);
1497 else if (StringFound(bottom))
1499 m_pwndBottomView->SetFocus();
1500 m_pwndBottomView->HiglightLines(m_nSearchIndex);
1503 else
1505 m_nSearchIndex = 0;
1510 int CMainFrame::FindSearchStart(int nDefault)
1512 // TortoiseMerge doesn't have a cursor which we could use to
1513 // anchor the search on.
1514 // Instead we use a line that is selected.
1515 // If however no line is selected, use the default line (which could
1516 // be the top of the document for a new search, or the line where the
1517 // search was successful on)
1518 int nLine = nDefault;
1519 int nSelStart = 0;
1520 int nSelEnd = 0;
1521 if (m_pwndLeftView)
1523 if (m_pwndLeftView->GetSelection(nSelStart, nSelEnd))
1525 if (nSelStart == nSelEnd)
1526 nLine = nSelStart;
1529 else if ((nLine == nDefault)&&(m_pwndRightView))
1531 if (m_pwndRightView->GetSelection(nSelStart, nSelEnd))
1533 if (nSelStart == nSelEnd)
1534 nLine = nSelStart;
1537 else if ((nLine == nDefault)&&(m_pwndBottomView))
1539 if (m_pwndBottomView->GetSelection(nSelStart, nSelEnd))
1541 if (nSelStart == nSelEnd)
1542 nLine = nSelStart;
1545 return nLine;
1548 void CMainFrame::OnViewLinedown()
1550 if (m_pwndLeftView)
1551 m_pwndLeftView->ScrollToLine(m_pwndLeftView->m_nTopLine+1);
1552 if (m_pwndRightView)
1553 m_pwndRightView->ScrollToLine(m_pwndRightView->m_nTopLine+1);
1554 if (m_pwndBottomView)
1555 m_pwndBottomView->ScrollToLine(m_pwndBottomView->m_nTopLine+1);
1556 m_wndLocatorBar.Invalidate();
1559 void CMainFrame::OnViewLineup()
1561 if (m_pwndLeftView)
1562 m_pwndLeftView->ScrollToLine(m_pwndLeftView->m_nTopLine-1);
1563 if (m_pwndRightView)
1564 m_pwndRightView->ScrollToLine(m_pwndRightView->m_nTopLine-1);
1565 if (m_pwndBottomView)
1566 m_pwndBottomView->ScrollToLine(m_pwndBottomView->m_nTopLine-1);
1567 m_wndLocatorBar.Invalidate();
1570 void CMainFrame::OnViewLineleft()
1572 if (m_pwndLeftView)
1573 m_pwndLeftView->ScrollSide(-1);
1574 if (m_pwndRightView)
1575 m_pwndRightView->ScrollSide(-1);
1576 if (m_pwndBottomView)
1577 m_pwndBottomView->ScrollSide(-1);
1580 void CMainFrame::OnViewLineright()
1582 if (m_pwndLeftView)
1583 m_pwndLeftView->ScrollSide(1);
1584 if (m_pwndRightView)
1585 m_pwndRightView->ScrollSide(1);
1586 if (m_pwndBottomView)
1587 m_pwndBottomView->ScrollSide(1);
1590 void CMainFrame::OnEditUseTheirs()
1592 if (m_pwndBottomView)
1593 m_pwndBottomView->UseTheirTextBlock();
1595 void CMainFrame::OnUpdateEditUsetheirblock(CCmdUI *pCmdUI)
1597 int nSelBlockStart = -1;
1598 int nSelBlockEnd = -1;
1599 if (m_pwndBottomView)
1600 m_pwndBottomView->GetSelection(nSelBlockStart, nSelBlockEnd);
1601 pCmdUI->Enable((nSelBlockStart >= 0)&&(nSelBlockEnd >= 0));
1605 void CMainFrame::OnEditUseMine()
1607 if (m_pwndBottomView)
1608 m_pwndBottomView->UseMyTextBlock();
1610 void CMainFrame::OnUpdateEditUsemyblock(CCmdUI *pCmdUI)
1612 int nSelBlockStart = -1;
1613 int nSelBlockEnd = -1;
1614 if (m_pwndBottomView)
1615 m_pwndBottomView->GetSelection(nSelBlockStart, nSelBlockEnd);
1616 pCmdUI->Enable((nSelBlockStart >= 0)&&(nSelBlockEnd >= 0));
1620 void CMainFrame::OnEditUseTheirsThenMine()
1622 if (m_pwndBottomView)
1623 m_pwndBottomView->UseTheirThenMyTextBlock();
1625 void CMainFrame::OnUpdateEditUsetheirthenmyblock(CCmdUI *pCmdUI)
1627 int nSelBlockStart = -1;
1628 int nSelBlockEnd = -1;
1629 if (m_pwndBottomView)
1630 m_pwndBottomView->GetSelection(nSelBlockStart, nSelBlockEnd);
1631 pCmdUI->Enable((nSelBlockStart >= 0)&&(nSelBlockEnd >= 0));
1635 void CMainFrame::OnEditUseMineThenTheirs()
1637 if (m_pwndBottomView)
1638 m_pwndBottomView->UseMyThenTheirTextBlock();
1640 void CMainFrame::OnUpdateEditUseminethentheirblock(CCmdUI *pCmdUI)
1642 int nSelBlockStart = -1;
1643 int nSelBlockEnd = -1;
1644 if (m_pwndBottomView)
1645 m_pwndBottomView->GetSelection(nSelBlockStart, nSelBlockEnd);
1646 pCmdUI->Enable((nSelBlockStart >= 0)&&(nSelBlockEnd >= 0));
1649 void CMainFrame::OnEditUseleftblock()
1651 if (m_pwndRightView)
1652 m_pwndRightView->UseBlock();
1655 void CMainFrame::OnUpdateEditUseleftblock(CCmdUI *pCmdUI)
1657 pCmdUI->Enable(m_pwndRightView && m_pwndRightView->IsWindowVisible() && m_pwndRightView->HasCaret() && m_pwndRightView->HasSelection());
1660 void CMainFrame::OnEditUseleftfile()
1662 if (m_pwndRightView)
1663 m_pwndRightView->UseFile();
1666 void CMainFrame::OnUpdateEditUseleftfile(CCmdUI *pCmdUI)
1668 pCmdUI->Enable(m_pwndRightView && m_pwndRightView->IsWindowVisible() && m_pwndRightView->HasCaret());
1671 void CMainFrame::OnEditUseblockfromleftbeforeright()
1673 if (m_pwndRightView)
1674 m_pwndRightView->UseLeftBeforeRight();
1677 void CMainFrame::OnUpdateEditUseblockfromleftbeforeright(CCmdUI *pCmdUI)
1679 pCmdUI->Enable(m_pwndRightView && m_pwndRightView->IsWindowVisible() && m_pwndRightView->HasCaret() && m_pwndRightView->HasSelection());
1682 void CMainFrame::OnEditUseblockfromrightbeforeleft()
1684 if (m_pwndRightView)
1685 m_pwndRightView->UseRightBeforeLeft();
1688 void CMainFrame::OnUpdateEditUseblockfromrightbeforeleft(CCmdUI *pCmdUI)
1690 pCmdUI->Enable(m_pwndRightView && m_pwndRightView->IsWindowVisible() && m_pwndRightView->HasCaret() && m_pwndRightView->HasSelection());
1694 void CMainFrame::OnFileReload()
1696 if (CheckForSave()==IDCANCEL)
1697 return;
1698 CDiffColors::GetInstance().LoadRegistry();
1699 LoadViews(true);
1702 void CMainFrame::ActivateFrame(int nCmdShow)
1704 // nCmdShow is the normal show mode this frame should be in
1705 // translate default nCmdShow (-1)
1706 if (nCmdShow == -1)
1708 if (!IsWindowVisible())
1709 nCmdShow = SW_SHOWNORMAL;
1710 else if (IsIconic())
1711 nCmdShow = SW_RESTORE;
1714 // bring to top before showing
1715 BringToTop(nCmdShow);
1717 if (nCmdShow != -1)
1719 // show the window as specified
1720 WINDOWPLACEMENT wp;
1722 if ( !ReadWindowPlacement(&wp) )
1724 ShowWindow(nCmdShow);
1726 else
1728 if ( nCmdShow != SW_SHOWNORMAL )
1729 wp.showCmd = nCmdShow;
1731 SetWindowPlacement(&wp);
1734 // and finally, bring to top after showing
1735 BringToTop(nCmdShow);
1737 return;
1740 BOOL CMainFrame::ReadWindowPlacement(WINDOWPLACEMENT * pwp)
1742 CRegString placement = CRegString(_T("Software\\TortoiseMerge\\WindowPos"));
1743 CString sPlacement = placement;
1744 if (sPlacement.IsEmpty())
1745 return FALSE;
1746 int nRead = _stscanf_s(sPlacement, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
1747 &pwp->flags, &pwp->showCmd,
1748 &pwp->ptMinPosition.x, &pwp->ptMinPosition.y,
1749 &pwp->ptMaxPosition.x, &pwp->ptMaxPosition.y,
1750 &pwp->rcNormalPosition.left, &pwp->rcNormalPosition.top,
1751 &pwp->rcNormalPosition.right, &pwp->rcNormalPosition.bottom);
1752 if ( nRead != 10 )
1753 return FALSE;
1754 pwp->length = sizeof(WINDOWPLACEMENT);
1756 return TRUE;
1759 void CMainFrame::WriteWindowPlacement(WINDOWPLACEMENT * pwp)
1761 CRegString placement = CRegString(_T("Software\\TortoiseMerge\\WindowPos"));
1762 TCHAR szBuffer[_countof("-32767")*8 + sizeof("65535")*2];
1763 CString s;
1765 _stprintf_s(szBuffer, _countof("-32767")*8 + sizeof("65535")*2, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
1766 pwp->flags, pwp->showCmd,
1767 pwp->ptMinPosition.x, pwp->ptMinPosition.y,
1768 pwp->ptMaxPosition.x, pwp->ptMaxPosition.y,
1769 pwp->rcNormalPosition.left, pwp->rcNormalPosition.top,
1770 pwp->rcNormalPosition.right, pwp->rcNormalPosition.bottom);
1771 placement = szBuffer;
1774 void CMainFrame::OnUpdateMergeMarkasresolved(CCmdUI *pCmdUI)
1776 if (pCmdUI == NULL)
1777 return;
1778 BOOL bEnable = FALSE;
1779 if ((!m_bReadOnly)&&(m_Data.m_mergedFile.InUse()))
1781 if (m_pwndBottomView)
1783 if ((m_pwndBottomView->IsWindowVisible())&&(m_pwndBottomView->m_pViewData))
1785 bEnable = TRUE;
1789 pCmdUI->Enable(bEnable);
1792 void CMainFrame::OnMergeMarkasresolved()
1794 int nConflictLine = CheckResolved();
1795 if (nConflictLine >= 0)
1797 CString sTemp;
1798 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
1799 if (MessageBox(sTemp, 0, MB_ICONERROR | MB_YESNO)!=IDYES)
1801 if (m_pwndBottomView)
1802 m_pwndBottomView->GoToLine(nConflictLine);
1803 return;
1806 // now check if the file has already been saved and if not, save it.
1807 if (m_Data.m_mergedFile.InUse())
1809 if (m_pwndBottomView)
1811 if ((m_pwndBottomView->IsWindowVisible())&&(m_pwndBottomView->m_pViewData))
1813 FileSave(false);
1817 MarkAsResolved();
1820 BOOL CMainFrame::MarkAsResolved()
1822 if (m_bReadOnly)
1823 return FALSE;
1824 if (!((m_pwndBottomView) && (m_pwndBottomView->IsWindowVisible())))
1825 return FALSE;
1827 CString cmd = _T("/command:resolve /path:\"");
1828 cmd += m_Data.m_mergedFile.GetFilename();
1829 cmd += _T("\" /closeonend:1 /noquestion /skipcheck");
1830 if (!CAppUtils::RunTortoiseProc(cmd))
1831 return FALSE;
1833 return TRUE;
1836 void CMainFrame::OnUpdateMergeNextconflict(CCmdUI *pCmdUI)
1838 pCmdUI->Enable(m_bHasConflicts);
1841 void CMainFrame::OnUpdateMergePreviousconflict(CCmdUI *pCmdUI)
1843 pCmdUI->Enable(m_bHasConflicts);
1846 void CMainFrame::OnMoving(UINT fwSide, LPRECT pRect)
1848 // if the pathfilelist dialog is attached to the mainframe,
1849 // move it along with the mainframe
1850 if (::IsWindow(m_dlgFilePatches.m_hWnd))
1852 RECT patchrect;
1853 m_dlgFilePatches.GetWindowRect(&patchrect);
1854 if (::IsWindow(m_hWnd))
1856 RECT thisrect;
1857 GetWindowRect(&thisrect);
1858 if (patchrect.right == thisrect.left)
1860 m_dlgFilePatches.SetWindowPos(NULL, patchrect.left - (thisrect.left - pRect->left), patchrect.top - (thisrect.top - pRect->top),
1861 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
1865 __super::OnMoving(fwSide, pRect);
1868 void CMainFrame::OnUpdateEditCopy(CCmdUI *pCmdUI)
1870 BOOL bShow = FALSE;
1871 if ((m_pwndBottomView)&&(m_pwndBottomView->HasSelection()))
1872 bShow = TRUE;
1873 if ((m_pwndRightView)&&(m_pwndRightView->HasSelection()))
1874 bShow = TRUE;
1875 if ((m_pwndLeftView)&&(m_pwndLeftView->HasSelection()))
1876 bShow = TRUE;
1877 pCmdUI->Enable(bShow);
1880 void CMainFrame::OnViewSwitchleft()
1882 int ret = IDNO;
1883 if (((m_pwndBottomView)&&(m_pwndBottomView->IsModified())) ||
1884 ((m_pwndRightView)&&(m_pwndRightView->IsModified())))
1886 CString sTemp;
1887 sTemp.LoadString(IDS_ASKFORSAVE);
1888 ret = MessageBox(sTemp, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
1889 if (ret == IDYES)
1891 if (!FileSave())
1892 return;
1895 if ((ret == IDNO)||(ret == IDYES))
1897 CWorkingFile file = m_Data.m_baseFile;
1898 m_Data.m_baseFile = m_Data.m_yourFile;
1899 m_Data.m_yourFile = file;
1900 if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_yourFile.GetFilename())==0)
1902 m_Data.m_mergedFile = m_Data.m_baseFile;
1904 else if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_baseFile.GetFilename())==0)
1906 m_Data.m_mergedFile = m_Data.m_yourFile;
1908 LoadViews();
1912 void CMainFrame::OnUpdateViewSwitchleft(CCmdUI *pCmdUI)
1914 BOOL bEnable = TRUE;
1915 if (m_pwndBottomView)
1917 if (m_pwndBottomView->IsWindowVisible())
1918 bEnable = FALSE;
1920 pCmdUI->Enable(bEnable);
1924 void CMainFrame::OnUpdateViewShowfilelist(CCmdUI *pCmdUI)
1926 if (m_dlgFilePatches.HasFiles())
1928 pCmdUI->Enable(true);
1930 else
1931 pCmdUI->Enable(false);
1932 pCmdUI->SetCheck(m_dlgFilePatches.IsWindowVisible());
1935 void CMainFrame::OnViewShowfilelist()
1937 m_dlgFilePatches.ShowWindow(m_dlgFilePatches.IsWindowVisible() ? SW_HIDE : SW_SHOW);
1940 void CMainFrame::OnEditUndo()
1942 if (CUndo::GetInstance().CanUndo())
1944 CUndo::GetInstance().Undo(m_pwndLeftView, m_pwndRightView, m_pwndBottomView);
1949 void CMainFrame::OnUpdateEditUndo(CCmdUI *pCmdUI)
1951 pCmdUI->Enable(CUndo::GetInstance().CanUndo());
1954 int CMainFrame::CheckForSave()
1956 int ret = IDNO;
1957 if (((m_pwndBottomView)&&(m_pwndBottomView->IsModified())) ||
1958 ((m_pwndRightView)&&(m_pwndRightView->IsModified())))
1960 CString sTemp;
1961 sTemp.LoadString(IDS_WARNMODIFIEDLOOSECHANGES);
1962 ret = MessageBox(sTemp, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
1964 if (ret == IDYES)
1966 FileSave();
1969 return ret;
1972 void CMainFrame::OnViewInlinediffword()
1974 m_bInlineWordDiff = !m_bInlineWordDiff;
1975 if (m_pwndLeftView)
1977 m_pwndLeftView->SetInlineWordDiff(m_bInlineWordDiff);
1978 m_pwndLeftView->Invalidate();
1980 if (m_pwndRightView)
1982 m_pwndRightView->SetInlineWordDiff(m_bInlineWordDiff);
1983 m_pwndRightView->Invalidate();
1985 if (m_pwndBottomView)
1987 m_pwndBottomView->SetInlineWordDiff(m_bInlineWordDiff);
1988 m_pwndBottomView->Invalidate();
1990 m_wndLineDiffBar.Invalidate();
1993 void CMainFrame::OnUpdateViewInlinediffword(CCmdUI *pCmdUI)
1995 pCmdUI->Enable(m_pwndLeftView && m_pwndLeftView->IsWindowVisible() &&
1996 m_pwndRightView && m_pwndRightView->IsWindowVisible());
1997 pCmdUI->SetCheck(m_bInlineWordDiff);
2000 void CMainFrame::OnUpdateEditCreateunifieddifffile(CCmdUI *pCmdUI)
2002 // "create unified diff file" is only available if two files
2003 // are diffed, not three.
2004 bool bEnabled = true;
2005 if ((m_pwndLeftView == NULL)||(!m_pwndLeftView->IsWindowVisible()))
2006 bEnabled = false;
2007 if ((m_pwndRightView == NULL)||(!m_pwndRightView->IsWindowVisible()))
2008 bEnabled = false;
2009 if ((m_pwndBottomView)&&(m_pwndBottomView->IsWindowVisible()))
2010 bEnabled = false;
2011 pCmdUI->Enable(bEnabled);
2014 void CMainFrame::OnEditCreateunifieddifffile()
2016 CString origFile, modifiedFile, outputFile;
2017 // the original file is the one on the left
2018 if (m_pwndLeftView)
2019 origFile = m_pwndLeftView->m_sFullFilePath;
2020 if (m_pwndRightView)
2021 modifiedFile = m_pwndRightView->m_sFullFilePath;
2022 if (!origFile.IsEmpty() && !modifiedFile.IsEmpty())
2024 // ask for the path to save the unified diff file to
2025 OPENFILENAME ofn = {0}; // common dialog box structure
2026 TCHAR szFile[MAX_PATH] = {0}; // buffer for file name
2027 ofn.lStructSize = sizeof(OPENFILENAME);
2028 ofn.lpstrFile = szFile;
2029 ofn.nMaxFile = _countof(szFile);
2030 CString temp;
2031 temp.LoadString(IDS_SAVEASTITLE);
2032 if (!temp.IsEmpty())
2033 ofn.lpstrTitle = temp;
2034 ofn.Flags = OFN_OVERWRITEPROMPT;
2035 CString sFilter;
2036 sFilter.LoadString(IDS_COMMONFILEFILTER);
2037 TCHAR * pszFilters = new TCHAR[sFilter.GetLength()+4];
2038 _tcscpy_s (pszFilters, sFilter.GetLength()+4, sFilter);
2039 // Replace '|' delimiters with '\0's
2040 TCHAR *ptr = pszFilters + _tcslen(pszFilters); //set ptr at the NULL
2041 while (ptr != pszFilters)
2043 if (*ptr == '|')
2044 *ptr = '\0';
2045 ptr--;
2047 ofn.lpstrFilter = pszFilters;
2048 ofn.nFilterIndex = 1;
2050 // Display the Save dialog box.
2051 CString sFile;
2052 if (GetSaveFileName(&ofn)==TRUE)
2054 outputFile = CString(ofn.lpstrFile);
2055 CAppUtils::CreateUnifiedDiff(origFile, modifiedFile, outputFile, true);
2057 delete [] pszFilters;
2061 void CMainFrame::OnUpdateViewLinediffbar(CCmdUI *pCmdUI)
2063 pCmdUI->SetCheck(m_bLineDiff);
2064 pCmdUI->Enable();
2067 void CMainFrame::OnViewLinediffbar()
2069 m_bLineDiff = !m_bLineDiff;
2070 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2071 m_wndLineDiffBar.DocumentUpdated();
2072 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2073 m_wndLocatorBar.DocumentUpdated();
2076 void CMainFrame::OnUpdateViewLocatorbar(CCmdUI *pCmdUI)
2078 pCmdUI->SetCheck(m_bLocatorBar);
2079 pCmdUI->Enable();
2082 void CMainFrame::OnViewLocatorbar()
2084 m_bLocatorBar = !m_bLocatorBar;
2085 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2086 m_wndLocatorBar.DocumentUpdated();
2087 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2088 m_wndLineDiffBar.DocumentUpdated();