optimize TGitCache for CLI operations
[TortoiseGit.git] / src / TortoiseMerge / MainFrm.cpp
blob5cf78c8067301ef811aa7df22a647fd1f4f8f07d
1 // TortoiseMerge - a Diff/Patch program
3 // Copyright (C) 2008-2012 - TortoiseGit
4 // Copyright (C) 2004-2009 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 #include "TortoiseMerge.h"
22 #include "OpenDlg.h"
23 #include "Patch.h"
24 #include "SysProgressDlg.h"
25 #include "Settings.h"
26 #include "MessageBox.h"
27 #include "AppUtils.h"
28 #include "PathUtils.h"
29 #include "MainFrm.h"
30 #include "LeftView.h"
31 #include "RightView.h"
32 #include "BottomView.h"
33 #include "DiffColors.h"
34 #include ".\mainfrm.h"
35 #include "FormatMessageWrapper.h"
37 #ifdef _DEBUG
38 #define new DEBUG_NEW
39 #endif
42 // CMainFrame
43 const UINT CMainFrame::m_FindDialogMessage = RegisterWindowMessage(FINDMSGSTRING);
45 IMPLEMENT_DYNCREATE(CMainFrame, CFrameWndEx)
47 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)
48 ON_WM_CREATE()
49 ON_COMMAND_RANGE(ID_VIEW_APPLOOK_WIN_2000, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnApplicationLook)
50 ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_APPLOOK_WIN_2000, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnUpdateApplicationLook)
51 // Global help commands
52 ON_COMMAND(ID_HELP_FINDER, CFrameWndEx::OnHelpFinder)
53 ON_COMMAND(ID_HELP, CFrameWndEx::OnHelp)
54 ON_COMMAND(ID_CONTEXT_HELP, CFrameWndEx::OnContextHelp)
55 ON_COMMAND(ID_DEFAULT_HELP, CFrameWndEx::OnHelpFinder)
56 ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
57 ON_COMMAND(ID_VIEW_WHITESPACES, OnViewWhitespaces)
58 ON_WM_SIZE()
59 ON_COMMAND(ID_FILE_SAVE, OnFileSave)
60 ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
61 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave)
62 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_AS, OnUpdateFileSaveAs)
63 ON_COMMAND(ID_VIEW_ONEWAYDIFF, OnViewOnewaydiff)
64 ON_UPDATE_COMMAND_UI(ID_VIEW_ONEWAYDIFF, OnUpdateViewOnewaydiff)
65 ON_UPDATE_COMMAND_UI(ID_VIEW_WHITESPACES, OnUpdateViewWhitespaces)
66 ON_COMMAND(ID_VIEW_OPTIONS, OnViewOptions)
67 ON_WM_CLOSE()
68 ON_COMMAND(ID_EDIT_FIND, OnEditFind)
69 ON_REGISTERED_MESSAGE(m_FindDialogMessage, OnFindDialogMessage)
70 ON_COMMAND(ID_EDIT_FINDNEXT, OnEditFindnext)
71 ON_COMMAND(ID_EDIT_FINDPREV, OnEditFindprev)
72 ON_COMMAND(ID_FILE_RELOAD, OnFileReload)
73 ON_COMMAND(ID_VIEW_LINEDOWN, OnViewLinedown)
74 ON_COMMAND(ID_VIEW_LINEUP, OnViewLineup)
75 ON_UPDATE_COMMAND_UI(ID_EDIT_MARKASRESOLVED, OnUpdateMergeMarkasresolved)
76 ON_COMMAND(ID_EDIT_MARKASRESOLVED, OnMergeMarkasresolved)
77 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTCONFLICT, OnUpdateMergeNextconflict)
78 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSCONFLICT, OnUpdateMergePreviousconflict)
79 ON_WM_MOVE()
80 ON_WM_MOVING()
81 ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
82 ON_COMMAND(ID_VIEW_SWITCHLEFT, OnViewSwitchleft)
83 ON_UPDATE_COMMAND_UI(ID_VIEW_SWITCHLEFT, OnUpdateViewSwitchleft)
84 ON_COMMAND(ID_VIEW_LINELEFT, &CMainFrame::OnViewLineleft)
85 ON_COMMAND(ID_VIEW_LINERIGHT, &CMainFrame::OnViewLineright)
86 ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWFILELIST, &CMainFrame::OnUpdateViewShowfilelist)
87 ON_COMMAND(ID_VIEW_SHOWFILELIST, &CMainFrame::OnViewShowfilelist)
88 ON_COMMAND(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnEditUseTheirs)
89 ON_COMMAND(ID_EDIT_USEMYBLOCK, &CMainFrame::OnEditUseMine)
90 ON_COMMAND(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnEditUseTheirsThenMine)
91 ON_COMMAND(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnEditUseMineThenTheirs)
92 ON_COMMAND(ID_EDIT_UNDO, &CMainFrame::OnEditUndo)
93 ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, &CMainFrame::OnUpdateEditUndo)
94 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnUpdateEditUseminethentheirblock)
95 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMYBLOCK, &CMainFrame::OnUpdateEditUsemyblock)
96 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnUpdateEditUsetheirblock)
97 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnUpdateEditUsetheirthenmyblock)
98 ON_COMMAND(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnViewInlinediffword)
99 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnUpdateViewInlinediffword)
100 ON_UPDATE_COMMAND_UI(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnUpdateEditCreateunifieddifffile)
101 ON_COMMAND(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnEditCreateunifieddifffile)
102 ON_UPDATE_COMMAND_UI(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnUpdateViewLinediffbar)
103 ON_COMMAND(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnViewLinediffbar)
104 ON_UPDATE_COMMAND_UI(ID_VIEW_LOCATORBAR, &CMainFrame::OnUpdateViewLocatorbar)
105 ON_COMMAND(ID_VIEW_LOCATORBAR, &CMainFrame::OnViewLocatorbar)
106 ON_COMMAND(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnEditUseleftblock)
107 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnUpdateEditUseleftblock)
108 ON_COMMAND(ID_EDIT_USELEFTFILE, &CMainFrame::OnEditUseleftfile)
109 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTFILE, &CMainFrame::OnUpdateEditUseleftfile)
110 ON_COMMAND(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnEditUseblockfromleftbeforeright)
111 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnUpdateEditUseblockfromleftbeforeright)
112 ON_COMMAND(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnEditUseblockfromrightbeforeleft)
113 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnUpdateEditUseblockfromrightbeforeleft)
114 END_MESSAGE_MAP()
116 static UINT indicators[] =
118 ID_SEPARATOR, // status line indicator
119 ID_INDICATOR_LEFTVIEW,
120 ID_INDICATOR_RIGHTVIEW,
121 ID_INDICATOR_BOTTOMVIEW,
122 ID_INDICATOR_CAPS,
123 ID_INDICATOR_NUM,
124 ID_INDICATOR_SCRL
128 // CMainFrame construction/destruction
130 CMainFrame::CMainFrame()
131 : m_pFindDialog(NULL)
132 , m_nSearchIndex(0)
133 , m_bInitSplitter(FALSE)
134 , m_bReversedPatch(FALSE)
135 , m_bHasConflicts(false)
136 , m_bInlineWordDiff(true)
137 , m_bLineDiff(true)
138 , m_bLocatorBar(true)
139 , m_nMoveMovesToIgnore(0)
140 , m_bLimitToDiff(false)
141 , m_bWholeWord(false)
142 , m_pwndLeftView(NULL)
143 , m_pwndRightView(NULL)
144 , m_pwndBottomView(NULL)
145 , m_bReadOnly(false)
146 , m_bBlame(false)
148 m_bOneWay = (0 != ((DWORD)CRegDWORD(_T("Software\\TortoiseMerge\\OnePane"))));
149 theApp.m_nAppLook = theApp.GetInt(_T("ApplicationLook"), ID_VIEW_APPLOOK_VS_2005);
152 CMainFrame::~CMainFrame()
156 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
158 if (CFrameWndEx::OnCreate(lpCreateStruct) == -1)
159 return -1;
161 OnApplicationLook(theApp.m_nAppLook);
163 if (!m_wndMenuBar.Create(this))
165 TRACE0("Failed to create menubar\n");
166 return -1; // fail to create
169 m_wndMenuBar.SetPaneStyle(m_wndMenuBar.GetPaneStyle() | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY);
171 // prevent the menu bar from taking the focus on activation
172 CMFCPopupMenu::SetForceMenuFocus(FALSE);
174 if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY) ||
175 !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
177 TRACE0("Failed to create toolbar\n");
178 return -1; // fail to create
180 m_wndToolBar.SetWindowText(_T("Main"));
182 if (!m_wndStatusBar.Create(this) ||
183 !m_wndStatusBar.SetIndicators(indicators,
184 _countof(indicators)))
186 TRACE0("Failed to create status bar\n");
187 return -1; // fail to create
190 if (!m_wndLocatorBar.Create(this, IDD_DIFFLOCATOR,
191 CBRS_ALIGN_LEFT | CBRS_SIZE_FIXED, ID_VIEW_LOCATORBAR))
193 TRACE0("Failed to create dialogbar\n");
194 return -1; // fail to create
196 if (!m_wndLineDiffBar.Create(this, IDD_LINEDIFF,
197 CBRS_ALIGN_BOTTOM | CBRS_SIZE_FIXED, ID_VIEW_LINEDIFFBAR))
199 TRACE0("Failed to create dialogbar\n");
200 return -1; // fail to create
202 m_wndLocatorBar.m_pMainFrm = this;
203 m_wndLineDiffBar.m_pMainFrm = this;
205 EnableDocking(CBRS_ALIGN_ANY);
206 m_wndMenuBar.EnableDocking(CBRS_ALIGN_TOP);
207 m_wndToolBar.EnableDocking(CBRS_ALIGN_TOP);
208 DockPane(&m_wndMenuBar);
209 DockPane(&m_wndToolBar);
210 DockPane(&m_wndLocatorBar);
211 DockPane(&m_wndLineDiffBar);
212 ShowPane(&m_wndLocatorBar, true, false, true);
213 ShowPane(&m_wndLineDiffBar, true, false, true);
215 m_wndLocatorBar.EnableGripper(FALSE);
216 m_wndLineDiffBar.EnableGripper(FALSE);
218 return 0;
221 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
223 if( !CFrameWndEx::PreCreateWindow(cs) )
224 return FALSE;
225 return TRUE;
228 void CMainFrame::OnApplicationLook(UINT id)
230 CWaitCursor wait;
232 theApp.m_nAppLook = id;
234 switch (theApp.m_nAppLook)
236 case ID_VIEW_APPLOOK_WIN_2000:
237 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManager));
238 break;
240 case ID_VIEW_APPLOOK_OFF_XP:
241 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOfficeXP));
242 break;
244 case ID_VIEW_APPLOOK_WIN_XP:
245 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
246 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
247 break;
249 case ID_VIEW_APPLOOK_OFF_2003:
250 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2003));
251 CDockingManager::SetDockingMode(DT_SMART);
252 break;
254 case ID_VIEW_APPLOOK_VS_2005:
255 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2005));
256 CDockingManager::SetDockingMode(DT_SMART);
257 break;
259 default:
260 switch (theApp.m_nAppLook)
262 case ID_VIEW_APPLOOK_OFF_2007_BLUE:
263 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_LunaBlue);
264 break;
266 case ID_VIEW_APPLOOK_OFF_2007_BLACK:
267 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_ObsidianBlack);
268 break;
270 case ID_VIEW_APPLOOK_OFF_2007_SILVER:
271 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Silver);
272 break;
274 case ID_VIEW_APPLOOK_OFF_2007_AQUA:
275 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Aqua);
276 break;
279 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));
280 CDockingManager::SetDockingMode(DT_SMART);
283 RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_FRAME | RDW_ERASE);
285 theApp.WriteInt(_T("ApplicationLook"), theApp.m_nAppLook);
288 void CMainFrame::OnUpdateApplicationLook(CCmdUI* pCmdUI)
290 pCmdUI->SetRadio(theApp.m_nAppLook == pCmdUI->m_nID);
294 // CMainFrame diagnostics
296 #ifdef _DEBUG
297 void CMainFrame::AssertValid() const
299 CFrameWndEx::AssertValid();
302 void CMainFrame::Dump(CDumpContext& dc) const
304 CFrameWndEx::Dump(dc);
307 #endif //_DEBUG
310 // CMainFrame message handlers
313 BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)
315 CRect cr;
316 GetClientRect( &cr);
319 // split into three panes:
320 // -------------
321 // | | |
322 // | | |
323 // |------------
324 // | |
325 // | |
326 // |------------
328 // create a splitter with 2 rows, 1 column
329 if (!m_wndSplitter.CreateStatic(this, 2, 1))
331 TRACE0("Failed to CreateStaticSplitter\n");
332 return FALSE;
335 // add the second splitter pane - which is a nested splitter with 2 columns
336 if (!m_wndSplitter2.CreateStatic(
337 &m_wndSplitter, // our parent window is the first splitter
338 1, 2, // the new splitter is 1 row, 2 columns
339 WS_CHILD | WS_VISIBLE | WS_BORDER, // style, WS_BORDER is needed
340 m_wndSplitter.IdFromRowCol(0, 0)
341 // new splitter is in the first row, 1st column of first splitter
344 TRACE0("Failed to create nested splitter\n");
345 return FALSE;
347 // add the first splitter pane - the default view in row 0
348 if (!m_wndSplitter.CreateView(1, 0,
349 RUNTIME_CLASS(CBottomView), CSize(cr.Width(), cr.Height()), pContext))
351 TRACE0("Failed to create first pane\n");
352 return FALSE;
354 m_pwndBottomView = (CBottomView *)m_wndSplitter.GetPane(1,0);
355 m_pwndBottomView->m_pwndLocator = &m_wndLocatorBar;
356 m_pwndBottomView->m_pwndLineDiffBar = &m_wndLineDiffBar;
357 m_pwndBottomView->m_pwndStatusBar = &m_wndStatusBar;
358 m_pwndBottomView->m_pMainFrame = this;
360 // now create the two views inside the nested splitter
362 if (!m_wndSplitter2.CreateView(0, 0,
363 RUNTIME_CLASS(CLeftView), CSize(cr.Width()/2, cr.Height()/2), pContext))
365 TRACE0("Failed to create second pane\n");
366 return FALSE;
368 m_pwndLeftView = (CLeftView *)m_wndSplitter2.GetPane(0,0);
369 m_pwndLeftView->m_pwndLocator = &m_wndLocatorBar;
370 m_pwndLeftView->m_pwndLineDiffBar = &m_wndLineDiffBar;
371 m_pwndLeftView->m_pwndStatusBar = &m_wndStatusBar;
372 m_pwndLeftView->m_pMainFrame = this;
374 if (!m_wndSplitter2.CreateView(0, 1,
375 RUNTIME_CLASS(CRightView), CSize(cr.Width()/2, cr.Height()/2), pContext))
377 TRACE0("Failed to create third pane\n");
378 return FALSE;
380 m_pwndRightView = (CRightView *)m_wndSplitter2.GetPane(0,1);
381 m_pwndRightView->m_pwndLocator = &m_wndLocatorBar;
382 m_pwndRightView->m_pwndLineDiffBar = &m_wndLineDiffBar;
383 m_pwndRightView->m_pwndStatusBar = &m_wndStatusBar;
384 m_pwndRightView->m_pMainFrame = this;
385 m_bInitSplitter = TRUE;
387 m_dlgFilePatches.Create(IDD_FILEPATCHES, this);
388 UpdateLayout();
389 return TRUE;
392 // Callback function
393 BOOL CMainFrame::PatchFile(CString sFilePath, CString sVersion, BOOL bAutoPatch,BOOL bIsReview,CString *Path2)
395 //first, do a "dry run" of patching...
396 if (!m_Patch.PatchFile(sFilePath))
398 //patching not successful, so retrieve the
399 //base file from version control and try
400 //again...
401 CString sTemp;
402 CSysProgressDlg progDlg;
403 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sVersion);
404 progDlg.SetLine(1, sTemp, true);
405 progDlg.SetLine(2, sFilePath, true);
406 sTemp.LoadString(IDS_GETVERSIONOFFILETITLE);
407 progDlg.SetTitle(sTemp);
408 progDlg.SetShowProgressBar(false);
409 progDlg.SetAnimation(IDR_DOWNLOAD);
410 progDlg.SetTime(FALSE);
412 if(!m_Patch.m_IsGitPatch)
413 progDlg.ShowModeless(this);
415 CString sBaseFile = m_TempFiles.GetTempFilePath();
416 if (!CAppUtils::GetVersionedFile(sFilePath, sVersion, sBaseFile, &progDlg, m_hWnd))
418 progDlg.Stop();
419 CString sErrMsg;
420 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sVersion, (LPCTSTR)sFilePath);
421 MessageBox(sErrMsg, NULL, MB_ICONERROR);
422 return FALSE;
424 progDlg.Stop();
425 CString sTempFile = m_TempFiles.GetTempFilePath();
426 if (!m_Patch.PatchFile(sFilePath, sTempFile, sBaseFile))
428 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
429 return FALSE;
432 CString temp;
433 if(bIsReview)
436 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)sVersion);
437 m_Data.m_baseFile.SetFileName(sBaseFile);
438 m_Data.m_baseFile.SetDescriptiveName(temp);
439 if( Path2)
440 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(*Path2), (LPCTSTR)m_Data.m_sPatchPatched);
441 else
442 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
443 m_Data.m_yourFile.SetFileName(sTempFile);
444 m_Data.m_yourFile.SetDescriptiveName(temp);
445 m_Data.m_theirFile.SetOutOfUse();
446 m_Data.m_mergedFile.SetOutOfUse();
449 else
451 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)sVersion);
452 m_Data.m_baseFile.SetFileName(sBaseFile);
453 m_Data.m_baseFile.SetDescriptiveName(temp);
454 if( Path2)
455 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(*Path2), (LPCTSTR)m_Data.m_sPatchPatched);
456 else
457 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
458 m_Data.m_theirFile.SetFileName(sTempFile);
459 m_Data.m_theirFile.SetDescriptiveName(temp);
460 m_Data.m_yourFile.SetFileName(sFilePath);
461 m_Data.m_yourFile.SetDescriptiveName(CPathUtils::GetFileNameFromPath(sFilePath));
462 m_Data.m_mergedFile.SetFileName(sFilePath);
463 m_Data.m_mergedFile.SetDescriptiveName(CPathUtils::GetFileNameFromPath(sFilePath));
465 TRACE(_T("comparing %s and %s\nagainst the base file %s\n"), (LPCTSTR)sTempFile, (LPCTSTR)sFilePath, (LPCTSTR)sBaseFile);
469 else
471 //"dry run" was successful, so save the patched file somewhere...
472 CString sTempFile = m_TempFiles.GetTempFilePath();
473 if (!m_Patch.PatchFile(sFilePath, sTempFile))
475 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
476 return FALSE;
478 if (m_bReversedPatch)
480 m_Data.m_baseFile.SetFileName(sTempFile);
481 CString temp;
482 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
483 m_Data.m_baseFile.SetDescriptiveName(temp);
484 m_Data.m_yourFile.SetFileName(sFilePath);
485 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchOriginal);
486 m_Data.m_yourFile.SetDescriptiveName(temp);
487 m_Data.m_theirFile.SetOutOfUse();
488 m_Data.m_mergedFile.SetOutOfUse();
490 else
492 if (!PathFileExists(sFilePath))
494 m_Data.m_baseFile.SetFileName(m_TempFiles.GetTempFilePath());
495 m_Data.m_baseFile.CreateEmptyFile();
497 else
499 m_Data.m_baseFile.SetFileName(sFilePath);
501 CString sDescription;
502 sDescription.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchOriginal);
503 m_Data.m_baseFile.SetDescriptiveName(sDescription);
504 m_Data.m_yourFile.SetFileName(sTempFile);
505 CString temp;
506 if( Path2)
508 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(*Path2), (LPCTSTR)m_Data.m_sPatchPatched);
510 else
511 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
513 m_Data.m_yourFile.SetDescriptiveName(temp);
514 m_Data.m_theirFile.SetOutOfUse();
515 m_Data.m_mergedFile.SetFileName(sFilePath);
517 TRACE(_T("comparing %s\nwith the patched result %s\n"), (LPCTSTR)sFilePath, (LPCTSTR)sTempFile);
519 LoadViews();
520 if (bAutoPatch)
522 OnFileSave();
524 return TRUE;
527 // Callback function
528 BOOL CMainFrame::DiffFiles(CString sURL1, CString sRev1, CString sURL2, CString sRev2)
530 CString tempfile1 = m_TempFiles.GetTempFilePath();
531 CString tempfile2 = m_TempFiles.GetTempFilePath();
533 ASSERT(tempfile1.Compare(tempfile2));
535 CString sTemp;
536 CSysProgressDlg progDlg;
537 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev1);
538 progDlg.SetLine(1, sTemp, true);
539 progDlg.SetLine(2, sURL1, true);
540 sTemp.LoadString(IDS_GETVERSIONOFFILETITLE);
541 progDlg.SetTitle(sTemp);
542 progDlg.SetShowProgressBar(true);
543 progDlg.SetAnimation(IDR_DOWNLOAD);
544 progDlg.SetTime(FALSE);
545 progDlg.SetProgress(1,100);
546 progDlg.ShowModeless(this);
547 if (!CAppUtils::GetVersionedFile(sURL1, sRev1, tempfile1, &progDlg, m_hWnd))
549 progDlg.Stop();
550 CString sErrMsg;
551 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev1, (LPCTSTR)sURL1);
552 MessageBox(sErrMsg, NULL, MB_ICONERROR);
553 return FALSE;
555 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev2);
556 progDlg.SetLine(1, sTemp, true);
557 progDlg.SetLine(2, sURL2, true);
558 progDlg.SetProgress(50, 100);
559 if (!CAppUtils::GetVersionedFile(sURL2, sRev2, tempfile2, &progDlg, m_hWnd))
561 progDlg.Stop();
562 CString sErrMsg;
563 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev2, (LPCTSTR)sURL2);
564 MessageBox(sErrMsg, NULL, MB_ICONERROR);
565 return FALSE;
567 progDlg.SetProgress(100,100);
568 progDlg.Stop();
569 CString temp;
570 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL1), (LPCTSTR)sRev1);
571 m_Data.m_baseFile.SetFileName(tempfile1);
572 m_Data.m_baseFile.SetDescriptiveName(temp);
573 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL2), (LPCTSTR)sRev2);
574 m_Data.m_yourFile.SetFileName(tempfile2);
575 m_Data.m_yourFile.SetDescriptiveName(temp);
577 LoadViews();
579 return TRUE;
582 void CMainFrame::OnFileOpen()
584 if (CheckForSave()==IDCANCEL)
585 return;
586 COpenDlg dlg;
587 if (dlg.DoModal()!=IDOK)
589 return;
591 m_dlgFilePatches.ShowWindow(SW_HIDE);
592 m_dlgFilePatches.Init(NULL, NULL, CString(), NULL);
593 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,
594 (LPCTSTR)dlg.m_sUnifiedDiffFile, (LPCTSTR)dlg.m_sPatchDirectory);
595 m_Data.m_baseFile.SetFileName(dlg.m_sBaseFile);
596 m_Data.m_theirFile.SetFileName(dlg.m_sTheirFile);
597 m_Data.m_yourFile.SetFileName(dlg.m_sYourFile);
598 m_Data.m_sDiffFile = dlg.m_sUnifiedDiffFile;
599 m_Data.m_sPatchPath = dlg.m_sPatchDirectory;
600 m_Data.m_mergedFile.SetOutOfUse();
601 g_crasher.AddFile((LPCSTR)(LPCTSTR)dlg.m_sBaseFile, (LPCSTR)(LPCTSTR)_T("Basefile"));
602 g_crasher.AddFile((LPCSTR)(LPCTSTR)dlg.m_sTheirFile, (LPCSTR)(LPCTSTR)_T("Theirfile"));
603 g_crasher.AddFile((LPCSTR)(LPCTSTR)dlg.m_sYourFile, (LPCSTR)(LPCTSTR)_T("Yourfile"));
604 g_crasher.AddFile((LPCSTR)(LPCTSTR)dlg.m_sUnifiedDiffFile, (LPCSTR)(LPCTSTR)_T("Difffile"));
606 if (!m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && m_Data.IsYourFileInUse())
608 // a diff between two files means "Yours" against "Base", not "Theirs" against "Yours"
609 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
611 if (m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && !m_Data.IsYourFileInUse())
613 // a diff between two files means "Yours" against "Base", not "Theirs" against "Base"
614 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
617 LoadViews();
620 void CMainFrame::ClearViewNamesAndPaths() {
621 m_pwndLeftView->m_sWindowName.Empty();
622 m_pwndLeftView->m_sFullFilePath.Empty();
623 m_pwndRightView->m_sWindowName.Empty();
624 m_pwndRightView->m_sFullFilePath.Empty();
625 m_pwndBottomView->m_sWindowName.Empty();
626 m_pwndBottomView->m_sFullFilePath.Empty();
629 bool CMainFrame::LoadViews(bool bRetainPosition)
631 m_Data.SetBlame(m_bBlame);
632 m_bHasConflicts = false;
633 CBaseView* pwndActiveView = m_pwndLeftView;
634 int nOldLine = m_pwndLeftView ? m_pwndLeftView->m_nTopLine : -1;
635 int nOldLineNumber =
636 m_pwndLeftView && m_pwndLeftView->m_pViewData ?
637 m_pwndLeftView->m_pViewData->GetLineNumber(m_pwndLeftView->m_nTopLine) : -1;
638 if (!m_Data.Load())
640 ::MessageBox(NULL, m_Data.GetError(), _T("TortoiseMerge"), MB_ICONERROR);
641 m_Data.m_mergedFile.SetOutOfUse();
642 return false;
645 m_pwndRightView->UseCaret(false);
646 m_pwndBottomView->UseCaret(false);
648 if (!m_Data.IsBaseFileInUse())
650 if (m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
652 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
654 else if ((!m_Data.m_sDiffFile.IsEmpty())&&(!m_Patch.OpenUnifiedDiffFile(m_Data.m_sDiffFile)))
656 ClearViewNamesAndPaths();
657 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
658 return false;
660 if (m_Patch.GetNumberOfFiles() > 0)
662 CString firstpath = m_Patch.GetFilename(0);
663 CString path=firstpath;
664 path.Replace('/','\\');
665 if ( !PathIsRelative(path) && !PathFileExists(path) )
667 // The absolute path mentioned in the patch does not exist. Lets
668 // try to find the correct relative path by stripping prefixes.
669 BOOL bFound = m_Patch.StripPrefixes(m_Data.m_sPatchPath);
670 CString strippedpath = m_Patch.GetFilename(0);
671 if (bFound)
673 CString msg;
674 msg.Format(IDS_WARNABSOLUTEPATHFOUND, (LPCTSTR)firstpath, (LPCTSTR)strippedpath);
675 if (CMessageBox::Show(m_hWnd, msg, _T("TortoiseMerge"), MB_ICONQUESTION | MB_YESNO)==IDNO)
676 return false;
678 else
680 CString msg;
681 msg.Format(IDS_WARNABSOLUTEPATHNOTFOUND, (LPCTSTR)firstpath);
682 CMessageBox::Show(m_hWnd, msg, _T("TortoiseMerge"), MB_ICONEXCLAMATION);
683 return false;
686 CString betterpatchpath = m_Patch.CheckPatchPath(m_Data.m_sPatchPath);
687 if (betterpatchpath.CompareNoCase(m_Data.m_sPatchPath)!=0)
689 CString msg;
690 msg.Format(IDS_WARNBETTERPATCHPATHFOUND, (LPCTSTR)m_Data.m_sPatchPath, (LPCTSTR)betterpatchpath);
691 if (CMessageBox::Show(m_hWnd, msg, _T("TortoiseMerge"), MB_ICONQUESTION | MB_YESNO)==IDYES)
692 m_Data.m_sPatchPath = betterpatchpath;
694 m_dlgFilePatches.Init(&m_Patch, this, m_Data.m_sPatchPath, this);
695 m_dlgFilePatches.ShowWindow(SW_SHOW);
696 ClearViewNamesAndPaths();
697 if (!m_wndSplitter.IsRowHidden(1))
698 m_wndSplitter.HideRow(1);
699 m_pwndLeftView->SetHidden(FALSE);
700 m_pwndRightView->SetHidden(FALSE);
701 m_pwndBottomView->SetHidden(TRUE);
704 if (m_Data.IsBaseFileInUse() && !m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
706 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
708 if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && !m_Data.IsTheirFileInUse())
710 //diff between YOUR and BASE
711 m_pwndRightView->UseCaret();
712 if (m_bOneWay)
714 if (!m_wndSplitter2.IsColumnHidden(1))
715 m_wndSplitter2.HideColumn(1);
717 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseBoth;
718 m_pwndLeftView->texttype = m_Data.m_arYourFile.GetUnicodeType();
719 m_pwndLeftView->lineendings = m_Data.m_arYourFile.GetLineEndings();
720 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName() + _T(" - ") + m_Data.m_yourFile.GetWindowName();
721 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename() + _T(" - ") + m_Data.m_yourFile.GetFilename();
723 m_pwndRightView->m_pViewData = NULL;
724 m_pwndBottomView->m_pViewData = NULL;
726 if (!m_wndSplitter.IsRowHidden(1))
727 m_wndSplitter.HideRow(1);
728 m_pwndLeftView->SetHidden(FALSE);
729 m_pwndRightView->SetHidden(TRUE);
730 m_pwndBottomView->SetHidden(TRUE);
731 ::SetWindowPos(m_pwndLeftView->m_hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
733 else
735 pwndActiveView = m_pwndRightView;
736 if (m_wndSplitter2.IsColumnHidden(1))
737 m_wndSplitter2.ShowColumn();
739 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseLeft;
740 m_pwndLeftView->texttype = m_Data.m_arBaseFile.GetUnicodeType();
741 m_pwndLeftView->lineendings = m_Data.m_arBaseFile.GetLineEndings();
742 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName();
743 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename();
745 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseRight;
746 m_pwndRightView->texttype = m_Data.m_arYourFile.GetUnicodeType();
747 m_pwndRightView->lineendings = m_Data.m_arYourFile.GetLineEndings();
748 m_pwndRightView->m_sWindowName = m_Data.m_yourFile.GetWindowName();
749 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
751 m_pwndBottomView->m_pViewData = NULL;
753 if (!m_wndSplitter.IsRowHidden(1))
754 m_wndSplitter.HideRow(1);
755 m_pwndLeftView->SetHidden(FALSE);
756 m_pwndRightView->SetHidden(FALSE);
757 m_pwndBottomView->SetHidden(TRUE);
760 else if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
762 //diff between THEIR, YOUR and BASE
763 m_pwndBottomView->UseCaret();
764 pwndActiveView = m_pwndBottomView;
766 m_pwndLeftView->m_pViewData = &m_Data.m_TheirBaseBoth;
767 m_pwndLeftView->texttype = m_Data.m_arTheirFile.GetUnicodeType();
768 m_pwndLeftView->lineendings = m_Data.m_arTheirFile.GetLineEndings();
769 m_pwndLeftView->m_sWindowName.LoadString(IDS_VIEWTITLE_THEIRS);
770 m_pwndLeftView->m_sWindowName += _T(" - ") + m_Data.m_theirFile.GetWindowName();
771 m_pwndLeftView->m_sFullFilePath = m_Data.m_theirFile.GetFilename();
773 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseBoth;
774 m_pwndRightView->texttype = m_Data.m_arYourFile.GetUnicodeType();
775 m_pwndRightView->lineendings = m_Data.m_arYourFile.GetLineEndings();
776 m_pwndRightView->m_sWindowName.LoadString(IDS_VIEWTITLE_MINE);
777 m_pwndRightView->m_sWindowName += _T(" - ") + m_Data.m_yourFile.GetWindowName();
778 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
780 m_pwndBottomView->m_pViewData = &m_Data.m_Diff3;
781 m_pwndBottomView->texttype = m_Data.m_arTheirFile.GetUnicodeType();
782 m_pwndBottomView->lineendings = m_Data.m_arTheirFile.GetLineEndings();
783 m_pwndBottomView->m_sWindowName.LoadString(IDS_VIEWTITLE_MERGED);
784 m_pwndBottomView->m_sWindowName += _T(" - ") + m_Data.m_mergedFile.GetWindowName();
785 m_pwndBottomView->m_sFullFilePath = m_Data.m_mergedFile.GetFilename();
787 if (m_wndSplitter2.IsColumnHidden(1))
788 m_wndSplitter2.ShowColumn();
789 if (m_wndSplitter.IsRowHidden(1))
790 m_wndSplitter.ShowRow();
791 m_pwndLeftView->SetHidden(FALSE);
792 m_pwndRightView->SetHidden(FALSE);
793 m_pwndBottomView->SetHidden(FALSE);
794 // in three pane view, hide the line diff bar
795 m_wndLineDiffBar.ShowPane(false, false, true);
796 m_wndLineDiffBar.DocumentUpdated();
798 if (!m_Data.m_mergedFile.InUse())
800 m_Data.m_mergedFile.SetFileName(m_Data.m_yourFile.GetFilename());
802 m_pwndLeftView->DocumentUpdated();
803 m_pwndRightView->DocumentUpdated();
804 m_pwndBottomView->DocumentUpdated();
805 m_wndLocatorBar.DocumentUpdated();
806 m_wndLineDiffBar.DocumentUpdated();
807 UpdateLayout();
808 SetActiveView(pwndActiveView);
810 if (bRetainPosition && m_pwndLeftView->m_pViewData)
812 int n = nOldLineNumber;
813 if (n >= 0)
814 n = m_pwndLeftView->m_pViewData->FindLineNumber(n);
815 if (n < 0)
816 n = nOldLine;
818 m_pwndLeftView->ScrollAllToLine(n);
819 POINT p;
820 p.x = 0;
821 p.y = n;
822 m_pwndLeftView->SetCaretPosition(p);
824 else
826 bool bGoFirstDiff = (0 != (DWORD)CRegDWORD(_T("Software\\TortoiseMerge\\FirstDiffOnLoad"), TRUE));
827 if (bGoFirstDiff) {
828 pwndActiveView->GoToFirstDifference();
829 // Ignore the first few Mouse Move messages, so that the line diff stays on
830 // the first diff line until the user actually moves the mouse
831 m_nMoveMovesToIgnore = 3;
835 // Avoid incorrect rendering of active pane.
836 m_pwndBottomView->ScrollToChar(0);
837 m_pwndLeftView->ScrollToChar(0);
838 m_pwndRightView->ScrollToChar(0);
839 CheckResolved();
840 CUndo::GetInstance().Clear();
841 return true;
844 void CMainFrame::UpdateLayout()
846 if (m_bInitSplitter)
848 CRect cr, rclocbar;
849 GetWindowRect(&cr);
850 int width = cr.Width();
851 if (::IsWindow(m_wndLocatorBar) && m_wndLocatorBar.IsWindowVisible())
853 m_wndLocatorBar.GetWindowRect(&rclocbar);
854 width -= rclocbar.Width();
856 m_wndSplitter.SetRowInfo(0, cr.Height()/2, 0);
857 m_wndSplitter.SetRowInfo(1, cr.Height()/2, 0);
858 m_wndSplitter.SetColumnInfo(0, width / 2, 50);
859 m_wndSplitter2.SetRowInfo(0, cr.Height()/2, 0);
860 m_wndSplitter2.SetColumnInfo(0, width / 2, 50);
861 m_wndSplitter2.SetColumnInfo(1, width / 2, 50);
863 m_wndSplitter.RecalcLayout();
867 void CMainFrame::OnSize(UINT nType, int cx, int cy)
869 if (m_bInitSplitter && nType != SIZE_MINIMIZED)
871 UpdateLayout();
873 CFrameWndEx::OnSize(nType, cx, cy);
876 void CMainFrame::OnViewWhitespaces()
878 CRegDWORD regViewWhitespaces = CRegDWORD(_T("Software\\TortoiseMerge\\ViewWhitespaces"), 1);
879 BOOL bViewWhitespaces = regViewWhitespaces;
880 if (m_pwndLeftView)
881 bViewWhitespaces = m_pwndLeftView->m_bViewWhitespace;
883 bViewWhitespaces = !bViewWhitespaces;
884 regViewWhitespaces = bViewWhitespaces;
885 if (m_pwndLeftView)
887 m_pwndLeftView->m_bViewWhitespace = bViewWhitespaces;
888 m_pwndLeftView->Invalidate();
890 if (m_pwndRightView)
892 m_pwndRightView->m_bViewWhitespace = bViewWhitespaces;
893 m_pwndRightView->Invalidate();
895 if (m_pwndBottomView)
897 m_pwndBottomView->m_bViewWhitespace = bViewWhitespaces;
898 m_pwndBottomView->Invalidate();
902 void CMainFrame::OnUpdateViewWhitespaces(CCmdUI *pCmdUI)
904 if (m_pwndLeftView)
905 pCmdUI->SetCheck(m_pwndLeftView->m_bViewWhitespace);
908 void CMainFrame::OnViewOnewaydiff()
910 if (CheckForSave()==IDCANCEL)
911 return;
912 m_bOneWay = !m_bOneWay;
913 if (m_bOneWay)
915 // in one way view, hide the line diff bar
916 m_wndLineDiffBar.ShowPane(false, false, true);
917 m_wndLineDiffBar.DocumentUpdated();
919 else
921 // restore the line diff bar
922 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
923 m_wndLineDiffBar.DocumentUpdated();
924 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
925 m_wndLocatorBar.DocumentUpdated();
927 LoadViews(true);
930 void CMainFrame::ShowDiffBar(bool bShow)
932 if (bShow)
934 // restore the line diff bar
935 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
936 m_wndLineDiffBar.DocumentUpdated();
937 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
938 m_wndLocatorBar.DocumentUpdated();
940 else
942 // in one way view, hide the line diff bar
943 m_wndLineDiffBar.ShowPane(false, false, true);
944 m_wndLineDiffBar.DocumentUpdated();
948 int CMainFrame::CheckResolved()
950 //only in three way diffs can be conflicts!
951 m_bHasConflicts = true;
952 if (m_pwndBottomView->IsWindowVisible())
954 if (m_pwndBottomView->m_pViewData)
956 for (int i=0; i<m_pwndBottomView->m_pViewData->GetCount(); i++)
958 if ((DIFFSTATE_CONFLICTED == m_pwndBottomView->m_pViewData->GetState(i))||
959 (DIFFSTATE_CONFLICTED_IGNORED == m_pwndBottomView->m_pViewData->GetState(i)))
960 return i;
964 m_bHasConflicts = false;
965 return -1;
968 int CMainFrame::SaveFile(const CString& sFilePath)
970 CViewData * pViewData = NULL;
971 CFileTextLines * pOriginFile = &m_Data.m_arBaseFile;
972 if ((m_pwndBottomView)&&(m_pwndBottomView->IsWindowVisible()))
974 pViewData = m_pwndBottomView->m_pViewData;
975 Invalidate();
977 else if ((m_pwndRightView)&&(m_pwndRightView->IsWindowVisible()))
979 pViewData = m_pwndRightView->m_pViewData;
980 if (m_Data.IsYourFileInUse())
981 pOriginFile = &m_Data.m_arYourFile;
982 else if (m_Data.IsTheirFileInUse())
983 pOriginFile = &m_Data.m_arTheirFile;
984 Invalidate();
986 else
988 // nothing to save!
989 return -1;
991 if ((pViewData)&&(pOriginFile))
993 CFileTextLines file;
994 pOriginFile->CopySettings(&file);
995 for (int i=0; i<pViewData->GetCount(); i++)
997 //only copy non-removed lines
998 DiffStates state = pViewData->GetState(i);
999 switch (state)
1001 case DIFFSTATE_CONFLICTED:
1002 case DIFFSTATE_CONFLICTED_IGNORED:
1004 int first = i;
1005 int last = i;
1008 last++;
1009 } while((last<pViewData->GetCount()) && ((pViewData->GetState(last)==DIFFSTATE_CONFLICTED)||(pViewData->GetState(last)==DIFFSTATE_CONFLICTED_IGNORED)));
1010 file.Add(_T("<<<<<<< .mine"), EOL_NOENDING);
1011 for (int j=first; j<last; j++)
1013 file.Add(m_pwndRightView->m_pViewData->GetLine(j), m_pwndRightView->m_pViewData->GetLineEnding(j));
1015 file.Add(_T("======="), EOL_NOENDING);
1016 for (int j=first; j<last; j++)
1018 file.Add(m_pwndLeftView->m_pViewData->GetLine(j), m_pwndLeftView->m_pViewData->GetLineEnding(j));
1020 file.Add(_T(">>>>>>> .theirs"), EOL_NOENDING);
1021 i = last-1;
1023 break;
1024 case DIFFSTATE_EMPTY:
1025 case DIFFSTATE_CONFLICTEMPTY:
1026 case DIFFSTATE_IDENTICALREMOVED:
1027 case DIFFSTATE_REMOVED:
1028 case DIFFSTATE_THEIRSREMOVED:
1029 case DIFFSTATE_YOURSREMOVED:
1030 case DIFFSTATE_CONFLICTRESOLVEDEMPTY:
1031 // do not save removed lines
1032 break;
1033 default:
1034 file.Add(pViewData->GetLine(i), pViewData->GetLineEnding(i));
1035 break;
1038 if (!file.Save(sFilePath, false))
1040 CMessageBox::Show(m_hWnd, file.GetErrorString(), _T("TortoiseMerge"), MB_ICONERROR);
1041 return -1;
1043 m_dlgFilePatches.SetFileStatusAsPatched(sFilePath);
1044 if (m_pwndBottomView)
1045 m_pwndBottomView->SetModified(FALSE);
1046 if (m_pwndRightView)
1047 m_pwndRightView->SetModified(FALSE);
1048 CUndo::GetInstance().MarkAsOriginalState();
1049 return file.GetCount();
1051 return -1;
1054 void CMainFrame::OnFileSave()
1056 FileSave();
1059 bool CMainFrame::FileSave(bool bCheckResolved /*=true*/)
1061 if (!m_Data.m_mergedFile.InUse())
1062 return FileSaveAs(bCheckResolved);
1063 // check if the file has the readonly attribute set
1064 bool bDoesNotExist = false;
1065 DWORD fAttribs = GetFileAttributes(m_Data.m_mergedFile.GetFilename());
1066 if ((fAttribs != INVALID_FILE_ATTRIBUTES)&&(fAttribs & FILE_ATTRIBUTE_READONLY))
1067 return FileSaveAs(bCheckResolved);
1068 if (fAttribs == INVALID_FILE_ATTRIBUTES)
1070 bDoesNotExist = (GetLastError() == ERROR_FILE_NOT_FOUND);
1072 if (bCheckResolved)
1074 int nConflictLine = CheckResolved();
1075 if (nConflictLine >= 0)
1077 CString sTemp;
1078 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
1079 if (MessageBox(sTemp, 0, MB_ICONERROR | MB_YESNO)!=IDYES)
1081 if (m_pwndBottomView)
1082 m_pwndBottomView->GoToLine(nConflictLine);
1083 return false;
1087 if (((DWORD)CRegDWORD(_T("Software\\TortoiseMerge\\Backup"))) != 0)
1089 MoveFileEx(m_Data.m_mergedFile.GetFilename(), m_Data.m_mergedFile.GetFilename() + _T(".bak"), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
1091 if (SaveFile(m_Data.m_mergedFile.GetFilename())==0)
1093 // file was saved with 0 lines!
1094 // ask the user if the file should be deleted
1095 CString sTemp;
1096 sTemp.Format(IDS_DELETEWHENEMPTY, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
1097 if (CMessageBox::ShowCheck(m_hWnd, sTemp, _T("TortoiseMerge"), MB_YESNO, _T("DeleteFileWhenEmpty")) == IDYES)
1099 DeleteFile(m_Data.m_mergedFile.GetFilename());
1103 if (bDoesNotExist)
1105 // call TortoiseProc to add the new file to version control
1106 CString cmd = _T("/command:add /noui /path:\"");
1107 cmd += m_Data.m_mergedFile.GetFilename() + _T("\"");
1108 CAppUtils::RunTortoiseProc(cmd);
1110 return true;
1113 void CMainFrame::OnFileSaveAs()
1115 FileSaveAs();
1118 bool CMainFrame::FileSaveAs(bool bCheckResolved /*=true*/)
1120 if (bCheckResolved)
1122 int nConflictLine = CheckResolved();
1123 if (nConflictLine >= 0)
1125 CString sTemp;
1126 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
1127 if (MessageBox(sTemp, 0, MB_ICONERROR | MB_YESNO)!=IDYES)
1129 if (m_pwndBottomView)
1130 m_pwndBottomView->GoToLine(nConflictLine);
1131 return false;
1135 OPENFILENAME ofn = {0}; // common dialog box structure
1136 TCHAR szFile[MAX_PATH] = {0}; // buffer for file name
1137 ofn.lStructSize = sizeof(OPENFILENAME);
1138 ofn.hwndOwner = m_hWnd;
1139 ofn.lpstrFile = szFile;
1140 ofn.nMaxFile = _countof(szFile);
1141 CString temp;
1142 temp.LoadString(IDS_SAVEASTITLE);
1143 if (!temp.IsEmpty())
1144 ofn.lpstrTitle = temp;
1145 ofn.Flags = OFN_OVERWRITEPROMPT;
1146 CString sFilter;
1147 sFilter.LoadString(IDS_COMMONFILEFILTER);
1148 TCHAR * pszFilters = new TCHAR[sFilter.GetLength()+4];
1149 _tcscpy_s (pszFilters, sFilter.GetLength()+4, sFilter);
1150 // Replace '|' delimiters with '\0's
1151 TCHAR *ptr = pszFilters + _tcslen(pszFilters); //set ptr at the NULL
1152 while (ptr != pszFilters)
1154 if (*ptr == '|')
1155 *ptr = '\0';
1156 ptr--;
1158 ofn.lpstrFilter = pszFilters;
1159 ofn.nFilterIndex = 1;
1161 // Display the Open dialog box.
1162 CString sFile;
1163 if (GetSaveFileName(&ofn)==TRUE)
1165 sFile = CString(ofn.lpstrFile);
1166 SaveFile(sFile);
1167 delete [] pszFilters;
1168 return true;
1170 delete [] pszFilters;
1171 return false;
1174 void CMainFrame::OnUpdateFileSave(CCmdUI *pCmdUI)
1176 BOOL bEnable = FALSE;
1177 if (m_Data.m_mergedFile.InUse())
1179 if (m_pwndBottomView)
1181 if ((m_pwndBottomView->IsWindowVisible())&&(m_pwndBottomView->m_pViewData))
1183 bEnable = TRUE;
1186 if (m_pwndRightView)
1188 if ((m_pwndRightView->IsWindowVisible())&&(m_pwndRightView->m_pViewData))
1190 if (m_pwndRightView->IsModified() || (m_Data.m_yourFile.GetWindowName().Right(9).Compare(_T(": patched"))==0))
1191 bEnable = TRUE;
1195 pCmdUI->Enable(bEnable);
1198 void CMainFrame::OnUpdateFileSaveAs(CCmdUI *pCmdUI)
1200 BOOL bEnable = FALSE;
1201 if (m_pwndBottomView)
1203 if ((m_pwndBottomView->IsWindowVisible())&&(m_pwndBottomView->m_pViewData))
1205 bEnable = TRUE;
1208 if (m_pwndRightView)
1210 if ((m_pwndRightView->IsWindowVisible())&&(m_pwndRightView->m_pViewData))
1212 bEnable = TRUE;
1215 pCmdUI->Enable(bEnable);
1219 void CMainFrame::OnUpdateViewOnewaydiff(CCmdUI *pCmdUI)
1221 pCmdUI->SetCheck(!m_bOneWay);
1222 BOOL bEnable = TRUE;
1223 if (m_pwndBottomView)
1225 if (m_pwndBottomView->IsWindowVisible())
1226 bEnable = FALSE;
1228 pCmdUI->Enable(bEnable);
1231 void CMainFrame::OnViewOptions()
1233 CString sTemp;
1234 sTemp.LoadString(IDS_SETTINGSTITLE);
1235 CSettings dlg(sTemp);
1236 dlg.DoModal();
1237 if (dlg.IsReloadNeeded())
1239 if (CheckForSave()==IDCANCEL)
1240 return;
1241 CDiffColors::GetInstance().LoadRegistry();
1242 LoadViews();
1243 return;
1245 CDiffColors::GetInstance().LoadRegistry();
1246 if (m_pwndBottomView)
1247 m_pwndBottomView->Invalidate();
1248 if (m_pwndLeftView)
1249 m_pwndLeftView->Invalidate();
1250 if (m_pwndRightView)
1251 m_pwndRightView->Invalidate();
1254 void CMainFrame::OnClose()
1256 if ((m_pFindDialog)&&(!m_pFindDialog->IsTerminating()))
1258 m_pFindDialog->SendMessage(WM_CLOSE);
1259 return;
1261 int ret = IDNO;
1262 if (((m_pwndBottomView)&&(m_pwndBottomView->IsModified())) ||
1263 ((m_pwndRightView)&&(m_pwndRightView->IsModified())))
1265 CString sTemp;
1266 sTemp.LoadString(IDS_ASKFORSAVE);
1267 ret = MessageBox(sTemp, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
1268 if (ret == IDYES)
1270 if (!FileSave())
1271 return;
1274 if ((ret == IDNO)||(ret == IDYES))
1276 WINDOWPLACEMENT wp;
1278 // before it is destroyed, save the position of the window
1279 wp.length = sizeof wp;
1281 if (GetWindowPlacement(&wp))
1284 if (IsIconic())
1285 // never restore to Iconic state
1286 wp.showCmd = SW_SHOW ;
1288 if ((wp.flags & WPF_RESTORETOMAXIMIZED) != 0)
1289 // if maximized and maybe iconic restore maximized state
1290 wp.showCmd = SW_SHOWMAXIMIZED ;
1292 // and write it to the .INI file
1293 WriteWindowPlacement(&wp);
1295 __super::OnClose();
1299 void CMainFrame::OnEditFind()
1301 if (m_pFindDialog)
1303 return;
1305 else
1307 // start searching from the start again
1308 // if no line is selected, otherwise start from
1309 // the selected line
1310 m_nSearchIndex = FindSearchStart(0);
1311 m_pFindDialog = new CFindDlg();
1312 m_pFindDialog->Create(this);
1316 LRESULT CMainFrame::OnFindDialogMessage(WPARAM /*wParam*/, LPARAM /*lParam*/)
1318 ASSERT(m_pFindDialog != NULL);
1320 if (m_pFindDialog->IsTerminating())
1322 // invalidate the handle identifying the dialog box.
1323 m_pFindDialog = NULL;
1324 return 0;
1327 if(m_pFindDialog->FindNext())
1329 //read data from dialog
1330 m_sFindText = m_pFindDialog->GetFindString();
1331 m_bMatchCase = (m_pFindDialog->MatchCase() == TRUE);
1332 m_bLimitToDiff = m_pFindDialog->LimitToDiffs();
1333 m_bWholeWord = m_pFindDialog->WholeWord();
1335 OnEditFindnext();
1338 return 0;
1341 bool CharIsDelimiter(const CString& ch)
1343 CString delimiters(_T(" .,:;=+-*/\\\n\t()[]<>@"));
1344 return delimiters.Find(ch) >= 0;
1347 bool CMainFrame::StringFound(const CString& str)const
1349 int nSubStringStartIdx = str.Find(m_sFindText);
1350 bool bStringFound = (nSubStringStartIdx >= 0);
1351 if (bStringFound && m_bWholeWord)
1353 if (nSubStringStartIdx)
1354 bStringFound = CharIsDelimiter(str.Mid(nSubStringStartIdx-1,1));
1356 if (bStringFound)
1358 int nEndIndex = nSubStringStartIdx + m_sFindText.GetLength();
1359 if (str.GetLength() > nEndIndex)
1360 bStringFound = CharIsDelimiter(str.Mid(nEndIndex, 1));
1363 return bStringFound;
1366 void CMainFrame::OnEditFindprev()
1368 Search(SearchPrevious);
1371 void CMainFrame::OnEditFindnext()
1373 Search(SearchNext);
1376 void CMainFrame::Search(SearchDirection srchDir)
1378 if (m_sFindText.IsEmpty())
1379 return;
1381 if ((m_pwndLeftView)&&(m_pwndLeftView->m_pViewData))
1383 bool bFound = FALSE;
1385 CString left;
1386 CString right;
1387 CString bottom;
1388 DiffStates leftstate = DIFFSTATE_NORMAL;
1389 DiffStates rightstate = DIFFSTATE_NORMAL;
1390 DiffStates bottomstate = DIFFSTATE_NORMAL;
1391 int i = 0;
1393 m_nSearchIndex = FindSearchStart(m_nSearchIndex);
1394 m_nSearchIndex++;
1395 if (m_nSearchIndex >= m_pwndLeftView->m_pViewData->GetCount())
1396 m_nSearchIndex = 0;
1397 if (srchDir == SearchPrevious)
1399 // SearchIndex points 1 past where we found the last match,
1400 // so if we are searching backwards we need to adjust accordingly
1401 m_nSearchIndex -= 2;
1402 // if at the top, start again from the end
1403 if (m_nSearchIndex < 0)
1404 m_nSearchIndex += m_pwndLeftView->m_pViewData->GetCount();
1406 const int idxLimits[2][2][2]={{{m_nSearchIndex, m_pwndLeftView->m_pViewData->GetCount()},
1407 {0, m_nSearchIndex}},
1408 {{m_nSearchIndex, -1},
1409 {m_pwndLeftView->m_pViewData->GetCount()-1, m_nSearchIndex}}};
1410 const int offsets[2]={+1, -1};
1412 for (int j=0; j != 2 && !bFound; ++j)
1414 for (i=idxLimits[srchDir][j][0]; i != idxLimits[srchDir][j][1]; i += offsets[srchDir])
1416 left = m_pwndLeftView->m_pViewData->GetLine(i);
1417 leftstate = m_pwndLeftView->m_pViewData->GetState(i);
1418 if ((!m_bOneWay)&&(m_pwndRightView->m_pViewData))
1420 right = m_pwndRightView->m_pViewData->GetLine(i);
1421 rightstate = m_pwndRightView->m_pViewData->GetState(i);
1423 if ((m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1425 bottom = m_pwndBottomView->m_pViewData->GetLine(i);
1426 bottomstate = m_pwndBottomView->m_pViewData->GetState(i);
1429 if (!m_bMatchCase)
1431 left = left.MakeLower();
1432 right = right.MakeLower();
1433 bottom = bottom.MakeLower();
1434 m_sFindText = m_sFindText.MakeLower();
1436 if (StringFound(left))
1438 if ((!m_bLimitToDiff)||(leftstate != DIFFSTATE_NORMAL))
1440 bFound = TRUE;
1441 break;
1444 else if (StringFound(right))
1446 if ((!m_bLimitToDiff)||(rightstate != DIFFSTATE_NORMAL))
1448 bFound = TRUE;
1449 break;
1452 else if (StringFound(bottom))
1454 if ((!m_bLimitToDiff)||(bottomstate != DIFFSTATE_NORMAL))
1456 bFound = TRUE;
1457 break;
1462 if (bFound)
1464 m_nSearchIndex = i;
1465 m_pwndLeftView->GoToLine(m_nSearchIndex);
1466 if (StringFound(left))
1468 m_pwndLeftView->SetFocus();
1469 m_pwndLeftView->HiglightLines(m_nSearchIndex);
1471 else if (StringFound(right))
1473 m_pwndRightView->SetFocus();
1474 m_pwndRightView->HiglightLines(m_nSearchIndex);
1476 else if (StringFound(bottom))
1478 m_pwndBottomView->SetFocus();
1479 m_pwndBottomView->HiglightLines(m_nSearchIndex);
1482 else
1484 m_nSearchIndex = 0;
1489 int CMainFrame::FindSearchStart(int nDefault)
1491 // TortoiseMerge doesn't have a cursor which we could use to
1492 // anchor the search on.
1493 // Instead we use a line that is selected.
1494 // If however no line is selected, use the default line (which could
1495 // be the top of the document for a new search, or the line where the
1496 // search was successful on)
1497 int nLine = nDefault;
1498 int nSelStart = 0;
1499 int nSelEnd = 0;
1500 if (m_pwndLeftView)
1502 if (m_pwndLeftView->GetSelection(nSelStart, nSelEnd))
1504 if (nSelStart == nSelEnd)
1505 nLine = nSelStart;
1508 else if ((nLine == nDefault)&&(m_pwndRightView))
1510 if (m_pwndRightView->GetSelection(nSelStart, nSelEnd))
1512 if (nSelStart == nSelEnd)
1513 nLine = nSelStart;
1516 else if ((nLine == nDefault)&&(m_pwndBottomView))
1518 if (m_pwndBottomView->GetSelection(nSelStart, nSelEnd))
1520 if (nSelStart == nSelEnd)
1521 nLine = nSelStart;
1524 return nLine;
1527 void CMainFrame::OnViewLinedown()
1529 if (m_pwndLeftView)
1530 m_pwndLeftView->ScrollToLine(m_pwndLeftView->m_nTopLine+1);
1531 if (m_pwndRightView)
1532 m_pwndRightView->ScrollToLine(m_pwndRightView->m_nTopLine+1);
1533 if (m_pwndBottomView)
1534 m_pwndBottomView->ScrollToLine(m_pwndBottomView->m_nTopLine+1);
1535 m_wndLocatorBar.Invalidate();
1538 void CMainFrame::OnViewLineup()
1540 if (m_pwndLeftView)
1541 m_pwndLeftView->ScrollToLine(m_pwndLeftView->m_nTopLine-1);
1542 if (m_pwndRightView)
1543 m_pwndRightView->ScrollToLine(m_pwndRightView->m_nTopLine-1);
1544 if (m_pwndBottomView)
1545 m_pwndBottomView->ScrollToLine(m_pwndBottomView->m_nTopLine-1);
1546 m_wndLocatorBar.Invalidate();
1549 void CMainFrame::OnViewLineleft()
1551 if (m_pwndLeftView)
1552 m_pwndLeftView->ScrollSide(-1);
1553 if (m_pwndRightView)
1554 m_pwndRightView->ScrollSide(-1);
1555 if (m_pwndBottomView)
1556 m_pwndBottomView->ScrollSide(-1);
1559 void CMainFrame::OnViewLineright()
1561 if (m_pwndLeftView)
1562 m_pwndLeftView->ScrollSide(1);
1563 if (m_pwndRightView)
1564 m_pwndRightView->ScrollSide(1);
1565 if (m_pwndBottomView)
1566 m_pwndBottomView->ScrollSide(1);
1569 void CMainFrame::OnEditUseTheirs()
1571 if (m_pwndBottomView)
1572 m_pwndBottomView->UseTheirTextBlock();
1574 void CMainFrame::OnUpdateEditUsetheirblock(CCmdUI *pCmdUI)
1576 int nSelBlockStart = -1;
1577 int nSelBlockEnd = -1;
1578 if (m_pwndBottomView)
1579 m_pwndBottomView->GetSelection(nSelBlockStart, nSelBlockEnd);
1580 pCmdUI->Enable((nSelBlockStart >= 0)&&(nSelBlockEnd >= 0));
1584 void CMainFrame::OnEditUseMine()
1586 if (m_pwndBottomView)
1587 m_pwndBottomView->UseMyTextBlock();
1589 void CMainFrame::OnUpdateEditUsemyblock(CCmdUI *pCmdUI)
1591 int nSelBlockStart = -1;
1592 int nSelBlockEnd = -1;
1593 if (m_pwndBottomView)
1594 m_pwndBottomView->GetSelection(nSelBlockStart, nSelBlockEnd);
1595 pCmdUI->Enable((nSelBlockStart >= 0)&&(nSelBlockEnd >= 0));
1599 void CMainFrame::OnEditUseTheirsThenMine()
1601 if (m_pwndBottomView)
1602 m_pwndBottomView->UseTheirThenMyTextBlock();
1604 void CMainFrame::OnUpdateEditUsetheirthenmyblock(CCmdUI *pCmdUI)
1606 int nSelBlockStart = -1;
1607 int nSelBlockEnd = -1;
1608 if (m_pwndBottomView)
1609 m_pwndBottomView->GetSelection(nSelBlockStart, nSelBlockEnd);
1610 pCmdUI->Enable((nSelBlockStart >= 0)&&(nSelBlockEnd >= 0));
1614 void CMainFrame::OnEditUseMineThenTheirs()
1616 if (m_pwndBottomView)
1617 m_pwndBottomView->UseMyThenTheirTextBlock();
1619 void CMainFrame::OnUpdateEditUseminethentheirblock(CCmdUI *pCmdUI)
1621 int nSelBlockStart = -1;
1622 int nSelBlockEnd = -1;
1623 if (m_pwndBottomView)
1624 m_pwndBottomView->GetSelection(nSelBlockStart, nSelBlockEnd);
1625 pCmdUI->Enable((nSelBlockStart >= 0)&&(nSelBlockEnd >= 0));
1628 void CMainFrame::OnEditUseleftblock()
1630 if (m_pwndRightView)
1631 m_pwndRightView->UseBlock();
1634 void CMainFrame::OnUpdateEditUseleftblock(CCmdUI *pCmdUI)
1636 pCmdUI->Enable(m_pwndRightView && m_pwndRightView->IsWindowVisible() && m_pwndRightView->HasCaret() && m_pwndRightView->HasSelection());
1639 void CMainFrame::OnEditUseleftfile()
1641 if (m_pwndRightView)
1642 m_pwndRightView->UseFile();
1645 void CMainFrame::OnUpdateEditUseleftfile(CCmdUI *pCmdUI)
1647 pCmdUI->Enable(m_pwndRightView && m_pwndRightView->IsWindowVisible() && m_pwndRightView->HasCaret());
1650 void CMainFrame::OnEditUseblockfromleftbeforeright()
1652 if (m_pwndRightView)
1653 m_pwndRightView->UseLeftBeforeRight();
1656 void CMainFrame::OnUpdateEditUseblockfromleftbeforeright(CCmdUI *pCmdUI)
1658 pCmdUI->Enable(m_pwndRightView && m_pwndRightView->IsWindowVisible() && m_pwndRightView->HasCaret() && m_pwndRightView->HasSelection());
1661 void CMainFrame::OnEditUseblockfromrightbeforeleft()
1663 if (m_pwndRightView)
1664 m_pwndRightView->UseRightBeforeLeft();
1667 void CMainFrame::OnUpdateEditUseblockfromrightbeforeleft(CCmdUI *pCmdUI)
1669 pCmdUI->Enable(m_pwndRightView && m_pwndRightView->IsWindowVisible() && m_pwndRightView->HasCaret() && m_pwndRightView->HasSelection());
1673 void CMainFrame::OnFileReload()
1675 if (CheckForSave()==IDCANCEL)
1676 return;
1677 CDiffColors::GetInstance().LoadRegistry();
1678 LoadViews(true);
1681 void CMainFrame::ActivateFrame(int nCmdShow)
1683 // nCmdShow is the normal show mode this frame should be in
1684 // translate default nCmdShow (-1)
1685 if (nCmdShow == -1)
1687 if (!IsWindowVisible())
1688 nCmdShow = SW_SHOWNORMAL;
1689 else if (IsIconic())
1690 nCmdShow = SW_RESTORE;
1693 // bring to top before showing
1694 BringToTop(nCmdShow);
1696 if (nCmdShow != -1)
1698 // show the window as specified
1699 WINDOWPLACEMENT wp;
1701 if ( !ReadWindowPlacement(&wp) )
1703 ShowWindow(nCmdShow);
1705 else
1707 if ( nCmdShow != SW_SHOWNORMAL )
1708 wp.showCmd = nCmdShow;
1710 SetWindowPlacement(&wp);
1713 // and finally, bring to top after showing
1714 BringToTop(nCmdShow);
1716 return;
1719 BOOL CMainFrame::ReadWindowPlacement(WINDOWPLACEMENT * pwp)
1721 CRegString placement = CRegString(_T("Software\\TortoiseMerge\\WindowPos"));
1722 CString sPlacement = placement;
1723 if (sPlacement.IsEmpty())
1724 return FALSE;
1725 int nRead = _stscanf_s(sPlacement, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
1726 &pwp->flags, &pwp->showCmd,
1727 &pwp->ptMinPosition.x, &pwp->ptMinPosition.y,
1728 &pwp->ptMaxPosition.x, &pwp->ptMaxPosition.y,
1729 &pwp->rcNormalPosition.left, &pwp->rcNormalPosition.top,
1730 &pwp->rcNormalPosition.right, &pwp->rcNormalPosition.bottom);
1731 if ( nRead != 10 )
1732 return FALSE;
1733 pwp->length = sizeof(WINDOWPLACEMENT);
1735 return TRUE;
1738 void CMainFrame::WriteWindowPlacement(WINDOWPLACEMENT * pwp)
1740 CRegString placement = CRegString(_T("Software\\TortoiseMerge\\WindowPos"));
1741 TCHAR szBuffer[_countof("-32767")*8 + sizeof("65535")*2];
1742 CString s;
1744 _stprintf_s(szBuffer, _countof("-32767")*8 + sizeof("65535")*2, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
1745 pwp->flags, pwp->showCmd,
1746 pwp->ptMinPosition.x, pwp->ptMinPosition.y,
1747 pwp->ptMaxPosition.x, pwp->ptMaxPosition.y,
1748 pwp->rcNormalPosition.left, pwp->rcNormalPosition.top,
1749 pwp->rcNormalPosition.right, pwp->rcNormalPosition.bottom);
1750 placement = szBuffer;
1753 void CMainFrame::OnUpdateMergeMarkasresolved(CCmdUI *pCmdUI)
1755 if (pCmdUI == NULL)
1756 return;
1757 BOOL bEnable = FALSE;
1758 if ((!m_bReadOnly)&&(m_Data.m_mergedFile.InUse()))
1760 if (m_pwndBottomView)
1762 if ((m_pwndBottomView->IsWindowVisible())&&(m_pwndBottomView->m_pViewData))
1764 bEnable = TRUE;
1768 pCmdUI->Enable(bEnable);
1771 void CMainFrame::OnMergeMarkasresolved()
1773 int nConflictLine = CheckResolved();
1774 if (nConflictLine >= 0)
1776 CString sTemp;
1777 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
1778 if (MessageBox(sTemp, 0, MB_ICONERROR | MB_YESNO)!=IDYES)
1780 if (m_pwndBottomView)
1781 m_pwndBottomView->GoToLine(nConflictLine);
1782 return;
1785 // now check if the file has already been saved and if not, save it.
1786 if (m_Data.m_mergedFile.InUse())
1788 if (m_pwndBottomView)
1790 if ((m_pwndBottomView->IsWindowVisible())&&(m_pwndBottomView->m_pViewData))
1792 FileSave(false);
1796 MarkAsResolved();
1799 BOOL CMainFrame::MarkAsResolved()
1801 if (m_bReadOnly)
1802 return FALSE;
1803 if (!((m_pwndBottomView) && (m_pwndBottomView->IsWindowVisible())))
1804 return FALSE;
1806 CString cmd = _T("/command:resolve /path:\"");
1807 cmd += m_Data.m_mergedFile.GetFilename();
1808 cmd += _T("\" /closeonend:1 /noquestion /skipcheck");
1809 if (!CAppUtils::RunTortoiseProc(cmd))
1810 return FALSE;
1812 return TRUE;
1815 void CMainFrame::OnUpdateMergeNextconflict(CCmdUI *pCmdUI)
1817 pCmdUI->Enable(m_bHasConflicts);
1820 void CMainFrame::OnUpdateMergePreviousconflict(CCmdUI *pCmdUI)
1822 pCmdUI->Enable(m_bHasConflicts);
1825 void CMainFrame::OnMoving(UINT fwSide, LPRECT pRect)
1827 // if the pathfilelist dialog is attached to the mainframe,
1828 // move it along with the mainframe
1829 if (::IsWindow(m_dlgFilePatches.m_hWnd))
1831 RECT patchrect;
1832 m_dlgFilePatches.GetWindowRect(&patchrect);
1833 if (::IsWindow(m_hWnd))
1835 RECT thisrect;
1836 GetWindowRect(&thisrect);
1837 if (patchrect.right == thisrect.left)
1839 m_dlgFilePatches.SetWindowPos(NULL, patchrect.left - (thisrect.left - pRect->left), patchrect.top - (thisrect.top - pRect->top),
1840 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
1844 __super::OnMoving(fwSide, pRect);
1847 void CMainFrame::OnUpdateEditCopy(CCmdUI *pCmdUI)
1849 BOOL bShow = FALSE;
1850 if ((m_pwndBottomView)&&(m_pwndBottomView->HasSelection()))
1851 bShow = TRUE;
1852 if ((m_pwndRightView)&&(m_pwndRightView->HasSelection()))
1853 bShow = TRUE;
1854 if ((m_pwndLeftView)&&(m_pwndLeftView->HasSelection()))
1855 bShow = TRUE;
1856 pCmdUI->Enable(bShow);
1859 void CMainFrame::OnViewSwitchleft()
1861 int ret = IDNO;
1862 if (((m_pwndBottomView)&&(m_pwndBottomView->IsModified())) ||
1863 ((m_pwndRightView)&&(m_pwndRightView->IsModified())))
1865 CString sTemp;
1866 sTemp.LoadString(IDS_ASKFORSAVE);
1867 ret = MessageBox(sTemp, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
1868 if (ret == IDYES)
1870 if (!FileSave())
1871 return;
1874 if ((ret == IDNO)||(ret == IDYES))
1876 CWorkingFile file = m_Data.m_baseFile;
1877 m_Data.m_baseFile = m_Data.m_yourFile;
1878 m_Data.m_yourFile = file;
1879 if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_yourFile.GetFilename())==0)
1881 m_Data.m_mergedFile = m_Data.m_baseFile;
1883 else if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_baseFile.GetFilename())==0)
1885 m_Data.m_mergedFile = m_Data.m_yourFile;
1887 LoadViews();
1891 void CMainFrame::OnUpdateViewSwitchleft(CCmdUI *pCmdUI)
1893 BOOL bEnable = TRUE;
1894 if (m_pwndBottomView)
1896 if (m_pwndBottomView->IsWindowVisible())
1897 bEnable = FALSE;
1899 pCmdUI->Enable(bEnable);
1903 void CMainFrame::OnUpdateViewShowfilelist(CCmdUI *pCmdUI)
1905 if (m_dlgFilePatches.HasFiles())
1907 pCmdUI->Enable(true);
1909 else
1910 pCmdUI->Enable(false);
1911 pCmdUI->SetCheck(m_dlgFilePatches.IsWindowVisible());
1914 void CMainFrame::OnViewShowfilelist()
1916 m_dlgFilePatches.ShowWindow(m_dlgFilePatches.IsWindowVisible() ? SW_HIDE : SW_SHOW);
1919 void CMainFrame::OnEditUndo()
1921 if (CUndo::GetInstance().CanUndo())
1923 CUndo::GetInstance().Undo(m_pwndLeftView, m_pwndRightView, m_pwndBottomView);
1928 void CMainFrame::OnUpdateEditUndo(CCmdUI *pCmdUI)
1930 pCmdUI->Enable(CUndo::GetInstance().CanUndo());
1933 int CMainFrame::CheckForSave()
1935 int ret = IDNO;
1936 if (((m_pwndBottomView)&&(m_pwndBottomView->IsModified())) ||
1937 ((m_pwndRightView)&&(m_pwndRightView->IsModified())))
1939 CString sTemp;
1940 sTemp.LoadString(IDS_WARNMODIFIEDLOOSECHANGES);
1941 ret = MessageBox(sTemp, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
1943 if (ret == IDYES)
1945 FileSave();
1948 return ret;
1951 void CMainFrame::OnViewInlinediffword()
1953 m_bInlineWordDiff = !m_bInlineWordDiff;
1954 if (m_pwndLeftView)
1956 m_pwndLeftView->SetInlineWordDiff(m_bInlineWordDiff);
1957 m_pwndLeftView->Invalidate();
1959 if (m_pwndRightView)
1961 m_pwndRightView->SetInlineWordDiff(m_bInlineWordDiff);
1962 m_pwndRightView->Invalidate();
1964 if (m_pwndBottomView)
1966 m_pwndBottomView->SetInlineWordDiff(m_bInlineWordDiff);
1967 m_pwndBottomView->Invalidate();
1969 m_wndLineDiffBar.Invalidate();
1972 void CMainFrame::OnUpdateViewInlinediffword(CCmdUI *pCmdUI)
1974 pCmdUI->Enable(m_pwndLeftView && m_pwndLeftView->IsWindowVisible() &&
1975 m_pwndRightView && m_pwndRightView->IsWindowVisible());
1976 pCmdUI->SetCheck(m_bInlineWordDiff);
1979 void CMainFrame::OnUpdateEditCreateunifieddifffile(CCmdUI *pCmdUI)
1981 // "create unified diff file" is only available if two files
1982 // are diffed, not three.
1983 bool bEnabled = true;
1984 if ((m_pwndLeftView == NULL)||(!m_pwndLeftView->IsWindowVisible()))
1985 bEnabled = false;
1986 if ((m_pwndRightView == NULL)||(!m_pwndRightView->IsWindowVisible()))
1987 bEnabled = false;
1988 if ((m_pwndBottomView)&&(m_pwndBottomView->IsWindowVisible()))
1989 bEnabled = false;
1990 pCmdUI->Enable(bEnabled);
1993 void CMainFrame::OnEditCreateunifieddifffile()
1995 CString origFile, modifiedFile, outputFile;
1996 // the original file is the one on the left
1997 if (m_pwndLeftView)
1998 origFile = m_pwndLeftView->m_sFullFilePath;
1999 if (m_pwndRightView)
2000 modifiedFile = m_pwndRightView->m_sFullFilePath;
2001 if (!origFile.IsEmpty() && !modifiedFile.IsEmpty())
2003 // ask for the path to save the unified diff file to
2004 OPENFILENAME ofn = {0}; // common dialog box structure
2005 TCHAR szFile[MAX_PATH] = {0}; // buffer for file name
2006 ofn.lStructSize = sizeof(OPENFILENAME);
2007 ofn.lpstrFile = szFile;
2008 ofn.nMaxFile = _countof(szFile);
2009 CString temp;
2010 temp.LoadString(IDS_SAVEASTITLE);
2011 if (!temp.IsEmpty())
2012 ofn.lpstrTitle = temp;
2013 ofn.Flags = OFN_OVERWRITEPROMPT;
2014 CString sFilter;
2015 sFilter.LoadString(IDS_COMMONFILEFILTER);
2016 TCHAR * pszFilters = new TCHAR[sFilter.GetLength()+4];
2017 _tcscpy_s (pszFilters, sFilter.GetLength()+4, sFilter);
2018 // Replace '|' delimiters with '\0's
2019 TCHAR *ptr = pszFilters + _tcslen(pszFilters); //set ptr at the NULL
2020 while (ptr != pszFilters)
2022 if (*ptr == '|')
2023 *ptr = '\0';
2024 ptr--;
2026 ofn.lpstrFilter = pszFilters;
2027 ofn.nFilterIndex = 1;
2029 // Display the Save dialog box.
2030 CString sFile;
2031 if (GetSaveFileName(&ofn)==TRUE)
2033 outputFile = CString(ofn.lpstrFile);
2034 CAppUtils::CreateUnifiedDiff(origFile, modifiedFile, outputFile, true);
2036 delete [] pszFilters;
2040 void CMainFrame::OnUpdateViewLinediffbar(CCmdUI *pCmdUI)
2042 pCmdUI->SetCheck(m_bLineDiff);
2043 pCmdUI->Enable();
2046 void CMainFrame::OnViewLinediffbar()
2048 m_bLineDiff = !m_bLineDiff;
2049 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2050 m_wndLineDiffBar.DocumentUpdated();
2051 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2052 m_wndLocatorBar.DocumentUpdated();
2055 void CMainFrame::OnUpdateViewLocatorbar(CCmdUI *pCmdUI)
2057 pCmdUI->SetCheck(m_bLocatorBar);
2058 pCmdUI->Enable();
2061 void CMainFrame::OnViewLocatorbar()
2063 m_bLocatorBar = !m_bLocatorBar;
2064 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2065 m_wndLocatorBar.DocumentUpdated();
2066 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2067 m_wndLineDiffBar.DocumentUpdated();