Fix checkout failure when running clone with libgit2 without specifying local branch...
[TortoiseGit.git] / src / TortoiseMerge / MainFrm.cpp
blob2fd086bed514d4d6a03ef5146ea1dbeb939c0dc8
1 // TortoiseGitMerge - a Diff/Patch program
3 // Copyright (C) 2008-2014 - TortoiseGit
4 // Copyright (C) 2004-2014 - TortoiseSVN
5 // Copyright (C) 2012-2014 - 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 "SelectFileFilter.h"
36 #include "FormatMessageWrapper.h"
37 #include "TaskbarUUID.h"
38 #include "git2.h"
39 #include "SmartLibgit2Ref.h" // needs to be included after git2.h
40 #include "RegexFiltersDlg.h"
41 #include "SysInfo.h"
43 #ifdef _DEBUG
44 #define new DEBUG_NEW
45 #endif
47 CCustomMFCRibbonButton button1;
49 // CMainFrame
50 const UINT TaskBarButtonCreated = RegisterWindowMessage(L"TaskbarButtonCreated");
51 #define IDT_RELOADCHECKTIMER 123
53 IMPLEMENT_DYNCREATE(CMainFrame, CFrameWndEx)
55 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)
56 ON_WM_CREATE()
57 ON_COMMAND_RANGE(ID_VIEW_APPLOOK_WIN7, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnApplicationLook)
58 ON_UPDATE_COMMAND_UI_RANGE(IDC_STYLEBUTTON, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnUpdateApplicationLook)
59 // Global help commands
60 ON_COMMAND(ID_HELP_FINDER, CFrameWndEx::OnHelpFinder)
61 ON_COMMAND(ID_HELP, CFrameWndEx::OnHelp)
62 ON_COMMAND(ID_CONTEXT_HELP, CFrameWndEx::OnContextHelp)
63 ON_COMMAND(ID_DEFAULT_HELP, CFrameWndEx::OnHelpFinder)
64 ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
65 ON_COMMAND(ID_VIEW_WHITESPACES, OnViewWhitespaces)
66 ON_WM_SIZE()
67 ON_COMMAND(ID_FILE_SAVE, OnFileSave)
68 ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
69 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave)
70 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_AS, OnUpdateFileSaveAs)
71 ON_COMMAND(ID_VIEW_ONEWAYDIFF, OnViewOnewaydiff)
72 ON_UPDATE_COMMAND_UI(ID_VIEW_ONEWAYDIFF, OnUpdateViewOnewaydiff)
73 ON_UPDATE_COMMAND_UI(ID_VIEW_WHITESPACES, OnUpdateViewWhitespaces)
74 ON_COMMAND(ID_VIEW_OPTIONS, OnViewOptions)
75 ON_WM_CLOSE()
76 ON_WM_ACTIVATE()
77 ON_COMMAND(ID_FILE_RELOAD, OnFileReload)
78 ON_COMMAND(ID_VIEW_LINEDOWN, OnViewLinedown)
79 ON_COMMAND(ID_VIEW_LINEUP, OnViewLineup)
80 ON_COMMAND(ID_VIEW_MOVEDBLOCKS, OnViewMovedBlocks)
81 ON_UPDATE_COMMAND_UI(ID_VIEW_MOVEDBLOCKS, OnUpdateViewMovedBlocks)
82 ON_UPDATE_COMMAND_UI(ID_EDIT_MARKASRESOLVED, OnUpdateMergeMarkasresolved)
83 ON_COMMAND(ID_EDIT_MARKASRESOLVED, OnMergeMarkasresolved)
84 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTCONFLICT, OnUpdateMergeNextconflict)
85 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSCONFLICT, OnUpdateMergePreviousconflict)
86 ON_WM_MOVE()
87 ON_WM_MOVING()
88 ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
89 ON_COMMAND(ID_VIEW_SWITCHLEFT, OnViewSwitchleft)
90 ON_UPDATE_COMMAND_UI(ID_VIEW_SWITCHLEFT, OnUpdateViewSwitchleft)
91 ON_COMMAND(ID_VIEW_LINELEFT, &CMainFrame::OnViewLineleft)
92 ON_COMMAND(ID_VIEW_LINERIGHT, &CMainFrame::OnViewLineright)
93 ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWFILELIST, &CMainFrame::OnUpdateViewShowfilelist)
94 ON_COMMAND(ID_VIEW_SHOWFILELIST, &CMainFrame::OnViewShowfilelist)
95 ON_COMMAND(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnEditUseTheirs)
96 ON_COMMAND(ID_EDIT_USEMYBLOCK, &CMainFrame::OnEditUseMine)
97 ON_COMMAND(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnEditUseTheirsThenMine)
98 ON_COMMAND(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnEditUseMineThenTheirs)
99 ON_COMMAND(ID_EDIT_UNDO, &CMainFrame::OnEditUndo)
100 ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, &CMainFrame::OnUpdateEditUndo)
101 ON_COMMAND(ID_EDIT_ENABLE, &CMainFrame::OnEditEnable)
102 ON_UPDATE_COMMAND_UI(ID_EDIT_ENABLE, &CMainFrame::OnUpdateEditEnable)
103 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnUpdateEditUseminethentheirblock)
104 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMYBLOCK, &CMainFrame::OnUpdateEditUsemyblock)
105 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnUpdateEditUsetheirblock)
106 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnUpdateEditUsetheirthenmyblock)
107 ON_COMMAND(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnViewInlinediffword)
108 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnUpdateViewInlinediffword)
109 ON_COMMAND(ID_VIEW_INLINEDIFF, &CMainFrame::OnViewInlinediff)
110 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFF, &CMainFrame::OnUpdateViewInlinediff)
111 ON_UPDATE_COMMAND_UI(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnUpdateEditCreateunifieddifffile)
112 ON_COMMAND(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnEditCreateunifieddifffile)
113 ON_UPDATE_COMMAND_UI(ID_EDIT_TABSPACE, &CMainFrame::OnUpdateEditTabspace)
114 ON_COMMAND(ID_EDIT_TABSPACE, &CMainFrame::OnEditTabspace)
115 ON_UPDATE_COMMAND_UI(ID_EDIT_SMARTTAB, &CMainFrame::OnUpdateEditSmartTab)
116 ON_COMMAND(ID_EDIT_SMARTTAB, &CMainFrame::OnEditSmartTab)
117 ON_UPDATE_COMMAND_UI(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnUpdateViewLinediffbar)
118 ON_COMMAND(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnViewLinediffbar)
119 ON_UPDATE_COMMAND_UI(ID_VIEW_LOCATORBAR, &CMainFrame::OnUpdateViewLocatorbar)
120 ON_COMMAND(ID_VIEW_LOCATORBAR, &CMainFrame::OnViewLocatorbar)
121 ON_COMMAND(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnEditUseleftblock)
122 ON_UPDATE_COMMAND_UI(ID_USEBLOCKS, &CMainFrame::OnUpdateUseBlock)
123 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnUpdateEditUseleftblock)
124 ON_COMMAND(ID_EDIT_USELEFTFILE, &CMainFrame::OnEditUseleftfile)
125 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTFILE, &CMainFrame::OnUpdateEditUseleftfile)
126 ON_COMMAND(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnEditUseblockfromleftbeforeright)
127 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnUpdateEditUseblockfromleftbeforeright)
128 ON_COMMAND(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnEditUseblockfromrightbeforeleft)
129 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnUpdateEditUseblockfromrightbeforeleft)
130 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTDIFFERENCE, &CMainFrame::OnUpdateNavigateNextdifference)
131 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSDIFFERENCE, &CMainFrame::OnUpdateNavigatePreviousdifference)
132 ON_COMMAND(ID_VIEW_COLLAPSED, &CMainFrame::OnViewCollapsed)
133 ON_UPDATE_COMMAND_UI(ID_VIEW_COLLAPSED, &CMainFrame::OnUpdateViewCollapsed)
134 ON_COMMAND(ID_VIEW_COMPAREWHITESPACES, &CMainFrame::OnViewComparewhitespaces)
135 ON_UPDATE_COMMAND_UI(ID_VIEW_COMPAREWHITESPACES, &CMainFrame::OnUpdateViewComparewhitespaces)
136 ON_COMMAND(ID_VIEW_IGNOREWHITESPACECHANGES, &CMainFrame::OnViewIgnorewhitespacechanges)
137 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREWHITESPACECHANGES, &CMainFrame::OnUpdateViewIgnorewhitespacechanges)
138 ON_COMMAND(ID_VIEW_IGNOREALLWHITESPACECHANGES, &CMainFrame::OnViewIgnoreallwhitespacechanges)
139 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREALLWHITESPACECHANGES, &CMainFrame::OnUpdateViewIgnoreallwhitespacechanges)
140 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTINLINEDIFF, &CMainFrame::OnUpdateNavigateNextinlinediff)
141 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVINLINEDIFF, &CMainFrame::OnUpdateNavigatePrevinlinediff)
142 ON_COMMAND(ID_VIEW_WRAPLONGLINES, &CMainFrame::OnViewWraplonglines)
143 ON_UPDATE_COMMAND_UI(ID_VIEW_WRAPLONGLINES, &CMainFrame::OnUpdateViewWraplonglines)
144 ON_REGISTERED_MESSAGE( TaskBarButtonCreated, CMainFrame::OnTaskbarButtonCreated )
145 ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, &CMainFrame::OnUpdateEditPaste)
146 ON_COMMAND(ID_INDICATOR_LEFTVIEW, &CMainFrame::OnIndicatorLeftview)
147 ON_COMMAND(ID_INDICATOR_RIGHTVIEW, &CMainFrame::OnIndicatorRightview)
148 ON_COMMAND(ID_INDICATOR_BOTTOMVIEW, &CMainFrame::OnIndicatorBottomview)
149 ON_WM_TIMER()
150 ON_COMMAND(ID_VIEW_IGNORECOMMENTS, &CMainFrame::OnViewIgnorecomments)
151 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNORECOMMENTS, &CMainFrame::OnUpdateViewIgnorecomments)
152 ON_COMMAND_RANGE(ID_REGEXFILTER, ID_REGEXFILTER+400, &CMainFrame::OnRegexfilter)
153 ON_UPDATE_COMMAND_UI_RANGE(ID_REGEXFILTER, ID_REGEXFILTER+400, &CMainFrame::OnUpdateViewRegexFilter)
154 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOENCODING, &CMainFrame::OnDummyEnabled)
155 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOENCODING, &CMainFrame::OnDummyEnabled)
156 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOENCODING, &CMainFrame::OnDummyEnabled)
157 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOEOL, &CMainFrame::OnDummyEnabled)
158 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOEOL, &CMainFrame::OnDummyEnabled)
159 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOEOL, &CMainFrame::OnDummyEnabled)
160 ON_COMMAND_RANGE(ID_INDICATOR_LEFTENCODINGSTART, ID_INDICATOR_LEFTENCODINGSTART+19, &CMainFrame::OnEncodingLeft)
161 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTENCODINGSTART, ID_INDICATOR_RIGHTENCODINGSTART+19, &CMainFrame::OnEncodingRight)
162 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMENCODINGSTART, ID_INDICATOR_BOTTOMENCODINGSTART+19, &CMainFrame::OnEncodingBottom)
163 ON_COMMAND_RANGE(ID_INDICATOR_LEFTEOLSTART, ID_INDICATOR_LEFTEOLSTART+19, &CMainFrame::OnEOLLeft)
164 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTEOLSTART, ID_INDICATOR_RIGHTEOLSTART+19, &CMainFrame::OnEOLRight)
165 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMEOLSTART, ID_INDICATOR_BOTTOMEOLSTART+19, &CMainFrame::OnEOLBottom)
166 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTENCODINGSTART, ID_INDICATOR_LEFTENCODINGSTART+19, &CMainFrame::OnUpdateEncodingLeft)
167 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTENCODINGSTART, ID_INDICATOR_RIGHTENCODINGSTART+19, &CMainFrame::OnUpdateEncodingRight)
168 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMENCODINGSTART, ID_INDICATOR_BOTTOMENCODINGSTART+19, &CMainFrame::OnUpdateEncodingBottom)
169 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTEOLSTART, ID_INDICATOR_LEFTEOLSTART+19, &CMainFrame::OnUpdateEOLLeft)
170 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTEOLSTART, ID_INDICATOR_RIGHTEOLSTART+19, &CMainFrame::OnUpdateEOLRight)
171 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMEOLSTART, ID_INDICATOR_BOTTOMEOLSTART+19, &CMainFrame::OnUpdateEOLBottom)
172 END_MESSAGE_MAP()
174 static UINT indicators[] =
176 ID_SEPARATOR, // status line indicator
177 ID_INDICATOR_LEFTVIEW,
178 ID_INDICATOR_RIGHTVIEW,
179 ID_INDICATOR_BOTTOMVIEW,
180 ID_INDICATOR_CAPS,
181 ID_INDICATOR_NUM,
185 // CMainFrame construction/destruction
187 CMainFrame::CMainFrame()
188 : m_bInitSplitter(FALSE)
189 , m_bReversedPatch(FALSE)
190 , m_bHasConflicts(false)
191 , m_bInlineWordDiff(true)
192 , m_bLineDiff(true)
193 , m_bLocatorBar(true)
194 , m_nMoveMovesToIgnore(0)
195 , m_pwndLeftView(NULL)
196 , m_pwndRightView(NULL)
197 , m_pwndBottomView(NULL)
198 , m_bReadOnly(false)
199 , m_bBlame(false)
200 , m_bCheckReload(false)
201 , m_bSaveRequired(false)
202 , m_bSaveRequiredOnConflicts(false)
203 , resolveMsgWnd(0)
204 , resolveMsgWParam(0)
205 , resolveMsgLParam(0)
206 , m_regWrapLines(L"Software\\TortoiseGitMerge\\WrapLines", 0)
207 , m_regViewModedBlocks(L"Software\\TortoiseGitMerge\\ViewMovedBlocks", TRUE)
208 , m_regOneWay(L"Software\\TortoiseGitMerge\\OnePane")
209 , m_regCollapsed(L"Software\\TortoiseGitMerge\\Collapsed", 0)
210 , m_regInlineDiff(L"Software\\TortoiseGitMerge\\DisplayBinDiff", TRUE)
211 , m_regUseRibbons(L"Software\\TortoiseGitMerge\\UseRibbons", TRUE)
212 , m_regUseTaskDialog(L"Software\\TortoiseGitMerge\\UseTaskDialog", TRUE)
213 , m_regIgnoreComments(_T("Software\\TortoiseGitMerge\\IgnoreComments"), FALSE)
214 , m_regexIndex(-1)
215 , m_regTabMode(L"Software\\TortoiseGitMerge\\TabMode", TABMODE_NONE)
217 m_bOneWay = (0 != ((DWORD)m_regOneWay));
218 theApp.m_nAppLook = theApp.GetInt(_T("ApplicationLook"), ID_VIEW_APPLOOK_VS_2005);
219 m_bCollapsed = !!(DWORD)m_regCollapsed;
220 m_bViewMovedBlocks = !!(DWORD)m_regViewModedBlocks;
221 m_bWrapLines = !!(DWORD)m_regWrapLines;
222 m_bInlineDiff = !!m_regInlineDiff;
223 m_bUseRibbons = !!m_regUseRibbons;
224 #if _WIN64
225 if (SysInfo::Instance().IsXP())
226 m_bUseRibbons = FALSE;
227 #endif
228 m_bUseTaskDialog = CTaskDialog::IsSupported() && (DWORD)m_regUseTaskDialog;
229 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
232 CMainFrame::~CMainFrame()
236 LRESULT CMainFrame::OnTaskbarButtonCreated(WPARAM /*wParam*/, LPARAM /*lParam*/)
238 SetUUIDOverlayIcon(m_hWnd);
239 return 0;
243 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
245 if (CFrameWndEx::OnCreate(lpCreateStruct) == -1)
246 return -1;
248 OnApplicationLook(theApp.m_nAppLook);
250 if (m_bUseRibbons)
252 m_wndRibbonBar.Create(this);
253 m_wndRibbonBar.LoadFromResource(IDR_RIBBON);
255 // enable the dialog launch button on the view panel
256 CMFCRibbonCategory * pMainCat = m_wndRibbonBar.GetCategory(1);
257 if (pMainCat)
259 CMFCRibbonPanel * pPanel = pMainCat->GetPanel(3);
260 if (pPanel)
261 pPanel->EnableLaunchButton(ID_VIEW_OPTIONS);
263 // now replace all buttons with our custom button class
264 for (int i = 0; i < m_wndRibbonBar.GetCategoryCount(); ++i)
266 CMFCRibbonCategory * pCat = m_wndRibbonBar.GetCategory(i);
267 for (int j = 0; j < pCat->GetPanelCount(); ++j)
269 CMFCRibbonPanel * pPanel = pCat->GetPanel(j);
270 CList<UINT, UINT> lstItems;
271 pPanel->GetItemIDsList(lstItems);
272 while (!lstItems.IsEmpty())
274 UINT id = lstItems.GetHead();
275 lstItems.RemoveHead();
276 CMFCRibbonButton * pButton = dynamic_cast<CMFCRibbonButton*>(pPanel->FindByID(id));
277 if (pButton)
279 CCustomMFCRibbonButton * c = new CCustomMFCRibbonButton(id, pButton->GetText());
280 pPanel->ReplaceByID(id, c);
285 BuildRegexSubitems();
286 if (!m_wndRibbonStatusBar.Create(this))
288 TRACE0("Failed to create ribbon status bar\n");
289 return -1; // fail to create
291 m_wndRibbonStatusBar.AddElement(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(AFX_IDS_IDLEMESSAGE)), TRUE), L"");
293 std::unique_ptr<CMFCRibbonButtonsGroup> apBtnGroupLeft(new CMFCRibbonButtonsGroup);
294 apBtnGroupLeft->SetID(ID_INDICATOR_LEFTVIEW);
295 apBtnGroupLeft->AddButton(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(IDS_STATUSBAR_LEFTVIEW)), TRUE));
296 CMFCRibbonButton * pButton = new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOENCODING, L"");
297 FillEncodingButton(pButton, ID_INDICATOR_LEFTENCODINGSTART);
298 apBtnGroupLeft->AddButton(pButton);
299 pButton = new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOEOL, L"");
300 FillEOLButton(pButton, ID_INDICATOR_LEFTEOLSTART);
301 apBtnGroupLeft->AddButton(pButton);
302 apBtnGroupLeft->AddButton(new CMFCRibbonStatusBarPane(ID_INDICATOR_LEFTVIEW, L"", TRUE));
303 m_wndRibbonStatusBar.AddExtendedElement(apBtnGroupLeft.release(), L"");
305 std::unique_ptr<CMFCRibbonButtonsGroup> apBtnGroupRight(new CMFCRibbonButtonsGroup);
306 apBtnGroupRight->SetID(ID_INDICATOR_RIGHTVIEW);
307 apBtnGroupRight->AddButton(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(IDS_STATUSBAR_RIGHTVIEW)), TRUE));
308 pButton = new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOENCODING, L"");
309 FillEncodingButton(pButton, ID_INDICATOR_RIGHTENCODINGSTART);
310 apBtnGroupRight->AddButton(pButton);
311 pButton = new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOEOL, L"");
312 FillEOLButton(pButton, ID_INDICATOR_RIGHTEOLSTART);
313 apBtnGroupRight->AddButton(pButton);
314 apBtnGroupRight->AddButton(new CMFCRibbonStatusBarPane(ID_INDICATOR_RIGHTVIEW, L"", TRUE));
315 m_wndRibbonStatusBar.AddExtendedElement(apBtnGroupRight.release(), L"");
317 else
319 if (!m_wndMenuBar.Create(this))
321 TRACE0("Failed to create menubar\n");
322 return -1; // fail to create
324 m_wndMenuBar.SetPaneStyle(m_wndMenuBar.GetPaneStyle() | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY);
326 // prevent the menu bar from taking the focus on activation
327 CMFCPopupMenu::SetForceMenuFocus(FALSE);
328 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))
330 TRACE0("Failed to create toolbar\n");
331 return -1; // fail to create
333 m_wndToolBar.SetWindowText(_T("Main"));
334 if (!m_wndStatusBar.Create(this) ||
335 !m_wndStatusBar.SetIndicators(indicators,
336 _countof(indicators)))
338 TRACE0("Failed to create status bar\n");
339 return -1; // fail to create
341 m_wndStatusBar.EnablePaneDoubleClick();
344 if (!m_wndLocatorBar.Create(this, IDD_DIFFLOCATOR,
345 CBRS_ALIGN_LEFT | CBRS_SIZE_FIXED, ID_VIEW_LOCATORBAR))
347 TRACE0("Failed to create dialogbar\n");
348 return -1; // fail to create
350 if (!m_wndLineDiffBar.Create(this, IDD_LINEDIFF,
351 CBRS_ALIGN_BOTTOM | CBRS_SIZE_FIXED, ID_VIEW_LINEDIFFBAR))
353 TRACE0("Failed to create dialogbar\n");
354 return -1; // fail to create
356 m_wndLocatorBar.m_pMainFrm = this;
357 m_wndLineDiffBar.m_pMainFrm = this;
359 EnableDocking(CBRS_ALIGN_ANY);
360 if (!m_bUseRibbons)
362 m_wndMenuBar.EnableDocking(CBRS_ALIGN_TOP);
363 m_wndToolBar.EnableDocking(CBRS_ALIGN_TOP);
364 DockPane(&m_wndMenuBar);
365 DockPane(&m_wndToolBar);
367 DockPane(&m_wndLocatorBar);
368 DockPane(&m_wndLineDiffBar);
369 ShowPane(&m_wndLocatorBar, true, false, true);
370 ShowPane(&m_wndLineDiffBar, true, false, true);
372 m_wndLocatorBar.EnableGripper(FALSE);
373 m_wndLineDiffBar.EnableGripper(FALSE);
375 return 0;
378 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
380 if( !CFrameWndEx::PreCreateWindow(cs) )
381 return FALSE;
382 return TRUE;
385 void CMainFrame::OnApplicationLook(UINT id)
387 CWaitCursor wait;
389 theApp.m_nAppLook = id;
391 switch (theApp.m_nAppLook)
393 case ID_VIEW_APPLOOK_WIN_2000:
394 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManager));
395 m_wndRibbonBar.SetWindows7Look(FALSE);
396 break;
398 case ID_VIEW_APPLOOK_OFF_XP:
399 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOfficeXP));
400 m_wndRibbonBar.SetWindows7Look(FALSE);
401 break;
403 case ID_VIEW_APPLOOK_WIN_XP:
404 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
405 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
406 m_wndRibbonBar.SetWindows7Look(FALSE);
407 break;
409 case ID_VIEW_APPLOOK_OFF_2003:
410 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2003));
411 CDockingManager::SetDockingMode(DT_SMART);
412 m_wndRibbonBar.SetWindows7Look(FALSE);
413 break;
415 case ID_VIEW_APPLOOK_VS_2005:
416 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2005));
417 CDockingManager::SetDockingMode(DT_SMART);
418 m_wndRibbonBar.SetWindows7Look(FALSE);
419 break;
421 case ID_VIEW_APPLOOK_VS_2008:
422 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2008));
423 CDockingManager::SetDockingMode(DT_SMART);
424 m_wndRibbonBar.SetWindows7Look(FALSE);
425 break;
427 case ID_VIEW_APPLOOK_WIN7:
428 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows7));
429 CDockingManager::SetDockingMode(DT_SMART);
430 m_wndRibbonBar.SetWindows7Look(TRUE);
431 break;
433 default:
434 switch (theApp.m_nAppLook)
436 case ID_VIEW_APPLOOK_OFF_2007_BLUE:
437 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_LunaBlue);
438 break;
440 case ID_VIEW_APPLOOK_OFF_2007_BLACK:
441 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_ObsidianBlack);
442 break;
444 case ID_VIEW_APPLOOK_OFF_2007_SILVER:
445 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Silver);
446 break;
448 case ID_VIEW_APPLOOK_OFF_2007_AQUA:
449 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Aqua);
450 break;
453 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));
454 CDockingManager::SetDockingMode(DT_SMART);
455 m_wndRibbonBar.SetWindows7Look(FALSE);
458 RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_FRAME | RDW_ERASE);
460 theApp.WriteInt(_T("ApplicationLook"), theApp.m_nAppLook);
463 void CMainFrame::OnUpdateApplicationLook(CCmdUI* pCmdUI)
465 pCmdUI->Enable();
466 pCmdUI->SetRadio(theApp.m_nAppLook == pCmdUI->m_nID);
470 // CMainFrame diagnostics
472 #ifdef _DEBUG
473 void CMainFrame::AssertValid() const
475 CFrameWndEx::AssertValid();
478 void CMainFrame::Dump(CDumpContext& dc) const
480 CFrameWndEx::Dump(dc);
483 #endif //_DEBUG
486 // CMainFrame message handlers
489 BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)
491 CRect cr;
492 GetClientRect( &cr);
495 // split into three panes:
496 // -------------
497 // | | |
498 // | | |
499 // |------------
500 // | |
501 // | |
502 // |------------
504 // create a splitter with 2 rows, 1 column
505 if (!m_wndSplitter.CreateStatic(this, 2, 1))
507 TRACE0("Failed to CreateStaticSplitter\n");
508 return FALSE;
511 // add the second splitter pane - which is a nested splitter with 2 columns
512 if (!m_wndSplitter2.CreateStatic(
513 &m_wndSplitter, // our parent window is the first splitter
514 1, 2, // the new splitter is 1 row, 2 columns
515 WS_CHILD | WS_VISIBLE | WS_BORDER, // style, WS_BORDER is needed
516 m_wndSplitter.IdFromRowCol(0, 0)
517 // new splitter is in the first row, 1st column of first splitter
520 TRACE0("Failed to create nested splitter\n");
521 return FALSE;
523 // add the first splitter pane - the default view in row 0
524 if (!m_wndSplitter.CreateView(1, 0,
525 RUNTIME_CLASS(CBottomView), CSize(cr.Width(), cr.Height()), pContext))
527 TRACE0("Failed to create first pane\n");
528 return FALSE;
530 m_pwndBottomView = (CBottomView *)m_wndSplitter.GetPane(1,0);
531 m_pwndBottomView->m_pwndLocator = &m_wndLocatorBar;
532 m_pwndBottomView->m_pwndLineDiffBar = &m_wndLineDiffBar;
533 if (m_bUseRibbons)
534 m_pwndBottomView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
535 else
536 m_pwndBottomView->m_pwndStatusBar = &m_wndStatusBar;
537 m_pwndBottomView->m_pMainFrame = this;
539 // now create the two views inside the nested splitter
541 if (!m_wndSplitter2.CreateView(0, 0,
542 RUNTIME_CLASS(CLeftView), CSize(cr.Width()/2, cr.Height()/2), pContext))
544 TRACE0("Failed to create second pane\n");
545 return FALSE;
547 m_pwndLeftView = (CLeftView *)m_wndSplitter2.GetPane(0,0);
548 m_pwndLeftView->m_pwndLocator = &m_wndLocatorBar;
549 m_pwndLeftView->m_pwndLineDiffBar = &m_wndLineDiffBar;
550 if (m_bUseRibbons)
551 m_pwndLeftView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
552 else
553 m_pwndLeftView->m_pwndStatusBar = &m_wndStatusBar;
554 m_pwndLeftView->m_pMainFrame = this;
556 if (!m_wndSplitter2.CreateView(0, 1,
557 RUNTIME_CLASS(CRightView), CSize(cr.Width()/2, cr.Height()/2), pContext))
559 TRACE0("Failed to create third pane\n");
560 return FALSE;
562 m_pwndRightView = (CRightView *)m_wndSplitter2.GetPane(0,1);
563 m_pwndRightView->m_pwndLocator = &m_wndLocatorBar;
564 m_pwndRightView->m_pwndLineDiffBar = &m_wndLineDiffBar;
565 if (m_bUseRibbons)
566 m_pwndRightView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
567 else
568 m_pwndRightView->m_pwndStatusBar = &m_wndStatusBar;
569 m_pwndRightView->m_pMainFrame = this;
570 m_bInitSplitter = TRUE;
572 m_dlgFilePatches.Create(IDD_FILEPATCHES, this);
573 UpdateLayout();
574 return TRUE;
577 // Callback function
578 BOOL CMainFrame::PatchFile(CString sFilePath, bool /*bContentMods*/, bool bPropMods, CString sVersion, BOOL bAutoPatch)
580 CString sDummy;
581 //"dry run" was successful, so save the patched file somewhere...
582 CString sTempFile = CTempFiles::Instance().GetTempFilePathString();
583 CString sRejectedFile, sBasePath;
584 if (m_Patch.GetPatchResult(sFilePath, sTempFile, sRejectedFile, sBasePath) < 0)
586 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
587 return FALSE;
589 sFilePath = m_Patch.GetTargetPath() + _T("\\") + sFilePath;
590 sFilePath.Replace('/', '\\');
591 if (sBasePath.IsEmpty())
592 sBasePath = sFilePath;
593 if (m_bReversedPatch)
595 m_Data.m_baseFile.SetFileName(sTempFile);
596 CString temp;
597 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
598 m_Data.m_baseFile.SetDescriptiveName(temp);
599 m_Data.m_yourFile.SetFileName(sFilePath);
600 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchOriginal);
601 m_Data.m_yourFile.SetDescriptiveName(temp);
602 m_Data.m_theirFile.SetOutOfUse();
603 m_Data.m_mergedFile.SetOutOfUse();
605 else
607 if ((!PathFileExists(sBasePath))||(PathIsDirectory(sBasePath)))
609 m_Data.m_baseFile.SetFileName(CTempFiles::Instance().GetTempFilePathString());
610 m_Data.m_baseFile.CreateEmptyFile();
612 else
614 m_Data.m_baseFile.SetFileName(sBasePath);
616 CString sDescription;
617 sDescription.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sBasePath), (LPCTSTR)m_Data.m_sPatchOriginal);
618 m_Data.m_baseFile.SetDescriptiveName(sDescription);
619 if (sBasePath == sFilePath)
621 m_Data.m_yourFile.SetFileName(sTempFile);
622 CString temp;
623 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sBasePath), (LPCTSTR)m_Data.m_sPatchPatched);
624 m_Data.m_yourFile.SetDescriptiveName(temp);
625 m_Data.m_theirFile.SetOutOfUse();
627 else
629 if (!PathFileExists(sFilePath) || PathIsDirectory(sFilePath))
631 m_Data.m_yourFile.SetFileName(CTempFiles::Instance().GetTempFilePathString());
632 m_Data.m_yourFile.CreateEmptyFile();
633 CString temp;
634 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), CString(MAKEINTRESOURCE(IDS_NOTFOUNDVIEWTITLEINDICATOR)));
635 m_Data.m_yourFile.SetDescriptiveName(temp);
637 else
638 m_Data.m_yourFile.SetFileName(sFilePath);
639 m_Data.m_theirFile.SetFileName(sTempFile);
640 CString temp;
641 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
642 m_Data.m_theirFile.SetDescriptiveName(temp);
644 m_Data.m_mergedFile.SetFileName(sFilePath);
645 m_Data.m_bPatchRequired = bPropMods;
647 TRACE(_T("comparing %s\nwith the patched result %s\n"), (LPCTSTR)sFilePath, (LPCTSTR)sTempFile);
649 LoadViews();
650 if (!sRejectedFile.IsEmpty())
652 #if 0 // TGIT TODO
653 // start TortoiseUDiff with the rejected hunks
654 CString sTitle;
655 sTitle.Format(IDS_TITLE_REJECTEDHUNKS, (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath));
656 CAppUtils::StartUnifiedDiffViewer(sRejectedFile, sTitle);
657 #endif
659 if (bAutoPatch)
661 if (sBasePath != sFilePath && HasConflictsWontKeep())
662 return FALSE;
664 PatchSave();
666 return TRUE;
669 // Callback function
670 BOOL CMainFrame::DiffFiles(CString sURL1, CString sRev1, CString sURL2, CString sRev2)
672 CString tempfile1 = CTempFiles::Instance().GetTempFilePathString();
673 CString tempfile2 = CTempFiles::Instance().GetTempFilePathString();
675 ASSERT(tempfile1.Compare(tempfile2));
677 CString sTemp;
678 CSysProgressDlg progDlg;
679 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev1);
680 progDlg.SetLine(1, sTemp, true);
681 progDlg.SetLine(2, sURL1, true);
682 sTemp.LoadString(IDS_GETVERSIONOFFILETITLE);
683 progDlg.SetTitle(sTemp);
684 progDlg.SetShowProgressBar(true);
685 progDlg.SetAnimation(IDR_DOWNLOAD);
686 progDlg.SetTime(FALSE);
687 progDlg.SetProgress(1,100);
688 progDlg.ShowModeless(this);
689 if (!CAppUtils::GetVersionedFile(sURL1, sRev1, tempfile1, &progDlg, m_hWnd))
691 progDlg.Stop();
692 CString sErrMsg;
693 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev1, (LPCTSTR)sURL1);
694 MessageBox(sErrMsg, NULL, MB_ICONERROR);
695 return FALSE;
697 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev2);
698 progDlg.SetLine(1, sTemp, true);
699 progDlg.SetLine(2, sURL2, true);
700 progDlg.SetProgress(50, 100);
701 if (!CAppUtils::GetVersionedFile(sURL2, sRev2, tempfile2, &progDlg, m_hWnd))
703 progDlg.Stop();
704 CString sErrMsg;
705 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev2, (LPCTSTR)sURL2);
706 MessageBox(sErrMsg, NULL, MB_ICONERROR);
707 return FALSE;
709 progDlg.SetProgress(100,100);
710 progDlg.Stop();
711 CString temp;
712 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL1), (LPCTSTR)sRev1);
713 m_Data.m_baseFile.SetFileName(tempfile1);
714 m_Data.m_baseFile.SetDescriptiveName(temp);
715 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL2), (LPCTSTR)sRev2);
716 m_Data.m_yourFile.SetFileName(tempfile2);
717 m_Data.m_yourFile.SetDescriptiveName(temp);
719 LoadViews();
721 return TRUE;
724 void CMainFrame::OnFileOpen()
726 if (CheckForSave(CHFSR_OPEN)==IDCANCEL)
727 return;
728 COpenDlg dlg;
729 if (dlg.DoModal()!=IDOK)
731 return;
733 m_dlgFilePatches.ShowWindow(SW_HIDE);
734 m_dlgFilePatches.Init(NULL, NULL, CString(), NULL);
735 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,
736 (LPCTSTR)dlg.m_sUnifiedDiffFile, (LPCTSTR)dlg.m_sPatchDirectory);
737 m_Data.m_baseFile.SetFileName(dlg.m_sBaseFile);
738 m_Data.m_theirFile.SetFileName(dlg.m_sTheirFile);
739 m_Data.m_yourFile.SetFileName(dlg.m_sYourFile);
740 m_Data.m_sDiffFile = dlg.m_sUnifiedDiffFile;
741 m_Data.m_sPatchPath = dlg.m_sPatchDirectory;
742 m_Data.m_mergedFile.SetOutOfUse();
743 CCrashReport::Instance().AddFile2(dlg.m_sBaseFile, NULL, _T("Basefile"), CR_AF_MAKE_FILE_COPY);
744 CCrashReport::Instance().AddFile2(dlg.m_sTheirFile, NULL, _T("Theirfile"), CR_AF_MAKE_FILE_COPY);
745 CCrashReport::Instance().AddFile2(dlg.m_sYourFile, NULL, _T("Yourfile"), CR_AF_MAKE_FILE_COPY);
746 CCrashReport::Instance().AddFile2(dlg.m_sUnifiedDiffFile, NULL, _T("Difffile"), CR_AF_MAKE_FILE_COPY);
748 if (!m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && m_Data.IsYourFileInUse())
750 // a diff between two files means "Yours" against "Base", not "Theirs" against "Yours"
751 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
753 if (m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && !m_Data.IsYourFileInUse())
755 // a diff between two files means "Yours" against "Base", not "Theirs" against "Base"
756 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
758 m_bSaveRequired = false;
760 LoadViews();
763 void CMainFrame::ClearViewNamesAndPaths()
765 m_pwndLeftView->m_sWindowName.Empty();
766 m_pwndLeftView->m_sFullFilePath.Empty();
767 m_pwndRightView->m_sWindowName.Empty();
768 m_pwndRightView->m_sFullFilePath.Empty();
769 m_pwndBottomView->m_sWindowName.Empty();
770 m_pwndBottomView->m_sFullFilePath.Empty();
773 bool CMainFrame::LoadViews(int line)
775 LoadIgnoreCommentData();
776 m_Data.SetBlame(m_bBlame);
777 m_Data.SetMovedBlocks(m_bViewMovedBlocks);
778 m_bHasConflicts = false;
779 CBaseView* pwndActiveView = m_pwndLeftView;
780 int nOldLine = m_pwndRightView ? m_pwndRightView->m_nTopLine : -1;
781 int nOldLineNumber =
782 m_pwndRightView && m_pwndRightView->m_pViewData ?
783 m_pwndRightView->m_pViewData->GetLineNumber(m_pwndRightView->m_nTopLine) : -1;
784 POINT ptOldCaretPos = {-1, -1};
785 if (m_pwndRightView && m_pwndRightView->IsTarget())
786 ptOldCaretPos = m_pwndRightView->GetCaretPosition();
787 if (m_pwndBottomView && m_pwndBottomView->IsTarget())
788 ptOldCaretPos = m_pwndBottomView->GetCaretPosition();
789 CString sExt = CPathUtils::GetFileExtFromPath(m_Data.m_baseFile.GetFilename()).MakeLower();
790 sExt.TrimLeft(L".");
791 auto sC = m_IgnoreCommentsMap.find(sExt);
792 if (sC == m_IgnoreCommentsMap.end())
794 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_yourFile.GetFilename()).MakeLower();
795 sC = m_IgnoreCommentsMap.find(sExt);
796 if (sC == m_IgnoreCommentsMap.end())
798 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_theirFile.GetFilename()).MakeLower();
799 sC = m_IgnoreCommentsMap.find(sExt);
802 if (sC != m_IgnoreCommentsMap.end())
803 m_Data.SetCommentTokens(std::get<0>(sC->second), std::get<1>(sC->second), std::get<2>(sC->second));
804 else
805 m_Data.SetCommentTokens(L"", L"", L"");
806 if (!m_Data.Load())
808 m_pwndLeftView->BuildAllScreen2ViewVector();
809 m_pwndLeftView->DocumentUpdated();
810 m_pwndRightView->DocumentUpdated();
811 m_pwndBottomView->DocumentUpdated();
812 m_wndLocatorBar.DocumentUpdated();
813 m_wndLineDiffBar.DocumentUpdated();
814 ::MessageBox(m_hWnd, m_Data.GetError(), _T("TortoiseGitMerge"), MB_ICONERROR);
815 m_Data.m_mergedFile.SetOutOfUse();
816 m_bSaveRequired = false;
817 return false;
819 SetWindowTitle();
820 m_pwndLeftView->BuildAllScreen2ViewVector();
821 m_pwndLeftView->DocumentUpdated();
822 m_pwndRightView->DocumentUpdated();
823 m_pwndBottomView->DocumentUpdated();
824 m_wndLocatorBar.DocumentUpdated();
825 m_wndLineDiffBar.DocumentUpdated();
827 m_pwndLeftView->SetWritable(false);
828 m_pwndLeftView->SetWritableIsChangable(false);
829 m_pwndLeftView->SetTarget(false);
830 m_pwndRightView->SetWritable(false);
831 m_pwndRightView->SetWritableIsChangable(false);
832 m_pwndRightView->SetTarget(false);
833 m_pwndBottomView->SetWritable(false);
834 m_pwndBottomView->SetWritableIsChangable(false);
835 m_pwndBottomView->SetTarget(false);
837 if (!m_Data.IsBaseFileInUse())
839 CSysProgressDlg progDlg;
840 if (m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
842 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
844 else if ((!m_Data.m_sDiffFile.IsEmpty())&&(!m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg)))
846 progDlg.Stop();
847 ClearViewNamesAndPaths();
848 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
849 m_bSaveRequired = false;
850 return false;
852 progDlg.Stop();
853 if (m_Patch.GetNumberOfFiles() > 0)
855 CString betterpatchpath = m_Patch.CheckPatchPath(m_Data.m_sPatchPath);
856 if (betterpatchpath.CompareNoCase(m_Data.m_sPatchPath)!=0)
858 CString msg;
859 msg.Format(IDS_WARNBETTERPATCHPATHFOUND, (LPCTSTR)m_Data.m_sPatchPath, (LPCTSTR)betterpatchpath);
860 if (m_bUseTaskDialog)
862 CTaskDialog taskdlg(msg,
863 CString(MAKEINTRESOURCE(IDS_WARNBETTERPATCHPATHFOUND_TASK2)),
864 L"TortoiseGitMerge",
866 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
867 CString task3;
868 WCHAR t3[MAX_PATH] = {0};
869 CString cp = betterpatchpath.Left(MAX_PATH-1);
870 PathCompactPathEx(t3, cp, 50, 0);
871 task3.Format(IDS_WARNBETTERPATCHPATHFOUND_TASK3, t3);
872 taskdlg.AddCommandControl(1, task3);
873 CString task4;
874 WCHAR t4[MAX_PATH] = {0};
875 cp = m_Data.m_sPatchPath.Left(MAX_PATH-1);
876 PathCompactPathEx(t4, cp, 50, 0);
877 task4.Format(IDS_WARNBETTERPATCHPATHFOUND_TASK4, t4);
878 taskdlg.AddCommandControl(2, task4);
879 taskdlg.SetDefaultCommandControl(1);
880 taskdlg.SetMainIcon(TD_INFORMATION_ICON);
881 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
882 if (taskdlg.DoModal(m_hWnd) == 1)
884 m_Data.m_sPatchPath = betterpatchpath;
885 m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg);
888 else if (::MessageBox(m_hWnd, msg, _T("TortoiseGitMerge"), MB_ICONQUESTION | MB_YESNO)==IDYES)
890 m_Data.m_sPatchPath = betterpatchpath;
891 m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg);
894 m_dlgFilePatches.Init(&m_Patch, this, m_Data.m_sPatchPath, this);
895 m_dlgFilePatches.ShowWindow(SW_SHOW);
896 ClearViewNamesAndPaths();
897 if (!m_wndSplitter.IsRowHidden(1))
898 m_wndSplitter.HideRow(1);
899 m_pwndLeftView->SetHidden(FALSE);
900 m_pwndRightView->SetHidden(FALSE);
901 m_pwndBottomView->SetHidden(TRUE);
904 if (m_Data.IsBaseFileInUse() && !m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
906 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
908 if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && !m_Data.IsTheirFileInUse())
910 //diff between YOUR and BASE
911 if (m_bOneWay)
913 pwndActiveView = m_pwndLeftView;
914 if (!m_wndSplitter2.IsColumnHidden(1))
915 m_wndSplitter2.HideColumn(1);
917 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseBoth;
918 m_pwndLeftView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
919 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
920 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName() + _T(" - ") + m_Data.m_yourFile.GetWindowName();
921 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename() + _T(" - ") + m_Data.m_yourFile.GetFilename();
922 m_pwndLeftView->m_pWorkingFile = &m_Data.m_yourFile;
923 m_pwndLeftView->SetTarget();
924 m_pwndLeftView->SetWritableIsChangable(true);
926 m_pwndRightView->m_pViewData = NULL;
927 m_pwndRightView->m_pWorkingFile = NULL;
928 m_pwndBottomView->m_pViewData = NULL;
929 m_pwndBottomView->m_pWorkingFile = NULL;
931 if (!m_wndSplitter.IsRowHidden(1))
932 m_wndSplitter.HideRow(1);
933 m_pwndLeftView->SetHidden(FALSE);
934 m_pwndRightView->SetHidden(TRUE);
935 m_pwndBottomView->SetHidden(TRUE);
936 ::SetWindowPos(m_pwndLeftView->m_hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
938 else
940 pwndActiveView = m_pwndRightView;
941 if (m_wndSplitter2.IsColumnHidden(1))
942 m_wndSplitter2.ShowColumn();
944 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseLeft;
945 m_pwndLeftView->SetTextType(m_Data.m_arBaseFile.GetUnicodeType());
946 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arBaseFile.GetLineEndings());
947 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName();
948 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename();
949 m_pwndLeftView->m_sConvertedFilePath = m_Data.m_baseFile.GetConvertedFileName();
950 m_pwndLeftView->m_pWorkingFile = &m_Data.m_baseFile;
951 m_pwndLeftView->SetWritableIsChangable(true);
953 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseRight;
954 m_pwndRightView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
955 m_pwndRightView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
956 m_pwndRightView->m_sWindowName = m_Data.m_yourFile.GetWindowName();
957 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
958 m_pwndRightView->m_sConvertedFilePath = m_Data.m_yourFile.GetConvertedFileName();
959 m_pwndRightView->m_pWorkingFile = &m_Data.m_yourFile;
960 m_pwndRightView->SetWritable();
961 m_pwndRightView->SetTarget();
963 m_pwndBottomView->m_pViewData = NULL;
964 m_pwndBottomView->m_pWorkingFile = NULL;
966 if (!m_wndSplitter.IsRowHidden(1))
967 m_wndSplitter.HideRow(1);
968 m_pwndLeftView->SetHidden(FALSE);
969 m_pwndRightView->SetHidden(FALSE);
970 m_pwndBottomView->SetHidden(TRUE);
972 bool hasMods, hasConflicts, hasWhitespaceMods;
973 pwndActiveView->CheckModifications(hasMods, hasConflicts, hasWhitespaceMods);
974 if (!hasMods && !hasConflicts)
976 // files appear identical, show a dialog informing the user that there are or might
977 // be other differences
978 bool hasEncodingDiff = m_Data.m_arBaseFile.GetUnicodeType() != m_Data.m_arYourFile.GetUnicodeType();
979 bool hasEOLDiff = m_Data.m_arBaseFile.GetLineEndings() != m_Data.m_arYourFile.GetLineEndings();
980 if (hasWhitespaceMods || hasEncodingDiff || hasEOLDiff)
982 // text is identical, but the files do not match
983 CString sWarning(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_MAIN));
984 CString sWhitespace(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_WHITESPACE));
985 CString sEncoding(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_ENCODING));
986 CString sEOL(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_EOL));
987 if (hasWhitespaceMods)
989 sWarning += L"\r\n";
990 sWarning += sWhitespace;
992 if (hasEncodingDiff)
994 sWarning += L"\r\n";
995 sWarning += sEncoding;
996 sWarning += L" (";
997 sWarning += m_Data.m_arBaseFile.GetEncodingName(m_Data.m_arBaseFile.GetUnicodeType());
998 sWarning += L", ";
999 sWarning += m_Data.m_arYourFile.GetEncodingName(m_Data.m_arYourFile.GetUnicodeType());
1000 sWarning += L")";
1002 if (hasEOLDiff)
1004 sWarning += L"\r\n";
1005 sWarning += sEOL;
1007 AfxMessageBox(sWarning, MB_ICONINFORMATION);
1011 else if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
1013 //diff between THEIR, YOUR and BASE
1014 m_pwndBottomView->SetWritable();
1015 m_pwndBottomView->SetTarget();
1016 pwndActiveView = m_pwndBottomView;
1018 m_pwndLeftView->m_pViewData = &m_Data.m_TheirBaseBoth;
1019 m_pwndLeftView->SetTextType(m_Data.m_arTheirFile.GetUnicodeType());
1020 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arTheirFile.GetLineEndings());
1021 m_pwndLeftView->m_sWindowName.LoadString(IDS_VIEWTITLE_THEIRS);
1022 m_pwndLeftView->m_sWindowName += _T(" - ") + m_Data.m_theirFile.GetWindowName();
1023 m_pwndLeftView->m_sFullFilePath = m_Data.m_theirFile.GetFilename();
1024 m_pwndLeftView->m_sConvertedFilePath = m_Data.m_theirFile.GetConvertedFileName();
1025 m_pwndLeftView->m_pWorkingFile = &m_Data.m_theirFile;
1027 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseBoth;
1028 m_pwndRightView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
1029 m_pwndRightView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
1030 m_pwndRightView->m_sWindowName.LoadString(IDS_VIEWTITLE_MINE);
1031 m_pwndRightView->m_sWindowName += _T(" - ") + m_Data.m_yourFile.GetWindowName();
1032 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
1033 m_pwndRightView->m_sConvertedFilePath = m_Data.m_yourFile.GetConvertedFileName();
1034 m_pwndRightView->m_pWorkingFile = &m_Data.m_yourFile;
1036 m_pwndBottomView->m_pViewData = &m_Data.m_Diff3;
1037 m_pwndBottomView->SetTextType(m_Data.m_arTheirFile.GetUnicodeType());
1038 m_pwndBottomView->SetLineEndingStyle(m_Data.m_arTheirFile.GetLineEndings());
1039 m_pwndBottomView->m_sWindowName.LoadString(IDS_VIEWTITLE_MERGED);
1040 m_pwndBottomView->m_sWindowName += _T(" - ") + m_Data.m_mergedFile.GetWindowName();
1041 m_pwndBottomView->m_sFullFilePath = m_Data.m_mergedFile.GetFilename();
1042 m_pwndBottomView->m_sConvertedFilePath = m_Data.m_mergedFile.GetConvertedFileName();
1043 m_pwndBottomView->m_pWorkingFile = &m_Data.m_mergedFile;
1045 if (m_wndSplitter2.IsColumnHidden(1))
1046 m_wndSplitter2.ShowColumn();
1047 if (m_wndSplitter.IsRowHidden(1))
1048 m_wndSplitter.ShowRow();
1049 m_pwndLeftView->SetHidden(FALSE);
1050 m_pwndRightView->SetHidden(FALSE);
1051 m_pwndBottomView->SetHidden(FALSE);
1052 // in three pane view, hide the line diff bar
1053 m_wndLineDiffBar.ShowPane(false, false, true);
1054 m_wndLineDiffBar.DocumentUpdated();
1056 if (!m_Data.m_mergedFile.InUse())
1058 m_Data.m_mergedFile.SetFileName(m_Data.m_yourFile.GetFilename());
1060 m_pwndLeftView->BuildAllScreen2ViewVector();
1061 m_pwndLeftView->DocumentUpdated();
1062 m_pwndRightView->DocumentUpdated();
1063 m_pwndBottomView->DocumentUpdated();
1064 m_wndLocatorBar.DocumentUpdated();
1065 m_wndLineDiffBar.DocumentUpdated();
1066 UpdateLayout();
1067 SetActiveView(pwndActiveView);
1069 if ((line >= -1) && m_pwndRightView->m_pViewData)
1071 int n = line == -1 ? min( nOldLineNumber, nOldLine ) : line;
1072 if (n >= 0)
1073 n = m_pwndRightView->m_pViewData->FindLineNumber(n);
1074 if (n < 0)
1075 n = nOldLine;
1077 m_pwndRightView->ScrollAllToLine(n);
1078 POINT p;
1079 p.x = 0;
1080 p.y = n;
1081 if ((ptOldCaretPos.x >= 0) || (ptOldCaretPos.y >= 0))
1082 p = ptOldCaretPos;
1083 m_pwndLeftView->SetCaretPosition(p);
1084 m_pwndRightView->SetCaretPosition(p);
1085 m_pwndBottomView->SetCaretPosition(p);
1086 m_pwndBottomView->ScrollToChar(0);
1087 m_pwndLeftView->ScrollToChar(0);
1088 m_pwndRightView->ScrollToChar(0);
1090 else
1092 CRegDWORD regFirstDiff = CRegDWORD(_T("Software\\TortoiseGitMerge\\FirstDiffOnLoad"), TRUE);
1093 CRegDWORD regFirstConflict = CRegDWORD(_T("Software\\TortoiseGitMerge\\FirstConflictOnLoad"), TRUE);
1094 bool bGoFirstDiff = (0 != (DWORD)regFirstDiff);
1095 bool bGoFirstConflict = (0 != (DWORD)regFirstConflict);
1096 if (bGoFirstConflict && (CheckResolved()>=0))
1098 pwndActiveView->GoToFirstConflict();
1099 // Ignore the first few Mouse Move messages, so that the line diff stays on
1100 // the first diff line until the user actually moves the mouse
1101 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1103 else if (bGoFirstDiff)
1105 pwndActiveView->GoToFirstDifference();
1106 // Ignore the first few Mouse Move messages, so that the line diff stays on
1107 // the first diff line until the user actually moves the mouse
1108 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1110 else
1112 // Avoid incorrect rendering of active pane.
1113 m_pwndBottomView->ScrollToChar(0);
1114 m_pwndLeftView->ScrollToChar(0);
1115 m_pwndRightView->ScrollToChar(0);
1118 CheckResolved();
1119 if (m_bHasConflicts && !m_bSaveRequiredOnConflicts)
1120 m_bSaveRequired = false;
1121 CUndo::GetInstance().Clear();
1122 return true;
1125 void CMainFrame::UpdateLayout()
1127 if (m_bInitSplitter)
1129 m_wndSplitter.CenterSplitter();
1130 m_wndSplitter2.CenterSplitter();
1134 void CMainFrame::OnSize(UINT nType, int cx, int cy)
1136 CFrameWndEx::OnSize(nType, cx, cy);
1137 if (m_bInitSplitter && nType != SIZE_MINIMIZED)
1139 if (m_wndSplitter.GetSafeHwnd())
1141 if (m_wndSplitter.HasOldRowSize() && (m_wndSplitter.GetOldRowCount() == 2))
1143 int oldTotal = m_wndSplitter.GetOldRowSize(0) + m_wndSplitter.GetOldRowSize(1);
1144 if (oldTotal)
1146 int cxCur0, cxCur1, cxMin0, cxMin1;
1147 m_wndSplitter.GetRowInfo(0, cxCur0, cxMin0);
1148 m_wndSplitter.GetRowInfo(1, cxCur1, cxMin1);
1149 cxCur0 = m_wndSplitter.GetOldRowSize(0) * (cxCur0 + cxCur1) / oldTotal;
1150 cxCur1 = m_wndSplitter.GetOldRowSize(1) * (cxCur0 + cxCur1) / oldTotal;
1151 m_wndSplitter.SetRowInfo(0, cxCur0, 0);
1152 m_wndSplitter.SetRowInfo(1, cxCur1, 0);
1153 m_wndSplitter.RecalcLayout();
1157 if (m_wndSplitter2.HasOldColSize() && (m_wndSplitter2.GetOldColCount() == 2))
1159 int oldTotal = m_wndSplitter2.GetOldColSize(0) + m_wndSplitter2.GetOldColSize(1);
1160 if (oldTotal)
1162 int cyCur0, cyCur1, cyMin0, cyMin1;
1163 m_wndSplitter2.GetColumnInfo(0, cyCur0, cyMin0);
1164 m_wndSplitter2.GetColumnInfo(1, cyCur1, cyMin1);
1165 cyCur0 = m_wndSplitter2.GetOldColSize(0) * (cyCur0 + cyCur1) / oldTotal;
1166 cyCur1 = m_wndSplitter2.GetOldColSize(1) * (cyCur0 + cyCur1) / oldTotal;
1167 m_wndSplitter2.SetColumnInfo(0, cyCur0, 0);
1168 m_wndSplitter2.SetColumnInfo(1, cyCur1, 0);
1169 m_wndSplitter2.RecalcLayout();
1174 if ((nType == SIZE_RESTORED)&&m_bCheckReload)
1176 m_bCheckReload = false;
1177 CheckForReload();
1179 #if _MSC_VER < 1800
1180 // workaround for ribbon interface when the task bar is on the left or top
1181 // The bug has been fixed in VS2013
1182 // http://connect.microsoft.com/VisualStudio/feedback/details/791229/cmfcribbonbar-app-does-not-maximize-correctly-if-windows-7-taskbar-is-docked-on-left
1183 if (nType == SIZE_MAXIMIZED)
1185 HMONITOR hMon = MonitorFromWindow(this->m_hWnd, MONITOR_DEFAULTTONEAREST);
1186 MONITORINFOEX mix;
1187 mix.cbSize = sizeof(MONITORINFOEX);
1188 bool primary = true; // assume primary monitor
1189 CRect rect(0, 0, 0, 0);
1190 if (GetMonitorInfo(hMon, &mix))
1192 primary = (mix.dwFlags == MONITORINFOF_PRIMARY);
1193 rect = mix.rcWork;
1195 else
1197 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
1199 if (primary)
1201 WINDOWPLACEMENT wp;
1202 GetWindowPlacement(&wp);
1203 if (wp.ptMaxPosition.x || wp.ptMaxPosition.y)
1205 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
1206 SetWindowPlacement(&wp);
1209 else
1211 MoveWindow(rect);
1214 #endif
1217 void CMainFrame::OnViewWhitespaces()
1219 CRegDWORD regViewWhitespaces = CRegDWORD(_T("Software\\TortoiseGitMerge\\ViewWhitespaces"), 1);
1220 BOOL bViewWhitespaces = regViewWhitespaces;
1221 if (m_pwndLeftView)
1222 bViewWhitespaces = m_pwndLeftView->m_bViewWhitespace;
1224 bViewWhitespaces = !bViewWhitespaces;
1225 regViewWhitespaces = bViewWhitespaces;
1226 if (m_pwndLeftView)
1228 m_pwndLeftView->m_bViewWhitespace = bViewWhitespaces;
1229 m_pwndLeftView->Invalidate();
1231 if (m_pwndRightView)
1233 m_pwndRightView->m_bViewWhitespace = bViewWhitespaces;
1234 m_pwndRightView->Invalidate();
1236 if (m_pwndBottomView)
1238 m_pwndBottomView->m_bViewWhitespace = bViewWhitespaces;
1239 m_pwndBottomView->Invalidate();
1243 void CMainFrame::OnUpdateViewWhitespaces(CCmdUI *pCmdUI)
1245 if (m_pwndLeftView)
1246 pCmdUI->SetCheck(m_pwndLeftView->m_bViewWhitespace);
1249 void CMainFrame::OnViewCollapsed()
1251 m_regCollapsed = !(DWORD)m_regCollapsed;
1252 m_bCollapsed = !!(DWORD)m_regCollapsed;
1254 OnViewTextFoldUnfold();
1255 m_wndLocatorBar.Invalidate();
1258 void CMainFrame::OnUpdateViewCollapsed(CCmdUI *pCmdUI)
1260 pCmdUI->SetCheck(m_bCollapsed);
1263 void CMainFrame::OnViewWraplonglines()
1265 m_bWrapLines = !(DWORD)m_regWrapLines;
1266 m_regWrapLines = m_bWrapLines;
1268 if (m_pwndLeftView) m_pwndLeftView ->WrapChanged();
1269 if (m_pwndRightView) m_pwndRightView ->WrapChanged();
1270 if (m_pwndBottomView) m_pwndBottomView->WrapChanged();
1271 OnViewTextFoldUnfold();
1272 m_wndLocatorBar.DocumentUpdated();
1275 void CMainFrame::OnViewTextFoldUnfold()
1277 OnViewTextFoldUnfold(m_pwndLeftView);
1278 OnViewTextFoldUnfold(m_pwndRightView);
1279 OnViewTextFoldUnfold(m_pwndBottomView);
1282 void CMainFrame::OnViewTextFoldUnfold(CBaseView* view)
1284 if (view == 0)
1285 return;
1286 view->BuildAllScreen2ViewVector();
1287 view->UpdateCaret();
1288 view->Invalidate();
1289 view->EnsureCaretVisible();
1292 void CMainFrame::OnUpdateViewWraplonglines(CCmdUI *pCmdUI)
1294 pCmdUI->SetCheck(m_bWrapLines);
1297 void CMainFrame::OnViewOnewaydiff()
1299 if (CheckForSave(CHFSR_RELOAD)==IDCANCEL)
1300 return;
1301 m_bOneWay = !m_bOneWay;
1302 ShowDiffBar(!m_bOneWay);
1303 LoadViews(-1);
1306 void CMainFrame::ShowDiffBar(bool bShow)
1308 if (bShow)
1310 // restore the line diff bar
1311 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
1312 m_wndLineDiffBar.DocumentUpdated();
1313 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
1314 m_wndLocatorBar.DocumentUpdated();
1316 else
1318 // in one way view, hide the line diff bar
1319 m_wndLineDiffBar.ShowPane(false, false, true);
1320 m_wndLineDiffBar.DocumentUpdated();
1324 int CMainFrame::CheckResolved()
1326 //only in three way diffs can be conflicts!
1327 m_bHasConflicts = true;
1328 if (IsViewGood(m_pwndBottomView))
1330 CViewData* viewdata = m_pwndBottomView->m_pViewData;
1331 if (viewdata)
1333 for (int i=0; i<viewdata->GetCount(); i++)
1335 const DiffStates state = viewdata->GetState(i);
1336 if ((DIFFSTATE_CONFLICTED == state)||(DIFFSTATE_CONFLICTED_IGNORED == state))
1337 return i;
1341 m_bHasConflicts = false;
1342 return -1;
1345 int CMainFrame::SaveFile(const CString& sFilePath)
1347 CBaseView * pView = NULL;
1348 CViewData * pViewData = NULL;
1349 CFileTextLines * pOriginFile = &m_Data.m_arBaseFile;
1350 if (IsViewGood(m_pwndBottomView))
1352 pView = m_pwndBottomView;
1353 pViewData = m_pwndBottomView->m_pViewData;
1355 else if (IsViewGood(m_pwndRightView))
1357 pView = m_pwndRightView;
1358 pViewData = m_pwndRightView->m_pViewData;
1359 if (m_Data.IsYourFileInUse())
1360 pOriginFile = &m_Data.m_arYourFile;
1361 else if (m_Data.IsTheirFileInUse())
1362 pOriginFile = &m_Data.m_arTheirFile;
1364 else
1366 // nothing to save!
1367 return 1;
1369 Invalidate();
1370 if ((pViewData)&&(pOriginFile))
1372 CFileTextLines file;
1373 pOriginFile->CopySettings(&file);
1374 CFileTextLines::SaveParams saveParams;
1375 saveParams.m_LineEndings = pView->GetLineEndings();
1376 saveParams.m_UnicodeType = pView->GetTextType();
1377 file.SetSaveParams(saveParams);
1378 for (int i=0; i<pViewData->GetCount(); i++)
1380 //only copy non-removed lines
1381 DiffStates state = pViewData->GetState(i);
1382 switch (state)
1384 case DIFFSTATE_CONFLICTED:
1385 case DIFFSTATE_CONFLICTED_IGNORED:
1387 int first = i;
1388 int last = i;
1391 last++;
1392 } while((last<pViewData->GetCount()) && ((pViewData->GetState(last)==DIFFSTATE_CONFLICTED)||(pViewData->GetState(last)==DIFFSTATE_CONFLICTED_IGNORED)));
1393 // TortoiseGitMerge changes here
1394 file.Add(_T("<<<<<<< .mine"), m_pwndRightView->GetLineEndings());
1395 for (int j=first; j<last; j++)
1397 EOL lineending = m_pwndRightView->m_pViewData->GetLineEnding(j);
1398 if (lineending == EOL_NOENDING)
1399 lineending = m_pwndRightView->GetLineEndings();
1400 file.Add(m_pwndRightView->m_pViewData->GetLine(j), lineending);
1402 file.Add(_T("======="), m_pwndRightView->GetLineEndings());
1403 for (int j=first; j<last; j++)
1405 EOL lineending = m_pwndLeftView->m_pViewData->GetLineEnding(j);
1406 if (lineending == EOL_NOENDING)
1407 lineending = m_pwndLeftView->GetLineEndings();
1408 file.Add(m_pwndLeftView->m_pViewData->GetLine(j), lineending);
1410 file.Add(_T(">>>>>>> .theirs"), m_pwndRightView->GetLineEndings());
1411 i = last-1;
1413 break;
1414 case DIFFSTATE_EMPTY:
1415 case DIFFSTATE_CONFLICTEMPTY:
1416 case DIFFSTATE_IDENTICALREMOVED:
1417 case DIFFSTATE_REMOVED:
1418 case DIFFSTATE_THEIRSREMOVED:
1419 case DIFFSTATE_YOURSREMOVED:
1420 case DIFFSTATE_CONFLICTRESOLVEDEMPTY:
1421 // do not save removed lines
1422 break;
1423 default:
1424 file.Add(pViewData->GetLine(i), pViewData->GetLineEnding(i));
1425 break;
1428 if (!file.Save(sFilePath, false, false))
1430 CMessageBox::Show(m_hWnd, file.GetErrorString(), _T("TortoiseGitMerge"), MB_ICONERROR);
1431 return -1;
1433 if (sFilePath == m_Data.m_baseFile.GetFilename())
1435 m_Data.m_baseFile.StoreFileAttributes();
1437 if (sFilePath == m_Data.m_theirFile.GetFilename())
1439 m_Data.m_theirFile.StoreFileAttributes();
1441 if (sFilePath == m_Data.m_yourFile.GetFilename())
1443 m_Data.m_yourFile.StoreFileAttributes();
1445 /*if (sFilePath == m_Data.m_mergedFile.GetFilename())
1447 m_Data.m_mergedFile.StoreFileAttributes();
1448 }//*/
1449 m_dlgFilePatches.SetFileStatusAsPatched(sFilePath);
1450 if (IsViewGood(m_pwndBottomView))
1451 m_pwndBottomView->SetModified(FALSE);
1452 else if (IsViewGood(m_pwndRightView))
1453 m_pwndRightView->SetModified(FALSE);
1454 CUndo::GetInstance().MarkAsOriginalState(
1455 false,
1456 IsViewGood(m_pwndRightView) && (pViewData == m_pwndRightView->m_pViewData),
1457 IsViewGood(m_pwndBottomView) && (pViewData == m_pwndBottomView->m_pViewData));
1458 if (file.GetCount() == 1 && file.GetAt(0).IsEmpty() && file.GetLineEnding(0) == EOL_NOENDING)
1459 return 0;
1460 return file.GetCount();
1462 return 1;
1465 void CMainFrame::OnFileSave()
1467 // when multiple files are set as writable we have to ask what file to save
1468 int nEditableViewCount =
1469 (CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsWritable() ? 1 : 0)
1470 + (CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsWritable() ? 1 : 0)
1471 + (CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsWritable() ? 1 : 0);
1472 bool bLeftIsModified = CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsModified();
1473 bool bRightIsModified = CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsModified();
1474 bool bBottomIsModified = CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsModified();
1475 int nModifiedViewCount =
1476 (bLeftIsModified ? 1 : 0)
1477 + (bRightIsModified ? 1 : 0)
1478 + (bBottomIsModified ? 1 : 0);
1479 if (nEditableViewCount>1)
1481 if (nModifiedViewCount == 1)
1483 if (bLeftIsModified)
1484 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1485 else
1486 FileSave();
1488 else if (nModifiedViewCount>0)
1490 // both views
1491 UINT ret = IDNO;
1492 if (m_bUseTaskDialog)
1494 CTaskDialog taskdlg(CString(MAKEINTRESOURCE(IDS_SAVE_MORE)),
1495 CString(MAKEINTRESOURCE(IDS_SAVE)),
1496 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1498 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
1499 CString sTaskTemp;
1500 if (m_pwndLeftView->m_pWorkingFile->InUse() && !m_pwndLeftView->m_pWorkingFile->IsReadonly())
1501 sTaskTemp.Format(IDS_ASKFORSAVE_SAVELEFT, (LPCTSTR)m_pwndLeftView->m_pWorkingFile->GetFilename());
1502 else
1503 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS));
1504 taskdlg.AddCommandControl(201, sTaskTemp, bLeftIsModified);// left
1505 if (bLeftIsModified) {
1506 taskdlg.SetDefaultCommandControl(201);
1508 if (m_pwndRightView->m_pWorkingFile->InUse() && !m_pwndRightView->m_pWorkingFile->IsReadonly())
1509 sTaskTemp.Format(IDS_ASKFORSAVE_SAVERIGHT, (LPCTSTR)m_pwndRightView->m_pWorkingFile->GetFilename());
1510 else
1511 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS));
1512 taskdlg.AddCommandControl(202, sTaskTemp, bRightIsModified); // right
1513 if (bRightIsModified) {
1514 taskdlg.SetDefaultCommandControl(202);
1516 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEALL2)), nModifiedViewCount>1); // both
1517 if (nModifiedViewCount>1) {
1518 taskdlg.SetDefaultCommandControl(203);
1520 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1521 taskdlg.SetMainIcon(TD_WARNING_ICON);
1522 ret = (UINT)taskdlg.DoModal(m_hWnd);
1523 switch (ret)
1525 case 201: // left
1526 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1527 break;
1528 case 203: // both
1529 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1530 case 202: // right
1531 m_pwndRightView->SaveFile();
1532 break;
1537 else
1539 // only target view was modified
1540 FileSave();
1544 void CMainFrame::PatchSave()
1546 bool bDoesNotExist = !PathFileExists(m_Data.m_mergedFile.GetFilename());
1547 if (m_Data.m_bPatchRequired)
1549 m_Patch.PatchPath(m_Data.m_mergedFile.GetFilename());
1551 if (!PathIsDirectory(m_Data.m_mergedFile.GetFilename()))
1553 int saveret = SaveFile(m_Data.m_mergedFile.GetFilename());
1554 if (saveret==0)
1556 // file was saved with 0 lines, remove it.
1557 m_Patch.RemoveFile(m_Data.m_mergedFile.GetFilename());
1558 // just in case
1559 DeleteFile(m_Data.m_mergedFile.GetFilename());
1561 m_Data.m_mergedFile.StoreFileAttributes();
1562 if (m_Data.m_mergedFile.GetFilename() == m_Data.m_yourFile.GetFilename())
1563 m_Data.m_yourFile.StoreFileAttributes();
1564 if ((bDoesNotExist)&&(DWORD(CRegDWORD(_T("Software\\TortoiseGitMerge\\AutoAdd"), TRUE))))
1566 // call TortoiseProc to add the new file to version control
1567 CString cmd = _T("/command:add /noui /path:\"");
1568 cmd += m_Data.m_mergedFile.GetFilename() + _T("\"");
1569 CAppUtils::RunTortoiseGitProc(cmd);
1574 bool CMainFrame::FileSave(bool bCheckResolved /*=true*/)
1576 if (!m_Data.m_mergedFile.InUse())
1577 return FileSaveAs(bCheckResolved);
1578 // check if the file has the readonly attribute set
1579 bool bDoesNotExist = false;
1580 DWORD fAttribs = GetFileAttributes(m_Data.m_mergedFile.GetFilename());
1581 if ((fAttribs != INVALID_FILE_ATTRIBUTES)&&(fAttribs & FILE_ATTRIBUTE_READONLY))
1582 return FileSaveAs(bCheckResolved);
1583 if (fAttribs == INVALID_FILE_ATTRIBUTES)
1585 bDoesNotExist = (GetLastError() == ERROR_FILE_NOT_FOUND);
1587 if (bCheckResolved && HasConflictsWontKeep())
1588 return false;
1590 if (((DWORD)CRegDWORD(_T("Software\\TortoiseGitMerge\\Backup"))) != 0)
1592 MoveFileEx(m_Data.m_mergedFile.GetFilename(), m_Data.m_mergedFile.GetFilename() + _T(".bak"), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
1594 if (m_Data.m_bPatchRequired)
1596 m_Patch.PatchPath(m_Data.m_mergedFile.GetFilename());
1598 int saveret = SaveFile(m_Data.m_mergedFile.GetFilename());
1599 if (saveret==0)
1601 // file was saved with 0 lines!
1602 // ask the user if the file should be deleted
1603 bool bDelete = false;
1604 if (m_bUseTaskDialog)
1606 CString msg;
1607 msg.Format(IDS_DELETEWHENEMPTY, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1608 CTaskDialog taskdlg(msg,
1609 CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK2)),
1610 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1612 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
1613 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK3)));
1614 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK4)));
1615 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1616 taskdlg.SetDefaultCommandControl(1);
1617 taskdlg.SetMainIcon(TD_WARNING_ICON);
1618 bDelete = (taskdlg.DoModal(m_hWnd) == 1);
1620 else
1622 CString sTemp;
1623 sTemp.Format(IDS_DELETEWHENEMPTY, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
1624 bDelete = (CMessageBox::ShowCheck(m_hWnd, sTemp, _T("TortoiseGitMerge"), MB_YESNO, _T("DeleteFileWhenEmpty")) == IDYES);
1626 if (bDelete)
1628 m_Patch.RemoveFile(m_Data.m_mergedFile.GetFilename());
1629 DeleteFile(m_Data.m_mergedFile.GetFilename());
1632 else if (saveret < 0)
1634 // error while saving the file
1635 return false;
1638 // if we're in conflict resolve mode (three pane view), check if there are no more conflicts
1639 // and if there aren't, ask to mark the file as resolved
1640 if (IsViewGood(m_pwndBottomView) && !m_bHasConflicts && bCheckResolved)
1642 CString projectRoot;
1643 if (g_GitAdminDir.HasAdminDir(m_Data.m_mergedFile.GetFilename(), false, &projectRoot))
1645 CString subpath = m_Data.m_mergedFile.GetFilename();
1646 subpath.Replace(_T('\\'), _T('/'));
1647 if (subpath.GetLength() >= projectRoot.GetLength())
1649 if (subpath[projectRoot.GetLength()] == _T('/'))
1650 subpath = subpath.Right(subpath.GetLength() - projectRoot.GetLength() - 1);
1651 else
1652 subpath = subpath.Right(subpath.GetLength() - projectRoot.GetLength());
1655 CAutoRepository repository(projectRoot);
1656 bool hasConflictInIndex = false;
1659 if (!repository)
1660 break;
1662 CAutoIndex index;
1663 if (git_repository_index(index.GetPointer(), repository))
1664 break;
1666 CStringA path = CUnicodeUtils::GetMulti(subpath, CP_UTF8);
1667 const git_index_entry * entry = git_index_get_bypath(index, path, 1);
1668 hasConflictInIndex = entry != nullptr;
1669 } while(0);
1671 if (hasConflictInIndex)
1673 bool bResolve = false;
1674 if (m_bUseTaskDialog)
1676 CString msg;
1677 msg.Format(IDS_MARKASRESOLVED, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1678 CTaskDialog taskdlg(msg,
1679 CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK2)),
1680 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1682 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
1683 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK3)));
1684 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK4)));
1685 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1686 taskdlg.SetDefaultCommandControl(1);
1687 taskdlg.SetMainIcon(TD_WARNING_ICON);
1688 bResolve = (taskdlg.DoModal(m_hWnd) == 1);
1690 else
1692 CString sTemp;
1693 sTemp.Format(IDS_MARKASRESOLVED, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1694 bResolve = (CMessageBox::Show(m_hWnd, sTemp, _T("TortoiseGitMerge"), MB_YESNO | MB_ICONQUESTION) == IDYES);
1696 if (bResolve)
1698 MarkAsResolved();
1704 m_bSaveRequired = false;
1705 m_Data.m_mergedFile.StoreFileAttributes();
1707 if ((bDoesNotExist)&&(DWORD(CRegDWORD(_T("Software\\TortoiseGitMerge\\AutoAdd"), TRUE))))
1709 // call TortoiseProc to add the new file to version control
1710 CString cmd = _T("/command:add /noui /path:\"");
1711 cmd += m_Data.m_mergedFile.GetFilename() + _T("\"");
1712 if(!CAppUtils::RunTortoiseGitProc(cmd))
1713 return false;
1715 return true;
1718 void CMainFrame::OnFileSaveAs()
1720 if (m_bUseTaskDialog)
1722 // ask what file to save as
1723 bool bHaveConflict = (CheckResolved() >= 0);
1724 CTaskDialog taskdlg(
1725 CString(MAKEINTRESOURCE(bHaveConflict ? IDS_ASKFORSAVEAS_MORECONFLICT : IDS_ASKFORSAVEAS_MORE)),
1726 CString(MAKEINTRESOURCE(IDS_ASKFORSAVEAS)),
1727 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1729 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
1730 // default can be last view (target) as was in 1.7 or actual (where is cursor) as is in most text editor
1731 if (IsViewGood(m_pwndLeftView))
1733 taskdlg.AddCommandControl(201, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS))); // left
1734 taskdlg.SetDefaultCommandControl(201);
1736 if (IsViewGood(m_pwndRightView))
1738 taskdlg.AddCommandControl(202, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS))); // right
1739 taskdlg.SetDefaultCommandControl(202);
1741 if (IsViewGood(m_pwndBottomView))
1743 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEBOTTOMAS))); // bottom
1744 taskdlg.SetDefaultCommandControl(203);
1746 if (bHaveConflict)
1748 taskdlg.AddCommandControl(204, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_NEEDRESOLVE))); // resolve
1749 taskdlg.SetDefaultCommandControl(204);
1751 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1752 taskdlg.SetMainIcon(bHaveConflict ? TD_WARNING_ICON : TD_INFORMATION_ICON);
1753 int nCommand = (int)taskdlg.DoModal(m_hWnd);
1754 CString sFileName;
1755 switch (nCommand)
1757 case 201: // left
1758 if (TryGetFileName(sFileName))
1760 // in 2, 3 view display we want to keep removed lines
1761 m_pwndLeftView->SaveFileTo(sFileName, IsViewGood(m_pwndRightView) ? SAVE_REMOVEDLINES : 0);
1763 break;
1764 case 202: // right
1765 if (TryGetFileName(sFileName))
1767 m_pwndRightView->SaveFileTo(sFileName);
1769 break;
1770 case 203: // bottom
1771 FileSaveAs();
1772 break;
1773 case 204: // continue resolving
1774 if (m_pwndBottomView)
1776 m_pwndBottomView->GoToLine(CheckResolved());
1778 break;
1781 else
1783 int nEditableViewCount =
1784 (CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsWritable() ? 1 : 0)
1785 + (CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsWritable() ? 1 : 0)
1786 + (CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsWritable() ? 1 : 0);
1787 bool bLeftIsModified = CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsModified();
1788 bool bRightIsModified = CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsModified();
1789 bool bBottomIsModified = CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsModified();
1790 int nModifiedViewCount =
1791 (bLeftIsModified ? 1 : 0)
1792 + (bRightIsModified ? 1 : 0)
1793 + (bBottomIsModified ? 1 : 0);
1794 if (nEditableViewCount>1)
1796 if (nModifiedViewCount == 1)
1798 if (bLeftIsModified)
1800 CString sFileName;
1801 if (TryGetFileName(sFileName))
1803 m_pwndLeftView->SaveFileTo(sFileName);
1806 else
1807 FileSaveAs();
1809 else
1811 FileSaveAs();
1812 CString sFileName;
1813 if (TryGetFileName(sFileName))
1815 m_pwndLeftView->SaveFileTo(sFileName);
1822 bool CMainFrame::FileSaveAs(bool bCheckResolved /*=true*/)
1824 if (bCheckResolved && HasConflictsWontKeep())
1825 return false;
1827 CString fileName;
1828 if(!TryGetFileName(fileName))
1829 return false;
1831 SaveFile(fileName);
1832 return true;
1835 void CMainFrame::OnUpdateFileSave(CCmdUI *pCmdUI)
1837 BOOL bEnable = FALSE;
1838 if (m_Data.m_mergedFile.InUse())
1840 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1841 bEnable = TRUE;
1842 else if ( (IsViewGood(m_pwndRightView)&&(m_pwndRightView->m_pViewData)) &&
1843 (m_pwndRightView->IsModified() || (m_Data.m_yourFile.GetWindowName().Right(9).Compare(_T(": patched"))==0)) )
1844 bEnable = TRUE;
1845 else if (IsViewGood(m_pwndLeftView)
1846 && (m_pwndLeftView->m_pViewData)
1847 && (m_pwndLeftView->IsModified()))
1848 bEnable = TRUE;
1850 pCmdUI->Enable(bEnable);
1853 void CMainFrame::OnUpdateFileSaveAs(CCmdUI *pCmdUI)
1855 // any file is open we can save it as
1856 BOOL bEnable = FALSE;
1857 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1858 bEnable = TRUE;
1859 else if (IsViewGood(m_pwndRightView)&&(m_pwndRightView->m_pViewData))
1860 bEnable = TRUE;
1861 else if (IsViewGood(m_pwndLeftView)&&(m_pwndLeftView->m_pViewData))
1862 bEnable = TRUE;
1863 pCmdUI->Enable(bEnable);
1866 void CMainFrame::OnUpdateViewOnewaydiff(CCmdUI *pCmdUI)
1868 pCmdUI->SetCheck(!m_bOneWay);
1869 BOOL bEnable = TRUE;
1870 if (IsViewGood(m_pwndBottomView))
1872 bEnable = FALSE;
1874 pCmdUI->Enable(bEnable);
1877 void CMainFrame::OnViewOptions()
1879 CString sTemp;
1880 sTemp.LoadString(IDS_SETTINGSTITLE);
1881 CSettings dlg(sTemp);
1882 dlg.DoModal();
1883 if (dlg.IsReloadNeeded())
1885 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
1886 return;
1887 CDiffColors::GetInstance().LoadRegistry();
1888 LoadViews();
1889 return;
1891 CDiffColors::GetInstance().LoadRegistry();
1892 if (m_pwndBottomView)
1893 m_pwndBottomView->Invalidate();
1894 if (m_pwndLeftView)
1895 m_pwndLeftView->Invalidate();
1896 if (m_pwndRightView)
1897 m_pwndRightView->Invalidate();
1900 void CMainFrame::OnClose()
1902 if (CheckForSave(CHFSR_CLOSE)!=IDCANCEL)
1904 WINDOWPLACEMENT wp;
1906 // before it is destroyed, save the position of the window
1907 wp.length = sizeof wp;
1909 if (GetWindowPlacement(&wp))
1912 if (IsIconic())
1913 // never restore to Iconic state
1914 wp.showCmd = SW_SHOW ;
1916 if ((wp.flags & WPF_RESTORETOMAXIMIZED) != 0)
1917 // if maximized and maybe iconic restore maximized state
1918 wp.showCmd = SW_SHOWMAXIMIZED ;
1920 // and write it
1921 WriteWindowPlacement(&wp);
1923 __super::OnClose();
1927 void CMainFrame::OnActivate(UINT nValue, CWnd* /*pwnd*/, BOOL /*bActivated?*/)
1929 if (nValue != 0) // activated
1931 if (IsIconic())
1933 m_bCheckReload = TRUE;
1935 else
1937 // use a timer to give other messages time to get processed
1938 // first, like e.g. the WM_CLOSE message in case the user
1939 // clicked the close button and that brought the window
1940 // to the front - in that case checking for reload wouldn't
1941 // do any good.
1942 SetTimer(IDT_RELOADCHECKTIMER, 300, NULL);
1947 void CMainFrame::OnViewLinedown()
1949 OnViewLineUpDown(1);
1952 void CMainFrame::OnViewLineup()
1954 OnViewLineUpDown(-1);
1957 void CMainFrame::OnViewLineUpDown(int direction)
1959 if (m_pwndLeftView)
1960 m_pwndLeftView->ScrollToLine(m_pwndLeftView->m_nTopLine+direction);
1961 if (m_pwndRightView)
1962 m_pwndRightView->ScrollToLine(m_pwndRightView->m_nTopLine+direction);
1963 if (m_pwndBottomView)
1964 m_pwndBottomView->ScrollToLine(m_pwndBottomView->m_nTopLine+direction);
1965 m_wndLocatorBar.Invalidate();
1966 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1969 void CMainFrame::OnViewLineleft()
1971 OnViewLineLeftRight(-1);
1974 void CMainFrame::OnViewLineright()
1976 OnViewLineLeftRight(1);
1979 void CMainFrame::OnViewLineLeftRight(int direction)
1981 if (m_pwndLeftView)
1982 m_pwndLeftView->ScrollSide(direction);
1983 if (m_pwndRightView)
1984 m_pwndRightView->ScrollSide(direction);
1985 if (m_pwndBottomView)
1986 m_pwndBottomView->ScrollSide(direction);
1989 void CMainFrame::OnEditUseTheirs()
1991 if (m_pwndBottomView)
1992 m_pwndBottomView->UseTheirTextBlock();
1994 void CMainFrame::OnUpdateEditUsetheirblock(CCmdUI *pCmdUI)
1996 pCmdUI->Enable(m_pwndBottomView && m_pwndBottomView->HasSelection());
1999 void CMainFrame::OnEditUseMine()
2001 if (m_pwndBottomView)
2002 m_pwndBottomView->UseMyTextBlock();
2004 void CMainFrame::OnUpdateEditUsemyblock(CCmdUI *pCmdUI)
2006 OnUpdateEditUsetheirblock(pCmdUI);
2009 void CMainFrame::OnEditUseTheirsThenMine()
2011 if (m_pwndBottomView)
2012 m_pwndBottomView->UseTheirAndYourBlock();
2015 void CMainFrame::OnUpdateEditUsetheirthenmyblock(CCmdUI *pCmdUI)
2017 OnUpdateEditUsetheirblock(pCmdUI);
2020 void CMainFrame::OnEditUseMineThenTheirs()
2022 if (m_pwndBottomView)
2023 m_pwndBottomView->UseYourAndTheirBlock();
2026 void CMainFrame::OnUpdateEditUseminethentheirblock(CCmdUI *pCmdUI)
2028 OnUpdateEditUsetheirblock(pCmdUI);
2031 void CMainFrame::OnEditUseleftblock()
2033 if (m_pwndBottomView->IsWindowVisible())
2034 m_pwndBottomView->UseRightBlock();
2035 else
2036 m_pwndRightView->UseLeftBlock();
2039 void CMainFrame::OnUpdateEditUseleftblock(CCmdUI *pCmdUI)
2041 pCmdUI->Enable(IsViewGood(m_pwndRightView) && m_pwndRightView->IsTarget() && m_pwndRightView->HasSelection());
2044 void CMainFrame::OnUpdateUseBlock(CCmdUI *pCmdUI)
2046 pCmdUI->Enable(TRUE);
2049 void CMainFrame::OnEditUseleftfile()
2051 if (m_pwndBottomView->IsWindowVisible())
2052 m_pwndBottomView->UseRightFile();
2053 else
2054 m_pwndRightView->UseLeftFile();
2057 void CMainFrame::OnUpdateEditUseleftfile(CCmdUI *pCmdUI)
2059 pCmdUI->Enable(IsViewGood(m_pwndRightView) && m_pwndRightView->IsTarget());
2062 void CMainFrame::OnEditUseblockfromleftbeforeright()
2064 if (m_pwndRightView)
2065 m_pwndRightView->UseBothLeftFirst();
2068 void CMainFrame::OnUpdateEditUseblockfromleftbeforeright(CCmdUI *pCmdUI)
2070 OnUpdateEditUseleftblock(pCmdUI);
2073 void CMainFrame::OnEditUseblockfromrightbeforeleft()
2075 if (m_pwndRightView)
2076 m_pwndRightView->UseBothRightFirst();
2079 void CMainFrame::OnUpdateEditUseblockfromrightbeforeleft(CCmdUI *pCmdUI)
2081 OnUpdateEditUseleftblock(pCmdUI);
2084 void CMainFrame::OnFileReload()
2086 if (CheckForSave(CHFSR_RELOAD)==IDCANCEL)
2087 return;
2088 CDiffColors::GetInstance().LoadRegistry();
2089 LoadViews(-1);
2092 void CMainFrame::ActivateFrame(int nCmdShow)
2094 // nCmdShow is the normal show mode this frame should be in
2095 // translate default nCmdShow (-1)
2096 if (nCmdShow == -1)
2098 if (!IsWindowVisible())
2099 nCmdShow = SW_SHOWNORMAL;
2100 else if (IsIconic())
2101 nCmdShow = SW_RESTORE;
2104 // bring to top before showing
2105 BringToTop(nCmdShow);
2107 if (nCmdShow != -1)
2109 // show the window as specified
2110 WINDOWPLACEMENT wp;
2112 if ( !ReadWindowPlacement(&wp) )
2114 ShowWindow(nCmdShow);
2116 else
2118 if ( nCmdShow != SW_SHOWNORMAL )
2119 wp.showCmd = nCmdShow;
2121 SetWindowPlacement(&wp);
2124 // and finally, bring to top after showing
2125 BringToTop(nCmdShow);
2129 BOOL CMainFrame::ReadWindowPlacement(WINDOWPLACEMENT * pwp)
2131 CRegString placement = CRegString(_T("Software\\TortoiseGitMerge\\WindowPos"));
2132 CString sPlacement = placement;
2133 if (sPlacement.IsEmpty())
2134 return FALSE;
2135 int nRead = _stscanf_s(sPlacement, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
2136 &pwp->flags, &pwp->showCmd,
2137 &pwp->ptMinPosition.x, &pwp->ptMinPosition.y,
2138 &pwp->ptMaxPosition.x, &pwp->ptMaxPosition.y,
2139 &pwp->rcNormalPosition.left, &pwp->rcNormalPosition.top,
2140 &pwp->rcNormalPosition.right, &pwp->rcNormalPosition.bottom);
2141 if ( nRead != 10 )
2142 return FALSE;
2143 pwp->length = sizeof(WINDOWPLACEMENT);
2145 return TRUE;
2148 void CMainFrame::WriteWindowPlacement(WINDOWPLACEMENT * pwp)
2150 CRegString placement = CRegString(_T("Software\\TortoiseGitMerge\\WindowPos"));
2151 TCHAR szBuffer[_countof("-32767")*8 + sizeof("65535")*2];
2153 _stprintf_s(szBuffer, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
2154 pwp->flags, pwp->showCmd,
2155 pwp->ptMinPosition.x, pwp->ptMinPosition.y,
2156 pwp->ptMaxPosition.x, pwp->ptMaxPosition.y,
2157 pwp->rcNormalPosition.left, pwp->rcNormalPosition.top,
2158 pwp->rcNormalPosition.right, pwp->rcNormalPosition.bottom);
2159 placement = szBuffer;
2162 void CMainFrame::OnUpdateMergeMarkasresolved(CCmdUI *pCmdUI)
2164 if (pCmdUI == NULL)
2165 return;
2166 BOOL bEnable = FALSE;
2167 if ((!m_bReadOnly)&&(m_Data.m_mergedFile.InUse()))
2169 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
2171 bEnable = TRUE;
2174 pCmdUI->Enable(bEnable);
2177 void CMainFrame::OnMergeMarkasresolved()
2179 if(HasConflictsWontKeep())
2180 return;
2182 // now check if the file has already been saved and if not, save it.
2183 if (m_Data.m_mergedFile.InUse())
2185 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
2187 FileSave(false);
2188 m_bSaveRequired = false;
2191 MarkAsResolved();
2194 BOOL CMainFrame::MarkAsResolved()
2196 if (m_bReadOnly)
2197 return FALSE;
2198 if (!IsViewGood(m_pwndBottomView))
2199 return FALSE;
2201 CString cmd = _T("/command:resolve /path:\"");
2202 cmd += m_Data.m_mergedFile.GetFilename();
2203 cmd += _T("\" /closeonend:1 /noquestion /skipcheck /silent");
2204 if (resolveMsgWnd)
2206 CString s;
2207 s.Format(L" /resolvemsghwnd:%I64d /resolvemsgwparam:%I64d /resolvemsglparam:%I64d", (__int64)resolveMsgWnd, (__int64)resolveMsgWParam, (__int64)resolveMsgLParam);
2208 cmd += s;
2210 if(!CAppUtils::RunTortoiseGitProc(cmd))
2211 return FALSE;
2212 m_bSaveRequired = false;
2213 return TRUE;
2216 void CMainFrame::OnUpdateMergeNextconflict(CCmdUI *pCmdUI)
2218 BOOL bShow = FALSE;
2219 if (HasNextConflict(m_pwndBottomView))
2220 bShow = TRUE;
2221 else if (HasNextConflict(m_pwndRightView))
2222 bShow = TRUE;
2223 else if (HasNextConflict(m_pwndLeftView))
2224 bShow = TRUE;
2225 pCmdUI->Enable(bShow);
2228 bool CMainFrame::HasNextConflict(CBaseView* view)
2230 if (view == 0)
2231 return false;
2232 if (!view->IsTarget())
2233 return false;
2234 return view->HasNextConflict();
2237 void CMainFrame::OnUpdateMergePreviousconflict(CCmdUI *pCmdUI)
2239 BOOL bShow = FALSE;
2240 if (HasPrevConflict(m_pwndBottomView))
2241 bShow = TRUE;
2242 else if (HasPrevConflict(m_pwndRightView))
2243 bShow = TRUE;
2244 else if (HasPrevConflict(m_pwndLeftView))
2245 bShow = TRUE;
2246 pCmdUI->Enable(bShow);
2249 bool CMainFrame::HasPrevConflict(CBaseView* view)
2251 if (view == 0)
2252 return false;
2253 if (!view->IsTarget())
2254 return false;
2255 return view->HasPrevConflict();
2258 void CMainFrame::OnUpdateNavigateNextdifference(CCmdUI *pCmdUI)
2260 CBaseView* baseView = GetActiveBaseView();
2261 BOOL bShow = FALSE;
2262 if (baseView != 0)
2263 bShow = baseView->HasNextDiff();
2264 pCmdUI->Enable(bShow);
2267 void CMainFrame::OnUpdateNavigatePreviousdifference(CCmdUI *pCmdUI)
2269 CBaseView* baseView = GetActiveBaseView();
2270 BOOL bShow = FALSE;
2271 if (baseView != 0)
2272 bShow = baseView->HasPrevDiff();
2273 pCmdUI->Enable(bShow);
2276 void CMainFrame::OnUpdateNavigateNextinlinediff(CCmdUI *pCmdUI)
2278 BOOL bShow = FALSE;
2279 if (HasNextInlineDiff(m_pwndBottomView))
2280 bShow = TRUE;
2281 else if (HasNextInlineDiff(m_pwndRightView))
2282 bShow = TRUE;
2283 else if (HasNextInlineDiff(m_pwndLeftView))
2284 bShow = TRUE;
2285 pCmdUI->Enable(bShow);
2288 bool CMainFrame::HasNextInlineDiff(CBaseView* view)
2290 if (view == 0)
2291 return false;
2292 if (!view->IsTarget())
2293 return false;
2294 return view->HasNextInlineDiff();
2297 void CMainFrame::OnUpdateNavigatePrevinlinediff(CCmdUI *pCmdUI)
2299 BOOL bShow = FALSE;
2300 if (HasPrevInlineDiff(m_pwndBottomView))
2301 bShow = TRUE;
2302 else if (HasPrevInlineDiff(m_pwndRightView))
2303 bShow = TRUE;
2304 else if (HasPrevInlineDiff(m_pwndLeftView))
2305 bShow = TRUE;
2306 pCmdUI->Enable(bShow);
2309 bool CMainFrame::HasPrevInlineDiff(CBaseView* view)
2311 if (view == 0)
2312 return false;
2313 if (!view->IsTarget())
2314 return false;
2315 return view->HasPrevInlineDiff();
2318 void CMainFrame::OnMoving(UINT fwSide, LPRECT pRect)
2320 // if the pathfilelist dialog is attached to the mainframe,
2321 // move it along with the mainframe
2322 if (::IsWindow(m_dlgFilePatches.m_hWnd))
2324 RECT patchrect;
2325 m_dlgFilePatches.GetWindowRect(&patchrect);
2326 if (::IsWindow(m_hWnd))
2328 RECT thisrect;
2329 GetWindowRect(&thisrect);
2330 if (patchrect.right == thisrect.left)
2332 m_dlgFilePatches.SetWindowPos(NULL, patchrect.left - (thisrect.left - pRect->left), patchrect.top - (thisrect.top - pRect->top),
2333 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
2337 __super::OnMoving(fwSide, pRect);
2340 void CMainFrame::OnUpdateEditCopy(CCmdUI *pCmdUI)
2342 BOOL bShow = FALSE;
2343 if ((m_pwndBottomView)&&(m_pwndBottomView->HasSelection()))
2344 bShow = TRUE;
2345 else if ((m_pwndRightView)&&(m_pwndRightView->HasSelection()))
2346 bShow = TRUE;
2347 else if ((m_pwndLeftView)&&(m_pwndLeftView->HasSelection()))
2348 bShow = TRUE;
2349 pCmdUI->Enable(bShow);
2352 void CMainFrame::OnUpdateEditPaste(CCmdUI *pCmdUI)
2354 BOOL bWritable = FALSE;
2355 if ((m_pwndBottomView)&&(m_pwndBottomView->IsWritable()))
2356 bWritable = TRUE;
2357 else if ((m_pwndRightView)&&(m_pwndRightView->IsWritable()))
2358 bWritable = TRUE;
2359 else if ((m_pwndLeftView)&&(m_pwndLeftView->IsWritable()))
2360 bWritable = TRUE;
2361 pCmdUI->Enable(bWritable && ::IsClipboardFormatAvailable(CF_TEXT));
2364 void CMainFrame::OnViewSwitchleft()
2366 if (CheckForSave(CHFSR_SWITCH)!=IDCANCEL)
2368 CWorkingFile file = m_Data.m_baseFile;
2369 m_Data.m_baseFile = m_Data.m_yourFile;
2370 m_Data.m_yourFile = file;
2371 if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_yourFile.GetFilename())==0)
2373 m_Data.m_mergedFile = m_Data.m_baseFile;
2375 else if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_baseFile.GetFilename())==0)
2377 m_Data.m_mergedFile = m_Data.m_yourFile;
2379 LoadViews();
2383 void CMainFrame::OnUpdateViewSwitchleft(CCmdUI *pCmdUI)
2385 BOOL bEnable = !IsViewGood(m_pwndBottomView);
2386 pCmdUI->Enable(bEnable);
2389 void CMainFrame::OnUpdateViewShowfilelist(CCmdUI *pCmdUI)
2391 BOOL bEnable = m_dlgFilePatches.HasFiles();
2392 pCmdUI->Enable(bEnable);
2393 pCmdUI->SetCheck(m_dlgFilePatches.IsWindowVisible());
2396 void CMainFrame::OnViewShowfilelist()
2398 m_dlgFilePatches.ShowWindow(m_dlgFilePatches.IsWindowVisible() ? SW_HIDE : SW_SHOW);
2401 void CMainFrame::OnEditUndo()
2403 if (CUndo::GetInstance().CanUndo())
2405 CUndo::GetInstance().Undo(m_pwndLeftView, m_pwndRightView, m_pwndBottomView);
2409 void CMainFrame::OnUpdateEditUndo(CCmdUI *pCmdUI)
2411 pCmdUI->Enable(CUndo::GetInstance().CanUndo());
2414 void CMainFrame::OnEditEnable()
2416 CBaseView * pView = GetActiveBaseView();
2417 if (pView && pView->IsReadonlyChangable())
2419 bool isReadOnly = pView->IsReadonly();
2420 pView->SetReadonly(!isReadOnly);
2424 void CMainFrame::OnUpdateEditEnable(CCmdUI *pCmdUI)
2426 CBaseView * pView = GetActiveBaseView();
2427 if (pView)
2429 pCmdUI->Enable(pView->IsReadonlyChangable() || !pView->IsReadonly());
2430 pCmdUI->SetCheck(!pView->IsReadonly());
2432 else
2434 pCmdUI->Enable(FALSE);
2438 void CMainFrame::OnIndicatorLeftview()
2440 if (m_bUseRibbons)
2441 return;
2442 if (IsViewGood(m_pwndLeftView))
2444 m_pwndLeftView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_LEFTVIEW);
2448 void CMainFrame::OnIndicatorRightview()
2450 if (m_bUseRibbons)
2451 return;
2452 if (IsViewGood(m_pwndRightView))
2454 m_pwndRightView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_RIGHTVIEW);
2458 void CMainFrame::OnIndicatorBottomview()
2460 if (m_bUseRibbons)
2461 return;
2462 if (IsViewGood(m_pwndBottomView))
2464 m_pwndBottomView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_BOTTOMVIEW);
2468 int CMainFrame::CheckForReload()
2470 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
2471 if (bLock)
2473 return IDNO;
2475 bLock = true;
2476 bool bSourceChanged =
2477 m_Data.m_baseFile.HasSourceFileChanged()
2478 || m_Data.m_yourFile.HasSourceFileChanged()
2479 || m_Data.m_theirFile.HasSourceFileChanged()
2480 /*|| m_Data.m_mergedFile.HasSourceFileChanged()*/;
2481 if (!bSourceChanged)
2483 bLock = false;
2484 return IDNO;
2487 UINT ret = IDNO;
2488 if (m_bUseTaskDialog)
2490 CString msg = HasUnsavedEdits() ? CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDELOOSECHANGES)) : CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE));
2491 CTaskDialog taskdlg(msg,
2492 CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE_TASK2)),
2493 L"TortoiseGitMerge",
2495 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
2496 CString sTask3;
2497 if (HasUnsavedEdits())
2498 sTask3.LoadString(IDS_WARNMODIFIEDOUTSIDE_TASK3);
2499 else
2500 sTask3.LoadString(IDS_WARNMODIFIEDOUTSIDE_TASK4);
2501 taskdlg.AddCommandControl(IDYES, sTask3);
2502 taskdlg.AddCommandControl(IDNO, CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE_TASK5)));
2503 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2504 taskdlg.SetDefaultCommandControl(IDYES);
2505 taskdlg.SetMainIcon(TD_WARNING_ICON);
2506 ret = (UINT)taskdlg.DoModal(m_hWnd);
2508 else
2510 int idsMessage = HasUnsavedEdits() ? IDS_WARNMODIFIEDOUTSIDELOOSECHANGES : IDS_WARNMODIFIEDOUTSIDE;
2511 ret = CMessageBox::Show(m_hWnd, idsMessage, IDS_APPNAME, MB_YESNO | MB_ICONQUESTION);
2514 if (ret == IDYES)
2516 CDiffColors::GetInstance().LoadRegistry();
2517 LoadViews(-1);
2519 else
2521 if (IsViewGood(m_pwndBottomView)) // three pane view
2523 /*if (m_Data.m_sourceFile.HasSourceFileChanged())
2524 m_pwndBottomView->SetModified();
2525 if (m_Data.m_mergedFile.HasSourceFileChanged())
2526 m_pwndBottomView->SetModified();//*/
2527 if (m_Data.m_yourFile.HasSourceFileChanged())
2528 m_pwndRightView->SetModified();
2529 if (m_Data.m_theirFile.HasSourceFileChanged())
2530 m_pwndLeftView->SetModified();
2532 else if (IsViewGood(m_pwndRightView)) // two pane view
2534 if (m_Data.m_baseFile.HasSourceFileChanged())
2535 m_pwndLeftView->SetModified();
2536 if (m_Data.m_yourFile.HasSourceFileChanged())
2537 m_pwndRightView->SetModified();
2539 else
2541 if (m_Data.m_yourFile.HasSourceFileChanged())
2542 m_pwndLeftView->SetModified();
2545 // no reload just store updated file time
2546 m_Data.m_baseFile.StoreFileAttributes();
2547 m_Data.m_theirFile.StoreFileAttributes();
2548 m_Data.m_yourFile.StoreFileAttributes();
2549 //m_Data.m_mergedFile.StoreFileAttributes();
2551 bLock = false;
2552 return ret;
2555 int CMainFrame::CheckForSave(ECheckForSaveReason eReason)
2557 int idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2558 int idNoSave = IDS_ASKFORSAVE_TASK7;
2559 int idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2560 switch (eReason)
2562 case CHFSR_CLOSE:
2563 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2564 idNoSave = IDS_ASKFORSAVE_TASK4;
2565 idCancelAction = IDS_ASKFORSAVE_TASK5;
2566 break;
2567 case CHFSR_SWITCH:
2568 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2569 //idNoSave = IDS_ASKFORSAVE_TASK7;
2570 idCancelAction = IDS_ASKFORSAVE_TASK8;
2571 break;
2572 case CHFSR_RELOAD:
2573 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2574 //idNoSave = IDS_ASKFORSAVE_TASK7;
2575 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2576 break;
2577 case CHFSR_OPTIONS:
2578 idTitle = IDS_WARNMODIFIEDLOOSECHANGESOPTIONS;
2579 //idNoSave = IDS_ASKFORSAVE_TASK7;
2580 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPTIONS;
2581 break;
2582 case CHFSR_OPEN:
2583 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2584 idNoSave = IDS_ASKFORSAVE_NOSAVE_OPEN;
2585 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2586 break;
2589 CString sTitle(MAKEINTRESOURCE(idTitle));
2590 CString sSubTitle(MAKEINTRESOURCE(IDS_ASKFORSAVE_TASK2));
2591 CString sNoSave(MAKEINTRESOURCE(idNoSave));
2592 CString sCancelAction(MAKEINTRESOURCE(idCancelAction));
2593 CString sAppName(MAKEINTRESOURCE(IDS_APPNAME));
2595 // TODO simplify logic, reduce code duplication
2596 if (CBaseView::IsViewGood(m_pwndBottomView))
2598 // three-way diff - by design only bottom can be changed
2599 // use 1.7 way to do that
2601 else if (CBaseView::IsViewGood(m_pwndRightView))
2603 // two-way diff -
2604 // 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
2605 if (HasUnsavedEdits(m_pwndLeftView))
2607 // both views
2608 UINT ret = IDNO;
2609 if (m_bUseTaskDialog)
2611 CTaskDialog taskdlg(sTitle,
2612 sSubTitle,
2613 sAppName,
2615 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
2616 CString sTaskTemp;
2617 if (m_pwndLeftView->m_pWorkingFile->InUse() && !m_pwndLeftView->m_pWorkingFile->IsReadonly())
2618 sTaskTemp.Format(IDS_ASKFORSAVE_SAVELEFT, (LPCTSTR)m_pwndLeftView->m_pWorkingFile->GetFilename());
2619 else
2620 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS));
2621 taskdlg.AddCommandControl(201, sTaskTemp); // left
2622 taskdlg.SetDefaultCommandControl(201);
2623 if (HasUnsavedEdits(m_pwndRightView))
2625 if (m_pwndRightView->m_pWorkingFile->InUse() && !m_pwndRightView->m_pWorkingFile->IsReadonly())
2626 sTaskTemp.Format(IDS_ASKFORSAVE_SAVERIGHT, (LPCTSTR)m_pwndRightView->m_pWorkingFile->GetFilename());
2627 else
2628 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS));
2629 taskdlg.AddCommandControl(202, sTaskTemp); // right
2630 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEALL2))); // both
2631 taskdlg.SetDefaultCommandControl(203);
2633 taskdlg.AddCommandControl(IDNO, sNoSave); // none
2634 taskdlg.AddCommandControl(IDCANCEL, sCancelAction); // cancel
2635 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2636 taskdlg.SetMainIcon(TD_WARNING_ICON);
2637 ret = (UINT)taskdlg.DoModal(m_hWnd);
2638 switch (ret)
2640 case 201: // left
2641 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
2642 break;
2643 case 203: // both
2644 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
2645 case 202: // right
2646 m_pwndRightView->SaveFile();
2647 break;
2649 return ret;
2651 else
2653 // show separate questions
2654 // first show question for left view
2655 ret = MessageBox(sTitle, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
2656 if (ret == IDCANCEL)
2658 return IDCANCEL;
2660 if (ret == IDYES)
2662 if (m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES)<0)
2664 return IDCANCEL;
2667 // right file is handled old way
2670 else
2672 // only secondary (left) view
2674 // only right view - 1.7 implementation is used
2676 else if (CBaseView::IsViewGood(m_pwndLeftView))
2678 // only one view - only one to save
2679 // 1.7 FileSave don't support this mode
2680 if (HasUnsavedEdits(m_pwndLeftView))
2682 UINT ret = IDNO;
2683 if (m_bUseTaskDialog)
2685 CTaskDialog taskdlg(sTitle,
2686 sSubTitle,
2687 sAppName,
2689 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
2690 CString sTask3;
2691 if (m_Data.m_mergedFile.InUse())
2692 sTask3.Format(IDS_ASKFORSAVE_TASK3, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
2693 else
2694 sTask3.LoadString(IDS_ASKFORSAVE_TASK6);
2695 taskdlg.AddCommandControl(IDYES, sTask3);
2696 taskdlg.AddCommandControl(IDNO, sNoSave);
2697 taskdlg.AddCommandControl(IDCANCEL, sCancelAction);
2698 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2699 taskdlg.SetDefaultCommandControl(IDYES);
2700 taskdlg.SetMainIcon(TD_WARNING_ICON);
2701 ret = (UINT)taskdlg.DoModal(m_hWnd);
2703 else
2705 ret = MessageBox(sTitle, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
2708 if (ret == IDYES)
2710 if (m_pwndLeftView->SaveFile()<0)
2711 return IDCANCEL;
2714 return IDNO;
2716 else
2718 return IDNO; // nothing to save
2721 // 1.7 implementation
2722 UINT ret = IDNO;
2723 if (HasUnsavedEdits())
2725 if (m_bUseTaskDialog)
2727 CTaskDialog taskdlg(sTitle,
2728 sSubTitle,
2729 sAppName,
2731 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
2732 CString sTask3;
2733 if (m_Data.m_mergedFile.InUse())
2734 sTask3.Format(IDS_ASKFORSAVE_TASK3, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
2735 else
2736 sTask3.LoadString(IDS_ASKFORSAVE_TASK6);
2737 taskdlg.AddCommandControl(IDYES, sTask3);
2738 taskdlg.AddCommandControl(IDNO, sNoSave);
2739 taskdlg.AddCommandControl(IDCANCEL, sCancelAction);
2740 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2741 taskdlg.SetDefaultCommandControl(IDYES);
2742 taskdlg.SetMainIcon(TD_WARNING_ICON);
2743 ret = (UINT)taskdlg.DoModal(m_hWnd);
2745 else
2747 ret = MessageBox(sTitle, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
2750 if (ret == IDYES)
2752 if (!FileSave())
2753 ret = IDCANCEL;
2756 return ret;
2759 bool CMainFrame::HasUnsavedEdits() const
2761 return HasUnsavedEdits(m_pwndBottomView) || HasUnsavedEdits(m_pwndRightView) || m_bSaveRequired;
2764 bool CMainFrame::HasUnsavedEdits(const CBaseView* view)
2766 if (!CBaseView::IsViewGood(view))
2767 return false;
2768 return view->IsModified();
2771 bool CMainFrame::IsViewGood(const CBaseView* view)
2773 return CBaseView::IsViewGood(view);
2776 void CMainFrame::OnViewInlinediffword()
2778 m_bInlineWordDiff = !m_bInlineWordDiff;
2779 if (m_pwndLeftView)
2781 m_pwndLeftView->SetInlineWordDiff(m_bInlineWordDiff);
2782 m_pwndLeftView->BuildAllScreen2ViewVector();
2783 m_pwndLeftView->DocumentUpdated();
2785 if (m_pwndRightView)
2787 m_pwndRightView->SetInlineWordDiff(m_bInlineWordDiff);
2788 m_pwndRightView->BuildAllScreen2ViewVector();
2789 m_pwndRightView->DocumentUpdated();
2791 if (m_pwndBottomView)
2793 m_pwndBottomView->SetInlineWordDiff(m_bInlineWordDiff);
2794 m_pwndBottomView->BuildAllScreen2ViewVector();
2795 m_pwndBottomView->DocumentUpdated();
2797 m_wndLineDiffBar.DocumentUpdated();
2800 void CMainFrame::OnUpdateViewInlinediffword(CCmdUI *pCmdUI)
2802 pCmdUI->Enable(m_bInlineDiff && IsViewGood(m_pwndLeftView) && IsViewGood(m_pwndRightView));
2803 pCmdUI->SetCheck(m_bInlineWordDiff);
2806 void CMainFrame::OnViewInlinediff()
2808 m_bInlineDiff = !m_bInlineDiff;
2809 if (m_pwndLeftView)
2811 m_pwndLeftView->SetInlineDiff(m_bInlineDiff);
2812 m_pwndLeftView->BuildAllScreen2ViewVector();
2813 m_pwndLeftView->DocumentUpdated();
2815 if (m_pwndRightView)
2817 m_pwndRightView->SetInlineDiff(m_bInlineDiff);
2818 m_pwndRightView->BuildAllScreen2ViewVector();
2819 m_pwndRightView->DocumentUpdated();
2821 if (m_pwndBottomView)
2823 m_pwndBottomView->SetInlineDiff(m_bInlineDiff);
2824 m_pwndBottomView->BuildAllScreen2ViewVector();
2825 m_pwndBottomView->DocumentUpdated();
2827 m_wndLineDiffBar.DocumentUpdated();
2830 void CMainFrame::OnUpdateViewInlinediff(CCmdUI *pCmdUI)
2832 pCmdUI->Enable(IsViewGood(m_pwndLeftView) && IsViewGood(m_pwndRightView));
2833 pCmdUI->SetCheck(m_bInlineDiff);
2836 void CMainFrame::OnUpdateEditCreateunifieddifffile(CCmdUI *pCmdUI)
2838 // "create unified diff file" is only available if two files
2839 // are diffed, not three.
2840 bool bEnabled = true;
2841 if (!IsViewGood(m_pwndLeftView))
2842 bEnabled = false;
2843 else if (!IsViewGood(m_pwndRightView))
2844 bEnabled = false;
2845 else if (IsViewGood(m_pwndBottomView)) //no negation here
2846 bEnabled = false;
2847 pCmdUI->Enable(bEnabled);
2850 void CMainFrame::OnEditCreateunifieddifffile()
2852 CString origFile, modifiedFile;
2853 // the original file is the one on the left
2854 if (m_pwndLeftView)
2855 origFile = m_pwndLeftView->m_sFullFilePath;
2856 if (m_pwndRightView)
2857 modifiedFile = m_pwndRightView->m_sFullFilePath;
2858 if (origFile.IsEmpty() || modifiedFile.IsEmpty())
2859 return;
2861 CString outputFile;
2862 if(!TryGetFileName(outputFile))
2863 return;
2865 CAppUtils::CreateUnifiedDiff(origFile, modifiedFile, outputFile, true);
2868 void CMainFrame::OnUpdateEditTabspace(CCmdUI *pCmdUI)
2870 pCmdUI->Enable(true);
2871 int nTabMode = m_regTabMode;
2872 pCmdUI->SetCheck(nTabMode & TABMODE_USESPACES);
2875 void CMainFrame::OnEditTabspace()
2877 int nTabMode = m_regTabMode;
2878 nTabMode ^= TABMODE_USESPACES;
2879 m_regTabMode = nTabMode;
2880 if (IsViewGood(m_pwndLeftView))
2881 m_pwndLeftView->m_nTabMode = nTabMode;
2882 if (IsViewGood(m_pwndRightView))
2883 m_pwndRightView->m_nTabMode = nTabMode;
2884 if (IsViewGood(m_pwndBottomView))
2885 m_pwndBottomView->m_nTabMode = nTabMode;
2888 void CMainFrame::OnUpdateEditSmartTab(CCmdUI *pCmdUI)
2890 pCmdUI->Enable(true);
2891 int nTabMode = m_regTabMode;
2892 pCmdUI->SetCheck(nTabMode & TABMODE_SMARTINDENT);
2895 void CMainFrame::OnEditSmartTab()
2897 int nTabMode = m_regTabMode;
2898 nTabMode ^= TABMODE_SMARTINDENT;
2899 m_regTabMode = nTabMode;
2900 if (IsViewGood(m_pwndLeftView))
2901 m_pwndLeftView->m_nTabMode = nTabMode;
2902 if (IsViewGood(m_pwndRightView))
2903 m_pwndRightView->m_nTabMode = nTabMode;
2904 if (IsViewGood(m_pwndBottomView))
2905 m_pwndBottomView->m_nTabMode = nTabMode;
2908 void CMainFrame::OnUpdateViewLinediffbar(CCmdUI *pCmdUI)
2910 pCmdUI->SetCheck(m_bLineDiff);
2911 pCmdUI->Enable();
2914 void CMainFrame::OnViewLinediffbar()
2916 m_bLineDiff = !m_bLineDiff;
2917 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2918 m_wndLineDiffBar.DocumentUpdated();
2919 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2920 m_wndLocatorBar.DocumentUpdated();
2923 void CMainFrame::OnUpdateViewLocatorbar(CCmdUI *pCmdUI)
2925 pCmdUI->SetCheck(m_bLocatorBar);
2926 pCmdUI->Enable();
2929 void CMainFrame::OnViewLocatorbar()
2931 m_bLocatorBar = !m_bLocatorBar;
2932 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2933 m_wndLocatorBar.DocumentUpdated();
2934 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2935 m_wndLineDiffBar.DocumentUpdated();
2938 void CMainFrame::OnViewComparewhitespaces()
2940 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2941 return;
2942 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2943 regIgnoreWS = 0;
2944 LoadViews(-1);
2947 void CMainFrame::OnUpdateViewComparewhitespaces(CCmdUI *pCmdUI)
2949 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2950 DWORD dwIgnoreWS = regIgnoreWS;
2951 pCmdUI->SetCheck(dwIgnoreWS == 0);
2954 void CMainFrame::OnViewIgnorewhitespacechanges()
2956 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2957 return;
2958 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2959 regIgnoreWS = 2;
2960 LoadViews(-1);
2963 void CMainFrame::OnUpdateViewIgnorewhitespacechanges(CCmdUI *pCmdUI)
2965 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2966 DWORD dwIgnoreWS = regIgnoreWS;
2967 pCmdUI->SetCheck(dwIgnoreWS == 2);
2970 void CMainFrame::OnViewIgnoreallwhitespacechanges()
2972 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2973 return;
2974 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2975 regIgnoreWS = 1;
2976 LoadViews(-1);
2979 void CMainFrame::OnUpdateViewIgnoreallwhitespacechanges(CCmdUI *pCmdUI)
2981 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2982 DWORD dwIgnoreWS = regIgnoreWS;
2983 pCmdUI->SetCheck(dwIgnoreWS == 1);
2986 void CMainFrame::OnViewMovedBlocks()
2988 m_bViewMovedBlocks = !(DWORD)m_regViewModedBlocks;
2989 m_regViewModedBlocks = m_bViewMovedBlocks;
2990 LoadViews(-1);
2993 void CMainFrame::OnUpdateViewMovedBlocks(CCmdUI *pCmdUI)
2995 pCmdUI->SetCheck(m_bViewMovedBlocks);
2996 BOOL bEnable = TRUE;
2997 if (IsViewGood(m_pwndBottomView))
2999 bEnable = FALSE;
3001 pCmdUI->Enable(bEnable);
3004 bool CMainFrame::HasConflictsWontKeep()
3006 const int nConflictLine = CheckResolved();
3007 if (nConflictLine < 0)
3008 return false;
3010 CString sTemp;
3011 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
3012 bool bSave = false;
3013 if (m_bUseTaskDialog)
3015 CTaskDialog taskdlg(sTemp,
3016 CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK2)),
3017 L"TortoiseGitMerge",
3019 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
3020 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK3)));
3021 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK4)));
3022 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
3023 taskdlg.SetDefaultCommandControl(2);
3024 taskdlg.SetMainIcon(TD_ERROR_ICON);
3025 bSave = (taskdlg.DoModal(m_hWnd) == 1);
3027 else
3029 bSave = (MessageBox(sTemp, 0, MB_ICONERROR | MB_YESNO)==IDYES);
3032 if (bSave)
3033 return false;
3035 if (m_pwndBottomView)
3036 m_pwndBottomView->GoToLine(nConflictLine);
3037 return true;
3040 bool CMainFrame::TryGetFileName(CString& result)
3042 return CCommonAppUtils::FileOpenSave(result, NULL, IDS_SAVEASTITLE, IDS_COMMONFILEFILTER, false, m_hWnd);
3045 CBaseView* CMainFrame::GetActiveBaseView() const
3047 CView* activeView = GetActiveView();
3048 CBaseView* activeBase = dynamic_cast<CBaseView*>( activeView );
3049 return activeBase;
3052 void CMainFrame::SetWindowTitle()
3054 // try to find a suitable window title
3055 CString sYour = m_Data.m_yourFile.GetDescriptiveName();
3056 if (sYour.Find(_T(" - "))>=0)
3057 sYour = sYour.Left(sYour.Find(_T(" - ")));
3058 if (sYour.Find(_T(" : "))>=0)
3059 sYour = sYour.Left(sYour.Find(_T(" : ")));
3060 CString sTheir = m_Data.m_theirFile.GetDescriptiveName();
3061 if (sTheir.IsEmpty())
3062 sTheir = m_Data.m_baseFile.GetDescriptiveName();
3063 if (sTheir.Find(_T(" - "))>=0)
3064 sTheir = sTheir.Left(sTheir.Find(_T(" - ")));
3065 if (sTheir.Find(_T(" : "))>=0)
3066 sTheir = sTheir.Left(sTheir.Find(_T(" : ")));
3068 if (!sYour.IsEmpty() && !sTheir.IsEmpty())
3070 if (sYour.CompareNoCase(sTheir)==0)
3071 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
3072 else if ((sYour.GetLength() < 10) &&
3073 (sTheir.GetLength() < 10))
3074 SetWindowText(sYour + _T(" - ") + sTheir + _T(" - TortoiseGitMerge"));
3075 else
3077 // we have two very long descriptive texts here, which
3078 // means we have to find a way to use them as a window
3079 // title in a shorter way.
3080 // for simplicity, we just use the one from "yourfile"
3081 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
3084 else if (!sYour.IsEmpty())
3085 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
3086 else if (!sTheir.IsEmpty())
3087 SetWindowText(sTheir + _T(" - TortoiseGitMerge"));
3088 else
3089 SetWindowText(L"TortoiseGitMerge");
3092 void CMainFrame::OnTimer(UINT_PTR nIDEvent)
3094 switch (nIDEvent)
3096 case IDT_RELOADCHECKTIMER:
3097 KillTimer(nIDEvent);
3098 CheckForReload();
3099 break;
3102 __super::OnTimer(nIDEvent);
3105 void CMainFrame::LoadIgnoreCommentData()
3107 static bool bLoaded = false;
3108 if (bLoaded)
3109 return;
3110 CString sPath = CPathUtils::GetAppDataDirectory() + L"ignorecomments.txt";
3111 if (!PathFileExists(sPath))
3113 // ignore comments file does not exist (yet), so create a default one
3114 HRSRC hRes = FindResource(NULL, MAKEINTRESOURCE(IDR_IGNORECOMMENTSTXT), L"config");
3115 if (hRes)
3117 HGLOBAL hResourceLoaded = LoadResource(NULL, hRes);
3118 if (hResourceLoaded)
3120 char * lpResLock = (char *) LockResource(hResourceLoaded);
3121 DWORD dwSizeRes = SizeofResource(NULL, hRes);
3122 if (lpResLock)
3124 HANDLE hFile = CreateFile(sPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3125 if (hFile != INVALID_HANDLE_VALUE)
3127 DWORD dwWritten = 0;
3128 WriteFile(hFile, lpResLock, dwSizeRes, &dwWritten, NULL);
3129 CloseHandle(hFile);
3135 CStdioFile file;
3136 if (file.Open(sPath, CFile::modeRead))
3138 CString sLine;
3139 while (file.ReadString(sLine))
3141 int eqpos = sLine.Find('=');
3142 if (eqpos >= 0)
3144 CString sExts = sLine.Left(eqpos);
3145 CString sComments = sLine.Mid(eqpos+1);
3147 int pos = sComments.Find(',');
3148 CString sLineStart = sComments.Left(pos);
3149 pos = sComments.Find(',', pos);
3150 int pos2 = sComments.Find(',', pos+1);
3151 CString sBlockStart = sComments.Mid(pos+1, pos2-pos-1);
3152 CString sBlockEnd = sComments.Mid(pos2+1);
3154 auto commentTuple = std::make_tuple(sLineStart, sBlockStart, sBlockEnd);
3156 pos = 0;
3157 CString temp;
3158 for (;;)
3160 temp = sExts.Tokenize(_T(","),pos);
3161 if (temp.IsEmpty())
3163 break;
3165 ASSERT(m_IgnoreCommentsMap.find(temp) == m_IgnoreCommentsMap.end());
3166 m_IgnoreCommentsMap[temp] = commentTuple;
3171 bLoaded = true;
3174 void CMainFrame::OnViewIgnorecomments()
3176 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3177 return;
3178 m_regIgnoreComments = !DWORD(m_regIgnoreComments);
3179 LoadViews(-1);
3182 void CMainFrame::OnUpdateViewIgnorecomments(CCmdUI *pCmdUI)
3184 // only enable if we have comments defined for this file extension
3185 CString sExt = CPathUtils::GetFileExtFromPath(m_Data.m_baseFile.GetFilename()).MakeLower();
3186 sExt.TrimLeft(L".");
3187 auto sC = m_IgnoreCommentsMap.find(sExt);
3188 if (sC == m_IgnoreCommentsMap.end())
3190 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_yourFile.GetFilename()).MakeLower();
3191 sExt.TrimLeft(L".");
3192 sC = m_IgnoreCommentsMap.find(sExt);
3193 if (sC == m_IgnoreCommentsMap.end())
3195 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_theirFile.GetFilename()).MakeLower();
3196 sExt.TrimLeft(L".");
3197 sC = m_IgnoreCommentsMap.find(sExt);
3200 pCmdUI->Enable(sC != m_IgnoreCommentsMap.end());
3202 pCmdUI->SetCheck(DWORD(m_regIgnoreComments) != 0);
3206 void CMainFrame::OnRegexfilter(UINT cmd)
3208 if ((cmd == ID_REGEXFILTER)||(cmd == (ID_REGEXFILTER+1)))
3210 CRegexFiltersDlg dlg(this);
3211 dlg.SetIniFile(&m_regexIni);
3212 if (dlg.DoModal() == IDOK)
3214 FILE * pFile = NULL;
3215 _tfopen_s(&pFile, CPathUtils::GetAppDataDirectory() + L"regexfilters.ini", _T("wb"));
3216 m_regexIni.SaveFile(pFile);
3217 fclose(pFile);
3219 BuildRegexSubitems();
3221 else
3223 if (cmd == (UINT)m_regexIndex)
3225 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3226 return;
3227 m_Data.SetRegexTokens(std::wregex(), L"");
3228 m_regexIndex = -1;
3229 LoadViews(-1);
3231 else
3233 CSimpleIni::TNamesDepend sections;
3234 m_regexIni.GetAllSections(sections);
3235 int index = ID_REGEXFILTER + 2;
3236 m_regexIndex = -1;
3237 for (const auto& section : sections)
3239 if (cmd == (UINT)index)
3241 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3242 break;
3245 std::wregex rx(m_regexIni.GetValue(section, L"regex", L""));
3246 m_Data.SetRegexTokens(rx, m_regexIni.GetValue(section, L"replace", L""));
3248 catch (std::exception &ex)
3250 MessageBox(_T("Regex is invalid!\r\n") + CString(ex.what()));
3252 m_regexIndex = index;
3253 LoadViews(-1);
3254 break;
3256 ++index;
3262 void CMainFrame::OnUpdateViewRegexFilter( CCmdUI *pCmdUI )
3264 pCmdUI->Enable();
3265 pCmdUI->SetCheck(pCmdUI->m_nID == (UINT)m_regexIndex);
3268 void CMainFrame::BuildRegexSubitems()
3270 CArray<CMFCRibbonBaseElement*, CMFCRibbonBaseElement*> arButtons;
3271 m_wndRibbonBar.GetElementsByID(ID_REGEXFILTER, arButtons);
3272 if (arButtons.GetCount() == 1)
3274 CMFCRibbonButton * pButton = (CMFCRibbonButton*)arButtons.GetAt(0);
3275 if (pButton)
3277 pButton->RemoveAllSubItems();
3278 pButton->AddSubItem(new CMFCRibbonButton(ID_REGEXFILTER+1, CString(MAKEINTRESOURCE(IDS_CONFIGUREREGEXES)), 47));
3280 CString sIniPath = CPathUtils::GetAppDataDirectory() + L"regexfilters.ini";
3281 if (!PathFileExists(sIniPath))
3283 // ini file does not exist (yet), so create a default one
3284 HRSRC hRes = FindResource(NULL, MAKEINTRESOURCE(IDR_REGEXFILTERINI), L"config");
3285 if (hRes)
3287 HGLOBAL hResourceLoaded = LoadResource(NULL, hRes);
3288 if (hResourceLoaded)
3290 char * lpResLock = (char *) LockResource(hResourceLoaded);
3291 DWORD dwSizeRes = SizeofResource(NULL, hRes);
3292 if (lpResLock)
3294 HANDLE hFile = CreateFile(sIniPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3295 if (hFile != INVALID_HANDLE_VALUE)
3297 DWORD dwWritten = 0;
3298 WriteFile(hFile, lpResLock, dwSizeRes, &dwWritten, NULL);
3299 CloseHandle(hFile);
3306 m_regexIni.LoadFile(sIniPath);
3307 CSimpleIni::TNamesDepend sections;
3308 m_regexIni.GetAllSections(sections);
3309 if (!sections.empty())
3310 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3311 int cmdIndex = 2;
3312 for (const auto& section : sections)
3314 pButton->AddSubItem(new CMFCRibbonButton(ID_REGEXFILTER+cmdIndex, section, 46));
3315 cmdIndex++;
3321 void CMainFrame::FillEncodingButton( CMFCRibbonButton * pButton, int start )
3323 pButton->SetDefaultCommand(FALSE);
3324 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::ASCII, L"ASCII" ));
3325 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::BINARY, L"BINARY" ));
3326 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_LE, L"UTF-16LE" ));
3327 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_LEBOM, L"UTF-16LE BOM"));
3328 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_BE, L"UTF-16BE" ));
3329 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_BEBOM, L"UTF-16BE BOM"));
3330 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF32_LE, L"UTF-32LE" ));
3331 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF32_BE, L"UTF-32BE" ));
3332 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF8, L"UTF-8" ));
3333 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF8BOM, L"UTF-8 BOM" ));
3336 void CMainFrame::FillEOLButton( CMFCRibbonButton * pButton, int start )
3338 pButton->SetDefaultCommand(FALSE);
3339 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LF , L"LF" ));
3340 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_CRLF, L"CRLF"));
3341 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LFCR, L"LRCR"));
3342 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_CR , L"CR" ));
3343 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_VT , L"VT" ));
3344 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_FF , L"FF" ));
3345 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_NEL , L"NEL" ));
3346 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LS , L"LS" ));
3347 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_PS , L"PS" ));
3350 void CMainFrame::OnEncodingLeft( UINT cmd )
3352 if (m_pwndLeftView)
3354 m_pwndLeftView->SetTextType(CFileTextLines::UnicodeType(cmd-ID_INDICATOR_LEFTENCODINGSTART));
3355 m_pwndLeftView->RefreshViews();
3359 void CMainFrame::OnEncodingRight( UINT cmd )
3361 if (m_pwndRightView)
3363 m_pwndRightView->SetTextType(CFileTextLines::UnicodeType(cmd-ID_INDICATOR_RIGHTENCODINGSTART));
3364 m_pwndRightView->RefreshViews();
3368 void CMainFrame::OnEncodingBottom( UINT cmd )
3370 if (m_pwndBottomView)
3372 m_pwndBottomView->SetTextType(CFileTextLines::UnicodeType(cmd-ID_INDICATOR_BOTTOMENCODINGSTART));
3373 m_pwndBottomView->RefreshViews();
3377 void CMainFrame::OnEOLLeft( UINT cmd )
3379 if (m_pwndLeftView)
3381 m_pwndLeftView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_LEFTEOLSTART));
3382 m_pwndLeftView->RefreshViews();
3386 void CMainFrame::OnEOLRight( UINT cmd )
3388 if (m_pwndRightView)
3390 m_pwndRightView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_RIGHTEOLSTART));
3391 m_pwndRightView->RefreshViews();
3395 void CMainFrame::OnEOLBottom( UINT cmd )
3397 if (m_pwndBottomView)
3399 m_pwndBottomView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_BOTTOMEOLSTART));
3400 m_pwndBottomView->RefreshViews();
3404 void CMainFrame::OnUpdateEncodingLeft( CCmdUI *pCmdUI )
3406 if (m_pwndLeftView)
3408 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_LEFTENCODINGSTART) == m_pwndLeftView->GetTextType());
3409 pCmdUI->Enable(m_pwndLeftView->IsWritable());
3411 else
3412 pCmdUI->Enable(FALSE);
3415 void CMainFrame::OnUpdateEncodingRight( CCmdUI *pCmdUI )
3417 if (m_pwndRightView)
3419 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_RIGHTENCODINGSTART) == m_pwndRightView->GetTextType());
3420 pCmdUI->Enable(m_pwndRightView->IsWritable());
3422 else
3423 pCmdUI->Enable(FALSE);
3426 void CMainFrame::OnUpdateEncodingBottom( CCmdUI *pCmdUI )
3428 if (m_pwndBottomView)
3430 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_BOTTOMENCODINGSTART) == m_pwndBottomView->GetTextType());
3431 pCmdUI->Enable(m_pwndBottomView->IsWritable());
3433 else
3434 pCmdUI->Enable(FALSE);
3437 void CMainFrame::OnUpdateEOLLeft( CCmdUI *pCmdUI )
3439 if (m_pwndLeftView)
3441 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_LEFTEOLSTART) == m_pwndLeftView->GetLineEndings());
3442 pCmdUI->Enable(m_pwndLeftView->IsWritable());
3444 else
3445 pCmdUI->Enable(FALSE);
3448 void CMainFrame::OnUpdateEOLRight( CCmdUI *pCmdUI )
3450 if (m_pwndRightView)
3452 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_RIGHTEOLSTART) == m_pwndRightView->GetLineEndings());
3453 pCmdUI->Enable(m_pwndRightView->IsWritable());
3455 else
3456 pCmdUI->Enable(FALSE);
3459 void CMainFrame::OnUpdateEOLBottom( CCmdUI *pCmdUI )
3461 if (m_pwndBottomView)
3463 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_BOTTOMEOLSTART) == m_pwndBottomView->GetLineEndings());
3464 pCmdUI->Enable(m_pwndBottomView->IsWritable());
3466 else
3467 pCmdUI->Enable(FALSE);