Ask what file to save as, defaults to last view
[TortoiseGit.git] / src / TortoiseMerge / MainFrm.cpp
blobacfbf75e523c4109865030b39cf090326328c835
1 // TortoiseGitMerge - a Diff/Patch program
3 // Copyright (C) 2008-2013 - TortoiseGit
4 // Copyright (C) 2004-2012 - TortoiseSVN
5 // Copyright (C) 2012-2013 - Sven Strickroth <email@cs-ware.de>
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software Foundation,
19 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "stdafx.h"
22 #include "TortoiseMerge.h"
23 #include "CustomMFCRibbonButton.h"
24 #include "OpenDlg.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 "SelectFileFilter.h"
37 #include "FormatMessageWrapper.h"
38 #include "TaskbarUUID.h"
39 #include "git2.h"
41 #ifdef _DEBUG
42 #define new DEBUG_NEW
43 #endif
45 CCustomMFCRibbonButton button1;
47 // CMainFrame
48 const UINT TaskBarButtonCreated = RegisterWindowMessage(L"TaskbarButtonCreated");
50 IMPLEMENT_DYNCREATE(CMainFrame, CFrameWndEx)
52 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)
53 ON_WM_CREATE()
54 ON_COMMAND_RANGE(ID_VIEW_APPLOOK_WIN7, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnApplicationLook)
55 ON_UPDATE_COMMAND_UI_RANGE(IDC_STYLEBUTTON, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnUpdateApplicationLook)
56 // Global help commands
57 ON_COMMAND(ID_HELP_FINDER, CFrameWndEx::OnHelpFinder)
58 ON_COMMAND(ID_HELP, CFrameWndEx::OnHelp)
59 ON_COMMAND(ID_CONTEXT_HELP, CFrameWndEx::OnContextHelp)
60 ON_COMMAND(ID_DEFAULT_HELP, CFrameWndEx::OnHelpFinder)
61 ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
62 ON_COMMAND(ID_VIEW_WHITESPACES, OnViewWhitespaces)
63 ON_WM_SIZE()
64 ON_COMMAND(ID_FILE_SAVE, OnFileSave)
65 ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
66 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave)
67 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_AS, OnUpdateFileSaveAs)
68 ON_COMMAND(ID_VIEW_ONEWAYDIFF, OnViewOnewaydiff)
69 ON_UPDATE_COMMAND_UI(ID_VIEW_ONEWAYDIFF, OnUpdateViewOnewaydiff)
70 ON_UPDATE_COMMAND_UI(ID_VIEW_WHITESPACES, OnUpdateViewWhitespaces)
71 ON_COMMAND(ID_VIEW_OPTIONS, OnViewOptions)
72 ON_WM_CLOSE()
73 ON_WM_ACTIVATE()
74 ON_COMMAND(ID_FILE_RELOAD, OnFileReload)
75 ON_COMMAND(ID_VIEW_LINEDOWN, OnViewLinedown)
76 ON_COMMAND(ID_VIEW_LINEUP, OnViewLineup)
77 ON_COMMAND(ID_VIEW_MOVEDBLOCKS, OnViewMovedBlocks)
78 ON_UPDATE_COMMAND_UI(ID_VIEW_MOVEDBLOCKS, OnUpdateViewMovedBlocks)
79 ON_UPDATE_COMMAND_UI(ID_EDIT_MARKASRESOLVED, OnUpdateMergeMarkasresolved)
80 ON_COMMAND(ID_EDIT_MARKASRESOLVED, OnMergeMarkasresolved)
81 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTCONFLICT, OnUpdateMergeNextconflict)
82 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSCONFLICT, OnUpdateMergePreviousconflict)
83 ON_WM_MOVE()
84 ON_WM_MOVING()
85 ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
86 ON_COMMAND(ID_VIEW_SWITCHLEFT, OnViewSwitchleft)
87 ON_UPDATE_COMMAND_UI(ID_VIEW_SWITCHLEFT, OnUpdateViewSwitchleft)
88 ON_COMMAND(ID_VIEW_LINELEFT, &CMainFrame::OnViewLineleft)
89 ON_COMMAND(ID_VIEW_LINERIGHT, &CMainFrame::OnViewLineright)
90 ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWFILELIST, &CMainFrame::OnUpdateViewShowfilelist)
91 ON_COMMAND(ID_VIEW_SHOWFILELIST, &CMainFrame::OnViewShowfilelist)
92 ON_COMMAND(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnEditUseTheirs)
93 ON_COMMAND(ID_EDIT_USEMYBLOCK, &CMainFrame::OnEditUseMine)
94 ON_COMMAND(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnEditUseTheirsThenMine)
95 ON_COMMAND(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnEditUseMineThenTheirs)
96 ON_COMMAND(ID_EDIT_UNDO, &CMainFrame::OnEditUndo)
97 ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, &CMainFrame::OnUpdateEditUndo)
98 ON_COMMAND(ID_EDIT_ENABLE, &CMainFrame::OnEditEnable)
99 ON_UPDATE_COMMAND_UI(ID_EDIT_ENABLE, &CMainFrame::OnUpdateEditEnable)
100 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnUpdateEditUseminethentheirblock)
101 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMYBLOCK, &CMainFrame::OnUpdateEditUsemyblock)
102 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnUpdateEditUsetheirblock)
103 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnUpdateEditUsetheirthenmyblock)
104 ON_COMMAND(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnViewInlinediffword)
105 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnUpdateViewInlinediffword)
106 ON_COMMAND(ID_VIEW_INLINEDIFF, &CMainFrame::OnViewInlinediff)
107 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFF, &CMainFrame::OnUpdateViewInlinediff)
108 ON_UPDATE_COMMAND_UI(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnUpdateEditCreateunifieddifffile)
109 ON_COMMAND(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnEditCreateunifieddifffile)
110 ON_UPDATE_COMMAND_UI(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnUpdateViewLinediffbar)
111 ON_COMMAND(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnViewLinediffbar)
112 ON_UPDATE_COMMAND_UI(ID_VIEW_LOCATORBAR, &CMainFrame::OnUpdateViewLocatorbar)
113 ON_COMMAND(ID_VIEW_LOCATORBAR, &CMainFrame::OnViewLocatorbar)
114 ON_COMMAND(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnEditUseleftblock)
115 ON_UPDATE_COMMAND_UI(ID_USEBLOCKS, &CMainFrame::OnUpdateUseBlock)
116 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnUpdateEditUseleftblock)
117 ON_COMMAND(ID_EDIT_USELEFTFILE, &CMainFrame::OnEditUseleftfile)
118 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTFILE, &CMainFrame::OnUpdateEditUseleftfile)
119 ON_COMMAND(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnEditUseblockfromleftbeforeright)
120 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnUpdateEditUseblockfromleftbeforeright)
121 ON_COMMAND(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnEditUseblockfromrightbeforeleft)
122 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnUpdateEditUseblockfromrightbeforeleft)
123 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTDIFFERENCE, &CMainFrame::OnUpdateNavigateNextdifference)
124 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSDIFFERENCE, &CMainFrame::OnUpdateNavigatePreviousdifference)
125 ON_COMMAND(ID_VIEW_COLLAPSED, &CMainFrame::OnViewCollapsed)
126 ON_UPDATE_COMMAND_UI(ID_VIEW_COLLAPSED, &CMainFrame::OnUpdateViewCollapsed)
127 ON_COMMAND(ID_VIEW_COMPAREWHITESPACES, &CMainFrame::OnViewComparewhitespaces)
128 ON_UPDATE_COMMAND_UI(ID_VIEW_COMPAREWHITESPACES, &CMainFrame::OnUpdateViewComparewhitespaces)
129 ON_COMMAND(ID_VIEW_IGNOREWHITESPACECHANGES, &CMainFrame::OnViewIgnorewhitespacechanges)
130 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREWHITESPACECHANGES, &CMainFrame::OnUpdateViewIgnorewhitespacechanges)
131 ON_COMMAND(ID_VIEW_IGNOREALLWHITESPACECHANGES, &CMainFrame::OnViewIgnoreallwhitespacechanges)
132 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREALLWHITESPACECHANGES, &CMainFrame::OnUpdateViewIgnoreallwhitespacechanges)
133 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTINLINEDIFF, &CMainFrame::OnUpdateNavigateNextinlinediff)
134 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVINLINEDIFF, &CMainFrame::OnUpdateNavigatePrevinlinediff)
135 ON_COMMAND(ID_VIEW_WRAPLONGLINES, &CMainFrame::OnViewWraplonglines)
136 ON_UPDATE_COMMAND_UI(ID_VIEW_WRAPLONGLINES, &CMainFrame::OnUpdateViewWraplonglines)
137 ON_REGISTERED_MESSAGE( TaskBarButtonCreated, CMainFrame::OnTaskbarButtonCreated )
138 ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, &CMainFrame::OnUpdateEditPaste)
139 END_MESSAGE_MAP()
141 static UINT indicators[] =
143 ID_SEPARATOR, // status line indicator
144 ID_INDICATOR_LEFTVIEW,
145 ID_INDICATOR_RIGHTVIEW,
146 ID_INDICATOR_BOTTOMVIEW,
147 ID_INDICATOR_CAPS,
148 ID_INDICATOR_NUM,
152 // CMainFrame construction/destruction
154 CMainFrame::CMainFrame()
155 : m_bInitSplitter(FALSE)
156 , m_bReversedPatch(FALSE)
157 , m_bHasConflicts(false)
158 , m_bInlineWordDiff(true)
159 , m_bLineDiff(true)
160 , m_bLocatorBar(true)
161 , m_nMoveMovesToIgnore(0)
162 , m_pwndLeftView(NULL)
163 , m_pwndRightView(NULL)
164 , m_pwndBottomView(NULL)
165 , m_bReadOnly(false)
166 , m_bBlame(false)
167 , m_bCheckReload(false)
168 , m_bSaveRequired(false)
169 , resolveMsgWnd(0)
170 , resolveMsgWParam(0)
171 , resolveMsgLParam(0)
172 , m_regWrapLines(L"Software\\TortoiseGitMerge\\WrapLines", 0)
173 , m_regViewModedBlocks(L"Software\\TortoiseGitMerge\\ViewMovedBlocks", TRUE)
174 , m_regOneWay(L"Software\\TortoiseGitMerge\\OnePane")
175 , m_regCollapsed(L"Software\\TortoiseGitMerge\\Collapsed", 0)
176 , m_regInlineDiff(L"Software\\TortoiseGitMerge\\DisplayBinDiff", TRUE)
177 , m_regUseRibbons(L"Software\\TortoiseGitMerge\\UseRibbons", TRUE)
179 m_bOneWay = (0 != ((DWORD)m_regOneWay));
180 theApp.m_nAppLook = theApp.GetInt(_T("ApplicationLook"), ID_VIEW_APPLOOK_VS_2005);
181 m_bCollapsed = !!(DWORD)m_regCollapsed;
182 m_bViewMovedBlocks = !!(DWORD)m_regViewModedBlocks;
183 m_bWrapLines = !!(DWORD)m_regWrapLines;
184 m_bInlineDiff = !!m_regInlineDiff;
185 m_bUseRibbons = !!m_regUseRibbons;
186 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
189 CMainFrame::~CMainFrame()
193 LRESULT CMainFrame::OnTaskbarButtonCreated(WPARAM /*wParam*/, LPARAM /*lParam*/)
195 SetUUIDOverlayIcon(m_hWnd);
196 return 0;
200 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
202 if (CFrameWndEx::OnCreate(lpCreateStruct) == -1)
203 return -1;
205 OnApplicationLook(theApp.m_nAppLook);
207 if (m_bUseRibbons)
209 m_wndRibbonBar.Create(this);
210 m_wndRibbonBar.LoadFromResource(IDR_RIBBON);
212 // enable the dialog launch button on the view panel
213 CMFCRibbonCategory * pMainCat = m_wndRibbonBar.GetCategory(1);
214 if (pMainCat)
216 CMFCRibbonPanel * pPanel = pMainCat->GetPanel(3);
217 if (pPanel)
218 pPanel->EnableLaunchButton(ID_VIEW_OPTIONS);
220 // now replace all buttons with our custom button class
221 for (int i = 0; i < m_wndRibbonBar.GetCategoryCount(); ++i)
223 CMFCRibbonCategory * pCat = m_wndRibbonBar.GetCategory(i);
224 for (int j = 0; j < pCat->GetPanelCount(); ++j)
226 CMFCRibbonPanel * pPanel = pCat->GetPanel(j);
227 CList<UINT, UINT> lstItems;
228 pPanel->GetItemIDsList(lstItems);
229 while (!lstItems.IsEmpty())
231 UINT id = lstItems.GetHead();
232 lstItems.RemoveHead();
233 CMFCRibbonButton * pButton = dynamic_cast<CMFCRibbonButton*>(pPanel->FindByID(id));
234 if (pButton)
236 CCustomMFCRibbonButton * c = new CCustomMFCRibbonButton(id, pButton->GetText());
237 pPanel->ReplaceByID(id, c);
243 else
245 if (!m_wndMenuBar.Create(this))
247 TRACE0("Failed to create menubar\n");
248 return -1; // fail to create
250 m_wndMenuBar.SetPaneStyle(m_wndMenuBar.GetPaneStyle() | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY);
252 // prevent the menu bar from taking the focus on activation
253 CMFCPopupMenu::SetForceMenuFocus(FALSE);
254 if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
256 TRACE0("Failed to create toolbar\n");
257 return -1; // fail to create
259 m_wndToolBar.SetWindowText(_T("Main"));
261 if (!m_wndStatusBar.Create(this) ||
262 !m_wndStatusBar.SetIndicators(indicators,
263 _countof(indicators)))
265 TRACE0("Failed to create status bar\n");
266 return -1; // fail to create
269 if (!m_wndLocatorBar.Create(this, IDD_DIFFLOCATOR,
270 CBRS_ALIGN_LEFT | CBRS_SIZE_FIXED, ID_VIEW_LOCATORBAR))
272 TRACE0("Failed to create dialogbar\n");
273 return -1; // fail to create
275 if (!m_wndLineDiffBar.Create(this, IDD_LINEDIFF,
276 CBRS_ALIGN_BOTTOM | CBRS_SIZE_FIXED, ID_VIEW_LINEDIFFBAR))
278 TRACE0("Failed to create dialogbar\n");
279 return -1; // fail to create
281 m_wndLocatorBar.m_pMainFrm = this;
282 m_wndLineDiffBar.m_pMainFrm = this;
284 EnableDocking(CBRS_ALIGN_ANY);
285 if (!m_bUseRibbons)
287 m_wndMenuBar.EnableDocking(CBRS_ALIGN_TOP);
288 m_wndToolBar.EnableDocking(CBRS_ALIGN_TOP);
289 DockPane(&m_wndMenuBar);
290 DockPane(&m_wndToolBar);
292 DockPane(&m_wndLocatorBar);
293 DockPane(&m_wndLineDiffBar);
294 ShowPane(&m_wndLocatorBar, true, false, true);
295 ShowPane(&m_wndLineDiffBar, true, false, true);
297 m_wndLocatorBar.EnableGripper(FALSE);
298 m_wndLineDiffBar.EnableGripper(FALSE);
300 return 0;
303 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
305 if( !CFrameWndEx::PreCreateWindow(cs) )
306 return FALSE;
307 return TRUE;
310 void CMainFrame::OnApplicationLook(UINT id)
312 CWaitCursor wait;
314 theApp.m_nAppLook = id;
316 switch (theApp.m_nAppLook)
318 case ID_VIEW_APPLOOK_WIN_2000:
319 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManager));
320 m_wndRibbonBar.SetWindows7Look(FALSE);
321 break;
323 case ID_VIEW_APPLOOK_OFF_XP:
324 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOfficeXP));
325 m_wndRibbonBar.SetWindows7Look(FALSE);
326 break;
328 case ID_VIEW_APPLOOK_WIN_XP:
329 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
330 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
331 m_wndRibbonBar.SetWindows7Look(FALSE);
332 break;
334 case ID_VIEW_APPLOOK_OFF_2003:
335 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2003));
336 CDockingManager::SetDockingMode(DT_SMART);
337 m_wndRibbonBar.SetWindows7Look(FALSE);
338 break;
340 case ID_VIEW_APPLOOK_VS_2005:
341 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2005));
342 CDockingManager::SetDockingMode(DT_SMART);
343 m_wndRibbonBar.SetWindows7Look(FALSE);
344 break;
346 case ID_VIEW_APPLOOK_VS_2008:
347 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2008));
348 CDockingManager::SetDockingMode(DT_SMART);
349 m_wndRibbonBar.SetWindows7Look(FALSE);
350 break;
352 case ID_VIEW_APPLOOK_WIN7:
353 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows7));
354 CDockingManager::SetDockingMode(DT_SMART);
355 m_wndRibbonBar.SetWindows7Look(TRUE);
356 break;
358 default:
359 switch (theApp.m_nAppLook)
361 case ID_VIEW_APPLOOK_OFF_2007_BLUE:
362 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_LunaBlue);
363 break;
365 case ID_VIEW_APPLOOK_OFF_2007_BLACK:
366 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_ObsidianBlack);
367 break;
369 case ID_VIEW_APPLOOK_OFF_2007_SILVER:
370 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Silver);
371 break;
373 case ID_VIEW_APPLOOK_OFF_2007_AQUA:
374 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Aqua);
375 break;
378 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));
379 CDockingManager::SetDockingMode(DT_SMART);
380 m_wndRibbonBar.SetWindows7Look(FALSE);
383 RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_FRAME | RDW_ERASE);
385 theApp.WriteInt(_T("ApplicationLook"), theApp.m_nAppLook);
388 void CMainFrame::OnUpdateApplicationLook(CCmdUI* pCmdUI)
390 pCmdUI->Enable();
391 pCmdUI->SetRadio(theApp.m_nAppLook == pCmdUI->m_nID);
395 // CMainFrame diagnostics
397 #ifdef _DEBUG
398 void CMainFrame::AssertValid() const
400 CFrameWndEx::AssertValid();
403 void CMainFrame::Dump(CDumpContext& dc) const
405 CFrameWndEx::Dump(dc);
408 #endif //_DEBUG
411 // CMainFrame message handlers
414 BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)
416 CRect cr;
417 GetClientRect( &cr);
420 // split into three panes:
421 // -------------
422 // | | |
423 // | | |
424 // |------------
425 // | |
426 // | |
427 // |------------
429 // create a splitter with 2 rows, 1 column
430 if (!m_wndSplitter.CreateStatic(this, 2, 1))
432 TRACE0("Failed to CreateStaticSplitter\n");
433 return FALSE;
436 // add the second splitter pane - which is a nested splitter with 2 columns
437 if (!m_wndSplitter2.CreateStatic(
438 &m_wndSplitter, // our parent window is the first splitter
439 1, 2, // the new splitter is 1 row, 2 columns
440 WS_CHILD | WS_VISIBLE | WS_BORDER, // style, WS_BORDER is needed
441 m_wndSplitter.IdFromRowCol(0, 0)
442 // new splitter is in the first row, 1st column of first splitter
445 TRACE0("Failed to create nested splitter\n");
446 return FALSE;
448 // add the first splitter pane - the default view in row 0
449 if (!m_wndSplitter.CreateView(1, 0,
450 RUNTIME_CLASS(CBottomView), CSize(cr.Width(), cr.Height()), pContext))
452 TRACE0("Failed to create first pane\n");
453 return FALSE;
455 m_pwndBottomView = (CBottomView *)m_wndSplitter.GetPane(1,0);
456 m_pwndBottomView->m_pwndLocator = &m_wndLocatorBar;
457 m_pwndBottomView->m_pwndLineDiffBar = &m_wndLineDiffBar;
458 m_pwndBottomView->m_pwndStatusBar = &m_wndStatusBar;
459 m_pwndBottomView->m_pMainFrame = this;
461 // now create the two views inside the nested splitter
463 if (!m_wndSplitter2.CreateView(0, 0,
464 RUNTIME_CLASS(CLeftView), CSize(cr.Width()/2, cr.Height()/2), pContext))
466 TRACE0("Failed to create second pane\n");
467 return FALSE;
469 m_pwndLeftView = (CLeftView *)m_wndSplitter2.GetPane(0,0);
470 m_pwndLeftView->m_pwndLocator = &m_wndLocatorBar;
471 m_pwndLeftView->m_pwndLineDiffBar = &m_wndLineDiffBar;
472 m_pwndLeftView->m_pwndStatusBar = &m_wndStatusBar;
473 m_pwndLeftView->m_pMainFrame = this;
475 if (!m_wndSplitter2.CreateView(0, 1,
476 RUNTIME_CLASS(CRightView), CSize(cr.Width()/2, cr.Height()/2), pContext))
478 TRACE0("Failed to create third pane\n");
479 return FALSE;
481 m_pwndRightView = (CRightView *)m_wndSplitter2.GetPane(0,1);
482 m_pwndRightView->m_pwndLocator = &m_wndLocatorBar;
483 m_pwndRightView->m_pwndLineDiffBar = &m_wndLineDiffBar;
484 m_pwndRightView->m_pwndStatusBar = &m_wndStatusBar;
485 m_pwndRightView->m_pMainFrame = this;
486 m_bInitSplitter = TRUE;
488 m_dlgFilePatches.Create(IDD_FILEPATCHES, this);
489 UpdateLayout();
490 return TRUE;
493 // Callback function
494 BOOL CMainFrame::PatchFile(CString sFilePath, bool /*bContentMods*/, bool bPropMods, CString sVersion, BOOL bAutoPatch)
496 CString sDummy;
497 //"dry run" was successful, so save the patched file somewhere...
498 CString sTempFile = CTempFiles::Instance().GetTempFilePathString();
499 CString sRejectedFile;
500 if (m_Patch.GetPatchResult(sFilePath, sTempFile, sRejectedFile) < 0)
502 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
503 return FALSE;
505 sFilePath = m_Patch.GetTargetPath() + _T("\\") + sFilePath;
506 sFilePath.Replace('/', '\\');
507 if (m_bReversedPatch)
509 m_Data.m_baseFile.SetFileName(sTempFile);
510 CString temp;
511 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
512 m_Data.m_baseFile.SetDescriptiveName(temp);
513 m_Data.m_yourFile.SetFileName(sFilePath);
514 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchOriginal);
515 m_Data.m_yourFile.SetDescriptiveName(temp);
516 m_Data.m_theirFile.SetOutOfUse();
517 m_Data.m_mergedFile.SetOutOfUse();
519 else
521 if ((!PathFileExists(sFilePath))||(PathIsDirectory(sFilePath)))
523 m_Data.m_baseFile.SetFileName(CTempFiles::Instance().GetTempFilePathString());
524 m_Data.m_baseFile.CreateEmptyFile();
526 else
528 m_Data.m_baseFile.SetFileName(sFilePath);
530 CString sDescription;
531 sDescription.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchOriginal);
532 m_Data.m_baseFile.SetDescriptiveName(sDescription);
533 m_Data.m_yourFile.SetFileName(sTempFile);
534 CString temp;
535 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
536 m_Data.m_yourFile.SetDescriptiveName(temp);
537 m_Data.m_theirFile.SetOutOfUse();
538 m_Data.m_mergedFile.SetFileName(sFilePath);
539 m_Data.m_bPatchRequired = bPropMods;
541 TRACE(_T("comparing %s\nwith the patched result %s\n"), (LPCTSTR)sFilePath, (LPCTSTR)sTempFile);
543 LoadViews();
544 if (!sRejectedFile.IsEmpty())
546 #if 0 // TGIT TODO
547 // start TortoiseUDiff with the rejected hunks
548 CString sTitle;
549 sTitle.Format(IDS_TITLE_REJECTEDHUNKS, (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath));
550 CAppUtils::StartUnifiedDiffViewer(sRejectedFile, sTitle);
551 #endif
553 if (bAutoPatch)
555 PatchSave();
557 return TRUE;
560 // Callback function
561 BOOL CMainFrame::DiffFiles(CString sURL1, CString sRev1, CString sURL2, CString sRev2)
563 CString tempfile1 = CTempFiles::Instance().GetTempFilePathString();
564 CString tempfile2 = CTempFiles::Instance().GetTempFilePathString();
566 ASSERT(tempfile1.Compare(tempfile2));
568 CString sTemp;
569 CSysProgressDlg progDlg;
570 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev1);
571 progDlg.SetLine(1, sTemp, true);
572 progDlg.SetLine(2, sURL1, true);
573 sTemp.LoadString(IDS_GETVERSIONOFFILETITLE);
574 progDlg.SetTitle(sTemp);
575 progDlg.SetShowProgressBar(true);
576 progDlg.SetAnimation(IDR_DOWNLOAD);
577 progDlg.SetTime(FALSE);
578 progDlg.SetProgress(1,100);
579 progDlg.ShowModeless(this);
580 if (!CAppUtils::GetVersionedFile(sURL1, sRev1, tempfile1, &progDlg, m_hWnd))
582 progDlg.Stop();
583 CString sErrMsg;
584 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev1, (LPCTSTR)sURL1);
585 MessageBox(sErrMsg, NULL, MB_ICONERROR);
586 return FALSE;
588 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev2);
589 progDlg.SetLine(1, sTemp, true);
590 progDlg.SetLine(2, sURL2, true);
591 progDlg.SetProgress(50, 100);
592 if (!CAppUtils::GetVersionedFile(sURL2, sRev2, tempfile2, &progDlg, m_hWnd))
594 progDlg.Stop();
595 CString sErrMsg;
596 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev2, (LPCTSTR)sURL2);
597 MessageBox(sErrMsg, NULL, MB_ICONERROR);
598 return FALSE;
600 progDlg.SetProgress(100,100);
601 progDlg.Stop();
602 CString temp;
603 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL1), (LPCTSTR)sRev1);
604 m_Data.m_baseFile.SetFileName(tempfile1);
605 m_Data.m_baseFile.SetDescriptiveName(temp);
606 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL2), (LPCTSTR)sRev2);
607 m_Data.m_yourFile.SetFileName(tempfile2);
608 m_Data.m_yourFile.SetDescriptiveName(temp);
610 LoadViews();
612 return TRUE;
615 void CMainFrame::OnFileOpen()
617 if (CheckForSave(CHFSR_OPEN)==IDCANCEL)
618 return;
619 COpenDlg dlg;
620 if (dlg.DoModal()!=IDOK)
622 return;
624 m_dlgFilePatches.ShowWindow(SW_HIDE);
625 m_dlgFilePatches.Init(NULL, NULL, CString(), NULL);
626 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,
627 (LPCTSTR)dlg.m_sUnifiedDiffFile, (LPCTSTR)dlg.m_sPatchDirectory);
628 m_Data.m_baseFile.SetFileName(dlg.m_sBaseFile);
629 m_Data.m_theirFile.SetFileName(dlg.m_sTheirFile);
630 m_Data.m_yourFile.SetFileName(dlg.m_sYourFile);
631 m_Data.m_sDiffFile = dlg.m_sUnifiedDiffFile;
632 m_Data.m_sPatchPath = dlg.m_sPatchDirectory;
633 m_Data.m_mergedFile.SetOutOfUse();
634 CCrashReport::Instance().AddFile2(dlg.m_sBaseFile, NULL, _T("Basefile"), CR_AF_MAKE_FILE_COPY);
635 CCrashReport::Instance().AddFile2(dlg.m_sTheirFile, NULL, _T("Theirfile"), CR_AF_MAKE_FILE_COPY);
636 CCrashReport::Instance().AddFile2(dlg.m_sYourFile, NULL, _T("Yourfile"), CR_AF_MAKE_FILE_COPY);
637 CCrashReport::Instance().AddFile2(dlg.m_sUnifiedDiffFile, NULL, _T("Difffile"), CR_AF_MAKE_FILE_COPY);
639 if (!m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && m_Data.IsYourFileInUse())
641 // a diff between two files means "Yours" against "Base", not "Theirs" against "Yours"
642 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
644 if (m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && !m_Data.IsYourFileInUse())
646 // a diff between two files means "Yours" against "Base", not "Theirs" against "Base"
647 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
649 m_bSaveRequired = false;
651 LoadViews();
654 void CMainFrame::ClearViewNamesAndPaths()
656 m_pwndLeftView->m_sWindowName.Empty();
657 m_pwndLeftView->m_sFullFilePath.Empty();
658 m_pwndRightView->m_sWindowName.Empty();
659 m_pwndRightView->m_sFullFilePath.Empty();
660 m_pwndBottomView->m_sWindowName.Empty();
661 m_pwndBottomView->m_sFullFilePath.Empty();
664 bool CMainFrame::LoadViews(int line)
666 m_Data.SetBlame(m_bBlame);
667 m_Data.SetMovedBlocks(m_bViewMovedBlocks);
668 m_bHasConflicts = false;
669 CBaseView* pwndActiveView = m_pwndLeftView;
670 int nOldLine = m_pwndRightView ? m_pwndRightView->m_nTopLine : -1;
671 int nOldLineNumber =
672 m_pwndRightView && m_pwndRightView->m_pViewData ?
673 m_pwndRightView->m_pViewData->GetLineNumber(m_pwndRightView->m_nTopLine) : -1;
674 POINT ptOldCaretPos = {-1, -1};
675 if (m_pwndRightView && m_pwndRightView->IsTarget())
676 ptOldCaretPos = m_pwndRightView->GetCaretPosition();
677 if (m_pwndBottomView && m_pwndBottomView->IsTarget())
678 ptOldCaretPos = m_pwndBottomView->GetCaretPosition();
679 if (!m_Data.Load())
681 m_pwndLeftView->BuildAllScreen2ViewVector();
682 m_pwndLeftView->DocumentUpdated();
683 m_pwndRightView->DocumentUpdated();
684 m_pwndBottomView->DocumentUpdated();
685 m_wndLocatorBar.DocumentUpdated();
686 m_wndLineDiffBar.DocumentUpdated();
687 ::MessageBox(m_hWnd, m_Data.GetError(), _T("TortoiseGitMerge"), MB_ICONERROR);
688 m_Data.m_mergedFile.SetOutOfUse();
689 m_bSaveRequired = false;
690 return false;
692 SetWindowTitle();
693 m_pwndLeftView->BuildAllScreen2ViewVector();
694 m_pwndLeftView->DocumentUpdated();
695 m_pwndRightView->DocumentUpdated();
696 m_pwndBottomView->DocumentUpdated();
697 m_wndLocatorBar.DocumentUpdated();
698 m_wndLineDiffBar.DocumentUpdated();
700 m_pwndLeftView->SetWritable(false);
701 m_pwndLeftView->SetWritableIsChangable(false);
702 m_pwndLeftView->SetTarget(false);
703 m_pwndRightView->SetWritable(false);
704 m_pwndRightView->SetWritableIsChangable(false);
705 m_pwndRightView->SetTarget(false);
706 m_pwndBottomView->SetWritable(false);
707 m_pwndBottomView->SetWritableIsChangable(false);
708 m_pwndBottomView->SetTarget(false);
710 if (!m_Data.IsBaseFileInUse())
712 CSysProgressDlg progDlg;
713 if (m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
715 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
717 else if ((!m_Data.m_sDiffFile.IsEmpty())&&(!m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg)))
719 progDlg.Stop();
720 ClearViewNamesAndPaths();
721 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
722 m_bSaveRequired = false;
723 return false;
725 progDlg.Stop();
726 if (m_Patch.GetNumberOfFiles() > 0)
728 CString betterpatchpath = m_Patch.CheckPatchPath(m_Data.m_sPatchPath);
729 if (betterpatchpath.CompareNoCase(m_Data.m_sPatchPath)!=0)
731 CString msg;
732 msg.Format(IDS_WARNBETTERPATCHPATHFOUND, (LPCTSTR)m_Data.m_sPatchPath, (LPCTSTR)betterpatchpath);
733 if (CMessageBox::Show(m_hWnd, msg, _T("TortoiseGitMerge"), MB_ICONQUESTION | MB_YESNO)==IDYES)
735 m_Data.m_sPatchPath = betterpatchpath;
736 m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg);
739 m_dlgFilePatches.Init(&m_Patch, this, m_Data.m_sPatchPath, this);
740 m_dlgFilePatches.ShowWindow(SW_SHOW);
741 ClearViewNamesAndPaths();
742 if (!m_wndSplitter.IsRowHidden(1))
743 m_wndSplitter.HideRow(1);
744 m_pwndLeftView->SetHidden(FALSE);
745 m_pwndRightView->SetHidden(FALSE);
746 m_pwndBottomView->SetHidden(TRUE);
749 if (m_Data.IsBaseFileInUse() && !m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
751 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
753 if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && !m_Data.IsTheirFileInUse())
755 //diff between YOUR and BASE
756 if (m_bOneWay)
758 if (!m_wndSplitter2.IsColumnHidden(1))
759 m_wndSplitter2.HideColumn(1);
761 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseBoth;
762 m_pwndLeftView->texttype = m_Data.m_arYourFile.GetUnicodeType();
763 m_pwndLeftView->lineendings = m_Data.m_arYourFile.GetLineEndings();
764 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName() + _T(" - ") + m_Data.m_yourFile.GetWindowName();
765 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename() + _T(" - ") + m_Data.m_yourFile.GetFilename();
766 m_pwndLeftView->m_pWorkingFile = &m_Data.m_yourFile;
767 m_pwndLeftView->SetTarget();
768 m_pwndLeftView->SetWritableIsChangable(true);
770 m_pwndRightView->m_pViewData = NULL;
771 m_pwndRightView->m_pWorkingFile = NULL;
772 m_pwndBottomView->m_pViewData = NULL;
773 m_pwndBottomView->m_pWorkingFile = NULL;
775 if (!m_wndSplitter.IsRowHidden(1))
776 m_wndSplitter.HideRow(1);
777 m_pwndLeftView->SetHidden(FALSE);
778 m_pwndRightView->SetHidden(TRUE);
779 m_pwndBottomView->SetHidden(TRUE);
780 ::SetWindowPos(m_pwndLeftView->m_hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
782 else
784 pwndActiveView = m_pwndRightView;
785 if (m_wndSplitter2.IsColumnHidden(1))
786 m_wndSplitter2.ShowColumn();
788 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseLeft;
789 m_pwndLeftView->texttype = m_Data.m_arBaseFile.GetUnicodeType();
790 m_pwndLeftView->lineendings = m_Data.m_arBaseFile.GetLineEndings();
791 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName();
792 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename();
793 m_pwndLeftView->m_sConvertedFilePath = m_Data.m_baseFile.GetConvertedFileName();
794 m_pwndLeftView->m_pWorkingFile = &m_Data.m_baseFile;
795 m_pwndLeftView->SetWritableIsChangable(true);
797 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseRight;
798 m_pwndRightView->texttype = m_Data.m_arYourFile.GetUnicodeType();
799 m_pwndRightView->lineendings = m_Data.m_arYourFile.GetLineEndings();
800 m_pwndRightView->m_sWindowName = m_Data.m_yourFile.GetWindowName();
801 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
802 m_pwndRightView->m_sConvertedFilePath = m_Data.m_yourFile.GetConvertedFileName();
803 m_pwndRightView->m_pWorkingFile = &m_Data.m_yourFile;
804 m_pwndRightView->SetWritable();
805 m_pwndRightView->SetTarget();
807 m_pwndBottomView->m_pViewData = NULL;
808 m_pwndBottomView->m_pWorkingFile = NULL;
810 if (!m_wndSplitter.IsRowHidden(1))
811 m_wndSplitter.HideRow(1);
812 m_pwndLeftView->SetHidden(FALSE);
813 m_pwndRightView->SetHidden(FALSE);
814 m_pwndBottomView->SetHidden(TRUE);
817 else if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
819 //diff between THEIR, YOUR and BASE
820 m_pwndBottomView->SetWritable();
821 m_pwndBottomView->SetTarget();
822 pwndActiveView = m_pwndBottomView;
824 m_pwndLeftView->m_pViewData = &m_Data.m_TheirBaseBoth;
825 m_pwndLeftView->texttype = m_Data.m_arTheirFile.GetUnicodeType();
826 m_pwndLeftView->lineendings = m_Data.m_arTheirFile.GetLineEndings();
827 m_pwndLeftView->m_sWindowName.LoadString(IDS_VIEWTITLE_THEIRS);
828 m_pwndLeftView->m_sWindowName += _T(" - ") + m_Data.m_theirFile.GetWindowName();
829 m_pwndLeftView->m_sFullFilePath = m_Data.m_theirFile.GetFilename();
830 m_pwndLeftView->m_sConvertedFilePath = m_Data.m_theirFile.GetConvertedFileName();
831 m_pwndLeftView->m_pWorkingFile = &m_Data.m_theirFile;
833 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseBoth;
834 m_pwndRightView->texttype = m_Data.m_arYourFile.GetUnicodeType();
835 m_pwndRightView->lineendings = m_Data.m_arYourFile.GetLineEndings();
836 m_pwndRightView->m_sWindowName.LoadString(IDS_VIEWTITLE_MINE);
837 m_pwndRightView->m_sWindowName += _T(" - ") + m_Data.m_yourFile.GetWindowName();
838 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
839 m_pwndRightView->m_sConvertedFilePath = m_Data.m_yourFile.GetConvertedFileName();
840 m_pwndRightView->m_pWorkingFile = &m_Data.m_yourFile;
842 m_pwndBottomView->m_pViewData = &m_Data.m_Diff3;
843 m_pwndBottomView->texttype = m_Data.m_arTheirFile.GetUnicodeType();
844 m_pwndBottomView->lineendings = m_Data.m_arTheirFile.GetLineEndings();
845 m_pwndBottomView->m_sWindowName.LoadString(IDS_VIEWTITLE_MERGED);
846 m_pwndBottomView->m_sWindowName += _T(" - ") + m_Data.m_mergedFile.GetWindowName();
847 m_pwndBottomView->m_sFullFilePath = m_Data.m_mergedFile.GetFilename();
848 m_pwndBottomView->m_sConvertedFilePath = m_Data.m_mergedFile.GetConvertedFileName();
849 m_pwndBottomView->m_pWorkingFile = &m_Data.m_mergedFile;
851 if (m_wndSplitter2.IsColumnHidden(1))
852 m_wndSplitter2.ShowColumn();
853 if (m_wndSplitter.IsRowHidden(1))
854 m_wndSplitter.ShowRow();
855 m_pwndLeftView->SetHidden(FALSE);
856 m_pwndRightView->SetHidden(FALSE);
857 m_pwndBottomView->SetHidden(FALSE);
858 // in three pane view, hide the line diff bar
859 m_wndLineDiffBar.ShowPane(false, false, true);
860 m_wndLineDiffBar.DocumentUpdated();
862 if (!m_Data.m_mergedFile.InUse())
864 m_Data.m_mergedFile.SetFileName(m_Data.m_yourFile.GetFilename());
866 m_pwndLeftView->BuildAllScreen2ViewVector();
867 m_pwndLeftView->DocumentUpdated();
868 m_pwndRightView->DocumentUpdated();
869 m_pwndBottomView->DocumentUpdated();
870 m_wndLocatorBar.DocumentUpdated();
871 m_wndLineDiffBar.DocumentUpdated();
872 UpdateLayout();
873 SetActiveView(pwndActiveView);
875 if ((line >= -1) && m_pwndRightView->m_pViewData)
877 int n = line == -1 ? min( nOldLineNumber, nOldLine ) : line;
878 if (n >= 0)
879 n = m_pwndRightView->m_pViewData->FindLineNumber(n);
880 if (n < 0)
881 n = nOldLine;
883 m_pwndRightView->ScrollAllToLine(n);
884 POINT p;
885 p.x = 0;
886 p.y = n;
887 if ((ptOldCaretPos.x >= 0) || (ptOldCaretPos.y >= 0))
888 p = ptOldCaretPos;
889 m_pwndLeftView->SetCaretPosition(p);
890 m_pwndRightView->SetCaretPosition(p);
891 m_pwndBottomView->SetCaretPosition(p);
892 m_pwndBottomView->ScrollToChar(0);
893 m_pwndLeftView->ScrollToChar(0);
894 m_pwndRightView->ScrollToChar(0);
896 else
898 CRegDWORD regFirstDiff = CRegDWORD(_T("Software\\TortoiseGitMerge\\FirstDiffOnLoad"), TRUE);
899 CRegDWORD regFirstConflict = CRegDWORD(_T("Software\\TortoiseGitMerge\\FirstConflictOnLoad"), TRUE);
900 bool bGoFirstDiff = (0 != (DWORD)regFirstDiff);
901 bool bGoFirstConflict = (0 != (DWORD)regFirstConflict);
902 if (bGoFirstConflict && (CheckResolved()>=0))
904 pwndActiveView->GoToFirstConflict();
905 // Ignore the first few Mouse Move messages, so that the line diff stays on
906 // the first diff line until the user actually moves the mouse
907 m_nMoveMovesToIgnore = MOVESTOIGNORE;
909 else if (bGoFirstDiff)
911 pwndActiveView->GoToFirstDifference();
912 // Ignore the first few Mouse Move messages, so that the line diff stays on
913 // the first diff line until the user actually moves the mouse
914 m_nMoveMovesToIgnore = MOVESTOIGNORE;
916 else
918 // Avoid incorrect rendering of active pane.
919 m_pwndBottomView->ScrollToChar(0);
920 m_pwndLeftView->ScrollToChar(0);
921 m_pwndRightView->ScrollToChar(0);
924 CheckResolved();
925 if (m_bHasConflicts)
926 m_bSaveRequired = false;
927 CUndo::GetInstance().Clear();
928 return true;
931 void CMainFrame::UpdateLayout()
933 if (m_bInitSplitter)
935 m_wndSplitter.CenterSplitter();
936 m_wndSplitter2.CenterSplitter();
940 void CMainFrame::OnSize(UINT nType, int cx, int cy)
942 CFrameWndEx::OnSize(nType, cx, cy);
943 if (m_bInitSplitter && nType != SIZE_MINIMIZED)
945 if (m_wndSplitter.GetSafeHwnd())
947 if (m_wndSplitter.HasOldRowSize() && (m_wndSplitter.GetOldRowCount() == 2))
949 int oldTotal = m_wndSplitter.GetOldRowSize(0) + m_wndSplitter.GetOldRowSize(1);
950 if (oldTotal)
952 int cxCur0, cxCur1, cxMin0, cxMin1;
953 m_wndSplitter.GetRowInfo(0, cxCur0, cxMin0);
954 m_wndSplitter.GetRowInfo(1, cxCur1, cxMin1);
955 cxCur0 = m_wndSplitter.GetOldRowSize(0) * (cxCur0 + cxCur1) / oldTotal;
956 cxCur1 = m_wndSplitter.GetOldRowSize(1) * (cxCur0 + cxCur1) / oldTotal;
957 m_wndSplitter.SetRowInfo(0, cxCur0, 0);
958 m_wndSplitter.SetRowInfo(1, cxCur1, 0);
959 m_wndSplitter.RecalcLayout();
963 if (m_wndSplitter2.HasOldColSize() && (m_wndSplitter2.GetOldColCount() == 2))
965 int oldTotal = m_wndSplitter2.GetOldColSize(0) + m_wndSplitter2.GetOldColSize(1);
966 if (oldTotal)
968 int cyCur0, cyCur1, cyMin0, cyMin1;
969 m_wndSplitter2.GetColumnInfo(0, cyCur0, cyMin0);
970 m_wndSplitter2.GetColumnInfo(1, cyCur1, cyMin1);
971 cyCur0 = m_wndSplitter2.GetOldColSize(0) * (cyCur0 + cyCur1) / oldTotal;
972 cyCur1 = m_wndSplitter2.GetOldColSize(1) * (cyCur0 + cyCur1) / oldTotal;
973 m_wndSplitter2.SetColumnInfo(0, cyCur0, 0);
974 m_wndSplitter2.SetColumnInfo(1, cyCur1, 0);
975 m_wndSplitter2.RecalcLayout();
980 if ((nType == SIZE_RESTORED)&&m_bCheckReload)
982 m_bCheckReload = false;
983 CheckForReload();
986 // workaround for ribbon interface when taskbar is on the left/top
987 if (nType == SIZE_MAXIMIZED)
989 WINDOWPLACEMENT wp;
990 GetWindowPlacement(&wp);
991 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
992 SetWindowPlacement(&wp);
996 void CMainFrame::OnViewWhitespaces()
998 CRegDWORD regViewWhitespaces = CRegDWORD(_T("Software\\TortoiseGitMerge\\ViewWhitespaces"), 1);
999 BOOL bViewWhitespaces = regViewWhitespaces;
1000 if (m_pwndLeftView)
1001 bViewWhitespaces = m_pwndLeftView->m_bViewWhitespace;
1003 bViewWhitespaces = !bViewWhitespaces;
1004 regViewWhitespaces = bViewWhitespaces;
1005 if (m_pwndLeftView)
1007 m_pwndLeftView->m_bViewWhitespace = bViewWhitespaces;
1008 m_pwndLeftView->Invalidate();
1010 if (m_pwndRightView)
1012 m_pwndRightView->m_bViewWhitespace = bViewWhitespaces;
1013 m_pwndRightView->Invalidate();
1015 if (m_pwndBottomView)
1017 m_pwndBottomView->m_bViewWhitespace = bViewWhitespaces;
1018 m_pwndBottomView->Invalidate();
1022 void CMainFrame::OnUpdateViewWhitespaces(CCmdUI *pCmdUI)
1024 if (m_pwndLeftView)
1025 pCmdUI->SetCheck(m_pwndLeftView->m_bViewWhitespace);
1028 void CMainFrame::OnViewCollapsed()
1030 m_regCollapsed = !(DWORD)m_regCollapsed;
1031 m_bCollapsed = !!(DWORD)m_regCollapsed;
1033 OnViewTextFoldUnfold();
1034 m_wndLocatorBar.Invalidate();
1037 void CMainFrame::OnUpdateViewCollapsed(CCmdUI *pCmdUI)
1039 pCmdUI->SetCheck(m_bCollapsed);
1042 void CMainFrame::OnViewWraplonglines()
1044 m_bWrapLines = !(DWORD)m_regWrapLines;
1045 m_regWrapLines = m_bWrapLines;
1047 if (m_pwndLeftView) m_pwndLeftView ->WrapChanged();
1048 if (m_pwndRightView) m_pwndRightView ->WrapChanged();
1049 if (m_pwndBottomView) m_pwndBottomView->WrapChanged();
1050 OnViewTextFoldUnfold();
1051 m_wndLocatorBar.DocumentUpdated();
1054 void CMainFrame::OnViewTextFoldUnfold()
1056 OnViewTextFoldUnfold(m_pwndLeftView);
1057 OnViewTextFoldUnfold(m_pwndRightView);
1058 OnViewTextFoldUnfold(m_pwndBottomView);
1061 void CMainFrame::OnViewTextFoldUnfold(CBaseView* view)
1063 if (view == 0)
1064 return;
1065 view->BuildAllScreen2ViewVector();
1066 view->UpdateCaret();
1067 view->Invalidate();
1068 view->EnsureCaretVisible();
1071 void CMainFrame::OnUpdateViewWraplonglines(CCmdUI *pCmdUI)
1073 pCmdUI->SetCheck(m_bWrapLines);
1076 void CMainFrame::OnViewOnewaydiff()
1078 if (CheckForSave(CHFSR_RELOAD)==IDCANCEL)
1079 return;
1080 m_bOneWay = !m_bOneWay;
1081 ShowDiffBar(!m_bOneWay);
1082 LoadViews(-1);
1085 void CMainFrame::ShowDiffBar(bool bShow)
1087 if (bShow)
1089 // restore the line diff bar
1090 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
1091 m_wndLineDiffBar.DocumentUpdated();
1092 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
1093 m_wndLocatorBar.DocumentUpdated();
1095 else
1097 // in one way view, hide the line diff bar
1098 m_wndLineDiffBar.ShowPane(false, false, true);
1099 m_wndLineDiffBar.DocumentUpdated();
1103 int CMainFrame::CheckResolved()
1105 //only in three way diffs can be conflicts!
1106 m_bHasConflicts = true;
1107 if (m_pwndBottomView->IsWindowVisible())
1109 CViewData* viewdata = m_pwndBottomView->m_pViewData;
1110 if (viewdata)
1112 for (int i=0; i<viewdata->GetCount(); i++)
1114 const DiffStates state = viewdata->GetState(i);
1115 if ((DIFFSTATE_CONFLICTED == state)||(DIFFSTATE_CONFLICTED_IGNORED == state))
1116 return i;
1120 m_bHasConflicts = false;
1121 return -1;
1124 int CMainFrame::SaveFile(const CString& sFilePath)
1126 CViewData * pViewData = NULL;
1127 CFileTextLines * pOriginFile = &m_Data.m_arBaseFile;
1128 if (IsViewGood(m_pwndBottomView))
1130 pViewData = m_pwndBottomView->m_pViewData;
1132 else if (IsViewGood(m_pwndRightView))
1134 pViewData = m_pwndRightView->m_pViewData;
1135 if (m_Data.IsYourFileInUse())
1136 pOriginFile = &m_Data.m_arYourFile;
1137 else if (m_Data.IsTheirFileInUse())
1138 pOriginFile = &m_Data.m_arTheirFile;
1140 else
1142 // nothing to save!
1143 return 1;
1145 Invalidate();
1146 if ((pViewData)&&(pOriginFile))
1148 CFileTextLines file;
1149 pOriginFile->CopySettings(&file);
1150 for (int i=0; i<pViewData->GetCount(); i++)
1152 //only copy non-removed lines
1153 DiffStates state = pViewData->GetState(i);
1154 switch (state)
1156 case DIFFSTATE_CONFLICTED:
1157 case DIFFSTATE_CONFLICTED_IGNORED:
1159 int first = i;
1160 int last = i;
1163 last++;
1164 } while((last<pViewData->GetCount()) && ((pViewData->GetState(last)==DIFFSTATE_CONFLICTED)||(pViewData->GetState(last)==DIFFSTATE_CONFLICTED_IGNORED)));
1165 // TortoiseGitMerge changes here
1166 file.Add(_T("<<<<<<< .mine"), m_pwndRightView->lineendings);
1167 for (int j=first; j<last; j++)
1169 EOL lineending = m_pwndRightView->m_pViewData->GetLineEnding(j);
1170 if (lineending == EOL_NOENDING)
1171 lineending = m_pwndRightView->lineendings;
1172 file.Add(m_pwndRightView->m_pViewData->GetLine(j), lineending);
1174 file.Add(_T("======="), m_pwndRightView->lineendings);
1175 for (int j=first; j<last; j++)
1177 EOL lineending = m_pwndLeftView->m_pViewData->GetLineEnding(j);
1178 if (lineending == EOL_NOENDING)
1179 lineending = m_pwndLeftView->lineendings;
1180 file.Add(m_pwndLeftView->m_pViewData->GetLine(j), lineending);
1182 file.Add(_T(">>>>>>> .theirs"), m_pwndRightView->lineendings);
1183 i = last-1;
1185 break;
1186 case DIFFSTATE_EMPTY:
1187 case DIFFSTATE_CONFLICTEMPTY:
1188 case DIFFSTATE_IDENTICALREMOVED:
1189 case DIFFSTATE_REMOVED:
1190 case DIFFSTATE_THEIRSREMOVED:
1191 case DIFFSTATE_YOURSREMOVED:
1192 case DIFFSTATE_CONFLICTRESOLVEDEMPTY:
1193 // do not save removed lines
1194 break;
1195 default:
1196 file.Add(pViewData->GetLine(i), pViewData->GetLineEnding(i));
1197 break;
1200 if (!file.Save(sFilePath, false, false))
1202 CMessageBox::Show(m_hWnd, file.GetErrorString(), _T("TortoiseGitMerge"), MB_ICONERROR);
1203 return -1;
1205 if (sFilePath == m_Data.m_baseFile.GetFilename())
1207 m_Data.m_baseFile.StoreFileAttributes();
1209 if (sFilePath == m_Data.m_theirFile.GetFilename())
1211 m_Data.m_theirFile.StoreFileAttributes();
1213 if (sFilePath == m_Data.m_yourFile.GetFilename())
1215 m_Data.m_yourFile.StoreFileAttributes();
1217 /*if (sFilePath == m_Data.m_mergedFile.GetFilename())
1219 m_Data.m_mergedFile.StoreFileAttributes();
1220 }//*/
1221 m_dlgFilePatches.SetFileStatusAsPatched(sFilePath);
1222 if (m_pwndBottomView)
1223 m_pwndBottomView->SetModified(FALSE);
1224 if (m_pwndRightView)
1225 m_pwndRightView->SetModified(FALSE);
1226 CUndo::GetInstance().MarkAsOriginalState();
1227 if (file.GetCount() == 1 && file.GetAt(0).IsEmpty() && file.GetLineEnding(0) == EOL_NOENDING)
1228 return 0;
1229 return file.GetCount();
1231 return 1;
1234 void CMainFrame::OnFileSave()
1236 // when mutiple files are set as writable we have to ask what file to save
1237 int nEditableViewCount =
1238 (CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsWritable() ? 1 : 0)
1239 + (CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsWritable() ? 1 : 0)
1240 + (CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsWritable() ? 1 : 0);
1241 bool bLeftIsModified = CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsModified();
1242 bool bRightIsModified = CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsModified();
1243 bool bBottomIsModified = CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsModified();
1244 int nModifiedViewCount =
1245 (bLeftIsModified ? 1 : 0)
1246 + (bRightIsModified ? 1 : 0)
1247 + (bBottomIsModified ? 1 : 0);
1248 if (nEditableViewCount>1)
1250 if (nModifiedViewCount>0)
1252 // both views
1253 UINT ret = IDNO;
1254 CString sSubTitle("Save");
1255 CString sTitle("There are more views set editable.\nWhat view you want to save?");
1257 // show separate questions
1258 // first show question for left view
1259 ret = MessageBox(sTitle, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
1260 if (ret == IDYES)
1262 m_pwndLeftView->SaveFile(SAVE_REMOVED);
1264 // right file is handled old way
1268 else
1270 // only target view was modified
1271 FileSave();
1275 void CMainFrame::PatchSave()
1277 bool bDoesNotExist = !PathFileExists(m_Data.m_mergedFile.GetFilename());
1278 if (m_Data.m_bPatchRequired)
1280 m_Patch.PatchPath(m_Data.m_mergedFile.GetFilename());
1282 if (!PathIsDirectory(m_Data.m_mergedFile.GetFilename()))
1284 int saveret = SaveFile(m_Data.m_mergedFile.GetFilename());
1285 if (saveret==0)
1287 // file was saved with 0 lines, remove it.
1288 m_Patch.RemoveFile(m_Data.m_mergedFile.GetFilename());
1289 // just in case
1290 DeleteFile(m_Data.m_mergedFile.GetFilename());
1292 m_Data.m_mergedFile.StoreFileAttributes();
1293 if (m_Data.m_mergedFile.GetFilename() == m_Data.m_yourFile.GetFilename())
1294 m_Data.m_yourFile.StoreFileAttributes();
1295 if ((bDoesNotExist)&&(DWORD(CRegDWORD(_T("Software\\TortoiseGitMerge\\AutoAdd"), TRUE))))
1297 // call TortoiseProc to add the new file to version control
1298 CString cmd = _T("/command:add /noui /path:\"");
1299 cmd += m_Data.m_mergedFile.GetFilename() + _T("\"");
1300 CAppUtils::RunTortoiseGitProc(cmd);
1305 bool CMainFrame::FileSave(bool bCheckResolved /*=true*/)
1307 if (!m_Data.m_mergedFile.InUse())
1308 return FileSaveAs(bCheckResolved);
1309 // check if the file has the readonly attribute set
1310 bool bDoesNotExist = false;
1311 DWORD fAttribs = GetFileAttributes(m_Data.m_mergedFile.GetFilename());
1312 if ((fAttribs != INVALID_FILE_ATTRIBUTES)&&(fAttribs & FILE_ATTRIBUTE_READONLY))
1313 return FileSaveAs(bCheckResolved);
1314 if (fAttribs == INVALID_FILE_ATTRIBUTES)
1316 bDoesNotExist = (GetLastError() == ERROR_FILE_NOT_FOUND);
1318 if (bCheckResolved && HasConflictsWontKeep())
1319 return false;
1321 if (((DWORD)CRegDWORD(_T("Software\\TortoiseGitMerge\\Backup"))) != 0)
1323 MoveFileEx(m_Data.m_mergedFile.GetFilename(), m_Data.m_mergedFile.GetFilename() + _T(".bak"), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
1325 if (m_Data.m_bPatchRequired)
1327 m_Patch.PatchPath(m_Data.m_mergedFile.GetFilename());
1329 int saveret = SaveFile(m_Data.m_mergedFile.GetFilename());
1330 if (saveret==0)
1332 // file was saved with 0 lines!
1333 // ask the user if the file should be deleted
1334 CString sTemp;
1335 sTemp.Format(IDS_DELETEWHENEMPTY, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
1336 if (CMessageBox::ShowCheck(m_hWnd, sTemp, _T("TortoiseGitMerge"), MB_YESNO, _T("DeleteFileWhenEmpty")) == IDYES)
1338 m_Patch.RemoveFile(m_Data.m_mergedFile.GetFilename());
1339 DeleteFile(m_Data.m_mergedFile.GetFilename());
1342 else if (saveret < 0)
1344 // error while saving the file
1345 return false;
1348 // if we're in conflict resolve mode (three pane view), check if there are no more conflicts
1349 // and if there aren't, ask to mark the file as resolved
1350 if (IsViewGood(m_pwndBottomView) && !m_bHasConflicts)
1352 CString projectRoot;
1353 if (g_GitAdminDir.HasAdminDir(m_Data.m_mergedFile.GetFilename(), false, &projectRoot))
1355 CString subpath = m_Data.m_mergedFile.GetFilename();
1356 subpath.Replace(_T('\\'), _T('/'));
1357 if (subpath.GetLength() >= projectRoot.GetLength())
1359 if (subpath[projectRoot.GetLength()] == _T('/'))
1360 subpath = subpath.Right(subpath.GetLength() - projectRoot.GetLength() - 1);
1361 else
1362 subpath = subpath.Right(subpath.GetLength() - projectRoot.GetLength());
1365 CStringA gitdir = CUnicodeUtils::GetMulti(projectRoot, CP_UTF8);
1366 git_repository *repository = NULL;
1367 git_index *index = NULL;
1368 bool hasConflictInIndex = false;
1371 if (git_repository_open(&repository, gitdir.GetBuffer()))
1373 gitdir.ReleaseBuffer();
1374 break;
1376 gitdir.ReleaseBuffer();
1378 if (git_repository_index(&index, repository))
1379 break;
1381 CStringA path = CUnicodeUtils::GetMulti(subpath, CP_UTF8);
1382 const git_index_entry * entry = git_index_get_bypath(index, path.GetBuffer(), 1);
1383 path.ReleaseBuffer();
1384 hasConflictInIndex = entry != nullptr;
1385 } while(0);
1387 if (index)
1388 git_index_free(index);
1390 if (repository)
1391 git_repository_free(repository);
1393 if (hasConflictInIndex)
1395 CString sTemp;
1396 sTemp.Format(IDS_MARKASRESOLVED, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1397 if (CMessageBox::Show(m_hWnd, sTemp, _T("TortoiseGitMerge"), MB_YESNO | MB_ICONQUESTION) == IDYES)
1398 MarkAsResolved();
1403 m_bSaveRequired = false;
1404 m_Data.m_mergedFile.StoreFileAttributes();
1406 if ((bDoesNotExist)&&(DWORD(CRegDWORD(_T("Software\\TortoiseGitMerge\\AutoAdd"), TRUE))))
1408 // call TortoiseProc to add the new file to version control
1409 CString cmd = _T("/command:add /noui /path:\"");
1410 cmd += m_Data.m_mergedFile.GetFilename() + _T("\"");
1411 if(!CAppUtils::RunTortoiseGitProc(cmd))
1412 return false;
1414 return true;
1417 void CMainFrame::OnFileSaveAs()
1420 // use 1.7 logic - only "target" can be saved
1421 if (IsViewGood(m_pwndBottomView) || IsViewGood(m_pwndRightView))
1423 // 2, 3 panel view was handled
1424 FileSaveAs();
1426 else if (IsViewGood(m_pwndLeftView))
1428 CString sFileName;
1429 if (TryGetFileName(sFileName))
1431 m_pwndLeftView->SaveFileTo(sFileName);
1434 return;
1438 bool CMainFrame::FileSaveAs(bool bCheckResolved /*=true*/)
1440 if (bCheckResolved && HasConflictsWontKeep())
1441 return false;
1443 CString fileName;
1444 if(!TryGetFileName(fileName))
1445 return false;
1447 SaveFile(fileName);
1448 return true;
1451 void CMainFrame::OnUpdateFileSave(CCmdUI *pCmdUI)
1453 BOOL bEnable = FALSE;
1454 if (m_Data.m_mergedFile.InUse())
1456 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1457 bEnable = TRUE;
1458 else if ( (IsViewGood(m_pwndRightView)&&(m_pwndRightView->m_pViewData)) &&
1459 (m_pwndRightView->IsModified() || (m_Data.m_yourFile.GetWindowName().Right(9).Compare(_T(": patched"))==0)) )
1460 bEnable = TRUE;
1462 pCmdUI->Enable(bEnable);
1465 void CMainFrame::OnUpdateFileSaveAs(CCmdUI *pCmdUI)
1467 BOOL bEnable = FALSE;
1468 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1469 bEnable = TRUE;
1470 else if (IsViewGood(m_pwndRightView)&&(m_pwndRightView->m_pViewData))
1471 bEnable = TRUE;
1472 pCmdUI->Enable(bEnable);
1475 void CMainFrame::OnUpdateViewOnewaydiff(CCmdUI *pCmdUI)
1477 pCmdUI->SetCheck(!m_bOneWay);
1478 BOOL bEnable = TRUE;
1479 if (IsViewGood(m_pwndBottomView))
1481 bEnable = FALSE;
1483 pCmdUI->Enable(bEnable);
1486 void CMainFrame::OnViewOptions()
1488 CString sTemp;
1489 sTemp.LoadString(IDS_SETTINGSTITLE);
1490 CSettings dlg(sTemp);
1491 dlg.DoModal();
1492 if (dlg.IsReloadNeeded())
1494 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
1495 return;
1496 CDiffColors::GetInstance().LoadRegistry();
1497 LoadViews();
1498 return;
1500 CDiffColors::GetInstance().LoadRegistry();
1501 if (m_pwndBottomView)
1502 m_pwndBottomView->Invalidate();
1503 if (m_pwndLeftView)
1504 m_pwndLeftView->Invalidate();
1505 if (m_pwndRightView)
1506 m_pwndRightView->Invalidate();
1509 void CMainFrame::OnClose()
1511 if (CheckForSave(CHFSR_CLOSE)!=IDCANCEL)
1513 WINDOWPLACEMENT wp;
1515 // before it is destroyed, save the position of the window
1516 wp.length = sizeof wp;
1518 if (GetWindowPlacement(&wp))
1521 if (IsIconic())
1522 // never restore to Iconic state
1523 wp.showCmd = SW_SHOW ;
1525 if ((wp.flags & WPF_RESTORETOMAXIMIZED) != 0)
1526 // if maximized and maybe iconic restore maximized state
1527 wp.showCmd = SW_SHOWMAXIMIZED ;
1529 // and write it
1530 WriteWindowPlacement(&wp);
1532 __super::OnClose();
1536 void CMainFrame::OnActivate(UINT nValue, CWnd* /*pwnd*/, BOOL /*bActivated?*/)
1538 if (nValue != 0) // activated
1540 if (IsIconic())
1542 m_bCheckReload = TRUE;
1544 else
1545 CheckForReload();
1549 void CMainFrame::OnViewLinedown()
1551 OnViewLineUpDown(1);
1554 void CMainFrame::OnViewLineup()
1556 OnViewLineUpDown(-1);
1559 void CMainFrame::OnViewLineUpDown(int direction)
1561 if (m_pwndLeftView)
1562 m_pwndLeftView->ScrollToLine(m_pwndLeftView->m_nTopLine+direction);
1563 if (m_pwndRightView)
1564 m_pwndRightView->ScrollToLine(m_pwndRightView->m_nTopLine+direction);
1565 if (m_pwndBottomView)
1566 m_pwndBottomView->ScrollToLine(m_pwndBottomView->m_nTopLine+direction);
1567 m_wndLocatorBar.Invalidate();
1568 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1571 void CMainFrame::OnViewLineleft()
1573 OnViewLineLeftRight(-1);
1576 void CMainFrame::OnViewLineright()
1578 OnViewLineLeftRight(1);
1581 void CMainFrame::OnViewLineLeftRight(int direction)
1583 if (m_pwndLeftView)
1584 m_pwndLeftView->ScrollSide(direction);
1585 if (m_pwndRightView)
1586 m_pwndRightView->ScrollSide(direction);
1587 if (m_pwndBottomView)
1588 m_pwndBottomView->ScrollSide(direction);
1591 void CMainFrame::OnEditUseTheirs()
1593 if (m_pwndBottomView)
1594 m_pwndBottomView->UseTheirTextBlock();
1596 void CMainFrame::OnUpdateEditUsetheirblock(CCmdUI *pCmdUI)
1598 pCmdUI->Enable(m_pwndBottomView && m_pwndBottomView->HasSelection());
1601 void CMainFrame::OnEditUseMine()
1603 if (m_pwndBottomView)
1604 m_pwndBottomView->UseMyTextBlock();
1606 void CMainFrame::OnUpdateEditUsemyblock(CCmdUI *pCmdUI)
1608 OnUpdateEditUsetheirblock(pCmdUI);
1611 void CMainFrame::OnEditUseTheirsThenMine()
1613 if (m_pwndBottomView)
1614 m_pwndBottomView->UseTheirAndYourBlock();
1617 void CMainFrame::OnUpdateEditUsetheirthenmyblock(CCmdUI *pCmdUI)
1619 OnUpdateEditUsetheirblock(pCmdUI);
1622 void CMainFrame::OnEditUseMineThenTheirs()
1624 if (m_pwndBottomView)
1625 m_pwndBottomView->UseYourAndTheirBlock();
1628 void CMainFrame::OnUpdateEditUseminethentheirblock(CCmdUI *pCmdUI)
1630 OnUpdateEditUsetheirblock(pCmdUI);
1633 void CMainFrame::OnEditUseleftblock()
1635 if (m_pwndBottomView->IsWindowVisible())
1636 m_pwndBottomView->UseRightBlock();
1637 else
1638 m_pwndRightView->UseLeftBlock();
1641 void CMainFrame::OnUpdateEditUseleftblock(CCmdUI *pCmdUI)
1643 pCmdUI->Enable(IsViewGood(m_pwndRightView) && m_pwndRightView->IsTarget() && m_pwndRightView->HasSelection());
1646 void CMainFrame::OnUpdateUseBlock(CCmdUI *pCmdUI)
1648 pCmdUI->Enable(TRUE);
1651 void CMainFrame::OnEditUseleftfile()
1653 if (m_pwndBottomView->IsWindowVisible())
1654 m_pwndBottomView->UseRightFile();
1655 else
1656 m_pwndRightView->UseLeftFile();
1659 void CMainFrame::OnUpdateEditUseleftfile(CCmdUI *pCmdUI)
1661 pCmdUI->Enable(IsViewGood(m_pwndRightView) && m_pwndRightView->IsTarget());
1664 void CMainFrame::OnEditUseblockfromleftbeforeright()
1666 if (m_pwndRightView)
1667 m_pwndRightView->UseBothLeftFirst();
1670 void CMainFrame::OnUpdateEditUseblockfromleftbeforeright(CCmdUI *pCmdUI)
1672 OnUpdateEditUseleftblock(pCmdUI);
1675 void CMainFrame::OnEditUseblockfromrightbeforeleft()
1677 if (m_pwndRightView)
1678 m_pwndRightView->UseBothRightFirst();
1681 void CMainFrame::OnUpdateEditUseblockfromrightbeforeleft(CCmdUI *pCmdUI)
1683 OnUpdateEditUseleftblock(pCmdUI);
1686 void CMainFrame::OnFileReload()
1688 if (CheckForSave(CHFSR_RELOAD)==IDCANCEL)
1689 return;
1690 CDiffColors::GetInstance().LoadRegistry();
1691 LoadViews(-1);
1694 void CMainFrame::ActivateFrame(int nCmdShow)
1696 // nCmdShow is the normal show mode this frame should be in
1697 // translate default nCmdShow (-1)
1698 if (nCmdShow == -1)
1700 if (!IsWindowVisible())
1701 nCmdShow = SW_SHOWNORMAL;
1702 else if (IsIconic())
1703 nCmdShow = SW_RESTORE;
1706 // bring to top before showing
1707 BringToTop(nCmdShow);
1709 if (nCmdShow != -1)
1711 // show the window as specified
1712 WINDOWPLACEMENT wp;
1714 if ( !ReadWindowPlacement(&wp) )
1716 ShowWindow(nCmdShow);
1718 else
1720 if ( nCmdShow != SW_SHOWNORMAL )
1721 wp.showCmd = nCmdShow;
1723 SetWindowPlacement(&wp);
1726 // and finally, bring to top after showing
1727 BringToTop(nCmdShow);
1731 BOOL CMainFrame::ReadWindowPlacement(WINDOWPLACEMENT * pwp)
1733 CRegString placement = CRegString(_T("Software\\TortoiseGitMerge\\WindowPos"));
1734 CString sPlacement = placement;
1735 if (sPlacement.IsEmpty())
1736 return FALSE;
1737 int nRead = _stscanf_s(sPlacement, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
1738 &pwp->flags, &pwp->showCmd,
1739 &pwp->ptMinPosition.x, &pwp->ptMinPosition.y,
1740 &pwp->ptMaxPosition.x, &pwp->ptMaxPosition.y,
1741 &pwp->rcNormalPosition.left, &pwp->rcNormalPosition.top,
1742 &pwp->rcNormalPosition.right, &pwp->rcNormalPosition.bottom);
1743 if ( nRead != 10 )
1744 return FALSE;
1745 pwp->length = sizeof(WINDOWPLACEMENT);
1747 return TRUE;
1750 void CMainFrame::WriteWindowPlacement(WINDOWPLACEMENT * pwp)
1752 CRegString placement = CRegString(_T("Software\\TortoiseGitMerge\\WindowPos"));
1753 TCHAR szBuffer[_countof("-32767")*8 + sizeof("65535")*2];
1755 _stprintf_s(szBuffer, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
1756 pwp->flags, pwp->showCmd,
1757 pwp->ptMinPosition.x, pwp->ptMinPosition.y,
1758 pwp->ptMaxPosition.x, pwp->ptMaxPosition.y,
1759 pwp->rcNormalPosition.left, pwp->rcNormalPosition.top,
1760 pwp->rcNormalPosition.right, pwp->rcNormalPosition.bottom);
1761 placement = szBuffer;
1764 void CMainFrame::OnUpdateMergeMarkasresolved(CCmdUI *pCmdUI)
1766 if (pCmdUI == NULL)
1767 return;
1768 BOOL bEnable = FALSE;
1769 if ((!m_bReadOnly)&&(m_Data.m_mergedFile.InUse()))
1771 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1773 bEnable = TRUE;
1776 pCmdUI->Enable(bEnable);
1779 void CMainFrame::OnMergeMarkasresolved()
1781 if(HasConflictsWontKeep())
1782 return;
1784 // now check if the file has already been saved and if not, save it.
1785 if (m_Data.m_mergedFile.InUse())
1787 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1789 FileSave(false);
1790 m_bSaveRequired = false;
1793 MarkAsResolved();
1796 BOOL CMainFrame::MarkAsResolved()
1798 if (m_bReadOnly)
1799 return FALSE;
1800 if (!IsViewGood(m_pwndBottomView))
1801 return FALSE;
1803 CString cmd = _T("/command:resolve /path:\"");
1804 cmd += m_Data.m_mergedFile.GetFilename();
1805 cmd += _T("\" /closeonend:1 /noquestion /skipcheck /silent");
1806 if (resolveMsgWnd)
1808 CString s;
1809 s.Format(L" /resolvemsghwnd:%I64d /resolvemsgwparam:%I64d /resolvemsglparam:%I64d", (__int64)resolveMsgWnd, (__int64)resolveMsgWParam, (__int64)resolveMsgLParam);
1810 cmd += s;
1812 if(!CAppUtils::RunTortoiseGitProc(cmd))
1813 return FALSE;
1814 m_bSaveRequired = false;
1815 return TRUE;
1818 void CMainFrame::OnUpdateMergeNextconflict(CCmdUI *pCmdUI)
1820 BOOL bShow = FALSE;
1821 if (HasNextConflict(m_pwndBottomView))
1822 bShow = TRUE;
1823 else if (HasNextConflict(m_pwndRightView))
1824 bShow = TRUE;
1825 else if (HasNextConflict(m_pwndLeftView))
1826 bShow = TRUE;
1827 pCmdUI->Enable(bShow);
1830 bool CMainFrame::HasNextConflict(CBaseView* view)
1832 if (view == 0)
1833 return false;
1834 if (!view->IsTarget())
1835 return false;
1836 return view->HasNextConflict();
1839 void CMainFrame::OnUpdateMergePreviousconflict(CCmdUI *pCmdUI)
1841 BOOL bShow = FALSE;
1842 if (HasPrevConflict(m_pwndBottomView))
1843 bShow = TRUE;
1844 else if (HasPrevConflict(m_pwndRightView))
1845 bShow = TRUE;
1846 else if (HasPrevConflict(m_pwndLeftView))
1847 bShow = TRUE;
1848 pCmdUI->Enable(bShow);
1851 bool CMainFrame::HasPrevConflict(CBaseView* view)
1853 if (view == 0)
1854 return false;
1855 if (!view->IsTarget())
1856 return false;
1857 return view->HasPrevConflict();
1860 void CMainFrame::OnUpdateNavigateNextdifference(CCmdUI *pCmdUI)
1862 CBaseView* baseView = GetActiveBaseView();
1863 BOOL bShow = FALSE;
1864 if (baseView != 0)
1865 bShow = baseView->HasNextDiff();
1866 pCmdUI->Enable(bShow);
1869 void CMainFrame::OnUpdateNavigatePreviousdifference(CCmdUI *pCmdUI)
1871 CBaseView* baseView = GetActiveBaseView();
1872 BOOL bShow = FALSE;
1873 if (baseView != 0)
1874 bShow = baseView->HasPrevDiff();
1875 pCmdUI->Enable(bShow);
1878 void CMainFrame::OnUpdateNavigateNextinlinediff(CCmdUI *pCmdUI)
1880 BOOL bShow = FALSE;
1881 if (HasNextInlineDiff(m_pwndBottomView))
1882 bShow = TRUE;
1883 else if (HasNextInlineDiff(m_pwndRightView))
1884 bShow = TRUE;
1885 else if (HasNextInlineDiff(m_pwndLeftView))
1886 bShow = TRUE;
1887 pCmdUI->Enable(bShow);
1890 bool CMainFrame::HasNextInlineDiff(CBaseView* view)
1892 if (view == 0)
1893 return false;
1894 if (!view->IsTarget())
1895 return false;
1896 return view->HasNextInlineDiff();
1899 void CMainFrame::OnUpdateNavigatePrevinlinediff(CCmdUI *pCmdUI)
1901 BOOL bShow = FALSE;
1902 if (HasPrevInlineDiff(m_pwndBottomView))
1903 bShow = TRUE;
1904 else if (HasPrevInlineDiff(m_pwndRightView))
1905 bShow = TRUE;
1906 else if (HasPrevInlineDiff(m_pwndLeftView))
1907 bShow = TRUE;
1908 pCmdUI->Enable(bShow);
1911 bool CMainFrame::HasPrevInlineDiff(CBaseView* view)
1913 if (view == 0)
1914 return false;
1915 if (!view->IsTarget())
1916 return false;
1917 return view->HasPrevInlineDiff();
1920 void CMainFrame::OnMoving(UINT fwSide, LPRECT pRect)
1922 // if the pathfilelist dialog is attached to the mainframe,
1923 // move it along with the mainframe
1924 if (::IsWindow(m_dlgFilePatches.m_hWnd))
1926 RECT patchrect;
1927 m_dlgFilePatches.GetWindowRect(&patchrect);
1928 if (::IsWindow(m_hWnd))
1930 RECT thisrect;
1931 GetWindowRect(&thisrect);
1932 if (patchrect.right == thisrect.left)
1934 m_dlgFilePatches.SetWindowPos(NULL, patchrect.left - (thisrect.left - pRect->left), patchrect.top - (thisrect.top - pRect->top),
1935 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
1939 __super::OnMoving(fwSide, pRect);
1942 void CMainFrame::OnUpdateEditCopy(CCmdUI *pCmdUI)
1944 BOOL bShow = FALSE;
1945 if ((m_pwndBottomView)&&(m_pwndBottomView->HasSelection()))
1946 bShow = TRUE;
1947 else if ((m_pwndRightView)&&(m_pwndRightView->HasSelection()))
1948 bShow = TRUE;
1949 else if ((m_pwndLeftView)&&(m_pwndLeftView->HasSelection()))
1950 bShow = TRUE;
1951 pCmdUI->Enable(bShow);
1954 void CMainFrame::OnUpdateEditPaste(CCmdUI *pCmdUI)
1956 BOOL bWritable = FALSE;
1957 if ((m_pwndBottomView)&&(m_pwndBottomView->IsWritable()))
1958 bWritable = TRUE;
1959 else if ((m_pwndRightView)&&(m_pwndRightView->IsWritable()))
1960 bWritable = TRUE;
1961 else if ((m_pwndLeftView)&&(m_pwndLeftView->IsWritable()))
1962 bWritable = TRUE;
1963 pCmdUI->Enable(bWritable && ::IsClipboardFormatAvailable(CF_TEXT));
1966 void CMainFrame::OnViewSwitchleft()
1968 if (CheckForSave(CHFSR_SWITCH)!=IDCANCEL)
1970 CWorkingFile file = m_Data.m_baseFile;
1971 m_Data.m_baseFile = m_Data.m_yourFile;
1972 m_Data.m_yourFile = file;
1973 if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_yourFile.GetFilename())==0)
1975 m_Data.m_mergedFile = m_Data.m_baseFile;
1977 else if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_baseFile.GetFilename())==0)
1979 m_Data.m_mergedFile = m_Data.m_yourFile;
1981 LoadViews();
1985 void CMainFrame::OnUpdateViewSwitchleft(CCmdUI *pCmdUI)
1987 BOOL bEnable = !IsViewGood(m_pwndBottomView);
1988 pCmdUI->Enable(bEnable);
1991 void CMainFrame::OnUpdateViewShowfilelist(CCmdUI *pCmdUI)
1993 BOOL bEnable = m_dlgFilePatches.HasFiles();
1994 pCmdUI->Enable(bEnable);
1995 pCmdUI->SetCheck(m_dlgFilePatches.IsWindowVisible());
1998 void CMainFrame::OnViewShowfilelist()
2000 m_dlgFilePatches.ShowWindow(m_dlgFilePatches.IsWindowVisible() ? SW_HIDE : SW_SHOW);
2003 void CMainFrame::OnEditUndo()
2005 if (CUndo::GetInstance().CanUndo())
2007 CUndo::GetInstance().Undo(m_pwndLeftView, m_pwndRightView, m_pwndBottomView);
2011 void CMainFrame::OnUpdateEditUndo(CCmdUI *pCmdUI)
2013 pCmdUI->Enable(CUndo::GetInstance().CanUndo());
2016 void CMainFrame::OnEditEnable()
2018 CBaseView * pView = GetActiveBaseView();
2019 if (pView && pView->IsReadonlyChangable())
2021 bool isReadOnly = pView->IsReadonly();
2022 pView->SetReadonly(!isReadOnly);
2026 void CMainFrame::OnUpdateEditEnable(CCmdUI *pCmdUI)
2028 CBaseView * pView = GetActiveBaseView();
2029 if (pView)
2031 pCmdUI->Enable(pView->IsReadonlyChangable() || !pView->IsReadonly());
2032 pCmdUI->SetCheck(!pView->IsReadonly());
2034 else
2036 pCmdUI->Enable(FALSE);
2040 int CMainFrame::CheckForReload()
2042 static bool bLock = false; //we don't want to check when activated after MessageBox we just created ... this is simple, but we don't need multithread lock
2043 if (bLock)
2045 return IDNO;
2047 bLock = true;
2048 bool bSourceChanged =
2049 m_Data.m_baseFile.HasSourceFileChanged()
2050 || m_Data.m_yourFile.HasSourceFileChanged()
2051 || m_Data.m_theirFile.HasSourceFileChanged()
2052 /*|| m_Data.m_mergedFile.HasSourceFileChanged()*/;
2053 if (!bSourceChanged)
2055 bLock = false;
2056 return IDNO;
2059 int idsMessage = HasUnsavedEdits() ? IDS_WARNMODIFIEDOUTSIDELOOSECHANGES : IDS_WARNMODIFIEDOUTSIDE;
2060 UINT ret = CMessageBox::Show(m_hWnd, idsMessage, IDS_APPNAME, MB_YESNO | MB_ICONQUESTION);
2062 if (ret == IDYES)
2064 CDiffColors::GetInstance().LoadRegistry();
2065 LoadViews(-1);
2067 else
2069 if (IsViewGood(m_pwndBottomView)) // three pane view
2071 /*if (m_Data.m_sourceFile.HasSourceFileChanged())
2072 m_pwndBottomView->SetModified();
2073 if (m_Data.m_mergedFile.HasSourceFileChanged())
2074 m_pwndBottomView->SetModified();//*/
2075 if (m_Data.m_yourFile.HasSourceFileChanged())
2076 m_pwndRightView->SetModified();
2077 if (m_Data.m_theirFile.HasSourceFileChanged())
2078 m_pwndLeftView->SetModified();
2080 else if (IsViewGood(m_pwndRightView)) // two pane view
2082 if (m_Data.m_baseFile.HasSourceFileChanged())
2083 m_pwndLeftView->SetModified();
2084 if (m_Data.m_yourFile.HasSourceFileChanged())
2085 m_pwndRightView->SetModified();
2087 else
2089 if (m_Data.m_yourFile.HasSourceFileChanged())
2090 m_pwndLeftView->SetModified();
2093 // no reload just store updated file time
2094 m_Data.m_baseFile.StoreFileAttributes();
2095 m_Data.m_theirFile.StoreFileAttributes();
2096 m_Data.m_yourFile.StoreFileAttributes();
2097 //m_Data.m_mergedFile.StoreFileAttributes();
2099 bLock = false;
2100 return ret;
2103 int CMainFrame::CheckForSave(ECheckForSaveReason eReason)
2105 CString sTitle(MAKEINTRESOURCE(IDS_WARNMODIFIEDLOOSECHANGES));
2106 // todo use resources instead of constants; we may hold resource id instaed of string
2107 switch (eReason)
2109 case CHFSR_CLOSE:
2110 sTitle = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE)); // use more descriptive IDS_WARNMODIFIEDLOOSECHANGES instead?
2111 break;
2112 case CHFSR_SWITCH:
2113 sTitle = CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDLOOSECHANGES));
2114 break;
2115 case CHFSR_RELOAD:
2116 sTitle = CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDLOOSECHANGES));
2117 break;
2118 case CHFSR_OPTIONS:
2119 sTitle = CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDLOOSECHANGESOPTIONS));
2120 break;
2121 case CHFSR_OPEN:
2122 sTitle = CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDLOOSECHANGES));
2123 break;
2126 // TODO simplify logic, reduce code duplication
2127 if (CBaseView::IsViewGood(m_pwndBottomView))
2129 // three-way diff - by design only bottom can be changed
2131 else if (CBaseView::IsViewGood(m_pwndRightView))
2133 // two-way diff -
2134 // in 1.7 version only right was saved, now left and/or right can be save, so we need to indicate what we are asking to save
2135 if (HasUnsavedEdits(m_pwndLeftView))
2137 // both views
2138 UINT ret = IDNO;
2140 // show separate questions
2141 // first show question for left view
2142 ret = MessageBox(sTitle, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
2143 if (ret == IDCANCEL)
2145 return IDCANCEL;
2147 if (ret == IDYES)
2149 if (m_pwndLeftView->SaveFile(SAVE_REMOVED)<0)
2151 return IDCANCEL;
2154 // right file is handled old way
2157 else
2159 // only secondary (left) view
2161 // otherwise 1.7 behaviour is used
2163 else if (CBaseView::IsViewGood(m_pwndLeftView))
2165 // only one view - only one to save
2166 // 1.7 FileSave don't support this mode
2167 if (HasUnsavedEdits(m_pwndLeftView))
2169 UINT ret = IDNO;
2171 ret = MessageBox(sTitle, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
2174 if (ret == IDYES)
2176 if (m_pwndLeftView->SaveFile(SAVE_REMOVED)<0)
2177 return IDCANCEL;
2180 return IDNO;
2182 else
2184 return IDNO; // nothing to save
2187 UINT ret = IDNO;
2188 if (HasUnsavedEdits())
2190 ret = MessageBox(sTitle, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
2192 if (ret == IDYES)
2194 if (!FileSave())
2195 ret = IDCANCEL;
2198 return ret;
2201 bool CMainFrame::HasUnsavedEdits() const
2203 return HasUnsavedEdits(m_pwndBottomView) || HasUnsavedEdits(m_pwndRightView) || m_bSaveRequired;
2206 bool CMainFrame::HasUnsavedEdits(const CBaseView* view)
2208 if(view == 0)
2209 return false;
2210 return view->IsModified();
2213 bool CMainFrame::IsViewGood(const CBaseView* view)
2215 return CBaseView::IsViewGood(view);
2218 void CMainFrame::OnViewInlinediffword()
2220 m_bInlineWordDiff = !m_bInlineWordDiff;
2221 if (m_pwndLeftView)
2223 m_pwndLeftView->SetInlineWordDiff(m_bInlineWordDiff);
2224 m_pwndLeftView->BuildAllScreen2ViewVector();
2225 m_pwndLeftView->DocumentUpdated();
2227 if (m_pwndRightView)
2229 m_pwndRightView->SetInlineWordDiff(m_bInlineWordDiff);
2230 m_pwndRightView->BuildAllScreen2ViewVector();
2231 m_pwndRightView->DocumentUpdated();
2233 if (m_pwndBottomView)
2235 m_pwndBottomView->SetInlineWordDiff(m_bInlineWordDiff);
2236 m_pwndBottomView->BuildAllScreen2ViewVector();
2237 m_pwndBottomView->DocumentUpdated();
2239 m_wndLineDiffBar.DocumentUpdated();
2242 void CMainFrame::OnUpdateViewInlinediffword(CCmdUI *pCmdUI)
2244 pCmdUI->Enable(m_bInlineDiff && IsViewGood(m_pwndLeftView) && IsViewGood(m_pwndRightView));
2245 pCmdUI->SetCheck(m_bInlineWordDiff);
2248 void CMainFrame::OnViewInlinediff()
2250 m_bInlineDiff = !m_bInlineDiff;
2251 if (m_pwndLeftView)
2253 m_pwndLeftView->SetInlineDiff(m_bInlineDiff);
2254 m_pwndLeftView->BuildAllScreen2ViewVector();
2255 m_pwndLeftView->DocumentUpdated();
2257 if (m_pwndRightView)
2259 m_pwndRightView->SetInlineDiff(m_bInlineDiff);
2260 m_pwndRightView->BuildAllScreen2ViewVector();
2261 m_pwndRightView->DocumentUpdated();
2263 if (m_pwndBottomView)
2265 m_pwndBottomView->SetInlineDiff(m_bInlineDiff);
2266 m_pwndBottomView->BuildAllScreen2ViewVector();
2267 m_pwndBottomView->DocumentUpdated();
2269 m_wndLineDiffBar.DocumentUpdated();
2272 void CMainFrame::OnUpdateViewInlinediff(CCmdUI *pCmdUI)
2274 pCmdUI->Enable(IsViewGood(m_pwndLeftView) && IsViewGood(m_pwndRightView));
2275 pCmdUI->SetCheck(m_bInlineDiff);
2278 void CMainFrame::OnUpdateEditCreateunifieddifffile(CCmdUI *pCmdUI)
2280 // "create unified diff file" is only available if two files
2281 // are diffed, not three.
2282 bool bEnabled = true;
2283 if (!IsViewGood(m_pwndLeftView))
2284 bEnabled = false;
2285 else if (!IsViewGood(m_pwndRightView))
2286 bEnabled = false;
2287 else if (IsViewGood(m_pwndBottomView)) //no negation here
2288 bEnabled = false;
2289 pCmdUI->Enable(bEnabled);
2292 void CMainFrame::OnEditCreateunifieddifffile()
2294 CString origFile, modifiedFile;
2295 // the original file is the one on the left
2296 if (m_pwndLeftView)
2297 origFile = m_pwndLeftView->m_sFullFilePath;
2298 if (m_pwndRightView)
2299 modifiedFile = m_pwndRightView->m_sFullFilePath;
2300 if (origFile.IsEmpty() || modifiedFile.IsEmpty())
2301 return;
2303 CString outputFile;
2304 if(!TryGetFileName(outputFile))
2305 return;
2307 CAppUtils::CreateUnifiedDiff(origFile, modifiedFile, outputFile, true);
2310 void CMainFrame::OnUpdateViewLinediffbar(CCmdUI *pCmdUI)
2312 pCmdUI->SetCheck(m_bLineDiff);
2313 pCmdUI->Enable();
2316 void CMainFrame::OnViewLinediffbar()
2318 m_bLineDiff = !m_bLineDiff;
2319 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2320 m_wndLineDiffBar.DocumentUpdated();
2321 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2322 m_wndLocatorBar.DocumentUpdated();
2325 void CMainFrame::OnUpdateViewLocatorbar(CCmdUI *pCmdUI)
2327 pCmdUI->SetCheck(m_bLocatorBar);
2328 pCmdUI->Enable();
2331 void CMainFrame::OnViewLocatorbar()
2333 m_bLocatorBar = !m_bLocatorBar;
2334 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2335 m_wndLocatorBar.DocumentUpdated();
2336 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2337 m_wndLineDiffBar.DocumentUpdated();
2340 void CMainFrame::OnViewComparewhitespaces()
2342 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2343 return;
2344 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2345 regIgnoreWS = 0;
2346 LoadViews(-1);
2349 void CMainFrame::OnUpdateViewComparewhitespaces(CCmdUI *pCmdUI)
2351 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2352 DWORD dwIgnoreWS = regIgnoreWS;
2353 pCmdUI->SetCheck(dwIgnoreWS == 0);
2356 void CMainFrame::OnViewIgnorewhitespacechanges()
2358 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2359 return;
2360 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2361 regIgnoreWS = 2;
2362 LoadViews(-1);
2365 void CMainFrame::OnUpdateViewIgnorewhitespacechanges(CCmdUI *pCmdUI)
2367 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2368 DWORD dwIgnoreWS = regIgnoreWS;
2369 pCmdUI->SetCheck(dwIgnoreWS == 2);
2372 void CMainFrame::OnViewIgnoreallwhitespacechanges()
2374 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2375 return;
2376 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2377 regIgnoreWS = 1;
2378 LoadViews(-1);
2381 void CMainFrame::OnUpdateViewIgnoreallwhitespacechanges(CCmdUI *pCmdUI)
2383 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2384 DWORD dwIgnoreWS = regIgnoreWS;
2385 pCmdUI->SetCheck(dwIgnoreWS == 1);
2388 void CMainFrame::OnViewMovedBlocks()
2390 m_bViewMovedBlocks = !(DWORD)m_regViewModedBlocks;
2391 m_regViewModedBlocks = m_bViewMovedBlocks;
2392 LoadViews(-1);
2395 void CMainFrame::OnUpdateViewMovedBlocks(CCmdUI *pCmdUI)
2397 pCmdUI->SetCheck(m_bViewMovedBlocks);
2398 BOOL bEnable = TRUE;
2399 if (IsViewGood(m_pwndBottomView))
2401 bEnable = FALSE;
2403 pCmdUI->Enable(bEnable);
2406 bool CMainFrame::HasConflictsWontKeep()
2408 const int nConflictLine = CheckResolved();
2409 if (nConflictLine < 0)
2410 return false;
2412 CString sTemp;
2413 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
2414 if (MessageBox(sTemp, 0, MB_ICONERROR | MB_YESNO)==IDYES)
2415 return false;
2417 if (m_pwndBottomView)
2418 m_pwndBottomView->GoToLine(nConflictLine);
2419 return true;
2422 bool CMainFrame::TryGetFileName(CString& result)
2424 return CCommonAppUtils::FileOpenSave(result, NULL, IDS_SAVEASTITLE, IDS_COMMONFILEFILTER, false, m_hWnd);
2427 CBaseView* CMainFrame::GetActiveBaseView() const
2429 CView* activeView = GetActiveView();
2430 CBaseView* activeBase = dynamic_cast<CBaseView*>( activeView );
2431 return activeBase;
2434 void CMainFrame::SetWindowTitle()
2436 // try to find a suitable window title
2437 CString sYour = m_Data.m_yourFile.GetDescriptiveName();
2438 if (sYour.Find(_T(" - "))>=0)
2439 sYour = sYour.Left(sYour.Find(_T(" - ")));
2440 if (sYour.Find(_T(" : "))>=0)
2441 sYour = sYour.Left(sYour.Find(_T(" : ")));
2442 CString sTheir = m_Data.m_theirFile.GetDescriptiveName();
2443 if (sTheir.IsEmpty())
2444 sTheir = m_Data.m_baseFile.GetDescriptiveName();
2445 if (sTheir.Find(_T(" - "))>=0)
2446 sTheir = sTheir.Left(sTheir.Find(_T(" - ")));
2447 if (sTheir.Find(_T(" : "))>=0)
2448 sTheir = sTheir.Left(sTheir.Find(_T(" : ")));
2450 if (!sYour.IsEmpty() && !sTheir.IsEmpty())
2452 if (sYour.CompareNoCase(sTheir)==0)
2453 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
2454 else if ((sYour.GetLength() < 10) &&
2455 (sTheir.GetLength() < 10))
2456 SetWindowText(sYour + _T(" - ") + sTheir + _T(" - TortoiseGitMerge"));
2457 else
2459 // we have two very long descriptive texts here, which
2460 // means we have to find a way to use them as a window
2461 // title in a shorter way.
2462 // for simplicity, we just use the one from "yourfile"
2463 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
2466 else if (!sYour.IsEmpty())
2467 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
2468 else if (!sTheir.IsEmpty())
2469 SetWindowText(sTheir + _T(" - TortoiseGitMerge"));
2470 else
2471 SetWindowText(L"TortoiseGitMerge");