File already included in stdafx.h
[TortoiseGit.git] / src / TortoiseMerge / MainFrm.cpp
bloba4d6d5ebedd53f9f5548e9e79c8ed6addcb0fbcb
1 // TortoiseGitMerge - a Diff/Patch program
3 // Copyright (C) 2008-2015 - TortoiseGit
4 // Copyright (C) 2004-2015 - 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 "RegexFiltersDlg.h"
39 #include "SysInfo.h"
41 #ifdef _DEBUG
42 #define new DEBUG_NEW
43 #endif
45 CCustomMFCRibbonButton button1;
47 // CMainFrame
48 const UINT TaskBarButtonCreated = RegisterWindowMessage(L"TaskbarButtonCreated");
49 #define IDT_RELOADCHECKTIMER 123
51 IMPLEMENT_DYNCREATE(CMainFrame, CFrameWndEx)
53 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)
54 ON_WM_CREATE()
55 ON_COMMAND_RANGE(ID_VIEW_APPLOOK_WIN7, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnApplicationLook)
56 ON_UPDATE_COMMAND_UI_RANGE(IDC_STYLEBUTTON, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnUpdateApplicationLook)
57 // Global help commands
58 ON_COMMAND(ID_HELP_FINDER, CFrameWndEx::OnHelpFinder)
59 ON_COMMAND(ID_HELP, CFrameWndEx::OnHelp)
60 ON_COMMAND(ID_CONTEXT_HELP, CFrameWndEx::OnContextHelp)
61 ON_COMMAND(ID_DEFAULT_HELP, CFrameWndEx::OnHelpFinder)
62 ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
63 ON_COMMAND(ID_VIEW_WHITESPACES, OnViewWhitespaces)
64 ON_WM_SIZE()
65 ON_COMMAND(ID_FILE_SAVE, OnFileSave)
66 ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
67 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave)
68 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_AS, OnUpdateFileSaveAs)
69 ON_COMMAND(ID_VIEW_ONEWAYDIFF, OnViewOnewaydiff)
70 ON_UPDATE_COMMAND_UI(ID_VIEW_ONEWAYDIFF, OnUpdateViewOnewaydiff)
71 ON_UPDATE_COMMAND_UI(ID_VIEW_WHITESPACES, OnUpdateViewWhitespaces)
72 ON_COMMAND(ID_VIEW_OPTIONS, OnViewOptions)
73 ON_WM_CLOSE()
74 ON_WM_ACTIVATE()
75 ON_COMMAND(ID_FILE_RELOAD, OnFileReload)
76 ON_COMMAND(ID_VIEW_LINEDOWN, OnViewLinedown)
77 ON_COMMAND(ID_VIEW_LINEUP, OnViewLineup)
78 ON_COMMAND(ID_VIEW_MOVEDBLOCKS, OnViewMovedBlocks)
79 ON_UPDATE_COMMAND_UI(ID_VIEW_MOVEDBLOCKS, OnUpdateViewMovedBlocks)
80 ON_UPDATE_COMMAND_UI(ID_EDIT_MARKASRESOLVED, OnUpdateMergeMarkasresolved)
81 ON_COMMAND(ID_EDIT_MARKASRESOLVED, OnMergeMarkasresolved)
82 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTCONFLICT, OnUpdateMergeNextconflict)
83 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSCONFLICT, OnUpdateMergePreviousconflict)
84 ON_WM_MOVE()
85 ON_WM_MOVING()
86 ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
87 ON_COMMAND(ID_VIEW_SWITCHLEFT, OnViewSwitchleft)
88 ON_UPDATE_COMMAND_UI(ID_VIEW_SWITCHLEFT, OnUpdateViewSwitchleft)
89 ON_COMMAND(ID_VIEW_LINELEFT, &CMainFrame::OnViewLineleft)
90 ON_COMMAND(ID_VIEW_LINERIGHT, &CMainFrame::OnViewLineright)
91 ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWFILELIST, &CMainFrame::OnUpdateViewShowfilelist)
92 ON_COMMAND(ID_VIEW_SHOWFILELIST, &CMainFrame::OnViewShowfilelist)
93 ON_COMMAND(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnEditUseTheirs)
94 ON_COMMAND(ID_EDIT_USEMYBLOCK, &CMainFrame::OnEditUseMine)
95 ON_COMMAND(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnEditUseTheirsThenMine)
96 ON_COMMAND(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnEditUseMineThenTheirs)
97 ON_COMMAND(ID_EDIT_UNDO, &CMainFrame::OnEditUndo)
98 ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, &CMainFrame::OnUpdateEditUndo)
99 ON_COMMAND(ID_EDIT_ENABLE, &CMainFrame::OnEditEnable)
100 ON_UPDATE_COMMAND_UI(ID_EDIT_ENABLE, &CMainFrame::OnUpdateEditEnable)
101 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnUpdateEditUseminethentheirblock)
102 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMYBLOCK, &CMainFrame::OnUpdateEditUsemyblock)
103 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnUpdateEditUsetheirblock)
104 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnUpdateEditUsetheirthenmyblock)
105 ON_COMMAND(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnViewInlinediffword)
106 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnUpdateViewInlinediffword)
107 ON_COMMAND(ID_VIEW_INLINEDIFF, &CMainFrame::OnViewInlinediff)
108 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFF, &CMainFrame::OnUpdateViewInlinediff)
109 ON_UPDATE_COMMAND_UI(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnUpdateEditCreateunifieddifffile)
110 ON_COMMAND(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnEditCreateunifieddifffile)
111 ON_UPDATE_COMMAND_UI(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnUpdateViewLinediffbar)
112 ON_COMMAND(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnViewLinediffbar)
113 ON_UPDATE_COMMAND_UI(ID_VIEW_LOCATORBAR, &CMainFrame::OnUpdateViewLocatorbar)
114 ON_COMMAND(ID_VIEW_LOCATORBAR, &CMainFrame::OnViewLocatorbar)
115 ON_COMMAND(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnEditUseleftblock)
116 ON_UPDATE_COMMAND_UI(ID_USEBLOCKS, &CMainFrame::OnUpdateUseBlock)
117 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnUpdateEditUseleftblock)
118 ON_COMMAND(ID_EDIT_USELEFTFILE, &CMainFrame::OnEditUseleftfile)
119 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTFILE, &CMainFrame::OnUpdateEditUseleftfile)
120 ON_COMMAND(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnEditUseblockfromleftbeforeright)
121 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnUpdateEditUseblockfromleftbeforeright)
122 ON_COMMAND(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnEditUseblockfromrightbeforeleft)
123 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnUpdateEditUseblockfromrightbeforeleft)
124 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTDIFFERENCE, &CMainFrame::OnUpdateNavigateNextdifference)
125 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSDIFFERENCE, &CMainFrame::OnUpdateNavigatePreviousdifference)
126 ON_COMMAND(ID_VIEW_COLLAPSED, &CMainFrame::OnViewCollapsed)
127 ON_UPDATE_COMMAND_UI(ID_VIEW_COLLAPSED, &CMainFrame::OnUpdateViewCollapsed)
128 ON_COMMAND(ID_VIEW_COMPAREWHITESPACES, &CMainFrame::OnViewComparewhitespaces)
129 ON_UPDATE_COMMAND_UI(ID_VIEW_COMPAREWHITESPACES, &CMainFrame::OnUpdateViewComparewhitespaces)
130 ON_COMMAND(ID_VIEW_IGNOREWHITESPACECHANGES, &CMainFrame::OnViewIgnorewhitespacechanges)
131 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREWHITESPACECHANGES, &CMainFrame::OnUpdateViewIgnorewhitespacechanges)
132 ON_COMMAND(ID_VIEW_IGNOREALLWHITESPACECHANGES, &CMainFrame::OnViewIgnoreallwhitespacechanges)
133 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREALLWHITESPACECHANGES, &CMainFrame::OnUpdateViewIgnoreallwhitespacechanges)
134 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTINLINEDIFF, &CMainFrame::OnUpdateNavigateNextinlinediff)
135 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVINLINEDIFF, &CMainFrame::OnUpdateNavigatePrevinlinediff)
136 ON_COMMAND(ID_VIEW_WRAPLONGLINES, &CMainFrame::OnViewWraplonglines)
137 ON_UPDATE_COMMAND_UI(ID_VIEW_WRAPLONGLINES, &CMainFrame::OnUpdateViewWraplonglines)
138 ON_REGISTERED_MESSAGE( TaskBarButtonCreated, CMainFrame::OnTaskbarButtonCreated )
139 ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, &CMainFrame::OnUpdateEditPaste)
140 ON_COMMAND(ID_INDICATOR_LEFTVIEW, &CMainFrame::OnIndicatorLeftview)
141 ON_COMMAND(ID_INDICATOR_RIGHTVIEW, &CMainFrame::OnIndicatorRightview)
142 ON_COMMAND(ID_INDICATOR_BOTTOMVIEW, &CMainFrame::OnIndicatorBottomview)
143 ON_WM_TIMER()
144 ON_COMMAND(ID_VIEW_IGNORECOMMENTS, &CMainFrame::OnViewIgnorecomments)
145 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNORECOMMENTS, &CMainFrame::OnUpdateViewIgnorecomments)
146 ON_COMMAND_RANGE(ID_REGEXFILTER, ID_REGEXFILTER+400, &CMainFrame::OnRegexfilter)
147 ON_UPDATE_COMMAND_UI_RANGE(ID_REGEXFILTER, ID_REGEXFILTER+400, &CMainFrame::OnUpdateViewRegexFilter)
148 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOENCODING, &CMainFrame::OnDummyEnabled)
149 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOENCODING, &CMainFrame::OnDummyEnabled)
150 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOENCODING, &CMainFrame::OnDummyEnabled)
151 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOEOL, &CMainFrame::OnDummyEnabled)
152 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOEOL, &CMainFrame::OnDummyEnabled)
153 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOEOL, &CMainFrame::OnDummyEnabled)
154 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOTABMODE, &CMainFrame::OnDummyEnabled)
155 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOTABMODE, &CMainFrame::OnDummyEnabled)
156 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOTABMODE, &CMainFrame::OnDummyEnabled)
157 ON_COMMAND_RANGE(ID_INDICATOR_LEFTENCODINGSTART, ID_INDICATOR_LEFTENCODINGSTART+19, &CMainFrame::OnEncodingLeft)
158 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTENCODINGSTART, ID_INDICATOR_RIGHTENCODINGSTART+19, &CMainFrame::OnEncodingRight)
159 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMENCODINGSTART, ID_INDICATOR_BOTTOMENCODINGSTART+19, &CMainFrame::OnEncodingBottom)
160 ON_COMMAND_RANGE(ID_INDICATOR_LEFTEOLSTART, ID_INDICATOR_LEFTEOLSTART+19, &CMainFrame::OnEOLLeft)
161 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTEOLSTART, ID_INDICATOR_RIGHTEOLSTART+19, &CMainFrame::OnEOLRight)
162 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMEOLSTART, ID_INDICATOR_BOTTOMEOLSTART+19, &CMainFrame::OnEOLBottom)
163 ON_COMMAND_RANGE(ID_INDICATOR_LEFTTABMODESTART, ID_INDICATOR_LEFTTABMODESTART+19, &CMainFrame::OnTabModeLeft)
164 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTTABMODESTART, ID_INDICATOR_RIGHTTABMODESTART+19, &CMainFrame::OnTabModeRight)
165 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMTABMODESTART, ID_INDICATOR_BOTTOMTABMODESTART+19, &CMainFrame::OnTabModeBottom)
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 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTTABMODESTART, ID_INDICATOR_LEFTTABMODESTART+19, &CMainFrame::OnUpdateTabModeLeft)
173 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTTABMODESTART, ID_INDICATOR_RIGHTTABMODESTART+19, &CMainFrame::OnUpdateTabModeRight)
174 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMTABMODESTART, ID_INDICATOR_BOTTOMTABMODESTART+19, &CMainFrame::OnUpdateTabModeBottom)
175 END_MESSAGE_MAP()
177 static UINT indicators[] =
179 ID_SEPARATOR, // status line indicator
180 ID_INDICATOR_LEFTVIEW,
181 ID_INDICATOR_RIGHTVIEW,
182 ID_INDICATOR_BOTTOMVIEW,
183 ID_INDICATOR_CAPS,
184 ID_INDICATOR_NUM,
188 // CMainFrame construction/destruction
190 CMainFrame::CMainFrame()
191 : m_bInitSplitter(FALSE)
192 , m_bReversedPatch(FALSE)
193 , m_bHasConflicts(false)
194 , m_bInlineWordDiff(true)
195 , m_bLineDiff(true)
196 , m_bLocatorBar(true)
197 , m_nMoveMovesToIgnore(0)
198 , m_pwndLeftView(NULL)
199 , m_pwndRightView(NULL)
200 , m_pwndBottomView(NULL)
201 , m_bReadOnly(false)
202 , m_bBlame(false)
203 , m_bCheckReload(false)
204 , m_bSaveRequired(false)
205 , m_bSaveRequiredOnConflicts(false)
206 , m_bDeleteBaseTheirsMineOnClose(false)
207 , resolveMsgWnd(0)
208 , resolveMsgWParam(0)
209 , resolveMsgLParam(0)
210 , m_regWrapLines(L"Software\\TortoiseGitMerge\\WrapLines", 0)
211 , m_regViewModedBlocks(L"Software\\TortoiseGitMerge\\ViewMovedBlocks", TRUE)
212 , m_regOneWay(L"Software\\TortoiseGitMerge\\OnePane")
213 , m_regCollapsed(L"Software\\TortoiseGitMerge\\Collapsed", 0)
214 , m_regInlineDiff(L"Software\\TortoiseGitMerge\\DisplayBinDiff", TRUE)
215 , m_regUseRibbons(L"Software\\TortoiseGitMerge\\UseRibbons", TRUE)
216 , m_regUseTaskDialog(L"Software\\TortoiseGitMerge\\UseTaskDialog", TRUE)
217 , m_regIgnoreComments(_T("Software\\TortoiseGitMerge\\IgnoreComments"), FALSE)
218 , m_regexIndex(-1)
220 m_bOneWay = (0 != ((DWORD)m_regOneWay));
221 theApp.m_nAppLook = theApp.GetInt(_T("ApplicationLook"), ID_VIEW_APPLOOK_VS_2005);
222 m_bCollapsed = !!(DWORD)m_regCollapsed;
223 m_bViewMovedBlocks = !!(DWORD)m_regViewModedBlocks;
224 m_bWrapLines = !!(DWORD)m_regWrapLines;
225 m_bInlineDiff = !!m_regInlineDiff;
226 m_bUseRibbons = !!m_regUseRibbons;
227 #if _WIN64
228 if (SysInfo::Instance().IsXP())
229 m_bUseRibbons = FALSE;
230 #endif
231 m_bUseTaskDialog = CTaskDialog::IsSupported() && (DWORD)m_regUseTaskDialog;
232 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
235 CMainFrame::~CMainFrame()
239 LRESULT CMainFrame::OnTaskbarButtonCreated(WPARAM /*wParam*/, LPARAM /*lParam*/)
241 SetUUIDOverlayIcon(m_hWnd);
242 return 0;
246 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
248 if (CFrameWndEx::OnCreate(lpCreateStruct) == -1)
249 return -1;
251 OnApplicationLook(theApp.m_nAppLook);
253 if (m_bUseRibbons)
255 m_wndRibbonBar.Create(this);
256 m_wndRibbonBar.LoadFromResource(IDR_RIBBON);
258 // enable the dialog launch button on the view panel
259 CMFCRibbonCategory * pMainCat = m_wndRibbonBar.GetCategory(1);
260 if (pMainCat)
262 CMFCRibbonPanel * pPanel = pMainCat->GetPanel(3);
263 if (pPanel)
264 pPanel->EnableLaunchButton(ID_VIEW_OPTIONS);
266 // now replace all buttons with our custom button class
267 for (int i = 0; i < m_wndRibbonBar.GetCategoryCount(); ++i)
269 CMFCRibbonCategory * pCat = m_wndRibbonBar.GetCategory(i);
270 for (int j = 0; j < pCat->GetPanelCount(); ++j)
272 CMFCRibbonPanel * pPanel = pCat->GetPanel(j);
273 CList<UINT, UINT> lstItems;
274 pPanel->GetItemIDsList(lstItems);
275 while (!lstItems.IsEmpty())
277 UINT id = lstItems.GetHead();
278 lstItems.RemoveHead();
279 CMFCRibbonButton * pButton = dynamic_cast<CMFCRibbonButton*>(pPanel->FindByID(id));
280 if (pButton)
282 CCustomMFCRibbonButton * c = new CCustomMFCRibbonButton(id, pButton->GetText());
283 pPanel->ReplaceByID(id, c);
288 BuildRegexSubitems();
289 if (!m_wndRibbonStatusBar.Create(this))
291 TRACE0("Failed to create ribbon status bar\n");
292 return -1; // fail to create
294 m_wndRibbonStatusBar.AddElement(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(AFX_IDS_IDLEMESSAGE)), TRUE), L"");
296 std::unique_ptr<CMFCRibbonButtonsGroup> apBtnGroupLeft(new CMFCRibbonButtonsGroup);
297 apBtnGroupLeft->SetID(ID_INDICATOR_LEFTVIEW);
298 apBtnGroupLeft->AddButton(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(IDS_STATUSBAR_LEFTVIEW)), TRUE));
299 CMFCRibbonButton * pButton = new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOENCODING, L"");
300 FillEncodingButton(pButton, ID_INDICATOR_LEFTENCODINGSTART);
301 apBtnGroupLeft->AddButton(pButton);
302 pButton = new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOEOL, L"");
303 FillEOLButton(pButton, ID_INDICATOR_LEFTEOLSTART);
304 apBtnGroupLeft->AddButton(pButton);
305 pButton = new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOTABMODE, L"");
306 FillTabModeButton(pButton, ID_INDICATOR_LEFTTABMODESTART);
307 apBtnGroupLeft->AddButton(pButton);
308 apBtnGroupLeft->AddButton(new CMFCRibbonStatusBarPane(ID_INDICATOR_LEFTVIEW, L"", TRUE));
309 m_wndRibbonStatusBar.AddExtendedElement(apBtnGroupLeft.release(), L"");
311 std::unique_ptr<CMFCRibbonButtonsGroup> apBtnGroupRight(new CMFCRibbonButtonsGroup);
312 apBtnGroupRight->SetID(ID_INDICATOR_RIGHTVIEW);
313 apBtnGroupRight->AddButton(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(IDS_STATUSBAR_RIGHTVIEW)), TRUE));
314 pButton = new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOENCODING, L"");
315 FillEncodingButton(pButton, ID_INDICATOR_RIGHTENCODINGSTART);
316 apBtnGroupRight->AddButton(pButton);
317 pButton = new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOEOL, L"");
318 FillEOLButton(pButton, ID_INDICATOR_RIGHTEOLSTART);
319 apBtnGroupRight->AddButton(pButton);
320 pButton = new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOTABMODE, L"");
321 FillTabModeButton(pButton, ID_INDICATOR_RIGHTTABMODESTART);
322 apBtnGroupRight->AddButton(pButton);
323 apBtnGroupRight->AddButton(new CMFCRibbonStatusBarPane(ID_INDICATOR_RIGHTVIEW, L"", TRUE));
324 m_wndRibbonStatusBar.AddExtendedElement(apBtnGroupRight.release(), L"");
326 else
328 if (!m_wndMenuBar.Create(this))
330 TRACE0("Failed to create menubar\n");
331 return -1; // fail to create
333 m_wndMenuBar.SetPaneStyle(m_wndMenuBar.GetPaneStyle() | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY);
335 // prevent the menu bar from taking the focus on activation
336 CMFCPopupMenu::SetForceMenuFocus(FALSE);
337 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))
339 TRACE0("Failed to create toolbar\n");
340 return -1; // fail to create
342 m_wndToolBar.SetWindowText(_T("Main"));
343 if (!m_wndStatusBar.Create(this) ||
344 !m_wndStatusBar.SetIndicators(indicators,
345 _countof(indicators)))
347 TRACE0("Failed to create status bar\n");
348 return -1; // fail to create
350 m_wndStatusBar.EnablePaneDoubleClick();
353 if (!m_wndLocatorBar.Create(this, IDD_DIFFLOCATOR,
354 CBRS_ALIGN_LEFT | CBRS_SIZE_FIXED, ID_VIEW_LOCATORBAR))
356 TRACE0("Failed to create dialogbar\n");
357 return -1; // fail to create
359 if (!m_wndLineDiffBar.Create(this, IDD_LINEDIFF,
360 CBRS_ALIGN_BOTTOM | CBRS_SIZE_FIXED, ID_VIEW_LINEDIFFBAR))
362 TRACE0("Failed to create dialogbar\n");
363 return -1; // fail to create
365 m_wndLocatorBar.m_pMainFrm = this;
366 m_wndLineDiffBar.m_pMainFrm = this;
368 EnableDocking(CBRS_ALIGN_ANY);
369 if (!m_bUseRibbons)
371 m_wndMenuBar.EnableDocking(CBRS_ALIGN_TOP);
372 m_wndToolBar.EnableDocking(CBRS_ALIGN_TOP);
373 DockPane(&m_wndMenuBar);
374 DockPane(&m_wndToolBar);
376 DockPane(&m_wndLocatorBar);
377 DockPane(&m_wndLineDiffBar);
378 ShowPane(&m_wndLocatorBar, true, false, true);
379 ShowPane(&m_wndLineDiffBar, true, false, true);
381 m_wndLocatorBar.EnableGripper(FALSE);
382 m_wndLineDiffBar.EnableGripper(FALSE);
384 return 0;
387 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
389 if( !CFrameWndEx::PreCreateWindow(cs) )
390 return FALSE;
391 return TRUE;
394 void CMainFrame::OnApplicationLook(UINT id)
396 CWaitCursor wait;
398 theApp.m_nAppLook = id;
400 switch (theApp.m_nAppLook)
402 case ID_VIEW_APPLOOK_WIN_2000:
403 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManager));
404 m_wndRibbonBar.SetWindows7Look(FALSE);
405 break;
407 case ID_VIEW_APPLOOK_OFF_XP:
408 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOfficeXP));
409 m_wndRibbonBar.SetWindows7Look(FALSE);
410 break;
412 case ID_VIEW_APPLOOK_WIN_XP:
413 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
414 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
415 m_wndRibbonBar.SetWindows7Look(FALSE);
416 break;
418 case ID_VIEW_APPLOOK_OFF_2003:
419 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2003));
420 CDockingManager::SetDockingMode(DT_SMART);
421 m_wndRibbonBar.SetWindows7Look(FALSE);
422 break;
424 case ID_VIEW_APPLOOK_VS_2005:
425 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2005));
426 CDockingManager::SetDockingMode(DT_SMART);
427 m_wndRibbonBar.SetWindows7Look(FALSE);
428 break;
430 case ID_VIEW_APPLOOK_VS_2008:
431 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2008));
432 CDockingManager::SetDockingMode(DT_SMART);
433 m_wndRibbonBar.SetWindows7Look(FALSE);
434 break;
436 case ID_VIEW_APPLOOK_WIN7:
437 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows7));
438 CDockingManager::SetDockingMode(DT_SMART);
439 m_wndRibbonBar.SetWindows7Look(TRUE);
440 break;
442 default:
443 switch (theApp.m_nAppLook)
445 case ID_VIEW_APPLOOK_OFF_2007_BLUE:
446 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_LunaBlue);
447 break;
449 case ID_VIEW_APPLOOK_OFF_2007_BLACK:
450 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_ObsidianBlack);
451 break;
453 case ID_VIEW_APPLOOK_OFF_2007_SILVER:
454 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Silver);
455 break;
457 case ID_VIEW_APPLOOK_OFF_2007_AQUA:
458 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Aqua);
459 break;
462 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));
463 CDockingManager::SetDockingMode(DT_SMART);
464 m_wndRibbonBar.SetWindows7Look(FALSE);
467 RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_FRAME | RDW_ERASE);
469 theApp.WriteInt(_T("ApplicationLook"), theApp.m_nAppLook);
472 void CMainFrame::OnUpdateApplicationLook(CCmdUI* pCmdUI)
474 pCmdUI->Enable();
475 pCmdUI->SetRadio(theApp.m_nAppLook == pCmdUI->m_nID);
479 // CMainFrame diagnostics
481 #ifdef _DEBUG
482 void CMainFrame::AssertValid() const
484 CFrameWndEx::AssertValid();
487 void CMainFrame::Dump(CDumpContext& dc) const
489 CFrameWndEx::Dump(dc);
492 #endif //_DEBUG
495 // CMainFrame message handlers
498 BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)
500 CRect cr;
501 GetClientRect( &cr);
504 // split into three panes:
505 // -------------
506 // | | |
507 // | | |
508 // |------------
509 // | |
510 // | |
511 // |------------
513 // create a splitter with 2 rows, 1 column
514 if (!m_wndSplitter.CreateStatic(this, 2, 1))
516 TRACE0("Failed to CreateStaticSplitter\n");
517 return FALSE;
520 // add the second splitter pane - which is a nested splitter with 2 columns
521 if (!m_wndSplitter2.CreateStatic(
522 &m_wndSplitter, // our parent window is the first splitter
523 1, 2, // the new splitter is 1 row, 2 columns
524 WS_CHILD | WS_VISIBLE | WS_BORDER, // style, WS_BORDER is needed
525 m_wndSplitter.IdFromRowCol(0, 0)
526 // new splitter is in the first row, 1st column of first splitter
529 TRACE0("Failed to create nested splitter\n");
530 return FALSE;
532 // add the first splitter pane - the default view in row 0
533 if (!m_wndSplitter.CreateView(1, 0,
534 RUNTIME_CLASS(CBottomView), CSize(cr.Width(), cr.Height()), pContext))
536 TRACE0("Failed to create first pane\n");
537 return FALSE;
539 m_pwndBottomView = (CBottomView *)m_wndSplitter.GetPane(1,0);
540 m_pwndBottomView->m_pwndLocator = &m_wndLocatorBar;
541 m_pwndBottomView->m_pwndLineDiffBar = &m_wndLineDiffBar;
542 if (m_bUseRibbons)
543 m_pwndBottomView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
544 else
545 m_pwndBottomView->m_pwndStatusBar = &m_wndStatusBar;
546 m_pwndBottomView->m_pMainFrame = this;
548 // now create the two views inside the nested splitter
550 if (!m_wndSplitter2.CreateView(0, 0,
551 RUNTIME_CLASS(CLeftView), CSize(cr.Width()/2, cr.Height()/2), pContext))
553 TRACE0("Failed to create second pane\n");
554 return FALSE;
556 m_pwndLeftView = (CLeftView *)m_wndSplitter2.GetPane(0,0);
557 m_pwndLeftView->m_pwndLocator = &m_wndLocatorBar;
558 m_pwndLeftView->m_pwndLineDiffBar = &m_wndLineDiffBar;
559 if (m_bUseRibbons)
560 m_pwndLeftView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
561 else
562 m_pwndLeftView->m_pwndStatusBar = &m_wndStatusBar;
563 m_pwndLeftView->m_pMainFrame = this;
565 if (!m_wndSplitter2.CreateView(0, 1,
566 RUNTIME_CLASS(CRightView), CSize(cr.Width()/2, cr.Height()/2), pContext))
568 TRACE0("Failed to create third pane\n");
569 return FALSE;
571 m_pwndRightView = (CRightView *)m_wndSplitter2.GetPane(0,1);
572 m_pwndRightView->m_pwndLocator = &m_wndLocatorBar;
573 m_pwndRightView->m_pwndLineDiffBar = &m_wndLineDiffBar;
574 if (m_bUseRibbons)
575 m_pwndRightView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
576 else
577 m_pwndRightView->m_pwndStatusBar = &m_wndStatusBar;
578 m_pwndRightView->m_pMainFrame = this;
579 m_bInitSplitter = TRUE;
581 m_dlgFilePatches.Create(IDD_FILEPATCHES, this);
582 UpdateLayout();
583 return TRUE;
586 // Callback function
587 BOOL CMainFrame::PatchFile(CString sFilePath, bool /*bContentMods*/, bool bPropMods, CString sVersion, BOOL bAutoPatch)
589 CString sDummy;
590 //"dry run" was successful, so save the patched file somewhere...
591 CString sTempFile = CTempFiles::Instance().GetTempFilePathString();
592 CString sRejectedFile, sBasePath;
593 if (m_Patch.GetPatchResult(sFilePath, sTempFile, sRejectedFile, sBasePath) < 0)
595 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
596 return FALSE;
598 sFilePath = m_Patch.GetTargetPath() + _T("\\") + sFilePath;
599 sFilePath.Replace('/', '\\');
600 if (sBasePath.IsEmpty())
601 sBasePath = sFilePath;
602 if (m_bReversedPatch)
604 m_Data.m_baseFile.SetFileName(sTempFile);
605 CString temp;
606 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
607 m_Data.m_baseFile.SetDescriptiveName(temp);
608 m_Data.m_yourFile.SetFileName(sFilePath);
609 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchOriginal);
610 m_Data.m_yourFile.SetDescriptiveName(temp);
611 m_Data.m_theirFile.SetOutOfUse();
612 m_Data.m_mergedFile.SetOutOfUse();
614 else
616 if ((!PathFileExists(sBasePath))||(PathIsDirectory(sBasePath)))
618 m_Data.m_baseFile.SetFileName(CTempFiles::Instance().GetTempFilePathString());
619 m_Data.m_baseFile.CreateEmptyFile();
621 else
623 m_Data.m_baseFile.SetFileName(sBasePath);
625 CString sDescription;
626 sDescription.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sBasePath), (LPCTSTR)m_Data.m_sPatchOriginal);
627 m_Data.m_baseFile.SetDescriptiveName(sDescription);
628 if (sBasePath == sFilePath)
630 m_Data.m_yourFile.SetFileName(sTempFile);
631 CString temp;
632 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sBasePath), (LPCTSTR)m_Data.m_sPatchPatched);
633 m_Data.m_yourFile.SetDescriptiveName(temp);
634 m_Data.m_theirFile.SetOutOfUse();
636 else
638 if (!PathFileExists(sFilePath) || PathIsDirectory(sFilePath))
640 m_Data.m_yourFile.SetFileName(CTempFiles::Instance().GetTempFilePathString());
641 m_Data.m_yourFile.CreateEmptyFile();
642 CString temp;
643 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), CString(MAKEINTRESOURCE(IDS_NOTFOUNDVIEWTITLEINDICATOR)));
644 m_Data.m_yourFile.SetDescriptiveName(temp);
646 else
647 m_Data.m_yourFile.SetFileName(sFilePath);
648 m_Data.m_theirFile.SetFileName(sTempFile);
649 CString temp;
650 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
651 m_Data.m_theirFile.SetDescriptiveName(temp);
653 m_Data.m_mergedFile.SetFileName(sFilePath);
654 m_Data.m_bPatchRequired = bPropMods;
656 TRACE(_T("comparing %s\nwith the patched result %s\n"), (LPCTSTR)sFilePath, (LPCTSTR)sTempFile);
658 LoadViews();
659 if (!sRejectedFile.IsEmpty())
661 #if 0 // TGIT TODO
662 // start TortoiseUDiff with the rejected hunks
663 CString sTitle;
664 sTitle.Format(IDS_TITLE_REJECTEDHUNKS, (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath));
665 CAppUtils::StartUnifiedDiffViewer(sRejectedFile, sTitle);
666 #endif
668 if (bAutoPatch)
670 if (sBasePath != sFilePath && HasConflictsWontKeep())
671 return FALSE;
673 PatchSave();
675 return TRUE;
678 // Callback function
679 BOOL CMainFrame::DiffFiles(CString sURL1, CString sRev1, CString sURL2, CString sRev2)
681 CString tempfile1 = CTempFiles::Instance().GetTempFilePathString();
682 CString tempfile2 = CTempFiles::Instance().GetTempFilePathString();
684 ASSERT(tempfile1.Compare(tempfile2));
686 CString sTemp;
687 CSysProgressDlg progDlg;
688 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev1);
689 progDlg.SetLine(1, sTemp, true);
690 progDlg.SetLine(2, sURL1, true);
691 sTemp.LoadString(IDS_GETVERSIONOFFILETITLE);
692 progDlg.SetTitle(sTemp);
693 progDlg.SetShowProgressBar(true);
694 progDlg.SetAnimation(IDR_DOWNLOAD);
695 progDlg.SetTime(FALSE);
696 progDlg.SetProgress(1,100);
697 progDlg.ShowModeless(this);
698 if (!CAppUtils::GetVersionedFile(sURL1, sRev1, tempfile1, &progDlg, m_hWnd))
700 progDlg.Stop();
701 CString sErrMsg;
702 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev1, (LPCTSTR)sURL1);
703 MessageBox(sErrMsg, NULL, MB_ICONERROR);
704 return FALSE;
706 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev2);
707 progDlg.SetLine(1, sTemp, true);
708 progDlg.SetLine(2, sURL2, true);
709 progDlg.SetProgress(50, 100);
710 if (!CAppUtils::GetVersionedFile(sURL2, sRev2, tempfile2, &progDlg, m_hWnd))
712 progDlg.Stop();
713 CString sErrMsg;
714 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev2, (LPCTSTR)sURL2);
715 MessageBox(sErrMsg, NULL, MB_ICONERROR);
716 return FALSE;
718 progDlg.SetProgress(100,100);
719 progDlg.Stop();
720 CString temp;
721 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL1), (LPCTSTR)sRev1);
722 m_Data.m_baseFile.SetFileName(tempfile1);
723 m_Data.m_baseFile.SetDescriptiveName(temp);
724 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL2), (LPCTSTR)sRev2);
725 m_Data.m_yourFile.SetFileName(tempfile2);
726 m_Data.m_yourFile.SetDescriptiveName(temp);
728 LoadViews();
730 return TRUE;
733 void CMainFrame::OnFileOpen()
735 if (CheckForSave(CHFSR_OPEN)==IDCANCEL)
736 return;
737 return OnFileOpen(false);
740 void CMainFrame::OnFileOpen(bool fillyours)
742 COpenDlg dlg;
743 if (fillyours)
744 dlg.m_sBaseFile = m_Data.m_yourFile.GetFilename();
745 if (dlg.DoModal() != IDOK)
747 return;
749 m_dlgFilePatches.ShowWindow(SW_HIDE);
750 m_dlgFilePatches.Init(NULL, NULL, CString(), NULL);
751 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,
752 (LPCTSTR)dlg.m_sUnifiedDiffFile, (LPCTSTR)dlg.m_sPatchDirectory);
753 m_Data.m_baseFile.SetFileName(dlg.m_sBaseFile);
754 m_Data.m_theirFile.SetFileName(dlg.m_sTheirFile);
755 m_Data.m_yourFile.SetFileName(dlg.m_sYourFile);
756 m_Data.m_sDiffFile = dlg.m_sUnifiedDiffFile;
757 m_Data.m_sPatchPath = dlg.m_sPatchDirectory;
758 m_Data.m_mergedFile.SetOutOfUse();
759 CCrashReport::Instance().AddFile2(dlg.m_sBaseFile, NULL, _T("Basefile"), CR_AF_MAKE_FILE_COPY);
760 CCrashReport::Instance().AddFile2(dlg.m_sTheirFile, NULL, _T("Theirfile"), CR_AF_MAKE_FILE_COPY);
761 CCrashReport::Instance().AddFile2(dlg.m_sYourFile, NULL, _T("Yourfile"), CR_AF_MAKE_FILE_COPY);
762 CCrashReport::Instance().AddFile2(dlg.m_sUnifiedDiffFile, NULL, _T("Difffile"), CR_AF_MAKE_FILE_COPY);
764 if (!m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && m_Data.IsYourFileInUse())
766 // a diff between two files means "Yours" against "Base", not "Theirs" against "Yours"
767 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
769 if (m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && !m_Data.IsYourFileInUse())
771 // a diff between two files means "Yours" against "Base", not "Theirs" against "Base"
772 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
774 m_bSaveRequired = false;
776 LoadViews();
779 void CMainFrame::ClearViewNamesAndPaths()
781 m_pwndLeftView->m_sWindowName.Empty();
782 m_pwndLeftView->m_sFullFilePath.Empty();
783 m_pwndLeftView->m_sReflectedName.Empty();
784 m_pwndRightView->m_sWindowName.Empty();
785 m_pwndRightView->m_sFullFilePath.Empty();
786 m_pwndRightView->m_sReflectedName.Empty();
787 m_pwndBottomView->m_sWindowName.Empty();
788 m_pwndBottomView->m_sFullFilePath.Empty();
789 m_pwndBottomView->m_sReflectedName.Empty();
792 bool CMainFrame::LoadViews(int line)
794 LoadIgnoreCommentData();
795 m_Data.SetBlame(m_bBlame);
796 m_Data.SetMovedBlocks(m_bViewMovedBlocks);
797 m_bHasConflicts = false;
798 CBaseView* pwndActiveView = m_pwndLeftView;
799 int nOldLine = m_pwndRightView ? m_pwndRightView->m_nTopLine : -1;
800 int nOldLineNumber =
801 m_pwndRightView && m_pwndRightView->m_pViewData ?
802 m_pwndRightView->m_pViewData->GetLineNumber(m_pwndRightView->m_nTopLine) : -1;
803 POINT ptOldCaretPos = {-1, -1};
804 if (m_pwndRightView && m_pwndRightView->IsTarget())
805 ptOldCaretPos = m_pwndRightView->GetCaretPosition();
806 if (m_pwndBottomView && m_pwndBottomView->IsTarget())
807 ptOldCaretPos = m_pwndBottomView->GetCaretPosition();
808 CString sExt = CPathUtils::GetFileExtFromPath(m_Data.m_baseFile.GetFilename()).MakeLower();
809 sExt.TrimLeft(L".");
810 auto sC = m_IgnoreCommentsMap.find(sExt);
811 if (sC == m_IgnoreCommentsMap.end())
813 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_yourFile.GetFilename()).MakeLower();
814 sC = m_IgnoreCommentsMap.find(sExt);
815 if (sC == m_IgnoreCommentsMap.end())
817 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_theirFile.GetFilename()).MakeLower();
818 sC = m_IgnoreCommentsMap.find(sExt);
821 if (sC != m_IgnoreCommentsMap.end())
822 m_Data.SetCommentTokens(std::get<0>(sC->second), std::get<1>(sC->second), std::get<2>(sC->second));
823 else
824 m_Data.SetCommentTokens(L"", L"", L"");
825 if (!m_Data.Load())
827 m_pwndLeftView->BuildAllScreen2ViewVector();
828 m_pwndLeftView->DocumentUpdated();
829 m_pwndRightView->DocumentUpdated();
830 m_pwndBottomView->DocumentUpdated();
831 m_wndLocatorBar.DocumentUpdated();
832 m_wndLineDiffBar.DocumentUpdated();
833 ::MessageBox(m_hWnd, m_Data.GetError(), _T("TortoiseGitMerge"), MB_ICONERROR);
834 m_Data.m_mergedFile.SetOutOfUse();
835 m_bSaveRequired = false;
836 return false;
838 SetWindowTitle();
839 m_pwndLeftView->BuildAllScreen2ViewVector();
840 m_pwndLeftView->DocumentUpdated();
841 m_pwndRightView->DocumentUpdated();
842 m_pwndBottomView->DocumentUpdated();
843 m_wndLocatorBar.DocumentUpdated();
844 m_wndLineDiffBar.DocumentUpdated();
846 m_pwndLeftView->SetWritable(false);
847 m_pwndLeftView->SetWritableIsChangable(false);
848 m_pwndLeftView->SetTarget(false);
849 m_pwndRightView->SetWritable(false);
850 m_pwndRightView->SetWritableIsChangable(false);
851 m_pwndRightView->SetTarget(false);
852 m_pwndBottomView->SetWritable(false);
853 m_pwndBottomView->SetWritableIsChangable(false);
854 m_pwndBottomView->SetTarget(false);
856 if (!m_Data.IsBaseFileInUse())
858 CSysProgressDlg progDlg;
859 if (m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
861 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
863 else if ((!m_Data.m_sDiffFile.IsEmpty())&&(!m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg)))
865 progDlg.Stop();
866 ClearViewNamesAndPaths();
867 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
868 m_bSaveRequired = false;
869 return false;
871 progDlg.Stop();
872 if (m_Patch.GetNumberOfFiles() > 0)
874 CString betterpatchpath = m_Patch.CheckPatchPath(m_Data.m_sPatchPath);
875 if (betterpatchpath.CompareNoCase(m_Data.m_sPatchPath)!=0)
877 CString msg;
878 msg.Format(IDS_WARNBETTERPATCHPATHFOUND, (LPCTSTR)m_Data.m_sPatchPath, (LPCTSTR)betterpatchpath);
879 if (m_bUseTaskDialog)
881 CTaskDialog taskdlg(msg,
882 CString(MAKEINTRESOURCE(IDS_WARNBETTERPATCHPATHFOUND_TASK2)),
883 L"TortoiseGitMerge",
885 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
886 CString task3;
887 WCHAR t3[MAX_PATH] = {0};
888 CString cp = betterpatchpath.Left(MAX_PATH-1);
889 PathCompactPathEx(t3, cp, 50, 0);
890 task3.Format(IDS_WARNBETTERPATCHPATHFOUND_TASK3, t3);
891 taskdlg.AddCommandControl(1, task3);
892 CString task4;
893 WCHAR t4[MAX_PATH] = {0};
894 cp = m_Data.m_sPatchPath.Left(MAX_PATH-1);
895 PathCompactPathEx(t4, cp, 50, 0);
896 task4.Format(IDS_WARNBETTERPATCHPATHFOUND_TASK4, t4);
897 taskdlg.AddCommandControl(2, task4);
898 taskdlg.SetDefaultCommandControl(1);
899 taskdlg.SetMainIcon(TD_INFORMATION_ICON);
900 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
901 if (taskdlg.DoModal(m_hWnd) == 1)
903 m_Data.m_sPatchPath = betterpatchpath;
904 m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg);
907 else if (::MessageBox(m_hWnd, msg, _T("TortoiseGitMerge"), MB_ICONQUESTION | MB_YESNO)==IDYES)
909 m_Data.m_sPatchPath = betterpatchpath;
910 m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg);
913 m_dlgFilePatches.Init(&m_Patch, this, m_Data.m_sPatchPath, this);
914 m_dlgFilePatches.ShowWindow(SW_SHOW);
915 ClearViewNamesAndPaths();
916 if (!m_wndSplitter.IsRowHidden(1))
917 m_wndSplitter.HideRow(1);
918 m_pwndLeftView->SetHidden(FALSE);
919 m_pwndRightView->SetHidden(FALSE);
920 m_pwndBottomView->SetHidden(TRUE);
923 if (m_Data.IsBaseFileInUse() && !m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
925 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
927 if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && !m_Data.IsTheirFileInUse())
929 //diff between YOUR and BASE
930 if (m_bOneWay)
932 pwndActiveView = m_pwndLeftView;
933 if (!m_wndSplitter2.IsColumnHidden(1))
934 m_wndSplitter2.HideColumn(1);
936 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseBoth;
937 m_pwndLeftView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
938 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
939 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName() + _T(" - ") + m_Data.m_yourFile.GetWindowName();
940 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename() + _T(" - ") + m_Data.m_yourFile.GetFilename();
941 m_pwndLeftView->m_sReflectedName = m_Data.m_yourFile.GetReflectedName();
942 m_pwndLeftView->m_pWorkingFile = &m_Data.m_yourFile;
943 m_pwndLeftView->SetTarget();
944 m_pwndLeftView->SetWritableIsChangable(true);
946 m_pwndRightView->m_pViewData = NULL;
947 m_pwndRightView->m_pWorkingFile = NULL;
948 m_pwndBottomView->m_pViewData = NULL;
949 m_pwndBottomView->m_pWorkingFile = NULL;
951 if (!m_wndSplitter.IsRowHidden(1))
952 m_wndSplitter.HideRow(1);
953 m_pwndLeftView->SetHidden(FALSE);
954 m_pwndRightView->SetHidden(TRUE);
955 m_pwndBottomView->SetHidden(TRUE);
956 ::SetWindowPos(m_pwndLeftView->m_hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
958 else
960 pwndActiveView = m_pwndRightView;
961 if (m_wndSplitter2.IsColumnHidden(1))
962 m_wndSplitter2.ShowColumn();
964 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseLeft;
965 m_pwndLeftView->SetTextType(m_Data.m_arBaseFile.GetUnicodeType());
966 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arBaseFile.GetLineEndings());
967 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName();
968 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename();
969 m_pwndLeftView->m_sConvertedFilePath = m_Data.m_baseFile.GetConvertedFileName();
970 m_pwndLeftView->m_sReflectedName = m_Data.m_baseFile.GetReflectedName();
971 m_pwndLeftView->m_pWorkingFile = &m_Data.m_baseFile;
972 m_pwndLeftView->SetWritableIsChangable(true);
974 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseRight;
975 m_pwndRightView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
976 m_pwndRightView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
977 m_pwndRightView->m_sWindowName = m_Data.m_yourFile.GetWindowName();
978 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
979 m_pwndRightView->m_sConvertedFilePath = m_Data.m_yourFile.GetConvertedFileName();
980 m_pwndRightView->m_sReflectedName = m_Data.m_yourFile.GetReflectedName();
981 m_pwndRightView->m_pWorkingFile = &m_Data.m_yourFile;
982 m_pwndRightView->SetWritable();
983 m_pwndRightView->SetTarget();
985 m_pwndBottomView->m_pViewData = NULL;
986 m_pwndBottomView->m_pWorkingFile = NULL;
988 if (!m_wndSplitter.IsRowHidden(1))
989 m_wndSplitter.HideRow(1);
990 m_pwndLeftView->SetHidden(FALSE);
991 m_pwndRightView->SetHidden(FALSE);
992 m_pwndBottomView->SetHidden(TRUE);
994 bool hasMods, hasConflicts, hasWhitespaceMods;
995 pwndActiveView->CheckModifications(hasMods, hasConflicts, hasWhitespaceMods);
996 if (!hasMods && !hasConflicts)
998 // files appear identical, show a dialog informing the user that there are or might
999 // be other differences
1000 bool hasEncodingDiff = m_Data.m_arBaseFile.GetUnicodeType() != m_Data.m_arYourFile.GetUnicodeType();
1001 bool hasEOLDiff = m_Data.m_arBaseFile.GetLineEndings() != m_Data.m_arYourFile.GetLineEndings();
1002 if (hasWhitespaceMods || hasEncodingDiff || hasEOLDiff)
1004 // text is identical, but the files do not match
1005 CString sWarning(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_MAIN));
1006 CString sWhitespace(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_WHITESPACE));
1007 CString sEncoding(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_ENCODING));
1008 CString sEOL(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_EOL));
1009 if (hasWhitespaceMods)
1011 sWarning += L"\r\n";
1012 sWarning += sWhitespace;
1014 if (hasEncodingDiff)
1016 sWarning += L"\r\n";
1017 sWarning += sEncoding;
1018 sWarning += L" (";
1019 sWarning += m_Data.m_arBaseFile.GetEncodingName(m_Data.m_arBaseFile.GetUnicodeType());
1020 sWarning += L", ";
1021 sWarning += m_Data.m_arYourFile.GetEncodingName(m_Data.m_arYourFile.GetUnicodeType());
1022 sWarning += L")";
1024 if (hasEOLDiff)
1026 sWarning += L"\r\n";
1027 sWarning += sEOL;
1029 AfxMessageBox(sWarning, MB_ICONINFORMATION);
1033 else if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
1035 //diff between THEIR, YOUR and BASE
1036 m_pwndBottomView->SetWritable();
1037 m_pwndBottomView->SetTarget();
1038 pwndActiveView = m_pwndBottomView;
1040 m_pwndLeftView->m_pViewData = &m_Data.m_TheirBaseBoth;
1041 m_pwndLeftView->SetTextType(m_Data.m_arTheirFile.GetUnicodeType());
1042 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arTheirFile.GetLineEndings());
1043 m_pwndLeftView->m_sWindowName.LoadString(IDS_VIEWTITLE_THEIRS);
1044 m_pwndLeftView->m_sWindowName += _T(" - ") + m_Data.m_theirFile.GetWindowName();
1045 m_pwndLeftView->m_sFullFilePath = m_Data.m_theirFile.GetFilename();
1046 m_pwndLeftView->m_sConvertedFilePath = m_Data.m_theirFile.GetConvertedFileName();
1047 m_pwndLeftView->m_sReflectedName = m_Data.m_theirFile.GetReflectedName();
1048 m_pwndLeftView->m_pWorkingFile = &m_Data.m_theirFile;
1050 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseBoth;
1051 m_pwndRightView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
1052 m_pwndRightView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
1053 m_pwndRightView->m_sWindowName.LoadString(IDS_VIEWTITLE_MINE);
1054 m_pwndRightView->m_sWindowName += _T(" - ") + m_Data.m_yourFile.GetWindowName();
1055 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
1056 m_pwndRightView->m_sConvertedFilePath = m_Data.m_yourFile.GetConvertedFileName();
1057 m_pwndRightView->m_sReflectedName = m_Data.m_yourFile.GetReflectedName();
1058 m_pwndRightView->m_pWorkingFile = &m_Data.m_yourFile;
1060 m_pwndBottomView->m_pViewData = &m_Data.m_Diff3;
1061 m_pwndBottomView->SetTextType(m_Data.m_arTheirFile.GetUnicodeType());
1062 m_pwndBottomView->SetLineEndingStyle(m_Data.m_arTheirFile.GetLineEndings());
1063 m_pwndBottomView->m_sWindowName.LoadString(IDS_VIEWTITLE_MERGED);
1064 m_pwndBottomView->m_sWindowName += _T(" - ") + m_Data.m_mergedFile.GetWindowName();
1065 m_pwndBottomView->m_sFullFilePath = m_Data.m_mergedFile.GetFilename();
1066 m_pwndBottomView->m_sConvertedFilePath = m_Data.m_mergedFile.GetConvertedFileName();
1067 m_pwndBottomView->m_sReflectedName = m_Data.m_mergedFile.GetReflectedName();
1068 m_pwndBottomView->m_pWorkingFile = &m_Data.m_mergedFile;
1070 if (m_wndSplitter2.IsColumnHidden(1))
1071 m_wndSplitter2.ShowColumn();
1072 if (m_wndSplitter.IsRowHidden(1))
1073 m_wndSplitter.ShowRow();
1074 m_pwndLeftView->SetHidden(FALSE);
1075 m_pwndRightView->SetHidden(FALSE);
1076 m_pwndBottomView->SetHidden(FALSE);
1077 // in three pane view, hide the line diff bar
1078 m_wndLineDiffBar.ShowPane(false, false, true);
1079 m_wndLineDiffBar.DocumentUpdated();
1081 if (!m_Data.m_mergedFile.InUse())
1083 m_Data.m_mergedFile.SetFileName(m_Data.m_yourFile.GetFilename());
1085 m_pwndLeftView->BuildAllScreen2ViewVector();
1086 m_pwndLeftView->DocumentUpdated();
1087 m_pwndRightView->DocumentUpdated();
1088 m_pwndBottomView->DocumentUpdated();
1089 m_wndLocatorBar.DocumentUpdated();
1090 m_wndLineDiffBar.DocumentUpdated();
1091 UpdateLayout();
1092 SetActiveView(pwndActiveView);
1094 if ((line >= -1) && m_pwndRightView->m_pViewData)
1096 int n = line == -1 ? min( nOldLineNumber, nOldLine ) : line;
1097 if (n >= 0)
1098 n = m_pwndRightView->m_pViewData->FindLineNumber(n);
1099 if (n < 0)
1100 n = nOldLine;
1102 m_pwndRightView->ScrollAllToLine(n);
1103 POINT p;
1104 p.x = 0;
1105 p.y = n;
1106 if ((ptOldCaretPos.x >= 0) || (ptOldCaretPos.y >= 0))
1107 p = ptOldCaretPos;
1108 m_pwndLeftView->SetCaretPosition(p);
1109 m_pwndRightView->SetCaretPosition(p);
1110 m_pwndBottomView->SetCaretPosition(p);
1111 m_pwndBottomView->ScrollToChar(0);
1112 m_pwndLeftView->ScrollToChar(0);
1113 m_pwndRightView->ScrollToChar(0);
1115 else
1117 CRegDWORD regFirstDiff = CRegDWORD(_T("Software\\TortoiseGitMerge\\FirstDiffOnLoad"), TRUE);
1118 CRegDWORD regFirstConflict = CRegDWORD(_T("Software\\TortoiseGitMerge\\FirstConflictOnLoad"), TRUE);
1119 bool bGoFirstDiff = (0 != (DWORD)regFirstDiff);
1120 bool bGoFirstConflict = (0 != (DWORD)regFirstConflict);
1121 if (bGoFirstConflict && (CheckResolved()>=0))
1123 pwndActiveView->GoToFirstConflict();
1124 // Ignore the first few Mouse Move messages, so that the line diff stays on
1125 // the first diff line until the user actually moves the mouse
1126 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1128 else if (bGoFirstDiff)
1130 pwndActiveView->GoToFirstDifference();
1131 // Ignore the first few Mouse Move messages, so that the line diff stays on
1132 // the first diff line until the user actually moves the mouse
1133 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1135 else
1137 // Avoid incorrect rendering of active pane.
1138 m_pwndBottomView->ScrollToChar(0);
1139 m_pwndLeftView->ScrollToChar(0);
1140 m_pwndRightView->ScrollToChar(0);
1143 CheckResolved();
1144 if (m_bHasConflicts && !m_bSaveRequiredOnConflicts)
1145 m_bSaveRequired = false;
1146 CUndo::GetInstance().Clear();
1147 return true;
1150 void CMainFrame::UpdateLayout()
1152 if (m_bInitSplitter)
1154 m_wndSplitter.CenterSplitter();
1155 m_wndSplitter2.CenterSplitter();
1159 void CMainFrame::OnSize(UINT nType, int cx, int cy)
1161 CFrameWndEx::OnSize(nType, cx, cy);
1162 if (m_bInitSplitter && nType != SIZE_MINIMIZED)
1164 if (m_wndSplitter.GetSafeHwnd())
1166 if (m_wndSplitter.HasOldRowSize() && (m_wndSplitter.GetOldRowCount() == 2))
1168 int oldTotal = m_wndSplitter.GetOldRowSize(0) + m_wndSplitter.GetOldRowSize(1);
1169 if (oldTotal)
1171 int cxCur0, cxCur1, cxMin0, cxMin1;
1172 m_wndSplitter.GetRowInfo(0, cxCur0, cxMin0);
1173 m_wndSplitter.GetRowInfo(1, cxCur1, cxMin1);
1174 cxCur0 = m_wndSplitter.GetOldRowSize(0) * (cxCur0 + cxCur1) / oldTotal;
1175 cxCur1 = m_wndSplitter.GetOldRowSize(1) * (cxCur0 + cxCur1) / oldTotal;
1176 m_wndSplitter.SetRowInfo(0, cxCur0, 0);
1177 m_wndSplitter.SetRowInfo(1, cxCur1, 0);
1178 m_wndSplitter.RecalcLayout();
1182 if (m_wndSplitter2.HasOldColSize() && (m_wndSplitter2.GetOldColCount() == 2))
1184 int oldTotal = m_wndSplitter2.GetOldColSize(0) + m_wndSplitter2.GetOldColSize(1);
1185 if (oldTotal)
1187 int cyCur0, cyCur1, cyMin0, cyMin1;
1188 m_wndSplitter2.GetColumnInfo(0, cyCur0, cyMin0);
1189 m_wndSplitter2.GetColumnInfo(1, cyCur1, cyMin1);
1190 cyCur0 = m_wndSplitter2.GetOldColSize(0) * (cyCur0 + cyCur1) / oldTotal;
1191 cyCur1 = m_wndSplitter2.GetOldColSize(1) * (cyCur0 + cyCur1) / oldTotal;
1192 m_wndSplitter2.SetColumnInfo(0, cyCur0, 0);
1193 m_wndSplitter2.SetColumnInfo(1, cyCur1, 0);
1194 m_wndSplitter2.RecalcLayout();
1199 if ((nType == SIZE_RESTORED)&&m_bCheckReload)
1201 m_bCheckReload = false;
1202 CheckForReload();
1204 #if _MSC_VER < 1800
1205 // workaround for ribbon interface when the task bar is on the left or top
1206 // The bug has been fixed in VS2013
1207 // http://connect.microsoft.com/VisualStudio/feedback/details/791229/cmfcribbonbar-app-does-not-maximize-correctly-if-windows-7-taskbar-is-docked-on-left
1208 if (nType == SIZE_MAXIMIZED)
1210 HMONITOR hMon = MonitorFromWindow(this->m_hWnd, MONITOR_DEFAULTTONEAREST);
1211 MONITORINFOEX mix;
1212 mix.cbSize = sizeof(MONITORINFOEX);
1213 bool primary = true; // assume primary monitor
1214 CRect rect(0, 0, 0, 0);
1215 if (GetMonitorInfo(hMon, &mix))
1217 primary = (mix.dwFlags == MONITORINFOF_PRIMARY);
1218 rect = mix.rcWork;
1220 else
1222 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
1224 if (primary)
1226 WINDOWPLACEMENT wp;
1227 GetWindowPlacement(&wp);
1228 if (wp.ptMaxPosition.x || wp.ptMaxPosition.y)
1230 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
1231 SetWindowPlacement(&wp);
1234 else
1236 MoveWindow(rect);
1239 #endif
1242 void CMainFrame::OnViewWhitespaces()
1244 CRegDWORD regViewWhitespaces = CRegDWORD(_T("Software\\TortoiseGitMerge\\ViewWhitespaces"), 1);
1245 BOOL bViewWhitespaces = regViewWhitespaces;
1246 if (m_pwndLeftView)
1247 bViewWhitespaces = m_pwndLeftView->m_bViewWhitespace;
1249 bViewWhitespaces = !bViewWhitespaces;
1250 regViewWhitespaces = bViewWhitespaces;
1251 if (m_pwndLeftView)
1253 m_pwndLeftView->m_bViewWhitespace = bViewWhitespaces;
1254 m_pwndLeftView->Invalidate();
1256 if (m_pwndRightView)
1258 m_pwndRightView->m_bViewWhitespace = bViewWhitespaces;
1259 m_pwndRightView->Invalidate();
1261 if (m_pwndBottomView)
1263 m_pwndBottomView->m_bViewWhitespace = bViewWhitespaces;
1264 m_pwndBottomView->Invalidate();
1268 void CMainFrame::OnUpdateViewWhitespaces(CCmdUI *pCmdUI)
1270 if (m_pwndLeftView)
1271 pCmdUI->SetCheck(m_pwndLeftView->m_bViewWhitespace);
1274 void CMainFrame::OnViewCollapsed()
1276 m_regCollapsed = !(DWORD)m_regCollapsed;
1277 m_bCollapsed = !!(DWORD)m_regCollapsed;
1279 OnViewTextFoldUnfold();
1280 m_wndLocatorBar.Invalidate();
1283 void CMainFrame::OnUpdateViewCollapsed(CCmdUI *pCmdUI)
1285 pCmdUI->SetCheck(m_bCollapsed);
1288 void CMainFrame::OnViewWraplonglines()
1290 m_bWrapLines = !(DWORD)m_regWrapLines;
1291 m_regWrapLines = m_bWrapLines;
1293 if (m_pwndLeftView) m_pwndLeftView ->WrapChanged();
1294 if (m_pwndRightView) m_pwndRightView ->WrapChanged();
1295 if (m_pwndBottomView) m_pwndBottomView->WrapChanged();
1296 OnViewTextFoldUnfold();
1297 m_wndLocatorBar.DocumentUpdated();
1300 void CMainFrame::OnViewTextFoldUnfold()
1302 OnViewTextFoldUnfold(m_pwndLeftView);
1303 OnViewTextFoldUnfold(m_pwndRightView);
1304 OnViewTextFoldUnfold(m_pwndBottomView);
1307 void CMainFrame::OnViewTextFoldUnfold(CBaseView* view)
1309 if (view == 0)
1310 return;
1311 view->BuildAllScreen2ViewVector();
1312 view->UpdateCaret();
1313 view->Invalidate();
1314 view->EnsureCaretVisible();
1317 void CMainFrame::OnUpdateViewWraplonglines(CCmdUI *pCmdUI)
1319 pCmdUI->SetCheck(m_bWrapLines);
1322 void CMainFrame::OnViewOnewaydiff()
1324 if (CheckForSave(CHFSR_RELOAD)==IDCANCEL)
1325 return;
1326 m_bOneWay = !m_bOneWay;
1327 ShowDiffBar(!m_bOneWay);
1328 LoadViews(-1);
1331 void CMainFrame::ShowDiffBar(bool bShow)
1333 if (bShow)
1335 // restore the line diff bar
1336 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
1337 m_wndLineDiffBar.DocumentUpdated();
1338 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
1339 m_wndLocatorBar.DocumentUpdated();
1341 else
1343 // in one way view, hide the line diff bar
1344 m_wndLineDiffBar.ShowPane(false, false, true);
1345 m_wndLineDiffBar.DocumentUpdated();
1349 int CMainFrame::CheckResolved()
1351 //only in three way diffs can be conflicts!
1352 m_bHasConflicts = true;
1353 if (IsViewGood(m_pwndBottomView))
1355 CViewData* viewdata = m_pwndBottomView->m_pViewData;
1356 if (viewdata)
1358 for (int i=0; i<viewdata->GetCount(); i++)
1360 const DiffStates state = viewdata->GetState(i);
1361 if ((DIFFSTATE_CONFLICTED == state)||(DIFFSTATE_CONFLICTED_IGNORED == state))
1362 return i;
1366 m_bHasConflicts = false;
1367 return -1;
1370 int CMainFrame::SaveFile(const CString& sFilePath)
1372 CBaseView * pView = NULL;
1373 CViewData * pViewData = NULL;
1374 CFileTextLines * pOriginFile = &m_Data.m_arBaseFile;
1375 if (IsViewGood(m_pwndBottomView))
1377 pView = m_pwndBottomView;
1378 pViewData = m_pwndBottomView->m_pViewData;
1380 else if (IsViewGood(m_pwndRightView))
1382 pView = m_pwndRightView;
1383 pViewData = m_pwndRightView->m_pViewData;
1384 if (m_Data.IsYourFileInUse())
1385 pOriginFile = &m_Data.m_arYourFile;
1386 else if (m_Data.IsTheirFileInUse())
1387 pOriginFile = &m_Data.m_arTheirFile;
1389 else
1391 // nothing to save!
1392 return 1;
1394 Invalidate();
1395 if ((pViewData)&&(pOriginFile))
1397 CFileTextLines file;
1398 pOriginFile->CopySettings(&file);
1399 CFileTextLines::SaveParams saveParams;
1400 saveParams.m_LineEndings = pView->GetLineEndings();
1401 saveParams.m_UnicodeType = pView->GetTextType();
1402 file.SetSaveParams(saveParams);
1403 for (int i=0; i<pViewData->GetCount(); i++)
1405 //only copy non-removed lines
1406 DiffStates state = pViewData->GetState(i);
1407 switch (state)
1409 case DIFFSTATE_CONFLICTED:
1410 case DIFFSTATE_CONFLICTED_IGNORED:
1412 int first = i;
1413 int last = i;
1416 last++;
1417 } while((last<pViewData->GetCount()) && ((pViewData->GetState(last)==DIFFSTATE_CONFLICTED)||(pViewData->GetState(last)==DIFFSTATE_CONFLICTED_IGNORED)));
1418 // TortoiseGitMerge changes here
1419 file.Add(_T("<<<<<<< .mine"), m_pwndRightView->GetLineEndings());
1420 for (int j=first; j<last; j++)
1422 EOL lineending = m_pwndRightView->m_pViewData->GetLineEnding(j);
1423 if (lineending == EOL_NOENDING)
1424 lineending = m_pwndRightView->GetLineEndings();
1425 file.Add(m_pwndRightView->m_pViewData->GetLine(j), lineending);
1427 file.Add(_T("======="), m_pwndRightView->GetLineEndings());
1428 for (int j=first; j<last; j++)
1430 EOL lineending = m_pwndLeftView->m_pViewData->GetLineEnding(j);
1431 if (lineending == EOL_NOENDING)
1432 lineending = m_pwndLeftView->GetLineEndings();
1433 file.Add(m_pwndLeftView->m_pViewData->GetLine(j), lineending);
1435 file.Add(_T(">>>>>>> .theirs"), m_pwndRightView->GetLineEndings());
1436 i = last-1;
1438 break;
1439 case DIFFSTATE_EMPTY:
1440 case DIFFSTATE_CONFLICTEMPTY:
1441 case DIFFSTATE_IDENTICALREMOVED:
1442 case DIFFSTATE_REMOVED:
1443 case DIFFSTATE_THEIRSREMOVED:
1444 case DIFFSTATE_YOURSREMOVED:
1445 case DIFFSTATE_CONFLICTRESOLVEDEMPTY:
1446 // do not save removed lines
1447 break;
1448 default:
1449 file.Add(pViewData->GetLine(i), pViewData->GetLineEnding(i));
1450 break;
1453 if (!file.Save(sFilePath, false, false))
1455 CMessageBox::Show(m_hWnd, file.GetErrorString(), _T("TortoiseGitMerge"), MB_ICONERROR);
1456 return -1;
1458 if (sFilePath == m_Data.m_baseFile.GetFilename())
1460 m_Data.m_baseFile.StoreFileAttributes();
1462 if (sFilePath == m_Data.m_theirFile.GetFilename())
1464 m_Data.m_theirFile.StoreFileAttributes();
1466 if (sFilePath == m_Data.m_yourFile.GetFilename())
1468 m_Data.m_yourFile.StoreFileAttributes();
1470 /*if (sFilePath == m_Data.m_mergedFile.GetFilename())
1472 m_Data.m_mergedFile.StoreFileAttributes();
1473 }//*/
1474 m_dlgFilePatches.SetFileStatusAsPatched(sFilePath);
1475 if (IsViewGood(m_pwndBottomView))
1476 m_pwndBottomView->SetModified(FALSE);
1477 else if (IsViewGood(m_pwndRightView))
1478 m_pwndRightView->SetModified(FALSE);
1479 CUndo::GetInstance().MarkAsOriginalState(
1480 false,
1481 IsViewGood(m_pwndRightView) && (pViewData == m_pwndRightView->m_pViewData),
1482 IsViewGood(m_pwndBottomView) && (pViewData == m_pwndBottomView->m_pViewData));
1483 if (file.GetCount() == 1 && file.GetAt(0).IsEmpty() && file.GetLineEnding(0) == EOL_NOENDING)
1484 return 0;
1485 return file.GetCount();
1487 return 1;
1490 void CMainFrame::OnFileSave()
1492 // when multiple files are set as writable we have to ask what file to save
1493 int nEditableViewCount =
1494 (CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsWritable() ? 1 : 0)
1495 + (CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsWritable() ? 1 : 0)
1496 + (CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsWritable() ? 1 : 0);
1497 bool bLeftIsModified = CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsModified();
1498 bool bRightIsModified = CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsModified();
1499 bool bBottomIsModified = CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsModified();
1500 int nModifiedViewCount =
1501 (bLeftIsModified ? 1 : 0)
1502 + (bRightIsModified ? 1 : 0)
1503 + (bBottomIsModified ? 1 : 0);
1504 if (nEditableViewCount>1)
1506 if (nModifiedViewCount == 1)
1508 if (bLeftIsModified)
1509 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1510 else
1511 FileSave();
1513 else if (nModifiedViewCount>0)
1515 // both views
1516 UINT ret = IDNO;
1517 if (m_bUseTaskDialog)
1519 CTaskDialog taskdlg(CString(MAKEINTRESOURCE(IDS_SAVE_MORE)),
1520 CString(MAKEINTRESOURCE(IDS_SAVE)),
1521 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1523 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
1524 CString sTaskTemp;
1525 if (m_pwndLeftView->m_pWorkingFile->InUse() && !m_pwndLeftView->m_pWorkingFile->IsReadonly())
1526 sTaskTemp.Format(IDS_ASKFORSAVE_SAVELEFT, (LPCTSTR)m_pwndLeftView->m_pWorkingFile->GetFilename());
1527 else
1528 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS));
1529 taskdlg.AddCommandControl(201, sTaskTemp, bLeftIsModified);// left
1530 if (bLeftIsModified) {
1531 taskdlg.SetDefaultCommandControl(201);
1533 if (m_pwndRightView->m_pWorkingFile->InUse() && !m_pwndRightView->m_pWorkingFile->IsReadonly())
1534 sTaskTemp.Format(IDS_ASKFORSAVE_SAVERIGHT, (LPCTSTR)m_pwndRightView->m_pWorkingFile->GetFilename());
1535 else
1536 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS));
1537 taskdlg.AddCommandControl(202, sTaskTemp, bRightIsModified); // right
1538 if (bRightIsModified) {
1539 taskdlg.SetDefaultCommandControl(202);
1541 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEALL2)), nModifiedViewCount>1); // both
1542 if (nModifiedViewCount>1) {
1543 taskdlg.SetDefaultCommandControl(203);
1545 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1546 taskdlg.SetMainIcon(TD_WARNING_ICON);
1547 ret = (UINT)taskdlg.DoModal(m_hWnd);
1548 switch (ret)
1550 case 201: // left
1551 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1552 break;
1553 case 203: // both
1554 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1555 case 202: // right
1556 m_pwndRightView->SaveFile();
1557 break;
1562 else
1564 // only target view was modified
1565 FileSave();
1569 void CMainFrame::PatchSave()
1571 bool bDoesNotExist = !PathFileExists(m_Data.m_mergedFile.GetFilename());
1572 if (m_Data.m_bPatchRequired)
1574 m_Patch.PatchPath(m_Data.m_mergedFile.GetFilename());
1576 if (!PathIsDirectory(m_Data.m_mergedFile.GetFilename()))
1578 int saveret = SaveFile(m_Data.m_mergedFile.GetFilename());
1579 if (saveret==0)
1581 // file was saved with 0 lines, remove it.
1582 m_Patch.RemoveFile(m_Data.m_mergedFile.GetFilename());
1583 // just in case
1584 DeleteFile(m_Data.m_mergedFile.GetFilename());
1586 m_Data.m_mergedFile.StoreFileAttributes();
1587 if (m_Data.m_mergedFile.GetFilename() == m_Data.m_yourFile.GetFilename())
1588 m_Data.m_yourFile.StoreFileAttributes();
1589 if ((bDoesNotExist)&&(DWORD(CRegDWORD(_T("Software\\TortoiseGitMerge\\AutoAdd"), TRUE))))
1591 // call TortoiseProc to add the new file to version control
1592 CString cmd = _T("/command:add /noui /path:\"");
1593 cmd += m_Data.m_mergedFile.GetFilename() + _T("\"");
1594 CAppUtils::RunTortoiseGitProc(cmd);
1599 bool CMainFrame::FileSave(bool bCheckResolved /*=true*/)
1601 if (HasMarkedBlocks())
1603 if (m_bUseTaskDialog)
1605 CString sTitle(MAKEINTRESOURCE(IDS_WARNMARKEDBLOCKS));
1606 CString sSubTitle(MAKEINTRESOURCE(IDS_ASKFORSAVE_MARKEDBLOCKS));
1607 CString sAppName(MAKEINTRESOURCE(IDS_APPNAME));
1608 CTaskDialog taskdlg(sTitle,
1609 sSubTitle,
1610 sAppName,
1612 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
1613 taskdlg.AddCommandControl(10, CString(MAKEINTRESOURCE(IDS_MARKEDBLOCKSSAVEINCLUDE)));
1614 taskdlg.AddCommandControl(11, CString(MAKEINTRESOURCE(IDS_MARKEDBLOCKSSAVEEXCLUDE)));
1615 taskdlg.AddCommandControl(12, CString(MAKEINTRESOURCE(IDS_MARKEDBLCOKSSAVEIGNORE)));
1616 taskdlg.AddCommandControl(IDCANCEL, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_CANCEL_OPEN)));
1617 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1618 taskdlg.SetDefaultCommandControl(10);
1619 taskdlg.SetMainIcon(TD_WARNING_ICON);
1620 UINT ret = (UINT)taskdlg.DoModal(m_hWnd);
1621 if (ret == 10)
1622 m_pwndRightView->LeaveOnlyMarkedBlocks();
1623 else if (ret == 11)
1624 m_pwndRightView->UseViewFileOfMarked();
1625 else if (ret == 12)
1626 m_pwndRightView->UseViewFileExceptEdited();
1627 else
1628 return false;
1630 else
1632 CString sTitle(MAKEINTRESOURCE(IDS_ASKFORSAVE_MARKEDBLOCKS));
1633 CString msg(MAKEINTRESOURCE(IDS_WARNMARKEDBLOCKS));
1634 msg += _T("\r\n\r\n") + CString(MAKEINTRESOURCE(IDS_MSGBOX_YES)) + _T(": ");
1635 msg += CString(MAKEINTRESOURCE(IDS_MARKEDBLOCKSSAVEINCLUDE));
1636 msg += _T("\r\n\r\n") + CString(MAKEINTRESOURCE(IDS_MSGBOX_NO)) + _T(": ");
1637 msg += CString(MAKEINTRESOURCE(IDS_MARKEDBLOCKSSAVEEXCLUDE));
1638 msg += _T("\r\n\r\n") + CString(MAKEINTRESOURCE(IDS_MSGBOX_CANCEL)) + _T(": ");
1639 msg += CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_CANCEL_OPEN));
1640 int ret = CMessageBox::Show(m_hWnd, msg, sTitle, MB_YESNOCANCEL | MB_ICONQUESTION);
1641 if (ret == IDYES)
1642 m_pwndRightView->LeaveOnlyMarkedBlocks();
1643 else if (ret == IDNO)
1644 m_pwndRightView->UseViewFileOfMarked();
1645 else
1646 return false;
1650 if (!m_Data.m_mergedFile.InUse())
1651 return FileSaveAs(bCheckResolved);
1652 // check if the file has the readonly attribute set
1653 bool bDoesNotExist = false;
1654 DWORD fAttribs = GetFileAttributes(m_Data.m_mergedFile.GetFilename());
1655 if ((fAttribs != INVALID_FILE_ATTRIBUTES)&&(fAttribs & FILE_ATTRIBUTE_READONLY))
1656 return FileSaveAs(bCheckResolved);
1657 if (fAttribs == INVALID_FILE_ATTRIBUTES)
1659 bDoesNotExist = (GetLastError() == ERROR_FILE_NOT_FOUND);
1661 if (bCheckResolved && HasConflictsWontKeep())
1662 return false;
1664 if (((DWORD)CRegDWORD(_T("Software\\TortoiseGitMerge\\Backup"))) != 0)
1666 MoveFileEx(m_Data.m_mergedFile.GetFilename(), m_Data.m_mergedFile.GetFilename() + _T(".bak"), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
1668 if (m_Data.m_bPatchRequired)
1670 m_Patch.PatchPath(m_Data.m_mergedFile.GetFilename());
1672 int saveret = SaveFile(m_Data.m_mergedFile.GetFilename());
1673 if (saveret==0)
1675 // file was saved with 0 lines!
1676 // ask the user if the file should be deleted
1677 bool bDelete = false;
1678 if (m_bUseTaskDialog)
1680 CString msg;
1681 msg.Format(IDS_DELETEWHENEMPTY, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1682 CTaskDialog taskdlg(msg,
1683 CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK2)),
1684 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1686 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
1687 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK3)));
1688 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK4)));
1689 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1690 taskdlg.SetDefaultCommandControl(1);
1691 taskdlg.SetMainIcon(TD_WARNING_ICON);
1692 bDelete = (taskdlg.DoModal(m_hWnd) == 1);
1694 else
1696 CString sTemp;
1697 sTemp.Format(IDS_DELETEWHENEMPTY, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
1698 bDelete = (CMessageBox::ShowCheck(m_hWnd, sTemp, _T("TortoiseGitMerge"), MB_YESNO, _T("DeleteFileWhenEmpty")) == IDYES);
1700 if (bDelete)
1702 m_Patch.RemoveFile(m_Data.m_mergedFile.GetFilename());
1703 DeleteFile(m_Data.m_mergedFile.GetFilename());
1706 else if (saveret < 0)
1708 // error while saving the file
1709 return false;
1712 // if we're in conflict resolve mode (three pane view), check if there are no more conflicts
1713 // and if there aren't, ask to mark the file as resolved
1714 if (IsViewGood(m_pwndBottomView) && !m_bHasConflicts && bCheckResolved)
1716 CString projectRoot;
1717 if (GitAdminDir::HasAdminDir(m_Data.m_mergedFile.GetFilename(), false, &projectRoot))
1719 CString subpath = m_Data.m_mergedFile.GetFilename();
1720 subpath.Replace(_T('\\'), _T('/'));
1721 if (subpath.GetLength() >= projectRoot.GetLength())
1723 if (subpath[projectRoot.GetLength()] == _T('/'))
1724 subpath = subpath.Right(subpath.GetLength() - projectRoot.GetLength() - 1);
1725 else
1726 subpath = subpath.Right(subpath.GetLength() - projectRoot.GetLength());
1729 CAutoRepository repository(projectRoot);
1730 bool hasConflictInIndex = false;
1733 if (!repository)
1734 break;
1736 CAutoIndex index;
1737 if (git_repository_index(index.GetPointer(), repository))
1738 break;
1740 CStringA path = CUnicodeUtils::GetMulti(subpath, CP_UTF8);
1741 const git_index_entry * entry = git_index_get_bypath(index, path, 1);
1742 hasConflictInIndex = entry != nullptr;
1743 } while(0);
1745 if (hasConflictInIndex)
1747 bool bResolve = false;
1748 if (m_bUseTaskDialog)
1750 CString msg;
1751 msg.Format(IDS_MARKASRESOLVED, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1752 CTaskDialog taskdlg(msg,
1753 CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK2)),
1754 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1756 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
1757 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK3)));
1758 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK4)));
1759 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1760 taskdlg.SetDefaultCommandControl(1);
1761 taskdlg.SetMainIcon(TD_WARNING_ICON);
1762 bResolve = (taskdlg.DoModal(m_hWnd) == 1);
1764 else
1766 CString sTemp;
1767 sTemp.Format(IDS_MARKASRESOLVED, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1768 bResolve = (CMessageBox::Show(m_hWnd, sTemp, _T("TortoiseGitMerge"), MB_YESNO | MB_ICONQUESTION) == IDYES);
1770 if (bResolve)
1772 MarkAsResolved();
1778 m_bSaveRequired = false;
1779 m_Data.m_mergedFile.StoreFileAttributes();
1781 if ((bDoesNotExist)&&(DWORD(CRegDWORD(_T("Software\\TortoiseGitMerge\\AutoAdd"), TRUE))))
1783 // call TortoiseProc to add the new file to version control
1784 CString cmd = _T("/command:add /noui /path:\"");
1785 cmd += m_Data.m_mergedFile.GetFilename() + _T("\"");
1786 if(!CAppUtils::RunTortoiseGitProc(cmd))
1787 return false;
1789 return true;
1792 void CMainFrame::OnFileSaveAs()
1794 if (m_bUseTaskDialog)
1796 // ask what file to save as
1797 bool bHaveConflict = (CheckResolved() >= 0);
1798 CTaskDialog taskdlg(
1799 CString(MAKEINTRESOURCE(bHaveConflict ? IDS_ASKFORSAVEAS_MORECONFLICT : IDS_ASKFORSAVEAS_MORE)),
1800 CString(MAKEINTRESOURCE(IDS_ASKFORSAVEAS)),
1801 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1803 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
1804 // default can be last view (target) as was in 1.7 or actual (where is cursor) as is in most text editor
1805 if (IsViewGood(m_pwndLeftView))
1807 taskdlg.AddCommandControl(201, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS))); // left
1808 taskdlg.SetDefaultCommandControl(201);
1810 if (IsViewGood(m_pwndRightView))
1812 taskdlg.AddCommandControl(202, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS))); // right
1813 taskdlg.SetDefaultCommandControl(202);
1815 if (IsViewGood(m_pwndBottomView))
1817 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEBOTTOMAS))); // bottom
1818 taskdlg.SetDefaultCommandControl(203);
1820 if (bHaveConflict)
1822 taskdlg.AddCommandControl(204, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_NEEDRESOLVE))); // resolve
1823 taskdlg.SetDefaultCommandControl(204);
1825 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1826 taskdlg.SetMainIcon(bHaveConflict ? TD_WARNING_ICON : TD_INFORMATION_ICON);
1827 int nCommand = (int)taskdlg.DoModal(m_hWnd);
1828 CString sFileName;
1829 switch (nCommand)
1831 case 201: // left
1832 if (TryGetFileName(sFileName))
1834 // in 2, 3 view display we want to keep removed lines
1835 m_pwndLeftView->SaveFileTo(sFileName, IsViewGood(m_pwndRightView) ? SAVE_REMOVEDLINES : 0);
1837 break;
1838 case 202: // right
1839 if (TryGetFileName(sFileName))
1841 m_pwndRightView->SaveFileTo(sFileName);
1843 break;
1844 case 203: // bottom
1845 FileSaveAs();
1846 break;
1847 case 204: // continue resolving
1848 if (m_pwndBottomView)
1850 m_pwndBottomView->GoToLine(CheckResolved());
1852 break;
1855 else
1857 int nEditableViewCount =
1858 (CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsWritable() ? 1 : 0)
1859 + (CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsWritable() ? 1 : 0)
1860 + (CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsWritable() ? 1 : 0);
1861 bool bLeftIsModified = CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsModified();
1862 bool bRightIsModified = CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsModified();
1863 bool bBottomIsModified = CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsModified();
1864 int nModifiedViewCount =
1865 (bLeftIsModified ? 1 : 0)
1866 + (bRightIsModified ? 1 : 0)
1867 + (bBottomIsModified ? 1 : 0);
1868 if (nEditableViewCount>1)
1870 if (nModifiedViewCount == 1)
1872 if (bLeftIsModified)
1874 CString sFileName;
1875 if (TryGetFileName(sFileName))
1877 m_pwndLeftView->SaveFileTo(sFileName);
1880 else
1881 FileSaveAs();
1883 else
1885 FileSaveAs();
1886 CString sFileName;
1887 if (TryGetFileName(sFileName))
1889 m_pwndLeftView->SaveFileTo(sFileName);
1896 bool CMainFrame::FileSaveAs(bool bCheckResolved /*=true*/)
1898 if (bCheckResolved && HasConflictsWontKeep())
1899 return false;
1901 CString fileName;
1902 if(!TryGetFileName(fileName))
1903 return false;
1905 SaveFile(fileName);
1906 return true;
1909 void CMainFrame::OnUpdateFileSave(CCmdUI *pCmdUI)
1911 BOOL bEnable = FALSE;
1912 if (m_Data.m_mergedFile.InUse())
1914 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1915 bEnable = TRUE;
1916 else if ( (IsViewGood(m_pwndRightView)&&(m_pwndRightView->m_pViewData)) &&
1917 (m_pwndRightView->IsModified() || (m_Data.m_yourFile.GetWindowName().Right(9).Compare(_T(": patched"))==0)) )
1918 bEnable = TRUE;
1919 else if (IsViewGood(m_pwndLeftView)
1920 && (m_pwndLeftView->m_pViewData)
1921 && (m_pwndLeftView->IsModified()))
1922 bEnable = TRUE;
1924 pCmdUI->Enable(bEnable);
1927 void CMainFrame::OnUpdateFileSaveAs(CCmdUI *pCmdUI)
1929 // any file is open we can save it as
1930 BOOL bEnable = FALSE;
1931 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1932 bEnable = TRUE;
1933 else if (IsViewGood(m_pwndRightView)&&(m_pwndRightView->m_pViewData))
1934 bEnable = TRUE;
1935 else if (IsViewGood(m_pwndLeftView)&&(m_pwndLeftView->m_pViewData))
1936 bEnable = TRUE;
1937 pCmdUI->Enable(bEnable);
1940 void CMainFrame::OnUpdateViewOnewaydiff(CCmdUI *pCmdUI)
1942 pCmdUI->SetCheck(!m_bOneWay);
1943 BOOL bEnable = TRUE;
1944 if (IsViewGood(m_pwndBottomView))
1946 bEnable = FALSE;
1948 pCmdUI->Enable(bEnable);
1951 void CMainFrame::OnViewOptions()
1953 CString sTemp;
1954 sTemp.LoadString(IDS_SETTINGSTITLE);
1955 CSettings dlg(sTemp);
1956 dlg.DoModal();
1957 if (dlg.IsReloadNeeded())
1959 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
1960 return;
1961 CDiffColors::GetInstance().LoadRegistry();
1962 LoadViews();
1963 return;
1965 CDiffColors::GetInstance().LoadRegistry();
1966 if (m_pwndBottomView)
1967 m_pwndBottomView->Invalidate();
1968 if (m_pwndLeftView)
1969 m_pwndLeftView->Invalidate();
1970 if (m_pwndRightView)
1971 m_pwndRightView->Invalidate();
1974 void CMainFrame::OnClose()
1976 if (CheckForSave(CHFSR_CLOSE)!=IDCANCEL)
1978 WINDOWPLACEMENT wp;
1980 // before it is destroyed, save the position of the window
1981 wp.length = sizeof wp;
1983 if (GetWindowPlacement(&wp))
1986 if (IsIconic())
1987 // never restore to Iconic state
1988 wp.showCmd = SW_SHOW ;
1990 if ((wp.flags & WPF_RESTORETOMAXIMIZED) != 0)
1991 // if maximized and maybe iconic restore maximized state
1992 wp.showCmd = SW_SHOWMAXIMIZED ;
1994 // and write it
1995 WriteWindowPlacement(&wp);
1997 __super::OnClose();
2001 void CMainFrame::OnActivate(UINT nValue, CWnd* /*pwnd*/, BOOL /*bActivated?*/)
2003 if (nValue != 0) // activated
2005 if (IsIconic())
2007 m_bCheckReload = TRUE;
2009 else
2011 // use a timer to give other messages time to get processed
2012 // first, like e.g. the WM_CLOSE message in case the user
2013 // clicked the close button and that brought the window
2014 // to the front - in that case checking for reload wouldn't
2015 // do any good.
2016 SetTimer(IDT_RELOADCHECKTIMER, 300, NULL);
2021 void CMainFrame::OnViewLinedown()
2023 OnViewLineUpDown(1);
2026 void CMainFrame::OnViewLineup()
2028 OnViewLineUpDown(-1);
2031 void CMainFrame::OnViewLineUpDown(int direction)
2033 if (m_pwndLeftView)
2034 m_pwndLeftView->ScrollToLine(m_pwndLeftView->m_nTopLine+direction);
2035 if (m_pwndRightView)
2036 m_pwndRightView->ScrollToLine(m_pwndRightView->m_nTopLine+direction);
2037 if (m_pwndBottomView)
2038 m_pwndBottomView->ScrollToLine(m_pwndBottomView->m_nTopLine+direction);
2039 m_wndLocatorBar.Invalidate();
2040 m_nMoveMovesToIgnore = MOVESTOIGNORE;
2043 void CMainFrame::OnViewLineleft()
2045 OnViewLineLeftRight(-1);
2048 void CMainFrame::OnViewLineright()
2050 OnViewLineLeftRight(1);
2053 void CMainFrame::OnViewLineLeftRight(int direction)
2055 if (m_pwndLeftView)
2056 m_pwndLeftView->ScrollSide(direction);
2057 if (m_pwndRightView)
2058 m_pwndRightView->ScrollSide(direction);
2059 if (m_pwndBottomView)
2060 m_pwndBottomView->ScrollSide(direction);
2063 void CMainFrame::OnEditUseTheirs()
2065 if (m_pwndBottomView)
2066 m_pwndBottomView->UseTheirTextBlock();
2068 void CMainFrame::OnUpdateEditUsetheirblock(CCmdUI *pCmdUI)
2070 pCmdUI->Enable(m_pwndBottomView && m_pwndBottomView->HasSelection());
2073 void CMainFrame::OnEditUseMine()
2075 if (m_pwndBottomView)
2076 m_pwndBottomView->UseMyTextBlock();
2078 void CMainFrame::OnUpdateEditUsemyblock(CCmdUI *pCmdUI)
2080 OnUpdateEditUsetheirblock(pCmdUI);
2083 void CMainFrame::OnEditUseTheirsThenMine()
2085 if (m_pwndBottomView)
2086 m_pwndBottomView->UseTheirAndYourBlock();
2089 void CMainFrame::OnUpdateEditUsetheirthenmyblock(CCmdUI *pCmdUI)
2091 OnUpdateEditUsetheirblock(pCmdUI);
2094 void CMainFrame::OnEditUseMineThenTheirs()
2096 if (m_pwndBottomView)
2097 m_pwndBottomView->UseYourAndTheirBlock();
2100 void CMainFrame::OnUpdateEditUseminethentheirblock(CCmdUI *pCmdUI)
2102 OnUpdateEditUsetheirblock(pCmdUI);
2105 void CMainFrame::OnEditUseleftblock()
2107 if (m_pwndBottomView->IsWindowVisible())
2108 m_pwndBottomView->UseRightBlock();
2109 else
2110 m_pwndRightView->UseLeftBlock();
2113 void CMainFrame::OnUpdateEditUseleftblock(CCmdUI *pCmdUI)
2115 pCmdUI->Enable(IsViewGood(m_pwndRightView) && m_pwndRightView->IsTarget() && m_pwndRightView->HasSelection());
2118 void CMainFrame::OnUpdateUseBlock(CCmdUI *pCmdUI)
2120 pCmdUI->Enable(TRUE);
2123 void CMainFrame::OnEditUseleftfile()
2125 if (m_pwndBottomView->IsWindowVisible())
2126 m_pwndBottomView->UseRightFile();
2127 else
2128 m_pwndRightView->UseLeftFile();
2131 void CMainFrame::OnUpdateEditUseleftfile(CCmdUI *pCmdUI)
2133 pCmdUI->Enable(IsViewGood(m_pwndRightView) && m_pwndRightView->IsTarget());
2136 void CMainFrame::OnEditUseblockfromleftbeforeright()
2138 if (m_pwndRightView)
2139 m_pwndRightView->UseBothLeftFirst();
2142 void CMainFrame::OnUpdateEditUseblockfromleftbeforeright(CCmdUI *pCmdUI)
2144 OnUpdateEditUseleftblock(pCmdUI);
2147 void CMainFrame::OnEditUseblockfromrightbeforeleft()
2149 if (m_pwndRightView)
2150 m_pwndRightView->UseBothRightFirst();
2153 void CMainFrame::OnUpdateEditUseblockfromrightbeforeleft(CCmdUI *pCmdUI)
2155 OnUpdateEditUseleftblock(pCmdUI);
2158 void CMainFrame::OnFileReload()
2160 if (CheckForSave(CHFSR_RELOAD)==IDCANCEL)
2161 return;
2162 CDiffColors::GetInstance().LoadRegistry();
2163 LoadViews(-1);
2166 void CMainFrame::ActivateFrame(int nCmdShow)
2168 // nCmdShow is the normal show mode this frame should be in
2169 // translate default nCmdShow (-1)
2170 if (nCmdShow == -1)
2172 if (!IsWindowVisible())
2173 nCmdShow = SW_SHOWNORMAL;
2174 else if (IsIconic())
2175 nCmdShow = SW_RESTORE;
2178 // bring to top before showing
2179 BringToTop(nCmdShow);
2181 if (nCmdShow != -1)
2183 // show the window as specified
2184 WINDOWPLACEMENT wp;
2186 if ( !ReadWindowPlacement(&wp) )
2188 ShowWindow(nCmdShow);
2190 else
2192 if ( nCmdShow != SW_SHOWNORMAL )
2193 wp.showCmd = nCmdShow;
2195 SetWindowPlacement(&wp);
2198 // and finally, bring to top after showing
2199 BringToTop(nCmdShow);
2203 BOOL CMainFrame::ReadWindowPlacement(WINDOWPLACEMENT * pwp)
2205 CRegString placement = CRegString(_T("Software\\TortoiseGitMerge\\WindowPos"));
2206 CString sPlacement = placement;
2207 if (sPlacement.IsEmpty())
2208 return FALSE;
2209 int nRead = _stscanf_s(sPlacement, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
2210 &pwp->flags, &pwp->showCmd,
2211 &pwp->ptMinPosition.x, &pwp->ptMinPosition.y,
2212 &pwp->ptMaxPosition.x, &pwp->ptMaxPosition.y,
2213 &pwp->rcNormalPosition.left, &pwp->rcNormalPosition.top,
2214 &pwp->rcNormalPosition.right, &pwp->rcNormalPosition.bottom);
2215 if ( nRead != 10 )
2216 return FALSE;
2217 pwp->length = sizeof(WINDOWPLACEMENT);
2219 return TRUE;
2222 void CMainFrame::WriteWindowPlacement(WINDOWPLACEMENT * pwp)
2224 CRegString placement(L"Software\\TortoiseGitMerge\\WindowPos");
2225 TCHAR szBuffer[_countof("-32767")*8 + sizeof("65535")*2];
2227 _stprintf_s(szBuffer, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
2228 pwp->flags, pwp->showCmd,
2229 pwp->ptMinPosition.x, pwp->ptMinPosition.y,
2230 pwp->ptMaxPosition.x, pwp->ptMaxPosition.y,
2231 pwp->rcNormalPosition.left, pwp->rcNormalPosition.top,
2232 pwp->rcNormalPosition.right, pwp->rcNormalPosition.bottom);
2233 placement = szBuffer;
2236 void CMainFrame::OnUpdateMergeMarkasresolved(CCmdUI *pCmdUI)
2238 if (pCmdUI == NULL)
2239 return;
2240 BOOL bEnable = FALSE;
2241 if ((!m_bReadOnly)&&(m_Data.m_mergedFile.InUse()))
2243 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
2245 bEnable = TRUE;
2248 pCmdUI->Enable(bEnable);
2251 void CMainFrame::OnMergeMarkasresolved()
2253 if(HasConflictsWontKeep())
2254 return;
2256 // now check if the file has already been saved and if not, save it.
2257 if (m_Data.m_mergedFile.InUse())
2259 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
2261 FileSave(false);
2262 m_bSaveRequired = false;
2265 MarkAsResolved();
2268 BOOL CMainFrame::MarkAsResolved()
2270 if (m_bReadOnly)
2271 return FALSE;
2272 if (!IsViewGood(m_pwndBottomView))
2273 return FALSE;
2275 CString cmd = _T("/command:resolve /path:\"");
2276 cmd += m_Data.m_mergedFile.GetFilename();
2277 cmd += _T("\" /closeonend:1 /noquestion /skipcheck /silent");
2278 if (resolveMsgWnd)
2280 CString s;
2281 s.Format(L" /resolvemsghwnd:%I64d /resolvemsgwparam:%I64d /resolvemsglparam:%I64d", (__int64)resolveMsgWnd, (__int64)resolveMsgWParam, (__int64)resolveMsgLParam);
2282 cmd += s;
2284 if(!CAppUtils::RunTortoiseGitProc(cmd))
2285 return FALSE;
2286 m_bSaveRequired = false;
2287 return TRUE;
2290 void CMainFrame::OnUpdateMergeNextconflict(CCmdUI *pCmdUI)
2292 BOOL bShow = FALSE;
2293 if (HasNextConflict(m_pwndBottomView))
2294 bShow = TRUE;
2295 else if (HasNextConflict(m_pwndRightView))
2296 bShow = TRUE;
2297 else if (HasNextConflict(m_pwndLeftView))
2298 bShow = TRUE;
2299 pCmdUI->Enable(bShow);
2302 bool CMainFrame::HasNextConflict(CBaseView* view)
2304 if (view == 0)
2305 return false;
2306 if (!view->IsTarget())
2307 return false;
2308 return view->HasNextConflict();
2311 void CMainFrame::OnUpdateMergePreviousconflict(CCmdUI *pCmdUI)
2313 BOOL bShow = FALSE;
2314 if (HasPrevConflict(m_pwndBottomView))
2315 bShow = TRUE;
2316 else if (HasPrevConflict(m_pwndRightView))
2317 bShow = TRUE;
2318 else if (HasPrevConflict(m_pwndLeftView))
2319 bShow = TRUE;
2320 pCmdUI->Enable(bShow);
2323 bool CMainFrame::HasPrevConflict(CBaseView* view)
2325 if (view == 0)
2326 return false;
2327 if (!view->IsTarget())
2328 return false;
2329 return view->HasPrevConflict();
2332 void CMainFrame::OnUpdateNavigateNextdifference(CCmdUI *pCmdUI)
2334 CBaseView* baseView = GetActiveBaseView();
2335 BOOL bShow = FALSE;
2336 if (baseView != 0)
2337 bShow = baseView->HasNextDiff();
2338 pCmdUI->Enable(bShow);
2341 void CMainFrame::OnUpdateNavigatePreviousdifference(CCmdUI *pCmdUI)
2343 CBaseView* baseView = GetActiveBaseView();
2344 BOOL bShow = FALSE;
2345 if (baseView != 0)
2346 bShow = baseView->HasPrevDiff();
2347 pCmdUI->Enable(bShow);
2350 void CMainFrame::OnUpdateNavigateNextinlinediff(CCmdUI *pCmdUI)
2352 BOOL bShow = FALSE;
2353 if (HasNextInlineDiff(m_pwndBottomView))
2354 bShow = TRUE;
2355 else if (HasNextInlineDiff(m_pwndRightView))
2356 bShow = TRUE;
2357 else if (HasNextInlineDiff(m_pwndLeftView))
2358 bShow = TRUE;
2359 pCmdUI->Enable(bShow);
2362 bool CMainFrame::HasNextInlineDiff(CBaseView* view)
2364 if (view == 0)
2365 return false;
2366 if (!view->IsTarget())
2367 return false;
2368 return view->HasNextInlineDiff();
2371 void CMainFrame::OnUpdateNavigatePrevinlinediff(CCmdUI *pCmdUI)
2373 BOOL bShow = FALSE;
2374 if (HasPrevInlineDiff(m_pwndBottomView))
2375 bShow = TRUE;
2376 else if (HasPrevInlineDiff(m_pwndRightView))
2377 bShow = TRUE;
2378 else if (HasPrevInlineDiff(m_pwndLeftView))
2379 bShow = TRUE;
2380 pCmdUI->Enable(bShow);
2383 bool CMainFrame::HasPrevInlineDiff(CBaseView* view)
2385 if (view == 0)
2386 return false;
2387 if (!view->IsTarget())
2388 return false;
2389 return view->HasPrevInlineDiff();
2392 void CMainFrame::OnMoving(UINT fwSide, LPRECT pRect)
2394 // if the pathfilelist dialog is attached to the mainframe,
2395 // move it along with the mainframe
2396 if (::IsWindow(m_dlgFilePatches.m_hWnd))
2398 RECT patchrect;
2399 m_dlgFilePatches.GetWindowRect(&patchrect);
2400 if (::IsWindow(m_hWnd))
2402 RECT thisrect;
2403 GetWindowRect(&thisrect);
2404 if (patchrect.right == thisrect.left)
2406 m_dlgFilePatches.SetWindowPos(NULL, patchrect.left - (thisrect.left - pRect->left), patchrect.top - (thisrect.top - pRect->top),
2407 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
2411 __super::OnMoving(fwSide, pRect);
2414 void CMainFrame::OnUpdateEditCopy(CCmdUI *pCmdUI)
2416 BOOL bShow = FALSE;
2417 if ((m_pwndBottomView)&&(m_pwndBottomView->HasSelection()))
2418 bShow = TRUE;
2419 else if ((m_pwndRightView)&&(m_pwndRightView->HasSelection()))
2420 bShow = TRUE;
2421 else if ((m_pwndLeftView)&&(m_pwndLeftView->HasSelection()))
2422 bShow = TRUE;
2423 pCmdUI->Enable(bShow);
2426 void CMainFrame::OnUpdateEditPaste(CCmdUI *pCmdUI)
2428 BOOL bWritable = FALSE;
2429 if ((m_pwndBottomView)&&(m_pwndBottomView->IsWritable()))
2430 bWritable = TRUE;
2431 else if ((m_pwndRightView)&&(m_pwndRightView->IsWritable()))
2432 bWritable = TRUE;
2433 else if ((m_pwndLeftView)&&(m_pwndLeftView->IsWritable()))
2434 bWritable = TRUE;
2435 pCmdUI->Enable(bWritable && ::IsClipboardFormatAvailable(CF_TEXT));
2438 void CMainFrame::OnViewSwitchleft()
2440 if (CheckForSave(CHFSR_SWITCH)!=IDCANCEL)
2442 CWorkingFile file = m_Data.m_baseFile;
2443 m_Data.m_baseFile = m_Data.m_yourFile;
2444 m_Data.m_yourFile = file;
2445 if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_yourFile.GetFilename())==0)
2447 m_Data.m_mergedFile = m_Data.m_baseFile;
2449 else if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_baseFile.GetFilename())==0)
2451 m_Data.m_mergedFile = m_Data.m_yourFile;
2453 LoadViews();
2457 void CMainFrame::OnUpdateViewSwitchleft(CCmdUI *pCmdUI)
2459 BOOL bEnable = !IsViewGood(m_pwndBottomView);
2460 pCmdUI->Enable(bEnable);
2463 void CMainFrame::OnUpdateViewShowfilelist(CCmdUI *pCmdUI)
2465 BOOL bEnable = m_dlgFilePatches.HasFiles();
2466 pCmdUI->Enable(bEnable);
2467 pCmdUI->SetCheck(m_dlgFilePatches.IsWindowVisible());
2470 void CMainFrame::OnViewShowfilelist()
2472 m_dlgFilePatches.ShowWindow(m_dlgFilePatches.IsWindowVisible() ? SW_HIDE : SW_SHOW);
2475 void CMainFrame::OnEditUndo()
2477 if (CUndo::GetInstance().CanUndo())
2479 CUndo::GetInstance().Undo(m_pwndLeftView, m_pwndRightView, m_pwndBottomView);
2483 void CMainFrame::OnUpdateEditUndo(CCmdUI *pCmdUI)
2485 pCmdUI->Enable(CUndo::GetInstance().CanUndo());
2488 void CMainFrame::OnEditEnable()
2490 CBaseView * pView = GetActiveBaseView();
2491 if (pView && pView->IsReadonlyChangable())
2493 bool isReadOnly = pView->IsReadonly();
2494 pView->SetReadonly(!isReadOnly);
2498 void CMainFrame::OnUpdateEditEnable(CCmdUI *pCmdUI)
2500 CBaseView * pView = GetActiveBaseView();
2501 if (pView)
2503 pCmdUI->Enable(pView->IsReadonlyChangable() || !pView->IsReadonly());
2504 pCmdUI->SetCheck(!pView->IsReadonly());
2506 else
2508 pCmdUI->Enable(FALSE);
2512 void CMainFrame::OnIndicatorLeftview()
2514 if (m_bUseRibbons)
2515 return;
2516 if (IsViewGood(m_pwndLeftView))
2518 m_pwndLeftView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_LEFTVIEW);
2522 void CMainFrame::OnIndicatorRightview()
2524 if (m_bUseRibbons)
2525 return;
2526 if (IsViewGood(m_pwndRightView))
2528 m_pwndRightView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_RIGHTVIEW);
2532 void CMainFrame::OnIndicatorBottomview()
2534 if (m_bUseRibbons)
2535 return;
2536 if (IsViewGood(m_pwndBottomView))
2538 m_pwndBottomView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_BOTTOMVIEW);
2542 int CMainFrame::CheckForReload()
2544 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
2545 if (bLock)
2547 return IDNO;
2549 bLock = true;
2550 bool bSourceChanged =
2551 m_Data.m_baseFile.HasSourceFileChanged()
2552 || m_Data.m_yourFile.HasSourceFileChanged()
2553 || m_Data.m_theirFile.HasSourceFileChanged()
2554 /*|| m_Data.m_mergedFile.HasSourceFileChanged()*/;
2555 if (!bSourceChanged)
2557 bLock = false;
2558 return IDNO;
2561 UINT ret = IDNO;
2562 if (m_bUseTaskDialog)
2564 CString msg = HasUnsavedEdits() ? CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDELOOSECHANGES)) : CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE));
2565 CTaskDialog taskdlg(msg,
2566 CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE_TASK2)),
2567 L"TortoiseGitMerge",
2569 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
2570 CString sTask3;
2571 if (HasUnsavedEdits())
2572 sTask3.LoadString(IDS_WARNMODIFIEDOUTSIDE_TASK3);
2573 else
2574 sTask3.LoadString(IDS_WARNMODIFIEDOUTSIDE_TASK4);
2575 taskdlg.AddCommandControl(IDYES, sTask3);
2576 taskdlg.AddCommandControl(IDNO, CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE_TASK5)));
2577 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2578 taskdlg.SetDefaultCommandControl(IDYES);
2579 taskdlg.SetMainIcon(TD_WARNING_ICON);
2580 ret = (UINT)taskdlg.DoModal(m_hWnd);
2582 else
2584 int idsMessage = HasUnsavedEdits() ? IDS_WARNMODIFIEDOUTSIDELOOSECHANGES : IDS_WARNMODIFIEDOUTSIDE;
2585 ret = CMessageBox::Show(m_hWnd, idsMessage, IDS_APPNAME, MB_YESNO | MB_ICONQUESTION);
2588 if (ret == IDYES)
2590 CDiffColors::GetInstance().LoadRegistry();
2591 LoadViews(-1);
2593 else
2595 if (IsViewGood(m_pwndBottomView)) // three pane view
2597 /*if (m_Data.m_sourceFile.HasSourceFileChanged())
2598 m_pwndBottomView->SetModified();
2599 if (m_Data.m_mergedFile.HasSourceFileChanged())
2600 m_pwndBottomView->SetModified();//*/
2601 if (m_Data.m_yourFile.HasSourceFileChanged())
2602 m_pwndRightView->SetModified();
2603 if (m_Data.m_theirFile.HasSourceFileChanged())
2604 m_pwndLeftView->SetModified();
2606 else if (IsViewGood(m_pwndRightView)) // two pane view
2608 if (m_Data.m_baseFile.HasSourceFileChanged())
2609 m_pwndLeftView->SetModified();
2610 if (m_Data.m_yourFile.HasSourceFileChanged())
2611 m_pwndRightView->SetModified();
2613 else
2615 if (m_Data.m_yourFile.HasSourceFileChanged())
2616 m_pwndLeftView->SetModified();
2619 // no reload just store updated file time
2620 m_Data.m_baseFile.StoreFileAttributes();
2621 m_Data.m_theirFile.StoreFileAttributes();
2622 m_Data.m_yourFile.StoreFileAttributes();
2623 //m_Data.m_mergedFile.StoreFileAttributes();
2625 bLock = false;
2626 return ret;
2629 int CMainFrame::CheckForSave(ECheckForSaveReason eReason)
2631 int idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2632 int idNoSave = IDS_ASKFORSAVE_TASK7;
2633 int idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2634 switch (eReason)
2636 case CHFSR_CLOSE:
2637 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2638 idNoSave = IDS_ASKFORSAVE_TASK4;
2639 idCancelAction = IDS_ASKFORSAVE_TASK5;
2640 break;
2641 case CHFSR_SWITCH:
2642 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2643 //idNoSave = IDS_ASKFORSAVE_TASK7;
2644 idCancelAction = IDS_ASKFORSAVE_TASK8;
2645 break;
2646 case CHFSR_RELOAD:
2647 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2648 //idNoSave = IDS_ASKFORSAVE_TASK7;
2649 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2650 break;
2651 case CHFSR_OPTIONS:
2652 idTitle = IDS_WARNMODIFIEDLOOSECHANGESOPTIONS;
2653 //idNoSave = IDS_ASKFORSAVE_TASK7;
2654 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPTIONS;
2655 break;
2656 case CHFSR_OPEN:
2657 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2658 idNoSave = IDS_ASKFORSAVE_NOSAVE_OPEN;
2659 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2660 break;
2663 CString sTitle(MAKEINTRESOURCE(idTitle));
2664 CString sSubTitle(MAKEINTRESOURCE(IDS_ASKFORSAVE_TASK2));
2665 CString sNoSave(MAKEINTRESOURCE(idNoSave));
2666 CString sCancelAction(MAKEINTRESOURCE(idCancelAction));
2667 CString sAppName(MAKEINTRESOURCE(IDS_APPNAME));
2669 // TODO simplify logic, reduce code duplication
2670 if (CBaseView::IsViewGood(m_pwndBottomView))
2672 // three-way diff - by design only bottom can be changed
2673 // use 1.7 way to do that
2675 else if (CBaseView::IsViewGood(m_pwndRightView))
2677 // two-way diff -
2678 // 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
2679 if (HasUnsavedEdits(m_pwndLeftView))
2681 // both views
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 sTaskTemp;
2691 if (m_pwndLeftView->m_pWorkingFile->InUse() && !m_pwndLeftView->m_pWorkingFile->IsReadonly())
2692 sTaskTemp.Format(IDS_ASKFORSAVE_SAVELEFT, (LPCTSTR)m_pwndLeftView->m_pWorkingFile->GetFilename());
2693 else
2694 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS));
2695 taskdlg.AddCommandControl(201, sTaskTemp); // left
2696 taskdlg.SetDefaultCommandControl(201);
2697 if (HasUnsavedEdits(m_pwndRightView))
2699 if (m_pwndRightView->m_pWorkingFile->InUse() && !m_pwndRightView->m_pWorkingFile->IsReadonly())
2700 sTaskTemp.Format(IDS_ASKFORSAVE_SAVERIGHT, (LPCTSTR)m_pwndRightView->m_pWorkingFile->GetFilename());
2701 else
2702 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS));
2703 taskdlg.AddCommandControl(202, sTaskTemp); // right
2704 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEALL2))); // both
2705 taskdlg.SetDefaultCommandControl(203);
2707 taskdlg.AddCommandControl(IDNO, sNoSave); // none
2708 taskdlg.AddCommandControl(IDCANCEL, sCancelAction); // cancel
2709 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2710 taskdlg.SetMainIcon(TD_WARNING_ICON);
2711 ret = (UINT)taskdlg.DoModal(m_hWnd);
2712 switch (ret)
2714 case 201: // left
2715 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
2716 break;
2717 case 203: // both
2718 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
2719 case 202: // right
2720 m_pwndRightView->SaveFile();
2721 break;
2723 if (ret != IDCANCEL && (eReason == CHFSR_CLOSE || eReason == CHFSR_OPEN))
2724 DeleteBaseTheirsMineOnClose();
2725 return ret;
2727 else
2729 // show separate questions
2730 // first show question for left view
2731 ret = MessageBox(sTitle, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
2732 if (ret == IDCANCEL)
2734 return IDCANCEL;
2736 if (ret == IDYES)
2738 if (m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES)<0)
2740 return IDCANCEL;
2743 // right file is handled old way
2744 if (eReason == CHFSR_CLOSE || eReason == CHFSR_OPEN)
2745 DeleteBaseTheirsMineOnClose();
2748 else
2750 // only secondary (left) view
2752 // only right view - 1.7 implementation is used
2754 else if (CBaseView::IsViewGood(m_pwndLeftView))
2756 // only one view - only one to save
2757 // 1.7 FileSave don't support this mode
2758 if (HasUnsavedEdits(m_pwndLeftView))
2760 UINT ret = IDNO;
2761 if (m_bUseTaskDialog)
2763 CTaskDialog taskdlg(sTitle,
2764 sSubTitle,
2765 sAppName,
2767 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
2768 CString sTask3;
2769 if (m_Data.m_mergedFile.InUse())
2770 sTask3.Format(IDS_ASKFORSAVE_TASK3, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
2771 else
2772 sTask3.LoadString(IDS_ASKFORSAVE_TASK6);
2773 taskdlg.AddCommandControl(IDYES, sTask3);
2774 taskdlg.AddCommandControl(IDNO, sNoSave);
2775 taskdlg.AddCommandControl(IDCANCEL, sCancelAction);
2776 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2777 taskdlg.SetDefaultCommandControl(IDYES);
2778 taskdlg.SetMainIcon(TD_WARNING_ICON);
2779 ret = (UINT)taskdlg.DoModal(m_hWnd);
2781 else
2783 ret = MessageBox(sTitle, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
2786 if (ret == IDYES)
2788 if (m_pwndLeftView->SaveFile()<0)
2789 return IDCANCEL;
2792 if (eReason == CHFSR_CLOSE || eReason == CHFSR_OPEN)
2793 DeleteBaseTheirsMineOnClose();
2794 return IDNO;
2796 else
2798 if (eReason == CHFSR_CLOSE || eReason == CHFSR_OPEN)
2799 DeleteBaseTheirsMineOnClose();
2800 return IDNO; // nothing to save
2803 // 1.7 implementation
2804 UINT ret = IDNO;
2805 if (HasUnsavedEdits())
2807 if (m_bUseTaskDialog)
2809 CTaskDialog taskdlg(sTitle,
2810 sSubTitle,
2811 sAppName,
2813 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
2814 CString sTask3;
2815 if (m_Data.m_mergedFile.InUse())
2816 sTask3.Format(IDS_ASKFORSAVE_TASK3, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
2817 else
2818 sTask3.LoadString(IDS_ASKFORSAVE_TASK6);
2819 taskdlg.AddCommandControl(IDYES, sTask3);
2820 taskdlg.AddCommandControl(IDNO, sNoSave);
2821 taskdlg.AddCommandControl(IDCANCEL, sCancelAction);
2822 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2823 taskdlg.SetDefaultCommandControl(IDYES);
2824 taskdlg.SetMainIcon(TD_WARNING_ICON);
2825 ret = (UINT)taskdlg.DoModal(m_hWnd);
2827 else
2829 ret = MessageBox(sTitle, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
2832 if (ret == IDYES)
2834 if (!FileSave())
2835 ret = IDCANCEL;
2839 if (ret != IDCANCEL && (eReason == CHFSR_CLOSE || eReason == CHFSR_OPEN))
2840 DeleteBaseTheirsMineOnClose();
2842 return ret;
2845 void CMainFrame::DeleteBaseTheirsMineOnClose()
2847 if (!m_bDeleteBaseTheirsMineOnClose)
2848 return;
2850 m_bDeleteBaseTheirsMineOnClose = false;
2852 DeleteFile(m_Data.m_baseFile.GetFilename());
2853 DeleteFile(m_Data.m_theirFile.GetFilename());
2854 DeleteFile(m_Data.m_yourFile.GetFilename());
2857 bool CMainFrame::HasUnsavedEdits() const
2859 return HasUnsavedEdits(m_pwndBottomView) || HasUnsavedEdits(m_pwndRightView) || m_bSaveRequired;
2862 bool CMainFrame::HasUnsavedEdits(const CBaseView* view)
2864 if (!CBaseView::IsViewGood(view))
2865 return false;
2866 return view->IsModified();
2869 bool CMainFrame::HasMarkedBlocks() const
2871 return CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->HasMarkedBlocks();
2874 bool CMainFrame::IsViewGood(const CBaseView* view)
2876 return CBaseView::IsViewGood(view);
2879 void CMainFrame::OnViewInlinediffword()
2881 m_bInlineWordDiff = !m_bInlineWordDiff;
2882 if (m_pwndLeftView)
2884 m_pwndLeftView->SetInlineWordDiff(m_bInlineWordDiff);
2885 m_pwndLeftView->BuildAllScreen2ViewVector();
2886 m_pwndLeftView->DocumentUpdated();
2888 if (m_pwndRightView)
2890 m_pwndRightView->SetInlineWordDiff(m_bInlineWordDiff);
2891 m_pwndRightView->BuildAllScreen2ViewVector();
2892 m_pwndRightView->DocumentUpdated();
2894 if (m_pwndBottomView)
2896 m_pwndBottomView->SetInlineWordDiff(m_bInlineWordDiff);
2897 m_pwndBottomView->BuildAllScreen2ViewVector();
2898 m_pwndBottomView->DocumentUpdated();
2900 m_wndLineDiffBar.DocumentUpdated();
2903 void CMainFrame::OnUpdateViewInlinediffword(CCmdUI *pCmdUI)
2905 pCmdUI->Enable(m_bInlineDiff && IsViewGood(m_pwndLeftView) && IsViewGood(m_pwndRightView));
2906 pCmdUI->SetCheck(m_bInlineWordDiff);
2909 void CMainFrame::OnViewInlinediff()
2911 m_bInlineDiff = !m_bInlineDiff;
2912 if (m_pwndLeftView)
2914 m_pwndLeftView->SetInlineDiff(m_bInlineDiff);
2915 m_pwndLeftView->BuildAllScreen2ViewVector();
2916 m_pwndLeftView->DocumentUpdated();
2918 if (m_pwndRightView)
2920 m_pwndRightView->SetInlineDiff(m_bInlineDiff);
2921 m_pwndRightView->BuildAllScreen2ViewVector();
2922 m_pwndRightView->DocumentUpdated();
2924 if (m_pwndBottomView)
2926 m_pwndBottomView->SetInlineDiff(m_bInlineDiff);
2927 m_pwndBottomView->BuildAllScreen2ViewVector();
2928 m_pwndBottomView->DocumentUpdated();
2930 m_wndLineDiffBar.DocumentUpdated();
2933 void CMainFrame::OnUpdateViewInlinediff(CCmdUI *pCmdUI)
2935 pCmdUI->Enable(IsViewGood(m_pwndLeftView) && IsViewGood(m_pwndRightView));
2936 pCmdUI->SetCheck(m_bInlineDiff);
2939 void CMainFrame::OnUpdateEditCreateunifieddifffile(CCmdUI *pCmdUI)
2941 // "create unified diff file" is only available if two files
2942 // are diffed, not three.
2943 bool bEnabled = true;
2944 if (!IsViewGood(m_pwndLeftView))
2945 bEnabled = false;
2946 else if (!IsViewGood(m_pwndRightView))
2947 bEnabled = false;
2948 else if (IsViewGood(m_pwndBottomView)) //no negation here
2949 bEnabled = false;
2950 pCmdUI->Enable(bEnabled);
2953 void CMainFrame::OnEditCreateunifieddifffile()
2955 CString origFile, modifiedFile;
2956 // the original file is the one on the left
2957 if (m_pwndLeftView)
2958 origFile = m_pwndLeftView->m_sFullFilePath;
2959 if (m_pwndRightView)
2960 modifiedFile = m_pwndRightView->m_sFullFilePath;
2961 if (origFile.IsEmpty() || modifiedFile.IsEmpty())
2962 return;
2964 CString outputFile;
2965 if(!TryGetFileName(outputFile))
2966 return;
2968 CRegStdDWORD regContextLines(L"Software\\TortoiseGitMerge\\ContextLines", (DWORD)-1);
2969 CAppUtils::CreateUnifiedDiff(origFile, modifiedFile, outputFile, regContextLines, true);
2972 void CMainFrame::OnUpdateViewLinediffbar(CCmdUI *pCmdUI)
2974 pCmdUI->SetCheck(m_bLineDiff);
2975 pCmdUI->Enable();
2978 void CMainFrame::OnViewLinediffbar()
2980 m_bLineDiff = !m_bLineDiff;
2981 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2982 m_wndLineDiffBar.DocumentUpdated();
2983 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2984 m_wndLocatorBar.DocumentUpdated();
2987 void CMainFrame::OnUpdateViewLocatorbar(CCmdUI *pCmdUI)
2989 pCmdUI->SetCheck(m_bLocatorBar);
2990 pCmdUI->Enable();
2993 void CMainFrame::OnViewLocatorbar()
2995 m_bLocatorBar = !m_bLocatorBar;
2996 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2997 m_wndLocatorBar.DocumentUpdated();
2998 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2999 m_wndLineDiffBar.DocumentUpdated();
3002 void CMainFrame::OnViewComparewhitespaces()
3004 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3005 return;
3006 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
3007 regIgnoreWS = 0;
3008 LoadViews(-1);
3011 void CMainFrame::OnUpdateViewComparewhitespaces(CCmdUI *pCmdUI)
3013 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
3014 DWORD dwIgnoreWS = regIgnoreWS;
3015 pCmdUI->SetCheck(dwIgnoreWS == 0);
3018 void CMainFrame::OnViewIgnorewhitespacechanges()
3020 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3021 return;
3022 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
3023 regIgnoreWS = 2;
3024 LoadViews(-1);
3027 void CMainFrame::OnUpdateViewIgnorewhitespacechanges(CCmdUI *pCmdUI)
3029 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
3030 DWORD dwIgnoreWS = regIgnoreWS;
3031 pCmdUI->SetCheck(dwIgnoreWS == 2);
3034 void CMainFrame::OnViewIgnoreallwhitespacechanges()
3036 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3037 return;
3038 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
3039 regIgnoreWS = 1;
3040 LoadViews(-1);
3043 void CMainFrame::OnUpdateViewIgnoreallwhitespacechanges(CCmdUI *pCmdUI)
3045 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
3046 DWORD dwIgnoreWS = regIgnoreWS;
3047 pCmdUI->SetCheck(dwIgnoreWS == 1);
3050 void CMainFrame::OnViewMovedBlocks()
3052 m_bViewMovedBlocks = !(DWORD)m_regViewModedBlocks;
3053 m_regViewModedBlocks = m_bViewMovedBlocks;
3054 LoadViews(-1);
3057 void CMainFrame::OnUpdateViewMovedBlocks(CCmdUI *pCmdUI)
3059 pCmdUI->SetCheck(m_bViewMovedBlocks);
3060 BOOL bEnable = TRUE;
3061 if (IsViewGood(m_pwndBottomView))
3063 bEnable = FALSE;
3065 pCmdUI->Enable(bEnable);
3068 bool CMainFrame::HasConflictsWontKeep()
3070 const int nConflictLine = CheckResolved();
3071 if (nConflictLine < 0)
3072 return false;
3073 if (m_pwndBottomView == nullptr)
3074 return false;
3076 CString sTemp;
3077 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
3078 bool bSave = false;
3079 if (m_bUseTaskDialog)
3081 CTaskDialog taskdlg(sTemp,
3082 CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK2)),
3083 L"TortoiseGitMerge",
3085 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
3086 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK3)));
3087 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK4)));
3088 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
3089 taskdlg.SetDefaultCommandControl(2);
3090 taskdlg.SetMainIcon(TD_ERROR_ICON);
3091 bSave = (taskdlg.DoModal(m_hWnd) == 1);
3093 else
3095 bSave = (MessageBox(sTemp, 0, MB_ICONERROR | MB_YESNO)==IDYES);
3098 if (bSave)
3099 return false;
3101 m_pwndBottomView->GoToLine(nConflictLine);
3102 return true;
3105 bool CMainFrame::TryGetFileName(CString& result)
3107 return CCommonAppUtils::FileOpenSave(result, NULL, IDS_SAVEASTITLE, IDS_COMMONFILEFILTER, false, m_hWnd);
3110 CBaseView* CMainFrame::GetActiveBaseView() const
3112 CView* activeView = GetActiveView();
3113 CBaseView* activeBase = dynamic_cast<CBaseView*>( activeView );
3114 return activeBase;
3117 void CMainFrame::SetWindowTitle()
3119 // try to find a suitable window title
3120 CString sYour = m_Data.m_yourFile.GetDescriptiveName();
3121 if (sYour.Find(_T(" - "))>=0)
3122 sYour = sYour.Left(sYour.Find(_T(" - ")));
3123 if (sYour.Find(_T(" : "))>=0)
3124 sYour = sYour.Left(sYour.Find(_T(" : ")));
3125 CString sTheir = m_Data.m_theirFile.GetDescriptiveName();
3126 if (sTheir.IsEmpty())
3127 sTheir = m_Data.m_baseFile.GetDescriptiveName();
3128 if (sTheir.Find(_T(" - "))>=0)
3129 sTheir = sTheir.Left(sTheir.Find(_T(" - ")));
3130 if (sTheir.Find(_T(" : "))>=0)
3131 sTheir = sTheir.Left(sTheir.Find(_T(" : ")));
3133 if (!sYour.IsEmpty() && !sTheir.IsEmpty())
3135 if (sYour.CompareNoCase(sTheir)==0)
3136 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
3137 else if ((sYour.GetLength() < 10) &&
3138 (sTheir.GetLength() < 10))
3139 SetWindowText(sYour + _T(" - ") + sTheir + _T(" - TortoiseGitMerge"));
3140 else
3142 // we have two very long descriptive texts here, which
3143 // means we have to find a way to use them as a window
3144 // title in a shorter way.
3145 // for simplicity, we just use the one from "yourfile"
3146 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
3149 else if (!sYour.IsEmpty())
3150 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
3151 else if (!sTheir.IsEmpty())
3152 SetWindowText(sTheir + _T(" - TortoiseGitMerge"));
3153 else
3154 SetWindowText(L"TortoiseGitMerge");
3157 void CMainFrame::OnTimer(UINT_PTR nIDEvent)
3159 switch (nIDEvent)
3161 case IDT_RELOADCHECKTIMER:
3162 KillTimer(nIDEvent);
3163 CheckForReload();
3164 break;
3167 __super::OnTimer(nIDEvent);
3170 void CMainFrame::LoadIgnoreCommentData()
3172 static bool bLoaded = false;
3173 if (bLoaded)
3174 return;
3175 CString sPath = CPathUtils::GetAppDataDirectory() + L"ignorecomments.txt";
3176 if (!PathFileExists(sPath))
3178 // ignore comments file does not exist (yet), so create a default one
3179 HRSRC hRes = FindResource(NULL, MAKEINTRESOURCE(IDR_IGNORECOMMENTSTXT), L"config");
3180 if (hRes)
3182 HGLOBAL hResourceLoaded = LoadResource(NULL, hRes);
3183 if (hResourceLoaded)
3185 char * lpResLock = (char *) LockResource(hResourceLoaded);
3186 DWORD dwSizeRes = SizeofResource(NULL, hRes);
3187 if (lpResLock)
3189 HANDLE hFile = CreateFile(sPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3190 if (hFile != INVALID_HANDLE_VALUE)
3192 DWORD dwWritten = 0;
3193 WriteFile(hFile, lpResLock, dwSizeRes, &dwWritten, NULL);
3194 CloseHandle(hFile);
3203 CStdioFile file;
3204 if (file.Open(sPath, CFile::modeRead))
3206 CString sLine;
3207 while (file.ReadString(sLine))
3209 int eqpos = sLine.Find('=');
3210 if (eqpos >= 0)
3212 CString sExts = sLine.Left(eqpos);
3213 CString sComments = sLine.Mid(eqpos+1);
3215 int pos = sComments.Find(',');
3216 CString sLineStart = sComments.Left(pos);
3217 pos = sComments.Find(',', pos);
3218 int pos2 = sComments.Find(',', pos+1);
3219 CString sBlockStart = sComments.Mid(pos+1, pos2-pos-1);
3220 CString sBlockEnd = sComments.Mid(pos2+1);
3222 auto commentTuple = std::make_tuple(sLineStart, sBlockStart, sBlockEnd);
3224 pos = 0;
3225 CString temp;
3226 for (;;)
3228 temp = sExts.Tokenize(_T(","),pos);
3229 if (temp.IsEmpty())
3231 break;
3233 ASSERT(m_IgnoreCommentsMap.find(temp) == m_IgnoreCommentsMap.end());
3234 m_IgnoreCommentsMap[temp] = commentTuple;
3240 catch (CFileException* e)
3242 e->Delete();
3244 bLoaded = true;
3247 void CMainFrame::OnViewIgnorecomments()
3249 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3250 return;
3251 m_regIgnoreComments = !DWORD(m_regIgnoreComments);
3252 LoadViews(-1);
3255 void CMainFrame::OnUpdateViewIgnorecomments(CCmdUI *pCmdUI)
3257 // only enable if we have comments defined for this file extension
3258 CString sExt = CPathUtils::GetFileExtFromPath(m_Data.m_baseFile.GetFilename()).MakeLower();
3259 sExt.TrimLeft(L".");
3260 auto sC = m_IgnoreCommentsMap.find(sExt);
3261 if (sC == m_IgnoreCommentsMap.end())
3263 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_yourFile.GetFilename()).MakeLower();
3264 sExt.TrimLeft(L".");
3265 sC = m_IgnoreCommentsMap.find(sExt);
3266 if (sC == m_IgnoreCommentsMap.end())
3268 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_theirFile.GetFilename()).MakeLower();
3269 sExt.TrimLeft(L".");
3270 sC = m_IgnoreCommentsMap.find(sExt);
3273 pCmdUI->Enable(sC != m_IgnoreCommentsMap.end());
3275 pCmdUI->SetCheck(DWORD(m_regIgnoreComments) != 0);
3279 void CMainFrame::OnRegexfilter(UINT cmd)
3281 if ((cmd == ID_REGEXFILTER)||(cmd == (ID_REGEXFILTER+1)))
3283 CRegexFiltersDlg dlg(this);
3284 dlg.SetIniFile(&m_regexIni);
3285 if (dlg.DoModal() == IDOK)
3287 FILE * pFile = NULL;
3288 _tfopen_s(&pFile, CPathUtils::GetAppDataDirectory() + L"regexfilters.ini", _T("wb"));
3289 m_regexIni.SaveFile(pFile);
3290 fclose(pFile);
3292 BuildRegexSubitems();
3294 else
3296 if (cmd == (UINT)m_regexIndex)
3298 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3299 return;
3300 m_Data.SetRegexTokens(std::wregex(), L"");
3301 m_regexIndex = -1;
3302 LoadViews(-1);
3304 else
3306 CSimpleIni::TNamesDepend sections;
3307 m_regexIni.GetAllSections(sections);
3308 int index = ID_REGEXFILTER + 2;
3309 m_regexIndex = -1;
3310 for (const auto& section : sections)
3312 if (cmd == (UINT)index)
3314 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3315 break;
3318 std::wregex rx(m_regexIni.GetValue(section, L"regex", L""));
3319 m_Data.SetRegexTokens(rx, m_regexIni.GetValue(section, L"replace", L""));
3321 catch (std::exception &ex)
3323 MessageBox(_T("Regex is invalid!\r\n") + CString(ex.what()));
3325 m_regexIndex = index;
3326 LoadViews(-1);
3327 break;
3329 ++index;
3335 void CMainFrame::OnUpdateViewRegexFilter( CCmdUI *pCmdUI )
3337 pCmdUI->Enable();
3338 pCmdUI->SetCheck(pCmdUI->m_nID == (UINT)m_regexIndex);
3341 void CMainFrame::BuildRegexSubitems()
3343 CArray<CMFCRibbonBaseElement*, CMFCRibbonBaseElement*> arButtons;
3344 m_wndRibbonBar.GetElementsByID(ID_REGEXFILTER, arButtons);
3345 if (arButtons.GetCount() == 1)
3347 CMFCRibbonButton * pButton = (CMFCRibbonButton*)arButtons.GetAt(0);
3348 if (pButton)
3350 pButton->RemoveAllSubItems();
3351 pButton->AddSubItem(new CMFCRibbonButton(ID_REGEXFILTER+1, CString(MAKEINTRESOURCE(IDS_CONFIGUREREGEXES)), 47));
3353 CString sIniPath = CPathUtils::GetAppDataDirectory() + L"regexfilters.ini";
3354 if (!PathFileExists(sIniPath))
3356 // ini file does not exist (yet), so create a default one
3357 HRSRC hRes = FindResource(NULL, MAKEINTRESOURCE(IDR_REGEXFILTERINI), L"config");
3358 if (hRes)
3360 HGLOBAL hResourceLoaded = LoadResource(NULL, hRes);
3361 if (hResourceLoaded)
3363 char * lpResLock = (char *) LockResource(hResourceLoaded);
3364 DWORD dwSizeRes = SizeofResource(NULL, hRes);
3365 if (lpResLock)
3367 HANDLE hFile = CreateFile(sIniPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3368 if (hFile != INVALID_HANDLE_VALUE)
3370 DWORD dwWritten = 0;
3371 WriteFile(hFile, lpResLock, dwSizeRes, &dwWritten, NULL);
3372 CloseHandle(hFile);
3379 m_regexIni.LoadFile(sIniPath);
3380 CSimpleIni::TNamesDepend sections;
3381 m_regexIni.GetAllSections(sections);
3382 if (!sections.empty())
3383 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3384 int cmdIndex = 2;
3385 for (const auto& section : sections)
3387 pButton->AddSubItem(new CMFCRibbonButton(ID_REGEXFILTER+cmdIndex, section, 46));
3388 cmdIndex++;
3394 void CMainFrame::FillEncodingButton( CMFCRibbonButton * pButton, int start )
3396 pButton->SetDefaultCommand(FALSE);
3397 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::ASCII, L"ASCII" ));
3398 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::BINARY, L"BINARY" ));
3399 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_LE, L"UTF-16LE" ));
3400 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_LEBOM, L"UTF-16LE BOM"));
3401 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_BE, L"UTF-16BE" ));
3402 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_BEBOM, L"UTF-16BE BOM"));
3403 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF32_LE, L"UTF-32LE" ));
3404 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF32_BE, L"UTF-32BE" ));
3405 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF8, L"UTF-8" ));
3406 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF8BOM, L"UTF-8 BOM" ));
3409 void CMainFrame::FillEOLButton( CMFCRibbonButton * pButton, int start )
3411 pButton->SetDefaultCommand(FALSE);
3412 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LF , L"LF" ));
3413 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_CRLF, L"CRLF"));
3414 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LFCR, L"LRCR"));
3415 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_CR , L"CR" ));
3416 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_VT , L"VT" ));
3417 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_FF , L"FF" ));
3418 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_NEL , L"NEL" ));
3419 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LS , L"LS" ));
3420 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_PS , L"PS" ));
3423 void CMainFrame::FillTabModeButton(CMFCRibbonButton * pButton, int start)
3425 pButton->SetDefaultCommand(FALSE);
3426 pButton->AddSubItem(new CMFCRibbonButton(start + TABMODE_NONE , L"Tab"));
3427 pButton->AddSubItem(new CMFCRibbonButton(start + TABMODE_USESPACES , L"Space"));
3428 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3429 pButton->AddSubItem(new CMFCRibbonButton(start + TABMODE_SMARTINDENT , L"Smart tab char"));
3430 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3431 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON1, L"1"));
3432 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON2, L"2"));
3433 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON4, L"4"));
3434 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON8, L"8"));
3435 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3436 pButton->AddSubItem(new CMFCRibbonButton(start + ENABLEEDITORCONFIG, L"EditorConfig"));
3439 void CMainFrame::OnEncodingLeft( UINT cmd )
3441 if (m_pwndLeftView)
3443 m_pwndLeftView->SetTextType(CFileTextLines::UnicodeType(cmd-ID_INDICATOR_LEFTENCODINGSTART));
3444 m_pwndLeftView->RefreshViews();
3448 void CMainFrame::OnEncodingRight( UINT cmd )
3450 if (m_pwndRightView)
3452 m_pwndRightView->SetTextType(CFileTextLines::UnicodeType(cmd-ID_INDICATOR_RIGHTENCODINGSTART));
3453 m_pwndRightView->RefreshViews();
3457 void CMainFrame::OnEncodingBottom( UINT cmd )
3459 if (m_pwndBottomView)
3461 m_pwndBottomView->SetTextType(CFileTextLines::UnicodeType(cmd-ID_INDICATOR_BOTTOMENCODINGSTART));
3462 m_pwndBottomView->RefreshViews();
3466 void CMainFrame::OnEOLLeft( UINT cmd )
3468 if (m_pwndLeftView)
3470 m_pwndLeftView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_LEFTEOLSTART));
3471 m_pwndLeftView->RefreshViews();
3475 void CMainFrame::OnEOLRight( UINT cmd )
3477 if (m_pwndRightView)
3479 m_pwndRightView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_RIGHTEOLSTART));
3480 m_pwndRightView->RefreshViews();
3484 void CMainFrame::OnEOLBottom( UINT cmd )
3486 if (m_pwndBottomView)
3488 m_pwndBottomView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_BOTTOMEOLSTART));
3489 m_pwndBottomView->RefreshViews();
3493 void CMainFrame::OnTabModeLeft( UINT cmd )
3495 OnTabMode(m_pwndLeftView, (int)cmd - ID_INDICATOR_LEFTTABMODESTART);
3498 void CMainFrame::OnTabModeRight( UINT cmd )
3500 OnTabMode(m_pwndRightView, (int)cmd - ID_INDICATOR_RIGHTTABMODESTART);
3503 void CMainFrame::OnTabModeBottom( UINT cmd )
3505 OnTabMode(m_pwndBottomView, (int)cmd - ID_INDICATOR_BOTTOMTABMODESTART);
3508 void CMainFrame::OnTabMode(CBaseView *view, int cmd)
3510 if (!view)
3511 return;
3512 int nTabMode = view->GetTabMode();
3513 if (cmd == TABMODE_NONE || cmd == TABMODE_USESPACES)
3514 view->SetTabMode((nTabMode & (~TABMODE_USESPACES)) | (cmd & TABMODE_USESPACES));
3515 else if (cmd == TABMODE_SMARTINDENT) // Toggle
3516 view->SetTabMode((nTabMode & (~TABMODE_SMARTINDENT)) | ((nTabMode & TABMODE_SMARTINDENT) ? 0 : TABMODE_SMARTINDENT));
3517 else if (cmd == TABSIZEBUTTON1)
3518 view->SetTabSize(1);
3519 else if (cmd == TABSIZEBUTTON2)
3520 view->SetTabSize(2);
3521 else if (cmd == TABSIZEBUTTON4)
3522 view->SetTabSize(4);
3523 else if (cmd == TABSIZEBUTTON8)
3524 view->SetTabSize(8);
3525 else if (cmd == ENABLEEDITORCONFIG)
3526 view->SetEditorConfigEnabled(!view->GetEditorConfigEnabled());
3527 view->RefreshViews();
3530 void CMainFrame::OnUpdateEncodingLeft( CCmdUI *pCmdUI )
3532 if (m_pwndLeftView)
3534 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_LEFTENCODINGSTART) == m_pwndLeftView->GetTextType());
3535 pCmdUI->Enable(m_pwndLeftView->IsWritable());
3537 else
3538 pCmdUI->Enable(FALSE);
3541 void CMainFrame::OnUpdateEncodingRight( CCmdUI *pCmdUI )
3543 if (m_pwndRightView)
3545 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_RIGHTENCODINGSTART) == m_pwndRightView->GetTextType());
3546 pCmdUI->Enable(m_pwndRightView->IsWritable());
3548 else
3549 pCmdUI->Enable(FALSE);
3552 void CMainFrame::OnUpdateEncodingBottom( CCmdUI *pCmdUI )
3554 if (m_pwndBottomView)
3556 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_BOTTOMENCODINGSTART) == m_pwndBottomView->GetTextType());
3557 pCmdUI->Enable(m_pwndBottomView->IsWritable());
3559 else
3560 pCmdUI->Enable(FALSE);
3563 void CMainFrame::OnUpdateEOLLeft( CCmdUI *pCmdUI )
3565 if (m_pwndLeftView)
3567 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_LEFTEOLSTART) == m_pwndLeftView->GetLineEndings());
3568 pCmdUI->Enable(m_pwndLeftView->IsWritable());
3570 else
3571 pCmdUI->Enable(FALSE);
3574 void CMainFrame::OnUpdateEOLRight( CCmdUI *pCmdUI )
3576 if (m_pwndRightView)
3578 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_RIGHTEOLSTART) == m_pwndRightView->GetLineEndings());
3579 pCmdUI->Enable(m_pwndRightView->IsWritable());
3581 else
3582 pCmdUI->Enable(FALSE);
3585 void CMainFrame::OnUpdateEOLBottom( CCmdUI *pCmdUI )
3587 if (m_pwndBottomView)
3589 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_BOTTOMEOLSTART) == m_pwndBottomView->GetLineEndings());
3590 pCmdUI->Enable(m_pwndBottomView->IsWritable());
3592 else
3593 pCmdUI->Enable(FALSE);
3596 void CMainFrame::OnUpdateTabModeLeft(CCmdUI *pCmdUI)
3598 OnUpdateTabMode(m_pwndLeftView, pCmdUI, ID_INDICATOR_LEFTTABMODESTART);
3601 void CMainFrame::OnUpdateTabModeRight(CCmdUI *pCmdUI)
3603 OnUpdateTabMode(m_pwndRightView, pCmdUI, ID_INDICATOR_RIGHTTABMODESTART);
3606 void CMainFrame::OnUpdateTabModeBottom(CCmdUI *pCmdUI)
3608 OnUpdateTabMode(m_pwndBottomView, pCmdUI, ID_INDICATOR_BOTTOMTABMODESTART);
3611 void CMainFrame::OnUpdateTabMode(CBaseView *view, CCmdUI *pCmdUI, int startid)
3613 if (view)
3615 int cmd = (int)pCmdUI->m_nID - startid;
3616 if (cmd == TABMODE_NONE)
3617 pCmdUI->SetCheck((view->GetTabMode() & TABMODE_USESPACES) == TABMODE_NONE);
3618 else if (cmd == TABMODE_USESPACES)
3619 pCmdUI->SetCheck(view->GetTabMode() & TABMODE_USESPACES);
3620 else if (cmd == TABMODE_SMARTINDENT)
3621 pCmdUI->SetCheck(view->GetTabMode() & TABMODE_SMARTINDENT);
3622 else if (cmd == TABSIZEBUTTON1)
3623 pCmdUI->SetCheck(view->GetTabSize() == 1);
3624 else if (cmd == TABSIZEBUTTON2)
3625 pCmdUI->SetCheck(view->GetTabSize() == 2);
3626 else if (cmd == TABSIZEBUTTON4)
3627 pCmdUI->SetCheck(view->GetTabSize() == 4);
3628 else if (cmd == TABSIZEBUTTON8)
3629 pCmdUI->SetCheck(view->GetTabSize() == 8);
3630 else if (cmd == ENABLEEDITORCONFIG)
3631 pCmdUI->SetCheck(view->GetEditorConfigEnabled());
3632 pCmdUI->Enable(view->IsWritable());
3633 if (cmd == ENABLEEDITORCONFIG)
3634 pCmdUI->Enable(view->IsWritable() && view->GetEditorConfigLoaded());
3636 else
3637 pCmdUI->Enable(FALSE);