TortoiseGitMerge: Use native ribbons
[TortoiseGit.git] / src / TortoiseMerge / MainFrm.cpp
blob0ba731b3be856dc2e4096b86ae7d34514fa88d2f
1 // TortoiseGitMerge - a Diff/Patch program
3 // Copyright (C) 2008-2017 - TortoiseGit
4 // Copyright (C) 2004-2017 - 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 "OpenDlg.h"
24 #include "SysProgressDlg.h"
25 #include "Settings.h"
26 #include "MessageBox.h"
27 #include "AppUtils.h"
28 #include "PathUtils.h"
29 #include "MainFrm.h"
30 #include "LeftView.h"
31 #include "RightView.h"
32 #include "BottomView.h"
33 #include "DiffColors.h"
34 #include "SelectFileFilter.h"
35 #include "FormatMessageWrapper.h"
36 #include "TaskbarUUID.h"
37 #include "RegexFiltersDlg.h"
39 #ifdef _DEBUG
40 #define new DEBUG_NEW
41 #endif
43 // CMainFrame
44 #define IDT_RELOADCHECKTIMER 123
46 IMPLEMENT_DYNCREATE(CMainFrame, CFrameWndEx)
48 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)
49 ON_WM_CREATE()
50 ON_WM_DESTROY()
51 ON_COMMAND_RANGE(ID_VIEW_APPLOOK_WIN7, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnApplicationLook)
52 ON_UPDATE_COMMAND_UI_RANGE(IDC_STYLEBUTTON, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnUpdateApplicationLook)
53 // Global help commands
54 ON_COMMAND(ID_HELP_FINDER, CFrameWndEx::OnHelpFinder)
55 ON_COMMAND(ID_HELP, CFrameWndEx::OnHelp)
56 ON_COMMAND(ID_CONTEXT_HELP, CFrameWndEx::OnContextHelp)
57 ON_COMMAND(ID_DEFAULT_HELP, CFrameWndEx::OnHelpFinder)
58 ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
59 ON_COMMAND(ID_VIEW_WHITESPACES, OnViewWhitespaces)
60 ON_WM_SIZE()
61 ON_COMMAND(ID_FILE_SAVE, OnFileSave)
62 ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
63 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave)
64 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_AS, OnUpdateFileSaveAs)
65 ON_COMMAND(ID_VIEW_ONEWAYDIFF, OnViewOnewaydiff)
66 ON_UPDATE_COMMAND_UI(ID_VIEW_ONEWAYDIFF, OnUpdateViewOnewaydiff)
67 ON_UPDATE_COMMAND_UI(ID_VIEW_WHITESPACES, OnUpdateViewWhitespaces)
68 ON_COMMAND(ID_VIEW_OPTIONS, OnViewOptions)
69 ON_MESSAGE(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI)
70 ON_WM_CLOSE()
71 ON_WM_ACTIVATE()
72 ON_COMMAND(ID_FILE_RELOAD, OnFileReload)
73 ON_COMMAND(ID_VIEW_LINEDOWN, OnViewLinedown)
74 ON_COMMAND(ID_VIEW_LINEUP, OnViewLineup)
75 ON_COMMAND(ID_VIEW_MOVEDBLOCKS, OnViewMovedBlocks)
76 ON_UPDATE_COMMAND_UI(ID_VIEW_MOVEDBLOCKS, OnUpdateViewMovedBlocks)
77 ON_UPDATE_COMMAND_UI(ID_EDIT_MARKASRESOLVED, OnUpdateMergeMarkasresolved)
78 ON_COMMAND(ID_EDIT_MARKASRESOLVED, OnMergeMarkasresolved)
79 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTCONFLICT, OnUpdateMergeNextconflict)
80 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSCONFLICT, OnUpdateMergePreviousconflict)
81 ON_WM_MOVE()
82 ON_WM_MOVING()
83 ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
84 ON_COMMAND(ID_VIEW_SWITCHLEFT, OnViewSwitchleft)
85 ON_UPDATE_COMMAND_UI(ID_VIEW_SWITCHLEFT, OnUpdateViewSwitchleft)
86 ON_COMMAND(ID_VIEW_LINELEFT, &CMainFrame::OnViewLineleft)
87 ON_COMMAND(ID_VIEW_LINERIGHT, &CMainFrame::OnViewLineright)
88 ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWFILELIST, &CMainFrame::OnUpdateViewShowfilelist)
89 ON_COMMAND(ID_VIEW_SHOWFILELIST, &CMainFrame::OnViewShowfilelist)
90 ON_COMMAND(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnEditUseTheirs)
91 ON_COMMAND(ID_EDIT_USEMYBLOCK, &CMainFrame::OnEditUseMine)
92 ON_COMMAND(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnEditUseTheirsThenMine)
93 ON_COMMAND(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnEditUseMineThenTheirs)
94 ON_COMMAND(ID_EDIT_UNDO, &CMainFrame::OnEditUndo)
95 ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, &CMainFrame::OnUpdateEditUndo)
96 ON_COMMAND(ID_EDIT_REDO, &CMainFrame::OnEditRedo)
97 ON_UPDATE_COMMAND_UI(ID_EDIT_REDO, &CMainFrame::OnUpdateEditRedo)
98 ON_COMMAND(ID_EDIT_ENABLE, &CMainFrame::OnEditEnable)
99 ON_UPDATE_COMMAND_UI(ID_EDIT_ENABLE, &CMainFrame::OnUpdateEditEnable)
100 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnUpdateEditUseminethentheirblock)
101 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMYBLOCK, &CMainFrame::OnUpdateEditUsemyblock)
102 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnUpdateEditUsetheirblock)
103 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnUpdateEditUsetheirthenmyblock)
104 ON_COMMAND(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnViewInlinediffword)
105 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnUpdateViewInlinediffword)
106 ON_COMMAND(ID_VIEW_INLINEDIFF, &CMainFrame::OnViewInlinediff)
107 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFF, &CMainFrame::OnUpdateViewInlinediff)
108 ON_UPDATE_COMMAND_UI(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnUpdateEditCreateunifieddifffile)
109 ON_COMMAND(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnEditCreateunifieddifffile)
110 ON_UPDATE_COMMAND_UI(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnUpdateViewLinediffbar)
111 ON_COMMAND(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnViewLinediffbar)
112 ON_UPDATE_COMMAND_UI(ID_VIEW_BARS, &CMainFrame::OnUpdateViewBars)
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_REGEX_NO_FILTER, &CMainFrame::OnRegexNoFilter)
149 ON_UPDATE_COMMAND_UI(ID_REGEX_NO_FILTER, &CMainFrame::OnUpdateRegexNoFilter)
150 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOENCODING, &CMainFrame::OnDummyEnabled)
151 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOENCODING, &CMainFrame::OnDummyEnabled)
152 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOENCODING, &CMainFrame::OnDummyEnabled)
153 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOEOL, &CMainFrame::OnDummyEnabled)
154 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOEOL, &CMainFrame::OnDummyEnabled)
155 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOEOL, &CMainFrame::OnDummyEnabled)
156 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOTABMODE, &CMainFrame::OnDummyEnabled)
157 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOTABMODE, &CMainFrame::OnDummyEnabled)
158 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOTABMODE, &CMainFrame::OnDummyEnabled)
159 ON_UPDATE_COMMAND_UI(ID_EDIT_THREEWAY_ACTIONS, &CMainFrame::OnUpdateThreeWayActions)
160 ON_COMMAND_RANGE(ID_INDICATOR_LEFTENCODINGSTART, ID_INDICATOR_LEFTENCODINGSTART+19, &CMainFrame::OnEncodingLeft)
161 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTENCODINGSTART, ID_INDICATOR_RIGHTENCODINGSTART+19, &CMainFrame::OnEncodingRight)
162 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMENCODINGSTART, ID_INDICATOR_BOTTOMENCODINGSTART+19, &CMainFrame::OnEncodingBottom)
163 ON_COMMAND_RANGE(ID_INDICATOR_LEFTEOLSTART, ID_INDICATOR_LEFTEOLSTART+19, &CMainFrame::OnEOLLeft)
164 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTEOLSTART, ID_INDICATOR_RIGHTEOLSTART+19, &CMainFrame::OnEOLRight)
165 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMEOLSTART, ID_INDICATOR_BOTTOMEOLSTART+19, &CMainFrame::OnEOLBottom)
166 ON_COMMAND_RANGE(ID_INDICATOR_LEFTTABMODESTART, ID_INDICATOR_LEFTTABMODESTART+19, &CMainFrame::OnTabModeLeft)
167 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTTABMODESTART, ID_INDICATOR_RIGHTTABMODESTART+19, &CMainFrame::OnTabModeRight)
168 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMTABMODESTART, ID_INDICATOR_BOTTOMTABMODESTART+19, &CMainFrame::OnTabModeBottom)
169 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTENCODINGSTART, ID_INDICATOR_LEFTENCODINGSTART+19, &CMainFrame::OnUpdateEncodingLeft)
170 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTENCODINGSTART, ID_INDICATOR_RIGHTENCODINGSTART+19, &CMainFrame::OnUpdateEncodingRight)
171 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMENCODINGSTART, ID_INDICATOR_BOTTOMENCODINGSTART+19, &CMainFrame::OnUpdateEncodingBottom)
172 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTEOLSTART, ID_INDICATOR_LEFTEOLSTART+19, &CMainFrame::OnUpdateEOLLeft)
173 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTEOLSTART, ID_INDICATOR_RIGHTEOLSTART+19, &CMainFrame::OnUpdateEOLRight)
174 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMEOLSTART, ID_INDICATOR_BOTTOMEOLSTART+19, &CMainFrame::OnUpdateEOLBottom)
175 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTTABMODESTART, ID_INDICATOR_LEFTTABMODESTART+19, &CMainFrame::OnUpdateTabModeLeft)
176 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTTABMODESTART, ID_INDICATOR_RIGHTTABMODESTART+19, &CMainFrame::OnUpdateTabModeRight)
177 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMTABMODESTART, ID_INDICATOR_BOTTOMTABMODESTART+19, &CMainFrame::OnUpdateTabModeBottom)
178 END_MESSAGE_MAP()
180 static UINT indicators[] =
182 ID_SEPARATOR, // status line indicator
183 ID_INDICATOR_LEFTVIEW,
184 ID_INDICATOR_RIGHTVIEW,
185 ID_INDICATOR_BOTTOMVIEW,
186 ID_INDICATOR_CAPS,
187 ID_INDICATOR_NUM,
188 ID_INDICATOR_SCRL
192 // CMainFrame construction/destruction
194 CMainFrame::CMainFrame()
195 : m_bInitSplitter(FALSE)
196 , m_bReversedPatch(FALSE)
197 , m_bHasConflicts(false)
198 , m_bInlineWordDiff(true)
199 , m_bLineDiff(true)
200 , m_bLocatorBar(true)
201 , m_nMoveMovesToIgnore(0)
202 , m_pwndLeftView(nullptr)
203 , m_pwndRightView(nullptr)
204 , m_pwndBottomView(nullptr)
205 , m_bReadOnly(false)
206 , m_bBlame(false)
207 , m_bCheckReload(false)
208 , m_bSaveRequired(false)
209 , m_bSaveRequiredOnConflicts(false)
210 , m_bDeleteBaseTheirsMineOnClose(false)
211 , resolveMsgWnd(0)
212 , resolveMsgWParam(0)
213 , resolveMsgLParam(0)
214 , m_regWrapLines(L"Software\\TortoiseGitMerge\\WrapLines", 0)
215 , m_regViewModedBlocks(L"Software\\TortoiseGitMerge\\ViewMovedBlocks", TRUE)
216 , m_regOneWay(L"Software\\TortoiseGitMerge\\OnePane")
217 , m_regCollapsed(L"Software\\TortoiseGitMerge\\Collapsed", 0)
218 , m_regInlineDiff(L"Software\\TortoiseGitMerge\\DisplayBinDiff", TRUE)
219 , m_regUseRibbons(L"Software\\TortoiseGitMerge\\UseRibbons", TRUE)
220 , m_regIgnoreComments(L"Software\\TortoiseGitMerge\\IgnoreComments", FALSE)
221 , m_regexIndex(-1)
223 m_bOneWay = (0 != ((DWORD)m_regOneWay));
224 theApp.m_nAppLook = theApp.GetInt(L"ApplicationLook", ID_VIEW_APPLOOK_VS_2005);
225 m_bCollapsed = !!(DWORD)m_regCollapsed;
226 m_bViewMovedBlocks = !!(DWORD)m_regViewModedBlocks;
227 m_bWrapLines = !!(DWORD)m_regWrapLines;
228 m_bInlineDiff = !!m_regInlineDiff;
229 m_bUseRibbons = !!m_regUseRibbons;
230 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
233 CMainFrame::~CMainFrame()
237 LRESULT CMainFrame::OnTaskbarButtonCreated(WPARAM /*wParam*/, LPARAM /*lParam*/)
239 SetUUIDOverlayIcon(m_hWnd);
240 return 0;
244 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
246 if (CFrameWndEx::OnCreate(lpCreateStruct) == -1)
247 return -1;
249 OnApplicationLook(theApp.m_nAppLook);
251 if (m_bUseRibbons)
253 HRESULT hr;
254 hr = m_pRibbonFramework.CoCreateInstance(__uuidof(UIRibbonFramework));
255 if (FAILED(hr))
257 TRACE(L"Failed to create ribbon framework (%08x)\n", hr);
258 return -1; // fail to create
261 m_pRibbonApp.reset(new CNativeRibbonApp(this, m_pRibbonFramework));
262 m_pRibbonApp->SetSettingsFileName(CPathUtils::GetAppDataDirectory() + L"TortoiseGitMerge-RibbonSettings");
264 hr = m_pRibbonFramework->Initialize(m_hWnd, m_pRibbonApp.get());
265 if (FAILED(hr))
267 TRACE(L"Failed to initialize ribbon framework (%08x)\n", hr);
268 return -1; // fail to create
271 hr = m_pRibbonFramework->LoadUI(AfxGetResourceHandle(), L"TORTOISEGITMERGERIBBON_RIBBON");
272 if (FAILED(hr))
274 TRACE(L"Failed to load ribbon UI (%08x)\n", hr);
275 return -1; // fail to create
277 BuildRegexSubitems();
278 if (!m_wndRibbonStatusBar.Create(this))
280 TRACE0("Failed to create ribbon status bar\n");
281 return -1; // fail to create
283 m_wndRibbonStatusBar.AddElement(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(AFX_IDS_IDLEMESSAGE)), TRUE), L"");
285 CString sTooltip(MAKEINTRESOURCE(IDS_ENCODING_COMBO_TOOLTIP));
286 auto apBtnGroupLeft = std::make_unique<CMFCRibbonButtonsGroup>();
287 apBtnGroupLeft->SetID(ID_INDICATOR_LEFTVIEW);
288 apBtnGroupLeft->AddButton(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(IDS_STATUSBAR_LEFTVIEW)), TRUE));
289 CMFCRibbonButton * pButton = new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOENCODING, L"");
290 pButton->SetToolTipText(sTooltip);
291 FillEncodingButton(pButton, ID_INDICATOR_LEFTENCODINGSTART);
292 apBtnGroupLeft->AddButton(pButton);
293 pButton = new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOEOL, L"");
294 FillEOLButton(pButton, ID_INDICATOR_LEFTEOLSTART);
295 apBtnGroupLeft->AddButton(pButton);
296 pButton = new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOTABMODE, L"");
297 FillTabModeButton(pButton, ID_INDICATOR_LEFTTABMODESTART);
298 apBtnGroupLeft->AddButton(pButton);
299 apBtnGroupLeft->AddButton(new CMFCRibbonStatusBarPane(ID_INDICATOR_LEFTVIEW, L"", TRUE));
300 m_wndRibbonStatusBar.AddExtendedElement(apBtnGroupLeft.release(), L"");
302 auto apBtnGroupRight = std::make_unique<CMFCRibbonButtonsGroup>();
303 apBtnGroupRight->SetID(ID_INDICATOR_RIGHTVIEW);
304 apBtnGroupRight->AddButton(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(IDS_STATUSBAR_RIGHTVIEW)), TRUE));
305 pButton = new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOENCODING, L"");
306 pButton->SetToolTipText(sTooltip);
307 FillEncodingButton(pButton, ID_INDICATOR_RIGHTENCODINGSTART);
308 apBtnGroupRight->AddButton(pButton);
309 pButton = new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOEOL, L"");
310 FillEOLButton(pButton, ID_INDICATOR_RIGHTEOLSTART);
311 apBtnGroupRight->AddButton(pButton);
312 pButton = new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOTABMODE, L"");
313 FillTabModeButton(pButton, ID_INDICATOR_RIGHTTABMODESTART);
314 apBtnGroupRight->AddButton(pButton);
315 apBtnGroupRight->AddButton(new CMFCRibbonStatusBarPane(ID_INDICATOR_RIGHTVIEW, L"", TRUE));
316 m_wndRibbonStatusBar.AddExtendedElement(apBtnGroupRight.release(), L"");
318 else
320 if (!m_wndMenuBar.Create(this))
322 TRACE0("Failed to create menubar\n");
323 return -1; // fail to create
325 m_wndMenuBar.SetPaneStyle(m_wndMenuBar.GetPaneStyle() | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY);
327 // prevent the menu bar from taking the focus on activation
328 CMFCPopupMenu::SetForceMenuFocus(FALSE);
329 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))
331 TRACE0("Failed to create toolbar\n");
332 return -1; // fail to create
334 m_wndToolBar.SetWindowText(L"Main");
335 if (!m_wndStatusBar.Create(this) ||
336 !m_wndStatusBar.SetIndicators(indicators,
337 _countof(indicators)))
339 TRACE0("Failed to create status bar\n");
340 return -1; // fail to create
342 m_wndStatusBar.EnablePaneDoubleClick();
345 if (!m_wndLocatorBar.Create(this, IDD_DIFFLOCATOR,
346 CBRS_ALIGN_LEFT | CBRS_SIZE_FIXED, ID_VIEW_LOCATORBAR))
348 TRACE0("Failed to create dialogbar\n");
349 return -1; // fail to create
351 if (!m_wndLineDiffBar.Create(this, IDD_LINEDIFF,
352 CBRS_ALIGN_BOTTOM | CBRS_SIZE_FIXED, ID_VIEW_LINEDIFFBAR))
354 TRACE0("Failed to create dialogbar\n");
355 return -1; // fail to create
357 m_wndLocatorBar.m_pMainFrm = this;
358 m_wndLineDiffBar.m_pMainFrm = this;
360 EnableDocking(CBRS_ALIGN_ANY);
361 if (!m_bUseRibbons)
363 m_wndMenuBar.EnableDocking(CBRS_ALIGN_TOP);
364 m_wndToolBar.EnableDocking(CBRS_ALIGN_TOP);
365 DockPane(&m_wndMenuBar);
366 DockPane(&m_wndToolBar);
368 DockPane(&m_wndLocatorBar);
369 DockPane(&m_wndLineDiffBar);
370 ShowPane(&m_wndLocatorBar, true, false, true);
371 ShowPane(&m_wndLineDiffBar, true, false, true);
373 m_wndLocatorBar.EnableGripper(FALSE);
374 m_wndLineDiffBar.EnableGripper(FALSE);
376 return 0;
379 void CMainFrame::OnDestroy()
381 if (m_pRibbonFramework)
382 m_pRibbonFramework->Destroy();
384 CFrameWndEx::OnDestroy();
387 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
389 if( !CFrameWndEx::PreCreateWindow(cs) )
390 return FALSE;
391 return TRUE;
394 void CMainFrame::OnApplicationLook(UINT id)
396 if (m_bUseRibbons)
398 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
399 return;
402 CWaitCursor wait;
404 theApp.m_nAppLook = id;
406 switch (theApp.m_nAppLook)
408 case ID_VIEW_APPLOOK_WIN_2000:
409 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManager));
410 break;
412 case ID_VIEW_APPLOOK_OFF_XP:
413 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOfficeXP));
414 break;
416 case ID_VIEW_APPLOOK_WIN_XP:
417 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
418 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
419 break;
421 case ID_VIEW_APPLOOK_OFF_2003:
422 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2003));
423 CDockingManager::SetDockingMode(DT_SMART);
424 break;
426 case ID_VIEW_APPLOOK_VS_2005:
427 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2005));
428 CDockingManager::SetDockingMode(DT_SMART);
429 break;
431 case ID_VIEW_APPLOOK_VS_2008:
432 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2008));
433 CDockingManager::SetDockingMode(DT_SMART);
434 break;
436 case ID_VIEW_APPLOOK_WIN7:
437 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows7));
438 CDockingManager::SetDockingMode(DT_SMART);
439 break;
441 default:
442 switch (theApp.m_nAppLook)
444 case ID_VIEW_APPLOOK_OFF_2007_BLUE:
445 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_LunaBlue);
446 break;
448 case ID_VIEW_APPLOOK_OFF_2007_BLACK:
449 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_ObsidianBlack);
450 break;
452 case ID_VIEW_APPLOOK_OFF_2007_SILVER:
453 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Silver);
454 break;
456 case ID_VIEW_APPLOOK_OFF_2007_AQUA:
457 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Aqua);
458 break;
461 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));
462 CDockingManager::SetDockingMode(DT_SMART);
465 RedrawWindow(nullptr, nullptr, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_FRAME | RDW_ERASE);
467 theApp.WriteInt(L"ApplicationLook", theApp.m_nAppLook);
470 void CMainFrame::OnUpdateApplicationLook(CCmdUI* pCmdUI)
472 pCmdUI->Enable();
473 pCmdUI->SetRadio(theApp.m_nAppLook == pCmdUI->m_nID);
477 // CMainFrame diagnostics
479 #ifdef _DEBUG
480 void CMainFrame::AssertValid() const
482 CFrameWndEx::AssertValid();
485 void CMainFrame::Dump(CDumpContext& dc) const
487 CFrameWndEx::Dump(dc);
490 #endif //_DEBUG
493 // CMainFrame message handlers
496 BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)
498 CRect cr;
499 GetClientRect( &cr);
502 // split into three panes:
503 // -------------
504 // | | |
505 // | | |
506 // |------------
507 // | |
508 // | |
509 // |------------
511 // create a splitter with 2 rows, 1 column
512 if (!m_wndSplitter.CreateStatic(this, 2, 1))
514 TRACE0("Failed to CreateStaticSplitter\n");
515 return FALSE;
518 // add the second splitter pane - which is a nested splitter with 2 columns
519 if (!m_wndSplitter2.CreateStatic(
520 &m_wndSplitter, // our parent window is the first splitter
521 1, 2, // the new splitter is 1 row, 2 columns
522 WS_CHILD | WS_VISIBLE | WS_BORDER, // style, WS_BORDER is needed
523 m_wndSplitter.IdFromRowCol(0, 0)
524 // new splitter is in the first row, 1st column of first splitter
527 TRACE0("Failed to create nested splitter\n");
528 return FALSE;
530 // add the first splitter pane - the default view in row 0
531 if (!m_wndSplitter.CreateView(1, 0,
532 RUNTIME_CLASS(CBottomView), CSize(cr.Width(), cr.Height()), pContext))
534 TRACE0("Failed to create first pane\n");
535 return FALSE;
537 m_pwndBottomView = static_cast<CBottomView*>(m_wndSplitter.GetPane(1, 0));
538 m_pwndBottomView->m_pwndLocator = &m_wndLocatorBar;
539 m_pwndBottomView->m_pwndLineDiffBar = &m_wndLineDiffBar;
540 if (m_bUseRibbons)
541 m_pwndBottomView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
542 else
543 m_pwndBottomView->m_pwndStatusBar = &m_wndStatusBar;
544 m_pwndBottomView->m_pMainFrame = this;
546 // now create the two views inside the nested splitter
548 if (!m_wndSplitter2.CreateView(0, 0,
549 RUNTIME_CLASS(CLeftView), CSize(cr.Width()/2, cr.Height()/2), pContext))
551 TRACE0("Failed to create second pane\n");
552 return FALSE;
554 m_pwndLeftView = static_cast<CLeftView*>(m_wndSplitter2.GetPane(0, 0));
555 m_pwndLeftView->m_pwndLocator = &m_wndLocatorBar;
556 m_pwndLeftView->m_pwndLineDiffBar = &m_wndLineDiffBar;
557 if (m_bUseRibbons)
558 m_pwndLeftView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
559 else
560 m_pwndLeftView->m_pwndStatusBar = &m_wndStatusBar;
561 m_pwndLeftView->m_pMainFrame = this;
563 if (!m_wndSplitter2.CreateView(0, 1,
564 RUNTIME_CLASS(CRightView), CSize(cr.Width()/2, cr.Height()/2), pContext))
566 TRACE0("Failed to create third pane\n");
567 return FALSE;
569 m_pwndRightView = static_cast<CRightView*>(m_wndSplitter2.GetPane(0, 1));
570 m_pwndRightView->m_pwndLocator = &m_wndLocatorBar;
571 m_pwndRightView->m_pwndLineDiffBar = &m_wndLineDiffBar;
572 if (m_bUseRibbons)
573 m_pwndRightView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
574 else
575 m_pwndRightView->m_pwndStatusBar = &m_wndStatusBar;
576 m_pwndRightView->m_pMainFrame = this;
577 m_bInitSplitter = TRUE;
579 m_dlgFilePatches.Create(IDD_FILEPATCHES, this);
580 UpdateLayout();
581 return TRUE;
584 // Callback function
585 BOOL CMainFrame::PatchFile(CString sFilePath, bool /*bContentMods*/, bool bPropMods, CString sVersion, BOOL bAutoPatch)
587 //"dry run" was successful, so save the patched file somewhere...
588 CString sTempFile = CTempFiles::Instance().GetTempFilePathString();
589 CString sRejectedFile, sBasePath;
590 if (m_Patch.GetPatchResult(sFilePath, sTempFile, sRejectedFile, sBasePath) < 0)
592 MessageBox(m_Patch.GetErrorMessage(), nullptr, MB_ICONERROR);
593 return FALSE;
595 sFilePath = m_Patch.GetTargetPath() + L'\\' + sFilePath;
596 sFilePath.Replace('/', '\\');
597 if (sBasePath.IsEmpty())
598 sBasePath = sFilePath;
599 if (m_bReversedPatch)
601 m_Data.m_baseFile.SetFileName(sTempFile);
602 CString temp;
603 temp.Format(L"%s %s", (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
604 m_Data.m_baseFile.SetDescriptiveName(temp);
605 m_Data.m_yourFile.SetFileName(sFilePath);
606 temp.Format(L"%s %s", (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchOriginal);
607 m_Data.m_yourFile.SetDescriptiveName(temp);
608 m_Data.m_theirFile.SetOutOfUse();
609 m_Data.m_mergedFile.SetOutOfUse();
611 else
613 if ((!PathFileExists(sBasePath))||(PathIsDirectory(sBasePath)))
615 m_Data.m_baseFile.SetFileName(CTempFiles::Instance().GetTempFilePathString());
616 m_Data.m_baseFile.CreateEmptyFile();
618 else
620 m_Data.m_baseFile.SetFileName(sBasePath);
622 CString sDescription;
623 sDescription.Format(L"%s %s", (LPCTSTR)CPathUtils::GetFileNameFromPath(sBasePath), (LPCTSTR)m_Data.m_sPatchOriginal);
624 m_Data.m_baseFile.SetDescriptiveName(sDescription);
625 if (sBasePath == sFilePath)
627 m_Data.m_yourFile.SetFileName(sTempFile);
628 CString temp;
629 temp.Format(L"%s %s", (LPCTSTR)CPathUtils::GetFileNameFromPath(sBasePath), (LPCTSTR)m_Data.m_sPatchPatched);
630 m_Data.m_yourFile.SetDescriptiveName(temp);
631 m_Data.m_theirFile.SetOutOfUse();
633 else
635 if (!PathFileExists(sFilePath) || PathIsDirectory(sFilePath))
637 m_Data.m_yourFile.SetFileName(CTempFiles::Instance().GetTempFilePathString());
638 m_Data.m_yourFile.CreateEmptyFile();
639 CString temp;
640 temp.Format(L"%s %s", (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)CString(MAKEINTRESOURCE(IDS_NOTFOUNDVIEWTITLEINDICATOR)));
641 m_Data.m_yourFile.SetDescriptiveName(temp);
643 else
644 m_Data.m_yourFile.SetFileName(sFilePath);
645 m_Data.m_theirFile.SetFileName(sTempFile);
646 CString temp;
647 temp.Format(L"%s %s", (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
648 m_Data.m_theirFile.SetDescriptiveName(temp);
650 m_Data.m_mergedFile.SetFileName(sFilePath);
651 m_Data.m_bPatchRequired = bPropMods;
653 TRACE(L"comparing %s\nwith the patched result %s\n", (LPCTSTR)sFilePath, (LPCTSTR)sTempFile);
655 LoadViews();
656 if (!sRejectedFile.IsEmpty())
658 #if 0 // TGIT TODO
659 // start TortoiseUDiff with the rejected hunks
660 CString sTitle;
661 sTitle.Format(IDS_TITLE_REJECTEDHUNKS, (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath));
662 CAppUtils::StartUnifiedDiffViewer(sRejectedFile, sTitle);
663 #endif
665 if (bAutoPatch)
667 if (sBasePath != sFilePath && HasConflictsWontKeep())
668 return FALSE;
670 PatchSave();
672 return TRUE;
675 // Callback function
676 BOOL CMainFrame::DiffFiles(CString sURL1, CString sRev1, CString sURL2, CString sRev2)
678 CString tempfile1 = CTempFiles::Instance().GetTempFilePathString();
679 CString tempfile2 = CTempFiles::Instance().GetTempFilePathString();
681 ASSERT(tempfile1.Compare(tempfile2));
683 CString sTemp;
684 CSysProgressDlg progDlg;
685 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev1);
686 progDlg.SetLine(1, sTemp, true);
687 progDlg.SetLine(2, sURL1, true);
688 sTemp.LoadString(IDS_GETVERSIONOFFILETITLE);
689 progDlg.SetTitle(sTemp);
690 progDlg.SetShowProgressBar(true);
691 progDlg.SetTime(FALSE);
692 progDlg.SetProgress(1,100);
693 progDlg.ShowModeless(this);
694 if (!CAppUtils::GetVersionedFile(sURL1, sRev1, tempfile1, &progDlg, m_hWnd))
696 progDlg.Stop();
697 CString sErrMsg;
698 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev1, (LPCTSTR)sURL1);
699 MessageBox(sErrMsg, nullptr, MB_ICONERROR);
700 return FALSE;
702 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev2);
703 progDlg.SetLine(1, sTemp, true);
704 progDlg.SetLine(2, sURL2, true);
705 progDlg.SetProgress(50, 100);
706 if (!CAppUtils::GetVersionedFile(sURL2, sRev2, tempfile2, &progDlg, m_hWnd))
708 progDlg.Stop();
709 CString sErrMsg;
710 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev2, (LPCTSTR)sURL2);
711 MessageBox(sErrMsg, nullptr, MB_ICONERROR);
712 return FALSE;
714 progDlg.SetProgress(100,100);
715 progDlg.Stop();
716 CString temp;
717 temp.Format(L"%s Revision %s", (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL1), (LPCTSTR)sRev1);
718 m_Data.m_baseFile.SetFileName(tempfile1);
719 m_Data.m_baseFile.SetDescriptiveName(temp);
720 temp.Format(L"%s Revision %s", (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL2), (LPCTSTR)sRev2);
721 m_Data.m_yourFile.SetFileName(tempfile2);
722 m_Data.m_yourFile.SetDescriptiveName(temp);
724 LoadViews();
726 return TRUE;
729 void CMainFrame::OnFileOpen()
731 if (CheckForSave(CHFSR_OPEN)==IDCANCEL)
732 return;
733 return OnFileOpen(false);
736 void CMainFrame::OnFileOpen(bool fillyours)
738 COpenDlg dlg;
739 if (fillyours)
740 dlg.m_sBaseFile = m_Data.m_yourFile.GetFilename();
741 if (dlg.DoModal() != IDOK)
743 return;
745 m_dlgFilePatches.ShowWindow(SW_HIDE);
746 m_dlgFilePatches.Init(nullptr, nullptr, CString(), nullptr);
747 TRACE(L"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,
748 (LPCTSTR)dlg.m_sUnifiedDiffFile, (LPCTSTR)dlg.m_sPatchDirectory);
749 m_Data.m_baseFile.SetFileName(dlg.m_sBaseFile);
750 m_Data.m_theirFile.SetFileName(dlg.m_sTheirFile);
751 m_Data.m_yourFile.SetFileName(dlg.m_sYourFile);
752 m_Data.m_sDiffFile = dlg.m_sUnifiedDiffFile;
753 m_Data.m_sPatchPath = dlg.m_sPatchDirectory;
754 m_Data.m_mergedFile.SetOutOfUse();
755 CCrashReport::Instance().AddFile2(dlg.m_sBaseFile, nullptr, L"Basefile", CR_AF_MAKE_FILE_COPY);
756 CCrashReport::Instance().AddFile2(dlg.m_sTheirFile, nullptr, L"Theirfile", CR_AF_MAKE_FILE_COPY);
757 CCrashReport::Instance().AddFile2(dlg.m_sYourFile, nullptr, L"Yourfile", CR_AF_MAKE_FILE_COPY);
758 CCrashReport::Instance().AddFile2(dlg.m_sUnifiedDiffFile, nullptr, L"Difffile", CR_AF_MAKE_FILE_COPY);
760 if (!m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && m_Data.IsYourFileInUse())
762 // a diff between two files means "Yours" against "Base", not "Theirs" against "Yours"
763 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
765 if (m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && !m_Data.IsYourFileInUse())
767 // a diff between two files means "Yours" against "Base", not "Theirs" against "Base"
768 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
770 m_bSaveRequired = false;
772 LoadViews();
775 void CMainFrame::ClearViewNamesAndPaths()
777 m_pwndLeftView->m_sWindowName.Empty();
778 m_pwndLeftView->m_sFullFilePath.Empty();
779 m_pwndLeftView->m_sReflectedName.Empty();
780 m_pwndRightView->m_sWindowName.Empty();
781 m_pwndRightView->m_sFullFilePath.Empty();
782 m_pwndRightView->m_sReflectedName.Empty();
783 m_pwndBottomView->m_sWindowName.Empty();
784 m_pwndBottomView->m_sFullFilePath.Empty();
785 m_pwndBottomView->m_sReflectedName.Empty();
788 bool CMainFrame::LoadViews(int line)
790 LoadIgnoreCommentData();
791 m_Data.SetBlame(m_bBlame);
792 m_Data.SetMovedBlocks(m_bViewMovedBlocks);
793 m_bHasConflicts = false;
794 CBaseView* pwndActiveView = m_pwndLeftView;
795 int nOldLine = m_pwndRightView ? m_pwndRightView->m_nTopLine : -1;
796 int nOldLineNumber =
797 m_pwndRightView && m_pwndRightView->m_pViewData ?
798 m_pwndRightView->m_pViewData->GetLineNumber(m_pwndRightView->m_nTopLine) : -1;
799 POINT ptOldCaretPos = {-1, -1};
800 if (m_pwndRightView && m_pwndRightView->IsTarget())
801 ptOldCaretPos = m_pwndRightView->GetCaretPosition();
802 if (m_pwndBottomView && m_pwndBottomView->IsTarget())
803 ptOldCaretPos = m_pwndBottomView->GetCaretPosition();
804 CString sExt = CPathUtils::GetFileExtFromPath(m_Data.m_baseFile.GetFilename()).MakeLower();
805 sExt.TrimLeft(L".");
806 auto sC = m_IgnoreCommentsMap.find(sExt);
807 if (sC == m_IgnoreCommentsMap.end())
809 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_yourFile.GetFilename()).MakeLower();
810 sC = m_IgnoreCommentsMap.find(sExt);
811 if (sC == m_IgnoreCommentsMap.end())
813 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_theirFile.GetFilename()).MakeLower();
814 sC = m_IgnoreCommentsMap.find(sExt);
817 if (sC != m_IgnoreCommentsMap.end())
818 m_Data.SetCommentTokens(std::get<0>(sC->second), std::get<1>(sC->second), std::get<2>(sC->second));
819 else
820 m_Data.SetCommentTokens(L"", L"", L"");
821 if (!m_Data.Load())
823 m_pwndLeftView->BuildAllScreen2ViewVector();
824 m_pwndLeftView->DocumentUpdated();
825 m_pwndRightView->DocumentUpdated();
826 m_pwndBottomView->DocumentUpdated();
827 m_wndLocatorBar.DocumentUpdated();
828 m_wndLineDiffBar.DocumentUpdated();
829 ::MessageBox(m_hWnd, m_Data.GetError(), L"TortoiseGitMerge", MB_ICONERROR);
830 m_Data.m_mergedFile.SetOutOfUse();
831 m_bSaveRequired = false;
832 return false;
834 SetWindowTitle();
835 m_pwndLeftView->BuildAllScreen2ViewVector();
836 m_pwndLeftView->DocumentUpdated();
837 m_pwndRightView->DocumentUpdated();
838 m_pwndBottomView->DocumentUpdated();
839 m_wndLocatorBar.DocumentUpdated();
840 m_wndLineDiffBar.DocumentUpdated();
842 m_pwndLeftView->SetWritable(false);
843 m_pwndLeftView->SetWritableIsChangable(false);
844 m_pwndLeftView->SetTarget(false);
845 m_pwndRightView->SetWritable(false);
846 m_pwndRightView->SetWritableIsChangable(false);
847 m_pwndRightView->SetTarget(false);
848 m_pwndBottomView->SetWritable(false);
849 m_pwndBottomView->SetWritableIsChangable(false);
850 m_pwndBottomView->SetTarget(false);
852 if (!m_Data.IsBaseFileInUse())
854 CSysProgressDlg progDlg;
855 if (m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
857 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
859 else if ((!m_Data.m_sDiffFile.IsEmpty())&&(!m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg)))
861 progDlg.Stop();
862 ClearViewNamesAndPaths();
863 MessageBox(m_Patch.GetErrorMessage(), nullptr, MB_ICONERROR);
864 m_bSaveRequired = false;
865 return false;
867 progDlg.Stop();
868 if (m_Patch.GetNumberOfFiles() > 0)
870 CString betterpatchpath = m_Patch.CheckPatchPath(m_Data.m_sPatchPath);
871 if (betterpatchpath.CompareNoCase(m_Data.m_sPatchPath)!=0)
873 CString msg;
874 msg.Format(IDS_WARNBETTERPATCHPATHFOUND, (LPCTSTR)m_Data.m_sPatchPath, (LPCTSTR)betterpatchpath);
875 CTaskDialog taskdlg(msg,
876 CString(MAKEINTRESOURCE(IDS_WARNBETTERPATCHPATHFOUND_TASK2)),
877 L"TortoiseGitMerge",
879 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
880 CString task3;
881 WCHAR t3[MAX_PATH] = { 0 };
882 CString cp = betterpatchpath.Left(MAX_PATH - 1);
883 PathCompactPathEx(t3, cp, 50, 0);
884 task3.Format(IDS_WARNBETTERPATCHPATHFOUND_TASK3, t3);
885 taskdlg.AddCommandControl(1, task3);
886 CString task4;
887 WCHAR t4[MAX_PATH] = { 0 };
888 cp = m_Data.m_sPatchPath.Left(MAX_PATH - 1);
889 PathCompactPathEx(t4, cp, 50, 0);
890 task4.Format(IDS_WARNBETTERPATCHPATHFOUND_TASK4, t4);
891 taskdlg.AddCommandControl(2, task4);
892 taskdlg.SetDefaultCommandControl(1);
893 taskdlg.SetMainIcon(TD_INFORMATION_ICON);
894 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
895 if (taskdlg.DoModal(m_hWnd) == 1)
897 m_Data.m_sPatchPath = betterpatchpath;
898 m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg);
901 m_dlgFilePatches.Init(&m_Patch, this, m_Data.m_sPatchPath, this);
902 m_dlgFilePatches.ShowWindow(SW_SHOW);
903 ClearViewNamesAndPaths();
904 if (!m_wndSplitter.IsRowHidden(1))
905 m_wndSplitter.HideRow(1);
906 m_pwndLeftView->SetHidden(FALSE);
907 m_pwndRightView->SetHidden(FALSE);
908 m_pwndBottomView->SetHidden(TRUE);
911 if (m_Data.IsBaseFileInUse() && !m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
913 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
915 if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && !m_Data.IsTheirFileInUse())
917 //diff between YOUR and BASE
918 if (m_bOneWay)
920 pwndActiveView = m_pwndLeftView;
921 if (!m_wndSplitter2.IsColumnHidden(1))
922 m_wndSplitter2.HideColumn(1);
924 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseBoth;
925 m_pwndLeftView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
926 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
927 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName() + L" - " + m_Data.m_yourFile.GetWindowName();
928 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename() + L" - " + m_Data.m_yourFile.GetFilename();
929 m_pwndLeftView->m_sReflectedName = m_Data.m_yourFile.GetReflectedName();
930 m_pwndLeftView->m_pWorkingFile = &m_Data.m_yourFile;
931 m_pwndLeftView->SetTarget();
932 m_pwndLeftView->SetWritableIsChangable(true);
934 m_pwndRightView->m_pViewData = nullptr;
935 m_pwndRightView->m_pWorkingFile = nullptr;
936 m_pwndBottomView->m_pViewData = nullptr;
937 m_pwndBottomView->m_pWorkingFile = nullptr;
939 if (!m_wndSplitter.IsRowHidden(1))
940 m_wndSplitter.HideRow(1);
941 m_pwndLeftView->SetHidden(FALSE);
942 m_pwndRightView->SetHidden(TRUE);
943 m_pwndBottomView->SetHidden(TRUE);
944 ::SetWindowPos(m_pwndLeftView->m_hWnd, nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
946 else
948 pwndActiveView = m_pwndRightView;
949 if (m_wndSplitter2.IsColumnHidden(1))
950 m_wndSplitter2.ShowColumn();
952 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseLeft;
953 m_pwndLeftView->SetTextType(m_Data.m_arBaseFile.GetUnicodeType());
954 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arBaseFile.GetLineEndings());
955 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName();
956 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename();
957 m_pwndLeftView->m_sConvertedFilePath = m_Data.m_baseFile.GetConvertedFileName();
958 m_pwndLeftView->m_sReflectedName = m_Data.m_baseFile.GetReflectedName();
959 m_pwndLeftView->m_pWorkingFile = &m_Data.m_baseFile;
960 m_pwndLeftView->SetWritableIsChangable(true);
962 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseRight;
963 m_pwndRightView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
964 m_pwndRightView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
965 m_pwndRightView->m_sWindowName = m_Data.m_yourFile.GetWindowName();
966 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
967 m_pwndRightView->m_sConvertedFilePath = m_Data.m_yourFile.GetConvertedFileName();
968 m_pwndRightView->m_sReflectedName = m_Data.m_yourFile.GetReflectedName();
969 m_pwndRightView->m_pWorkingFile = &m_Data.m_yourFile;
970 m_pwndRightView->SetWritable();
971 m_pwndRightView->SetTarget();
973 m_pwndBottomView->m_pViewData = nullptr;
974 m_pwndBottomView->m_pWorkingFile = nullptr;
976 if (!m_wndSplitter.IsRowHidden(1))
977 m_wndSplitter.HideRow(1);
978 m_pwndLeftView->SetHidden(FALSE);
979 m_pwndRightView->SetHidden(FALSE);
980 m_pwndBottomView->SetHidden(TRUE);
982 bool hasMods, hasConflicts, hasWhitespaceMods, hasFilteredMods;
983 pwndActiveView->CheckModifications(hasMods, hasConflicts, hasWhitespaceMods, hasFilteredMods);
984 if (!hasMods && !hasConflicts)
986 // files appear identical, show a dialog informing the user that there are or might
987 // be other differences
988 bool hasEncodingDiff = m_Data.m_arBaseFile.GetUnicodeType() != m_Data.m_arYourFile.GetUnicodeType();
989 bool hasEOLDiff = m_Data.m_arBaseFile.GetLineEndings() != m_Data.m_arYourFile.GetLineEndings();
990 if (hasWhitespaceMods || hasEncodingDiff || hasEOLDiff)
992 // text is identical, but the files do not match
993 CString sWarning(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_MAIN));
994 CString sWhitespace(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_WHITESPACE));
995 CString sEncoding(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_ENCODING));
996 CString sEOL(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_EOL));
997 if (hasWhitespaceMods)
999 sWarning += L"\r\n";
1000 sWarning += sWhitespace;
1002 if (hasEncodingDiff)
1004 sWarning += L"\r\n";
1005 sWarning += sEncoding;
1006 sWarning += L" (";
1007 sWarning += m_Data.m_arBaseFile.GetEncodingName(m_Data.m_arBaseFile.GetUnicodeType());
1008 sWarning += L", ";
1009 sWarning += m_Data.m_arYourFile.GetEncodingName(m_Data.m_arYourFile.GetUnicodeType());
1010 sWarning += L")";
1012 if (hasEOLDiff)
1014 sWarning += L"\r\n";
1015 sWarning += sEOL;
1017 AfxMessageBox(sWarning, MB_ICONINFORMATION);
1021 else if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
1023 //diff between THEIR, YOUR and BASE
1024 m_pwndBottomView->SetWritable();
1025 m_pwndBottomView->SetTarget();
1026 pwndActiveView = m_pwndBottomView;
1028 m_pwndLeftView->m_pViewData = &m_Data.m_TheirBaseBoth;
1029 m_pwndLeftView->SetTextType(m_Data.m_arTheirFile.GetUnicodeType());
1030 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arTheirFile.GetLineEndings());
1031 m_pwndLeftView->m_sWindowName = m_Data.m_theirFile.GetWindowName(IDS_VIEWTITLE_THEIRS);
1032 m_pwndLeftView->m_sFullFilePath = m_Data.m_theirFile.GetFilename();
1033 m_pwndLeftView->m_sConvertedFilePath = m_Data.m_theirFile.GetConvertedFileName();
1034 m_pwndLeftView->m_sReflectedName = m_Data.m_theirFile.GetReflectedName();
1035 m_pwndLeftView->m_pWorkingFile = &m_Data.m_theirFile;
1037 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseBoth;
1038 m_pwndRightView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
1039 m_pwndRightView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
1040 m_pwndRightView->m_sWindowName = m_Data.m_yourFile.GetWindowName(IDS_VIEWTITLE_MINE);
1041 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
1042 m_pwndRightView->m_sConvertedFilePath = m_Data.m_yourFile.GetConvertedFileName();
1043 m_pwndRightView->m_sReflectedName = m_Data.m_yourFile.GetReflectedName();
1044 m_pwndRightView->m_pWorkingFile = &m_Data.m_yourFile;
1046 m_pwndBottomView->m_pViewData = &m_Data.m_Diff3;
1047 m_pwndBottomView->SetTextType(m_Data.m_arTheirFile.GetUnicodeType());
1048 m_pwndBottomView->SetLineEndingStyle(m_Data.m_arTheirFile.GetLineEndings());
1049 m_pwndBottomView->m_sWindowName.LoadString(IDS_VIEWTITLE_MERGED);
1050 m_pwndBottomView->m_sWindowName += L" - " + m_Data.m_mergedFile.GetWindowName();
1051 m_pwndBottomView->m_sFullFilePath = m_Data.m_mergedFile.GetFilename();
1052 m_pwndBottomView->m_sConvertedFilePath = m_Data.m_mergedFile.GetConvertedFileName();
1053 m_pwndBottomView->m_sReflectedName = m_Data.m_mergedFile.GetReflectedName();
1054 m_pwndBottomView->m_pWorkingFile = &m_Data.m_mergedFile;
1056 if (m_wndSplitter2.IsColumnHidden(1))
1057 m_wndSplitter2.ShowColumn();
1058 if (m_wndSplitter.IsRowHidden(1))
1059 m_wndSplitter.ShowRow();
1060 m_pwndLeftView->SetHidden(FALSE);
1061 m_pwndRightView->SetHidden(FALSE);
1062 m_pwndBottomView->SetHidden(FALSE);
1063 // in three pane view, hide the line diff bar
1064 m_wndLineDiffBar.ShowPane(false, false, true);
1065 m_wndLineDiffBar.DocumentUpdated();
1067 if (!m_Data.m_mergedFile.InUse())
1069 m_Data.m_mergedFile.SetFileName(m_Data.m_yourFile.GetFilename());
1071 m_pwndLeftView->BuildAllScreen2ViewVector();
1072 m_pwndLeftView->DocumentUpdated();
1073 m_pwndRightView->DocumentUpdated();
1074 m_pwndBottomView->DocumentUpdated();
1075 m_wndLocatorBar.DocumentUpdated();
1076 m_wndLineDiffBar.DocumentUpdated();
1077 UpdateLayout();
1078 SetActiveView(pwndActiveView);
1080 if ((line >= -1) && m_pwndRightView->m_pViewData)
1082 int n = line == -1 ? min( nOldLineNumber, nOldLine ) : line;
1083 if (n >= 0)
1085 n = m_pwndRightView->m_pViewData->FindLineNumber(n);
1086 if (m_bCollapsed)
1088 // adjust the goto-line position if we're collapsed
1089 int step = m_pwndRightView->m_nTopLine > n ? -1 : 1;
1090 int skip = 0;
1091 for (int i = m_pwndRightView->m_nTopLine; i != n; i += step)
1093 if (m_pwndRightView->m_pViewData->GetHideState(i) == HIDESTATE_HIDDEN)
1094 ++skip;
1096 if (m_pwndRightView->m_pViewData->GetHideState(n) == HIDESTATE_HIDDEN)
1097 OnViewTextFoldUnfold();
1098 else
1099 n = n + (skip * step * -1);
1102 if (n < 0)
1103 n = nOldLine;
1105 m_pwndRightView->ScrollAllToLine(n);
1106 POINT p;
1107 p.x = 0;
1108 p.y = n;
1109 if ((ptOldCaretPos.x >= 0) || (ptOldCaretPos.y >= 0))
1110 p = ptOldCaretPos;
1111 m_pwndLeftView->SetCaretPosition(p);
1112 m_pwndRightView->SetCaretPosition(p);
1113 m_pwndBottomView->SetCaretPosition(p);
1114 m_pwndBottomView->ScrollToChar(0);
1115 m_pwndLeftView->ScrollToChar(0);
1116 m_pwndRightView->ScrollToChar(0);
1118 else
1120 CRegDWORD regFirstDiff = CRegDWORD(L"Software\\TortoiseGitMerge\\FirstDiffOnLoad", TRUE);
1121 CRegDWORD regFirstConflict = CRegDWORD(L"Software\\TortoiseGitMerge\\FirstConflictOnLoad", TRUE);
1122 bool bGoFirstDiff = (0 != (DWORD)regFirstDiff);
1123 bool bGoFirstConflict = (0 != (DWORD)regFirstConflict);
1124 if (bGoFirstConflict && (CheckResolved()>=0))
1126 pwndActiveView->GoToFirstConflict();
1127 // Ignore the first few Mouse Move messages, so that the line diff stays on
1128 // the first diff line until the user actually moves the mouse
1129 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1131 else if (bGoFirstDiff)
1133 pwndActiveView->GoToFirstDifference();
1134 // Ignore the first few Mouse Move messages, so that the line diff stays on
1135 // the first diff line until the user actually moves the mouse
1136 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1138 else
1140 // Avoid incorrect rendering of active pane.
1141 m_pwndBottomView->ScrollToChar(0);
1142 m_pwndLeftView->ScrollToChar(0);
1143 m_pwndRightView->ScrollToChar(0);
1146 CheckResolved();
1147 if (m_bHasConflicts && !m_bSaveRequiredOnConflicts)
1148 m_bSaveRequired = false;
1149 CUndo::GetInstance().Clear();
1150 return true;
1153 void CMainFrame::UpdateLayout()
1155 if (m_bInitSplitter)
1157 m_wndSplitter.CenterSplitter();
1158 m_wndSplitter2.CenterSplitter();
1162 void CMainFrame::RecalcLayout(BOOL bNotify)
1164 GetClientRect(&m_dockManager.m_rectInPlace);
1165 if (m_pRibbonApp)
1166 m_dockManager.m_rectInPlace.top += m_pRibbonApp->GetRibbonHeight();
1167 CFrameWndEx::RecalcLayout(bNotify);
1170 void CMainFrame::OnSize(UINT nType, int cx, int cy)
1172 CFrameWndEx::OnSize(nType, cx, cy);
1173 if (m_bInitSplitter && nType != SIZE_MINIMIZED)
1175 if (m_wndSplitter.GetSafeHwnd())
1177 if (m_wndSplitter.HasOldRowSize() && (m_wndSplitter.GetOldRowCount() == 2))
1179 int oldTotal = m_wndSplitter.GetOldRowSize(0) + m_wndSplitter.GetOldRowSize(1);
1180 if (oldTotal)
1182 int cxCur0, cxCur1, cxMin0, cxMin1;
1183 m_wndSplitter.GetRowInfo(0, cxCur0, cxMin0);
1184 m_wndSplitter.GetRowInfo(1, cxCur1, cxMin1);
1185 cxCur0 = m_wndSplitter.GetOldRowSize(0) * (cxCur0 + cxCur1) / oldTotal;
1186 cxCur1 = m_wndSplitter.GetOldRowSize(1) * (cxCur0 + cxCur1) / oldTotal;
1187 m_wndSplitter.SetRowInfo(0, cxCur0, 0);
1188 m_wndSplitter.SetRowInfo(1, cxCur1, 0);
1189 m_wndSplitter.RecalcLayout();
1193 if (m_wndSplitter2.HasOldColSize() && (m_wndSplitter2.GetOldColCount() == 2))
1195 int oldTotal = m_wndSplitter2.GetOldColSize(0) + m_wndSplitter2.GetOldColSize(1);
1196 if (oldTotal)
1198 int cyCur0, cyCur1, cyMin0, cyMin1;
1199 m_wndSplitter2.GetColumnInfo(0, cyCur0, cyMin0);
1200 m_wndSplitter2.GetColumnInfo(1, cyCur1, cyMin1);
1201 cyCur0 = m_wndSplitter2.GetOldColSize(0) * (cyCur0 + cyCur1) / oldTotal;
1202 cyCur1 = m_wndSplitter2.GetOldColSize(1) * (cyCur0 + cyCur1) / oldTotal;
1203 m_wndSplitter2.SetColumnInfo(0, cyCur0, 0);
1204 m_wndSplitter2.SetColumnInfo(1, cyCur1, 0);
1205 m_wndSplitter2.RecalcLayout();
1210 if ((nType == SIZE_RESTORED)&&m_bCheckReload)
1212 m_bCheckReload = false;
1213 CheckForReload();
1217 void CMainFrame::OnViewWhitespaces()
1219 CRegDWORD regViewWhitespaces = CRegDWORD(L"Software\\TortoiseGitMerge\\ViewWhitespaces", 1);
1220 BOOL bViewWhitespaces = regViewWhitespaces;
1221 if (m_pwndLeftView)
1222 bViewWhitespaces = m_pwndLeftView->m_bViewWhitespace;
1224 bViewWhitespaces = !bViewWhitespaces;
1225 regViewWhitespaces = bViewWhitespaces;
1226 if (m_pwndLeftView)
1228 m_pwndLeftView->m_bViewWhitespace = bViewWhitespaces;
1229 m_pwndLeftView->Invalidate();
1231 if (m_pwndRightView)
1233 m_pwndRightView->m_bViewWhitespace = bViewWhitespaces;
1234 m_pwndRightView->Invalidate();
1236 if (m_pwndBottomView)
1238 m_pwndBottomView->m_bViewWhitespace = bViewWhitespaces;
1239 m_pwndBottomView->Invalidate();
1243 void CMainFrame::OnUpdateViewWhitespaces(CCmdUI *pCmdUI)
1245 if (m_pwndLeftView)
1246 pCmdUI->SetCheck(m_pwndLeftView->m_bViewWhitespace);
1249 void CMainFrame::OnViewCollapsed()
1251 m_regCollapsed = !(DWORD)m_regCollapsed;
1252 m_bCollapsed = !!(DWORD)m_regCollapsed;
1254 OnViewTextFoldUnfold();
1255 m_wndLocatorBar.Invalidate();
1258 void CMainFrame::OnUpdateViewCollapsed(CCmdUI *pCmdUI)
1260 pCmdUI->SetCheck(m_bCollapsed);
1263 void CMainFrame::OnViewWraplonglines()
1265 m_bWrapLines = !(DWORD)m_regWrapLines;
1266 m_regWrapLines = m_bWrapLines;
1268 if (m_pwndLeftView) m_pwndLeftView ->WrapChanged();
1269 if (m_pwndRightView) m_pwndRightView ->WrapChanged();
1270 if (m_pwndBottomView) m_pwndBottomView->WrapChanged();
1271 OnViewTextFoldUnfold();
1272 m_wndLocatorBar.DocumentUpdated();
1275 void CMainFrame::OnViewTextFoldUnfold()
1277 OnViewTextFoldUnfold(m_pwndLeftView);
1278 OnViewTextFoldUnfold(m_pwndRightView);
1279 OnViewTextFoldUnfold(m_pwndBottomView);
1282 void CMainFrame::OnViewTextFoldUnfold(CBaseView* view)
1284 if (view == 0)
1285 return;
1286 view->BuildAllScreen2ViewVector();
1287 view->UpdateCaret();
1288 view->Invalidate();
1289 view->EnsureCaretVisible();
1292 void CMainFrame::OnUpdateViewWraplonglines(CCmdUI *pCmdUI)
1294 pCmdUI->SetCheck(m_bWrapLines);
1297 void CMainFrame::OnViewOnewaydiff()
1299 if (CheckForSave(CHFSR_RELOAD)==IDCANCEL)
1300 return;
1301 m_bOneWay = !m_bOneWay;
1302 ShowDiffBar(!m_bOneWay);
1303 LoadViews(-1);
1306 void CMainFrame::DiffLeftToBase()
1308 DiffTwo(m_Data.m_baseFile, m_Data.m_theirFile);
1311 void CMainFrame::DiffRightToBase()
1313 DiffTwo(m_Data.m_baseFile, m_Data.m_yourFile);
1316 void CMainFrame::DiffTwo(const CWorkingFile& file1, const CWorkingFile& file2)
1318 wchar_t ownpath[MAX_PATH] = { 0 };
1319 GetModuleFileName(nullptr, ownpath, MAX_PATH);
1320 CString sCmd;
1321 sCmd.Format(L"\"%s\"", ownpath);
1322 sCmd += L" /base:\"";
1323 sCmd += file1.GetFilename();
1324 sCmd += L"\" /mine:\"";
1325 sCmd += file2.GetFilename();
1326 sCmd += L'"';
1327 if (!file1.GetWindowName().IsEmpty())
1328 sCmd += L" /basename:\"" + file1.GetWindowName() + L"\"";
1329 if (!file2.GetWindowName().IsEmpty())
1330 sCmd += L" /yourname:\"" + file2.GetWindowName() + L"\"";
1332 CAppUtils::LaunchApplication(sCmd, 0, false);
1335 void CMainFrame::ShowDiffBar(bool bShow)
1337 if (bShow)
1339 // restore the line diff bar
1340 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
1341 m_wndLineDiffBar.DocumentUpdated();
1342 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
1343 m_wndLocatorBar.DocumentUpdated();
1345 else
1347 // in one way view, hide the line diff bar
1348 m_wndLineDiffBar.ShowPane(false, false, true);
1349 m_wndLineDiffBar.DocumentUpdated();
1353 int CMainFrame::CheckResolved()
1355 //only in three way diffs can be conflicts!
1356 m_bHasConflicts = true;
1357 if (IsViewGood(m_pwndBottomView))
1359 CViewData* viewdata = m_pwndBottomView->m_pViewData;
1360 if (viewdata)
1362 for (int i=0; i<viewdata->GetCount(); i++)
1364 const DiffStates state = viewdata->GetState(i);
1365 if ((DIFFSTATE_CONFLICTED == state)||(DIFFSTATE_CONFLICTED_IGNORED == state))
1366 return i;
1370 m_bHasConflicts = false;
1371 return -1;
1374 int CMainFrame::SaveFile(const CString& sFilePath)
1376 CBaseView* pView = nullptr;
1377 CViewData* pViewData = nullptr;
1378 CFileTextLines * pOriginFile = &m_Data.m_arBaseFile;
1379 if (IsViewGood(m_pwndBottomView))
1381 pView = m_pwndBottomView;
1382 pViewData = m_pwndBottomView->m_pViewData;
1384 else if (IsViewGood(m_pwndRightView))
1386 pView = m_pwndRightView;
1387 pViewData = m_pwndRightView->m_pViewData;
1388 if (m_Data.IsYourFileInUse())
1389 pOriginFile = &m_Data.m_arYourFile;
1390 else if (m_Data.IsTheirFileInUse())
1391 pOriginFile = &m_Data.m_arTheirFile;
1393 else
1395 // nothing to save!
1396 return 1;
1398 Invalidate();
1399 if ((pViewData)&&(pOriginFile))
1401 CFileTextLines file;
1402 pOriginFile->CopySettings(&file);
1403 CFileTextLines::SaveParams saveParams;
1404 saveParams.m_LineEndings = pView->GetLineEndings();
1405 saveParams.m_UnicodeType = pView->GetTextType();
1406 file.SetSaveParams(saveParams);
1407 for (int i=0; i<pViewData->GetCount(); i++)
1409 //only copy non-removed lines
1410 DiffStates state = pViewData->GetState(i);
1411 switch (state)
1413 case DIFFSTATE_CONFLICTED:
1414 case DIFFSTATE_CONFLICTED_IGNORED:
1416 int first = i;
1417 int last = i;
1420 last++;
1421 } while((last<pViewData->GetCount()) && ((pViewData->GetState(last)==DIFFSTATE_CONFLICTED)||(pViewData->GetState(last)==DIFFSTATE_CONFLICTED_IGNORED)));
1422 // TortoiseGitMerge changes here
1423 file.Add(L"<<<<<<< .mine", m_pwndRightView->GetLineEndings());
1424 for (int j=first; j<last; j++)
1426 EOL lineending = m_pwndRightView->m_pViewData->GetLineEnding(j);
1427 if (lineending == EOL_NOENDING)
1428 lineending = m_pwndRightView->GetLineEndings();
1429 file.Add(m_pwndRightView->m_pViewData->GetLine(j), lineending);
1431 file.Add(L"=======", m_pwndRightView->GetLineEndings());
1432 for (int j=first; j<last; j++)
1434 EOL lineending = m_pwndLeftView->m_pViewData->GetLineEnding(j);
1435 if (lineending == EOL_NOENDING)
1436 lineending = m_pwndLeftView->GetLineEndings();
1437 file.Add(m_pwndLeftView->m_pViewData->GetLine(j), lineending);
1439 file.Add(L">>>>>>> .theirs", m_pwndRightView->GetLineEndings());
1440 i = last-1;
1442 break;
1443 case DIFFSTATE_EMPTY:
1444 case DIFFSTATE_CONFLICTEMPTY:
1445 case DIFFSTATE_IDENTICALREMOVED:
1446 case DIFFSTATE_REMOVED:
1447 case DIFFSTATE_THEIRSREMOVED:
1448 case DIFFSTATE_YOURSREMOVED:
1449 case DIFFSTATE_CONFLICTRESOLVEDEMPTY:
1450 // do not save removed lines
1451 break;
1452 default:
1453 file.Add(pViewData->GetLine(i), pViewData->GetLineEnding(i));
1454 break;
1457 if (!file.Save(sFilePath, false, false))
1459 CMessageBox::Show(m_hWnd, file.GetErrorString(), L"TortoiseGitMerge", MB_ICONERROR);
1460 return -1;
1462 if (sFilePath == m_Data.m_baseFile.GetFilename())
1464 m_Data.m_baseFile.StoreFileAttributes();
1466 if (sFilePath == m_Data.m_theirFile.GetFilename())
1468 m_Data.m_theirFile.StoreFileAttributes();
1470 if (sFilePath == m_Data.m_yourFile.GetFilename())
1472 m_Data.m_yourFile.StoreFileAttributes();
1474 /*if (sFilePath == m_Data.m_mergedFile.GetFilename())
1476 m_Data.m_mergedFile.StoreFileAttributes();
1477 }//*/
1478 m_dlgFilePatches.SetFileStatusAsPatched(sFilePath);
1479 if (IsViewGood(m_pwndBottomView))
1480 m_pwndBottomView->SetModified(FALSE);
1481 else if (IsViewGood(m_pwndRightView))
1482 m_pwndRightView->SetModified(FALSE);
1483 CUndo::GetInstance().MarkAsOriginalState(
1484 false,
1485 IsViewGood(m_pwndRightView) && (pViewData == m_pwndRightView->m_pViewData),
1486 IsViewGood(m_pwndBottomView) && (pViewData == m_pwndBottomView->m_pViewData));
1487 if (file.GetCount() == 1 && file.GetAt(0).IsEmpty() && file.GetLineEnding(0) == EOL_NOENDING)
1488 return 0;
1489 return file.GetCount();
1491 return 1;
1494 void CMainFrame::OnFileSave()
1496 // when multiple files are set as writable we have to ask what file to save
1497 int nEditableViewCount =
1498 (CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsWritable() ? 1 : 0)
1499 + (CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsWritable() ? 1 : 0)
1500 + (CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsWritable() ? 1 : 0);
1501 bool bLeftIsModified = CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsModified();
1502 bool bRightIsModified = CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsModified();
1503 bool bBottomIsModified = CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsModified();
1504 int nModifiedViewCount =
1505 (bLeftIsModified ? 1 : 0)
1506 + (bRightIsModified ? 1 : 0)
1507 + (bBottomIsModified ? 1 : 0);
1508 if (nEditableViewCount>1)
1510 if (nModifiedViewCount == 1)
1512 if (bLeftIsModified)
1513 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1514 else
1515 FileSave();
1517 else if (nModifiedViewCount>0)
1519 // both views
1520 CTaskDialog taskdlg(CString(MAKEINTRESOURCE(IDS_SAVE_MORE)),
1521 CString(MAKEINTRESOURCE(IDS_SAVE)),
1522 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1524 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
1525 CString sTaskTemp;
1526 if (m_pwndLeftView->m_pWorkingFile->InUse() && !m_pwndLeftView->m_pWorkingFile->IsReadonly())
1527 sTaskTemp.Format(IDS_ASKFORSAVE_SAVELEFT, (LPCTSTR)m_pwndLeftView->m_pWorkingFile->GetFilename());
1528 else
1529 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS));
1530 taskdlg.AddCommandControl(201, sTaskTemp, bLeftIsModified);// left
1531 if (bLeftIsModified)
1532 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);
1540 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEALL2)), nModifiedViewCount>1); // both
1541 if (nModifiedViewCount > 1)
1542 taskdlg.SetDefaultCommandControl(203);
1543 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1544 taskdlg.SetMainIcon(TD_WARNING_ICON);
1545 UINT ret = (UINT)taskdlg.DoModal(m_hWnd);
1546 switch (ret)
1548 case 201: // left
1549 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1550 break;
1551 case 203: // both
1552 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1553 case 202: // right
1554 m_pwndRightView->SaveFile();
1555 break;
1559 else
1561 // only target view was modified
1562 FileSave();
1566 void CMainFrame::PatchSave()
1568 bool bDoesNotExist = !PathFileExists(m_Data.m_mergedFile.GetFilename());
1569 if (m_Data.m_bPatchRequired)
1571 m_Patch.PatchPath(m_Data.m_mergedFile.GetFilename());
1573 if (!PathIsDirectory(m_Data.m_mergedFile.GetFilename()))
1575 int saveret = SaveFile(m_Data.m_mergedFile.GetFilename());
1576 if (saveret==0)
1578 // file was saved with 0 lines, remove it.
1579 m_Patch.RemoveFile(m_Data.m_mergedFile.GetFilename());
1580 // just in case
1581 DeleteFile(m_Data.m_mergedFile.GetFilename());
1583 m_Data.m_mergedFile.StoreFileAttributes();
1584 if (m_Data.m_mergedFile.GetFilename() == m_Data.m_yourFile.GetFilename())
1585 m_Data.m_yourFile.StoreFileAttributes();
1586 if (bDoesNotExist && (DWORD(CRegDWORD(L"Software\\TortoiseGitMerge\\AutoAdd", TRUE))))
1588 // call TortoiseProc to add the new file to version control
1589 CString cmd = L"/command:add /noui /path:\"";
1590 cmd += m_Data.m_mergedFile.GetFilename() + L'"';
1591 CAppUtils::RunTortoiseGitProc(cmd);
1596 bool CMainFrame::FileSave(bool bCheckResolved /*=true*/)
1598 if (HasMarkedBlocks())
1600 CString sTitle(MAKEINTRESOURCE(IDS_WARNMARKEDBLOCKS));
1601 CString sSubTitle(MAKEINTRESOURCE(IDS_ASKFORSAVE_MARKEDBLOCKS));
1602 CString sAppName(MAKEINTRESOURCE(IDS_APPNAME));
1603 CTaskDialog taskdlg(sTitle,
1604 sSubTitle,
1605 sAppName,
1607 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
1608 taskdlg.AddCommandControl(10, CString(MAKEINTRESOURCE(IDS_MARKEDBLOCKSSAVEINCLUDE)));
1609 taskdlg.AddCommandControl(11, CString(MAKEINTRESOURCE(IDS_MARKEDBLOCKSSAVEEXCLUDE)));
1610 taskdlg.AddCommandControl(12, CString(MAKEINTRESOURCE(IDS_MARKEDBLCOKSSAVEIGNORE)));
1611 taskdlg.AddCommandControl(IDCANCEL, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_CANCEL_OPEN)));
1612 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1613 taskdlg.SetDefaultCommandControl(10);
1614 taskdlg.SetMainIcon(TD_WARNING_ICON);
1615 UINT ret = (UINT)taskdlg.DoModal(m_hWnd);
1616 if (ret == 10)
1617 m_pwndRightView->LeaveOnlyMarkedBlocks();
1618 else if (ret == 11)
1619 m_pwndRightView->UseViewFileOfMarked();
1620 else if (ret == 12)
1621 m_pwndRightView->UseViewFileExceptEdited();
1622 else
1623 return false;
1626 if (!m_Data.m_mergedFile.InUse())
1627 return FileSaveAs(bCheckResolved);
1628 // check if the file has the readonly attribute set
1629 bool bDoesNotExist = false;
1630 DWORD fAttribs = GetFileAttributes(m_Data.m_mergedFile.GetFilename());
1631 if ((fAttribs != INVALID_FILE_ATTRIBUTES)&&(fAttribs & FILE_ATTRIBUTE_READONLY))
1632 return FileSaveAs(bCheckResolved);
1633 if (fAttribs == INVALID_FILE_ATTRIBUTES)
1635 bDoesNotExist = (GetLastError() == ERROR_FILE_NOT_FOUND);
1637 if (bCheckResolved && HasConflictsWontKeep())
1638 return false;
1640 if (((DWORD)CRegDWORD(L"Software\\TortoiseGitMerge\\Backup")) != 0)
1642 MoveFileEx(m_Data.m_mergedFile.GetFilename(), m_Data.m_mergedFile.GetFilename() + L".bak", MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
1644 if (m_Data.m_bPatchRequired)
1646 m_Patch.PatchPath(m_Data.m_mergedFile.GetFilename());
1648 int saveret = SaveFile(m_Data.m_mergedFile.GetFilename());
1649 if (saveret==0)
1651 // file was saved with 0 lines!
1652 // ask the user if the file should be deleted
1653 CString msg;
1654 msg.Format(IDS_DELETEWHENEMPTY, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1655 CTaskDialog taskdlg(msg,
1656 CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK2)),
1657 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1659 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
1660 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK3)));
1661 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK4)));
1662 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1663 taskdlg.SetDefaultCommandControl(1);
1664 taskdlg.SetMainIcon(TD_WARNING_ICON);
1665 if (taskdlg.DoModal(m_hWnd) == 1)
1667 m_Patch.RemoveFile(m_Data.m_mergedFile.GetFilename());
1668 DeleteFile(m_Data.m_mergedFile.GetFilename());
1671 else if (saveret < 0)
1673 // error while saving the file
1674 return false;
1677 // if we're in conflict resolve mode (three pane view), check if there are no more conflicts
1678 // and if there aren't, ask to mark the file as resolved
1679 if (IsViewGood(m_pwndBottomView) && !m_bHasConflicts && bCheckResolved)
1681 CString projectRoot;
1682 if (GitAdminDir::HasAdminDir(m_Data.m_mergedFile.GetFilename(), false, &projectRoot))
1684 CString subpath = m_Data.m_mergedFile.GetFilename();
1685 subpath.Replace(L'\\', L'/');
1686 if (subpath.GetLength() >= projectRoot.GetLength())
1688 if (subpath[projectRoot.GetLength()] == L'/')
1689 subpath = subpath.Right(subpath.GetLength() - projectRoot.GetLength() - 1);
1690 else
1691 subpath = subpath.Right(subpath.GetLength() - projectRoot.GetLength());
1694 CAutoRepository repository(projectRoot);
1695 bool hasConflictInIndex = false;
1698 if (!repository)
1699 break;
1701 CAutoIndex index;
1702 if (git_repository_index(index.GetPointer(), repository))
1703 break;
1705 CStringA path = CUnicodeUtils::GetMulti(subpath, CP_UTF8);
1706 hasConflictInIndex = git_index_get_bypath(index, path, 1) || git_index_get_bypath(index, path, 2);
1707 } while(0);
1709 if (hasConflictInIndex)
1711 CString msg;
1712 msg.Format(IDS_MARKASRESOLVED, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1713 CTaskDialog taskdlg(msg,
1714 CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK2)),
1715 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1717 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
1718 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK3)));
1719 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK4)));
1720 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1721 taskdlg.SetDefaultCommandControl(1);
1722 taskdlg.SetMainIcon(TD_WARNING_ICON);
1723 if (taskdlg.DoModal(m_hWnd) == 1)
1724 MarkAsResolved();
1729 m_bSaveRequired = false;
1730 m_Data.m_mergedFile.StoreFileAttributes();
1732 if (bDoesNotExist && (DWORD(CRegDWORD(L"Software\\TortoiseGitMerge\\AutoAdd", TRUE))))
1734 // call TortoiseProc to add the new file to version control
1735 CString cmd = L"/command:add /noui /path:\"";
1736 cmd += m_Data.m_mergedFile.GetFilename() + L'"';
1737 if(!CAppUtils::RunTortoiseGitProc(cmd))
1738 return false;
1740 return true;
1743 void CMainFrame::OnFileSaveAs()
1745 // ask what file to save as
1746 bool bHaveConflict = (CheckResolved() >= 0);
1747 CTaskDialog taskdlg(
1748 CString(MAKEINTRESOURCE(bHaveConflict ? IDS_ASKFORSAVEAS_MORECONFLICT : IDS_ASKFORSAVEAS_MORE)),
1749 CString(MAKEINTRESOURCE(IDS_ASKFORSAVEAS)),
1750 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1752 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
1753 // default can be last view (target) as was in 1.7 or actual (where is cursor) as is in most text editor
1754 if (IsViewGood(m_pwndLeftView))
1756 taskdlg.AddCommandControl(201, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS))); // left
1757 taskdlg.SetDefaultCommandControl(201);
1759 if (IsViewGood(m_pwndRightView))
1761 taskdlg.AddCommandControl(202, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS))); // right
1762 taskdlg.SetDefaultCommandControl(202);
1764 if (IsViewGood(m_pwndBottomView))
1766 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEBOTTOMAS))); // bottom
1767 taskdlg.SetDefaultCommandControl(203);
1769 if (bHaveConflict)
1771 taskdlg.AddCommandControl(204, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_NEEDRESOLVE))); // resolve
1772 taskdlg.SetDefaultCommandControl(204);
1774 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1775 taskdlg.SetMainIcon(bHaveConflict ? TD_WARNING_ICON : TD_INFORMATION_ICON);
1776 int nCommand = (int)taskdlg.DoModal(m_hWnd);
1777 CString sFileName;
1778 switch (nCommand)
1780 case 201: // left
1781 if (TryGetFileName(sFileName))
1783 // in 2, 3 view display we want to keep removed lines
1784 m_pwndLeftView->SaveFileTo(sFileName, IsViewGood(m_pwndRightView) ? SAVE_REMOVEDLINES : 0);
1786 break;
1787 case 202: // right
1788 if (TryGetFileName(sFileName))
1790 m_pwndRightView->SaveFileTo(sFileName);
1792 break;
1793 case 203: // bottom
1794 FileSaveAs();
1795 break;
1796 case 204: // continue resolving
1797 if (IsViewGood(m_pwndBottomView))
1799 m_pwndBottomView->GoToLine(CheckResolved());
1801 break;
1805 bool CMainFrame::FileSaveAs(bool bCheckResolved /*=true*/)
1807 if (bCheckResolved && HasConflictsWontKeep())
1808 return false;
1810 CString fileName;
1811 if(!TryGetFileName(fileName))
1812 return false;
1814 SaveFile(fileName);
1815 return true;
1818 void CMainFrame::OnUpdateFileSave(CCmdUI *pCmdUI)
1820 BOOL bEnable = FALSE;
1821 if (m_Data.m_mergedFile.InUse())
1823 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1824 bEnable = TRUE;
1825 else if ( (IsViewGood(m_pwndRightView)&&(m_pwndRightView->m_pViewData)) &&
1826 (m_pwndRightView->IsModified() || (m_Data.m_yourFile.GetWindowName().Right(9).Compare(L": patched") == 0)))
1827 bEnable = TRUE;
1828 else if (IsViewGood(m_pwndLeftView)
1829 && (m_pwndLeftView->m_pViewData)
1830 && (m_pwndLeftView->IsModified()))
1831 bEnable = TRUE;
1833 pCmdUI->Enable(bEnable);
1836 void CMainFrame::OnUpdateFileSaveAs(CCmdUI *pCmdUI)
1838 // any file is open we can save it as
1839 BOOL bEnable = FALSE;
1840 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1841 bEnable = TRUE;
1842 else if (IsViewGood(m_pwndRightView)&&(m_pwndRightView->m_pViewData))
1843 bEnable = TRUE;
1844 else if (IsViewGood(m_pwndLeftView)&&(m_pwndLeftView->m_pViewData))
1845 bEnable = TRUE;
1846 pCmdUI->Enable(bEnable);
1849 void CMainFrame::OnUpdateViewOnewaydiff(CCmdUI *pCmdUI)
1851 pCmdUI->SetCheck(!m_bOneWay);
1852 BOOL bEnable = TRUE;
1853 if (IsViewGood(m_pwndBottomView))
1855 bEnable = FALSE;
1857 pCmdUI->Enable(bEnable);
1860 void CMainFrame::OnViewOptions()
1862 CString sTemp;
1863 sTemp.LoadString(IDS_SETTINGSTITLE);
1864 CSettings dlg(sTemp);
1865 dlg.DoModal();
1866 if (dlg.IsReloadNeeded())
1868 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
1869 return;
1870 CDiffColors::GetInstance().LoadRegistry();
1871 LoadViews();
1872 return;
1874 CDiffColors::GetInstance().LoadRegistry();
1875 if (m_pwndBottomView)
1876 m_pwndBottomView->Invalidate();
1877 if (m_pwndLeftView)
1878 m_pwndLeftView->Invalidate();
1879 if (m_pwndRightView)
1880 m_pwndRightView->Invalidate();
1883 void CMainFrame::OnClose()
1885 if (!IsWindowEnabled())
1886 return; // just in case someone sends a WM_CLOSE to the main window while another window (dialog,...) is open
1887 if (CheckForSave(CHFSR_CLOSE)!=IDCANCEL)
1889 WINDOWPLACEMENT wp;
1891 // before it is destroyed, save the position of the window
1892 wp.length = sizeof wp;
1894 if (GetWindowPlacement(&wp))
1897 if (IsIconic())
1898 // never restore to Iconic state
1899 wp.showCmd = SW_SHOW ;
1901 if ((wp.flags & WPF_RESTORETOMAXIMIZED) != 0)
1902 // if maximized and maybe iconic restore maximized state
1903 wp.showCmd = SW_SHOWMAXIMIZED ;
1905 // and write it
1906 WriteWindowPlacement(&wp);
1908 __super::OnClose();
1912 void CMainFrame::OnActivate(UINT nValue, CWnd* /*pwnd*/, BOOL /*bActivated?*/)
1914 if (nValue != 0) // activated
1916 if (IsIconic())
1918 m_bCheckReload = TRUE;
1920 else
1922 // use a timer to give other messages time to get processed
1923 // first, like e.g. the WM_CLOSE message in case the user
1924 // clicked the close button and that brought the window
1925 // to the front - in that case checking for reload wouldn't
1926 // do any good.
1927 SetTimer(IDT_RELOADCHECKTIMER, 300, nullptr);
1932 void CMainFrame::OnViewLinedown()
1934 OnViewLineUpDown(1);
1937 void CMainFrame::OnViewLineup()
1939 OnViewLineUpDown(-1);
1942 void CMainFrame::OnViewLineUpDown(int direction)
1944 if (m_pwndLeftView)
1945 m_pwndLeftView->ScrollToLine(m_pwndLeftView->m_nTopLine+direction);
1946 if (m_pwndRightView)
1947 m_pwndRightView->ScrollToLine(m_pwndRightView->m_nTopLine+direction);
1948 if (m_pwndBottomView)
1949 m_pwndBottomView->ScrollToLine(m_pwndBottomView->m_nTopLine+direction);
1950 m_wndLocatorBar.Invalidate();
1951 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1954 void CMainFrame::OnViewLineleft()
1956 OnViewLineLeftRight(-1);
1959 void CMainFrame::OnViewLineright()
1961 OnViewLineLeftRight(1);
1964 void CMainFrame::OnViewLineLeftRight(int direction)
1966 if (m_pwndLeftView)
1967 m_pwndLeftView->ScrollSide(direction);
1968 if (m_pwndRightView)
1969 m_pwndRightView->ScrollSide(direction);
1970 if (m_pwndBottomView)
1971 m_pwndBottomView->ScrollSide(direction);
1974 void CMainFrame::OnEditUseTheirs()
1976 if (m_pwndBottomView)
1977 m_pwndBottomView->UseTheirTextBlock();
1979 void CMainFrame::OnUpdateEditUsetheirblock(CCmdUI *pCmdUI)
1981 pCmdUI->Enable(m_pwndBottomView && m_pwndBottomView->HasSelection());
1984 void CMainFrame::OnEditUseMine()
1986 if (m_pwndBottomView)
1987 m_pwndBottomView->UseMyTextBlock();
1989 void CMainFrame::OnUpdateEditUsemyblock(CCmdUI *pCmdUI)
1991 OnUpdateEditUsetheirblock(pCmdUI);
1994 void CMainFrame::OnEditUseTheirsThenMine()
1996 if (m_pwndBottomView)
1997 m_pwndBottomView->UseTheirAndYourBlock();
2000 void CMainFrame::OnUpdateEditUsetheirthenmyblock(CCmdUI *pCmdUI)
2002 OnUpdateEditUsetheirblock(pCmdUI);
2005 void CMainFrame::OnEditUseMineThenTheirs()
2007 if (m_pwndBottomView)
2008 m_pwndBottomView->UseYourAndTheirBlock();
2011 void CMainFrame::OnUpdateEditUseminethentheirblock(CCmdUI *pCmdUI)
2013 OnUpdateEditUsetheirblock(pCmdUI);
2016 void CMainFrame::OnEditUseleftblock()
2018 if (m_pwndBottomView->IsWindowVisible())
2019 m_pwndBottomView->UseRightBlock();
2020 else
2021 m_pwndRightView->UseLeftBlock();
2024 void CMainFrame::OnUpdateEditUseleftblock(CCmdUI *pCmdUI)
2026 pCmdUI->Enable(IsViewGood(m_pwndRightView) && m_pwndRightView->IsTarget() && m_pwndRightView->HasSelection());
2029 void CMainFrame::OnUpdateUseBlock(CCmdUI *pCmdUI)
2031 pCmdUI->Enable(TRUE);
2034 void CMainFrame::OnEditUseleftfile()
2036 if (m_pwndBottomView->IsWindowVisible())
2037 m_pwndBottomView->UseRightFile();
2038 else
2039 m_pwndRightView->UseLeftFile();
2042 void CMainFrame::OnUpdateEditUseleftfile(CCmdUI *pCmdUI)
2044 pCmdUI->Enable(IsViewGood(m_pwndRightView) && m_pwndRightView->IsTarget());
2047 void CMainFrame::OnEditUseblockfromleftbeforeright()
2049 if (m_pwndRightView)
2050 m_pwndRightView->UseBothLeftFirst();
2053 void CMainFrame::OnUpdateEditUseblockfromleftbeforeright(CCmdUI *pCmdUI)
2055 OnUpdateEditUseleftblock(pCmdUI);
2058 void CMainFrame::OnEditUseblockfromrightbeforeleft()
2060 if (m_pwndRightView)
2061 m_pwndRightView->UseBothRightFirst();
2064 void CMainFrame::OnUpdateEditUseblockfromrightbeforeleft(CCmdUI *pCmdUI)
2066 OnUpdateEditUseleftblock(pCmdUI);
2069 void CMainFrame::OnFileReload()
2071 if (CheckForSave(CHFSR_RELOAD)==IDCANCEL)
2072 return;
2073 CDiffColors::GetInstance().LoadRegistry();
2074 LoadViews(-1);
2077 void CMainFrame::ActivateFrame(int nCmdShow)
2079 // nCmdShow is the normal show mode this frame should be in
2080 // translate default nCmdShow (-1)
2081 if (nCmdShow == -1)
2083 if (!IsWindowVisible())
2084 nCmdShow = SW_SHOWNORMAL;
2085 else if (IsIconic())
2086 nCmdShow = SW_RESTORE;
2089 // bring to top before showing
2090 BringToTop(nCmdShow);
2092 if (nCmdShow != -1)
2094 // show the window as specified
2095 WINDOWPLACEMENT wp;
2097 if ( !ReadWindowPlacement(&wp) )
2099 ShowWindow(nCmdShow);
2101 else
2103 if ( nCmdShow != SW_SHOWNORMAL )
2104 wp.showCmd = nCmdShow;
2106 SetWindowPlacement(&wp);
2109 // and finally, bring to top after showing
2110 BringToTop(nCmdShow);
2114 BOOL CMainFrame::ReadWindowPlacement(WINDOWPLACEMENT * pwp)
2116 CRegString placement = CRegString(L"Software\\TortoiseGitMerge\\WindowPos");
2117 CString sPlacement = placement;
2118 if (sPlacement.IsEmpty())
2119 return FALSE;
2120 int nRead = swscanf_s(sPlacement, L"%u,%u,%d,%d,%d,%d,%d,%d,%d,%d",
2121 &pwp->flags, &pwp->showCmd,
2122 &pwp->ptMinPosition.x, &pwp->ptMinPosition.y,
2123 &pwp->ptMaxPosition.x, &pwp->ptMaxPosition.y,
2124 &pwp->rcNormalPosition.left, &pwp->rcNormalPosition.top,
2125 &pwp->rcNormalPosition.right, &pwp->rcNormalPosition.bottom);
2126 if ( nRead != 10 )
2127 return FALSE;
2128 pwp->length = sizeof(WINDOWPLACEMENT);
2130 return TRUE;
2133 void CMainFrame::WriteWindowPlacement(WINDOWPLACEMENT * pwp)
2135 CRegString placement(L"Software\\TortoiseGitMerge\\WindowPos");
2136 TCHAR szBuffer[_countof("-32767")*8 + sizeof("65535")*2];
2138 swprintf_s(szBuffer, L"%u,%u,%d,%d,%d,%d,%d,%d,%d,%d",
2139 pwp->flags, pwp->showCmd,
2140 pwp->ptMinPosition.x, pwp->ptMinPosition.y,
2141 pwp->ptMaxPosition.x, pwp->ptMaxPosition.y,
2142 pwp->rcNormalPosition.left, pwp->rcNormalPosition.top,
2143 pwp->rcNormalPosition.right, pwp->rcNormalPosition.bottom);
2144 placement = szBuffer;
2147 void CMainFrame::OnUpdateMergeMarkasresolved(CCmdUI *pCmdUI)
2149 if (!pCmdUI)
2150 return;
2151 BOOL bEnable = FALSE;
2152 if ((!m_bReadOnly)&&(m_Data.m_mergedFile.InUse()))
2154 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
2156 bEnable = TRUE;
2159 pCmdUI->Enable(bEnable);
2162 void CMainFrame::OnMergeMarkasresolved()
2164 if(HasConflictsWontKeep())
2165 return;
2167 // now check if the file has already been saved and if not, save it.
2168 if (m_Data.m_mergedFile.InUse())
2170 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
2172 if (!FileSave(false))
2173 return;
2174 m_bSaveRequired = false;
2177 MarkAsResolved();
2180 BOOL CMainFrame::MarkAsResolved()
2182 if (m_bReadOnly)
2183 return FALSE;
2184 if (!IsViewGood(m_pwndBottomView))
2185 return FALSE;
2187 CString cmd = L"/command:resolve /path:\"";
2188 cmd += m_Data.m_mergedFile.GetFilename();
2189 cmd += L"\" /closeonend:1 /noquestion /skipcheck /silent";
2190 if (resolveMsgWnd)
2192 CString s;
2193 s.Format(L" /resolvemsghwnd:%I64d /resolvemsgwparam:%I64d /resolvemsglparam:%I64d", (__int64)resolveMsgWnd, (__int64)resolveMsgWParam, (__int64)resolveMsgLParam);
2194 cmd += s;
2196 if(!CAppUtils::RunTortoiseGitProc(cmd))
2197 return FALSE;
2198 m_bSaveRequired = false;
2199 return TRUE;
2202 void CMainFrame::OnUpdateMergeNextconflict(CCmdUI *pCmdUI)
2204 BOOL bShow = FALSE;
2205 if (HasNextConflict(m_pwndBottomView))
2206 bShow = TRUE;
2207 else if (HasNextConflict(m_pwndRightView))
2208 bShow = TRUE;
2209 else if (HasNextConflict(m_pwndLeftView))
2210 bShow = TRUE;
2211 pCmdUI->Enable(bShow);
2214 bool CMainFrame::HasNextConflict(CBaseView* view)
2216 if (view == 0)
2217 return false;
2218 if (!view->IsTarget())
2219 return false;
2220 return view->HasNextConflict();
2223 void CMainFrame::OnUpdateMergePreviousconflict(CCmdUI *pCmdUI)
2225 BOOL bShow = FALSE;
2226 if (HasPrevConflict(m_pwndBottomView))
2227 bShow = TRUE;
2228 else if (HasPrevConflict(m_pwndRightView))
2229 bShow = TRUE;
2230 else if (HasPrevConflict(m_pwndLeftView))
2231 bShow = TRUE;
2232 pCmdUI->Enable(bShow);
2235 bool CMainFrame::HasPrevConflict(CBaseView* view)
2237 if (view == 0)
2238 return false;
2239 if (!view->IsTarget())
2240 return false;
2241 return view->HasPrevConflict();
2244 void CMainFrame::OnUpdateNavigateNextdifference(CCmdUI *pCmdUI)
2246 CBaseView* baseView = GetActiveBaseView();
2247 BOOL bShow = FALSE;
2248 if (baseView != 0)
2249 bShow = baseView->HasNextDiff();
2250 pCmdUI->Enable(bShow);
2253 void CMainFrame::OnUpdateNavigatePreviousdifference(CCmdUI *pCmdUI)
2255 CBaseView* baseView = GetActiveBaseView();
2256 BOOL bShow = FALSE;
2257 if (baseView != 0)
2258 bShow = baseView->HasPrevDiff();
2259 pCmdUI->Enable(bShow);
2262 void CMainFrame::OnUpdateNavigateNextinlinediff(CCmdUI *pCmdUI)
2264 BOOL bShow = FALSE;
2265 if (HasNextInlineDiff(m_pwndBottomView))
2266 bShow = TRUE;
2267 else if (HasNextInlineDiff(m_pwndRightView))
2268 bShow = TRUE;
2269 else if (HasNextInlineDiff(m_pwndLeftView))
2270 bShow = TRUE;
2271 pCmdUI->Enable(bShow);
2274 bool CMainFrame::HasNextInlineDiff(CBaseView* view)
2276 if (view == 0)
2277 return false;
2278 if (!view->IsTarget())
2279 return false;
2280 return view->HasNextInlineDiff();
2283 void CMainFrame::OnUpdateNavigatePrevinlinediff(CCmdUI *pCmdUI)
2285 BOOL bShow = FALSE;
2286 if (HasPrevInlineDiff(m_pwndBottomView))
2287 bShow = TRUE;
2288 else if (HasPrevInlineDiff(m_pwndRightView))
2289 bShow = TRUE;
2290 else if (HasPrevInlineDiff(m_pwndLeftView))
2291 bShow = TRUE;
2292 pCmdUI->Enable(bShow);
2295 bool CMainFrame::HasPrevInlineDiff(CBaseView* view)
2297 if (view == 0)
2298 return false;
2299 if (!view->IsTarget())
2300 return false;
2301 return view->HasPrevInlineDiff();
2304 void CMainFrame::OnMoving(UINT fwSide, LPRECT pRect)
2306 // if the pathfilelist dialog is attached to the mainframe,
2307 // move it along with the mainframe
2308 if (::IsWindow(m_dlgFilePatches.m_hWnd))
2310 RECT patchrect;
2311 m_dlgFilePatches.GetWindowRect(&patchrect);
2312 if (::IsWindow(m_hWnd))
2314 RECT thisrect;
2315 GetWindowRect(&thisrect);
2316 if (patchrect.right == thisrect.left)
2318 m_dlgFilePatches.SetWindowPos(nullptr, patchrect.left - (thisrect.left - pRect->left), patchrect.top - (thisrect.top - pRect->top),
2319 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
2323 __super::OnMoving(fwSide, pRect);
2326 void CMainFrame::OnUpdateEditCopy(CCmdUI *pCmdUI)
2328 BOOL bShow = FALSE;
2329 if ((m_pwndBottomView)&&(m_pwndBottomView->HasSelection()))
2330 bShow = TRUE;
2331 else if ((m_pwndRightView)&&(m_pwndRightView->HasSelection()))
2332 bShow = TRUE;
2333 else if ((m_pwndLeftView)&&(m_pwndLeftView->HasSelection()))
2334 bShow = TRUE;
2335 pCmdUI->Enable(bShow);
2338 void CMainFrame::OnUpdateEditPaste(CCmdUI *pCmdUI)
2340 BOOL bWritable = FALSE;
2341 if ((m_pwndBottomView)&&(m_pwndBottomView->IsWritable()))
2342 bWritable = TRUE;
2343 else if ((m_pwndRightView)&&(m_pwndRightView->IsWritable()))
2344 bWritable = TRUE;
2345 else if ((m_pwndLeftView)&&(m_pwndLeftView->IsWritable()))
2346 bWritable = TRUE;
2347 pCmdUI->Enable(bWritable && ::IsClipboardFormatAvailable(CF_TEXT));
2350 void CMainFrame::OnViewSwitchleft()
2352 if (CheckForSave(CHFSR_SWITCH)!=IDCANCEL)
2354 CWorkingFile file = m_Data.m_baseFile;
2355 m_Data.m_baseFile = m_Data.m_yourFile;
2356 m_Data.m_yourFile = file;
2357 if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_yourFile.GetFilename())==0)
2359 m_Data.m_mergedFile = m_Data.m_baseFile;
2361 else if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_baseFile.GetFilename())==0)
2363 m_Data.m_mergedFile = m_Data.m_yourFile;
2365 LoadViews();
2369 void CMainFrame::OnUpdateViewSwitchleft(CCmdUI *pCmdUI)
2371 BOOL bEnable = !IsViewGood(m_pwndBottomView);
2372 pCmdUI->Enable(bEnable);
2375 void CMainFrame::OnUpdateViewShowfilelist(CCmdUI *pCmdUI)
2377 BOOL bEnable = m_dlgFilePatches.HasFiles();
2378 pCmdUI->Enable(bEnable);
2379 pCmdUI->SetCheck(m_dlgFilePatches.IsWindowVisible());
2382 void CMainFrame::OnViewShowfilelist()
2384 m_dlgFilePatches.ShowWindow(m_dlgFilePatches.IsWindowVisible() ? SW_HIDE : SW_SHOW);
2387 void CMainFrame::OnEditUndo()
2389 if (CUndo::GetInstance().CanUndo())
2391 CUndo::GetInstance().Undo(m_pwndLeftView, m_pwndRightView, m_pwndBottomView);
2395 void CMainFrame::OnUpdateEditUndo(CCmdUI *pCmdUI)
2397 pCmdUI->Enable(CUndo::GetInstance().CanUndo());
2400 void CMainFrame::OnEditRedo()
2402 if (CUndo::GetInstance().CanRedo())
2404 CUndo::GetInstance().Redo(m_pwndLeftView, m_pwndRightView, m_pwndBottomView);
2408 void CMainFrame::OnUpdateEditRedo(CCmdUI *pCmdUI)
2410 pCmdUI->Enable(CUndo::GetInstance().CanRedo());
2413 void CMainFrame::OnEditEnable()
2415 CBaseView * pView = GetActiveBaseView();
2416 if (pView && pView->IsReadonlyChangable())
2418 bool isReadOnly = pView->IsReadonly();
2419 pView->SetReadonly(!isReadOnly);
2423 void CMainFrame::OnUpdateEditEnable(CCmdUI *pCmdUI)
2425 CBaseView * pView = GetActiveBaseView();
2426 if (pView)
2428 pCmdUI->Enable(pView->IsReadonlyChangable() || !pView->IsReadonly());
2429 pCmdUI->SetCheck(!pView->IsReadonly());
2431 else
2433 pCmdUI->Enable(FALSE);
2437 void CMainFrame::OnIndicatorLeftview()
2439 if (m_bUseRibbons)
2440 return;
2441 if (IsViewGood(m_pwndLeftView))
2443 m_pwndLeftView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_LEFTVIEW);
2447 void CMainFrame::OnIndicatorRightview()
2449 if (m_bUseRibbons)
2450 return;
2451 if (IsViewGood(m_pwndRightView))
2453 m_pwndRightView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_RIGHTVIEW);
2457 void CMainFrame::OnIndicatorBottomview()
2459 if (m_bUseRibbons)
2460 return;
2461 if (IsViewGood(m_pwndBottomView))
2463 m_pwndBottomView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_BOTTOMVIEW);
2467 int CMainFrame::CheckForReload()
2469 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
2470 if (bLock)
2472 return IDNO;
2474 bLock = true;
2475 bool bSourceChanged =
2476 m_Data.m_baseFile.HasSourceFileChanged()
2477 || m_Data.m_yourFile.HasSourceFileChanged()
2478 || m_Data.m_theirFile.HasSourceFileChanged()
2479 /*|| m_Data.m_mergedFile.HasSourceFileChanged()*/;
2480 if (!bSourceChanged)
2482 bLock = false;
2483 return IDNO;
2486 CString msg = HasUnsavedEdits() ? CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDELOOSECHANGES)) : CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE));
2487 CTaskDialog taskdlg(msg,
2488 CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE_TASK2)),
2489 L"TortoiseGitMerge",
2491 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
2492 CString sTask3;
2493 if (HasUnsavedEdits())
2494 sTask3.LoadString(IDS_WARNMODIFIEDOUTSIDE_TASK3);
2495 else
2496 sTask3.LoadString(IDS_WARNMODIFIEDOUTSIDE_TASK4);
2497 taskdlg.AddCommandControl(IDYES, sTask3);
2498 taskdlg.AddCommandControl(IDNO, CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE_TASK5)));
2499 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2500 taskdlg.SetDefaultCommandControl(IDYES);
2501 taskdlg.SetMainIcon(TD_WARNING_ICON);
2502 UINT ret = (UINT)taskdlg.DoModal(m_hWnd);
2503 if (ret == IDYES)
2505 CDiffColors::GetInstance().LoadRegistry();
2506 LoadViews(-1);
2508 else
2510 if (IsViewGood(m_pwndBottomView)) // three pane view
2512 /*if (m_Data.m_sourceFile.HasSourceFileChanged())
2513 m_pwndBottomView->SetModified();
2514 if (m_Data.m_mergedFile.HasSourceFileChanged())
2515 m_pwndBottomView->SetModified();//*/
2516 if (m_Data.m_yourFile.HasSourceFileChanged())
2517 m_pwndRightView->SetModified();
2518 if (m_Data.m_theirFile.HasSourceFileChanged())
2519 m_pwndLeftView->SetModified();
2521 else if (IsViewGood(m_pwndRightView)) // two pane view
2523 if (m_Data.m_baseFile.HasSourceFileChanged())
2524 m_pwndLeftView->SetModified();
2525 if (m_Data.m_yourFile.HasSourceFileChanged())
2526 m_pwndRightView->SetModified();
2528 else
2530 if (m_Data.m_yourFile.HasSourceFileChanged())
2531 m_pwndLeftView->SetModified();
2534 // no reload just store updated file time
2535 m_Data.m_baseFile.StoreFileAttributes();
2536 m_Data.m_theirFile.StoreFileAttributes();
2537 m_Data.m_yourFile.StoreFileAttributes();
2538 //m_Data.m_mergedFile.StoreFileAttributes();
2540 bLock = false;
2541 return ret;
2544 int CMainFrame::CheckForSave(ECheckForSaveReason eReason)
2546 int idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2547 int idNoSave = IDS_ASKFORSAVE_TASK7;
2548 int idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2549 switch (eReason)
2551 case CHFSR_CLOSE:
2552 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2553 idNoSave = IDS_ASKFORSAVE_TASK4;
2554 idCancelAction = IDS_ASKFORSAVE_TASK5;
2555 break;
2556 case CHFSR_SWITCH:
2557 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2558 //idNoSave = IDS_ASKFORSAVE_TASK7;
2559 idCancelAction = IDS_ASKFORSAVE_TASK8;
2560 break;
2561 case CHFSR_RELOAD:
2562 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2563 //idNoSave = IDS_ASKFORSAVE_TASK7;
2564 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2565 break;
2566 case CHFSR_OPTIONS:
2567 idTitle = IDS_WARNMODIFIEDLOOSECHANGESOPTIONS;
2568 //idNoSave = IDS_ASKFORSAVE_TASK7;
2569 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPTIONS;
2570 break;
2571 case CHFSR_OPEN:
2572 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2573 idNoSave = IDS_ASKFORSAVE_NOSAVE_OPEN;
2574 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2575 break;
2578 CString sTitle(MAKEINTRESOURCE(idTitle));
2579 CString sSubTitle(MAKEINTRESOURCE(IDS_ASKFORSAVE_TASK2));
2580 CString sNoSave(MAKEINTRESOURCE(idNoSave));
2581 CString sCancelAction(MAKEINTRESOURCE(idCancelAction));
2582 CString sAppName(MAKEINTRESOURCE(IDS_APPNAME));
2584 // TODO simplify logic, reduce code duplication
2585 if (CBaseView::IsViewGood(m_pwndBottomView))
2587 // three-way diff - by design only bottom can be changed
2588 // use 1.7 way to do that
2590 else if (CBaseView::IsViewGood(m_pwndRightView))
2592 // two-way diff -
2593 // 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
2594 if (HasUnsavedEdits(m_pwndLeftView))
2596 // both views
2597 CTaskDialog taskdlg(sTitle,
2598 sSubTitle,
2599 sAppName,
2601 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
2602 CString sTaskTemp;
2603 if (m_pwndLeftView->m_pWorkingFile->InUse() && !m_pwndLeftView->m_pWorkingFile->IsReadonly())
2604 sTaskTemp.Format(IDS_ASKFORSAVE_SAVELEFT, (LPCTSTR)m_pwndLeftView->m_pWorkingFile->GetFilename());
2605 else
2606 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS));
2607 taskdlg.AddCommandControl(201, sTaskTemp); // left
2608 taskdlg.SetDefaultCommandControl(201);
2609 if (HasUnsavedEdits(m_pwndRightView))
2611 if (m_pwndRightView->m_pWorkingFile->InUse() && !m_pwndRightView->m_pWorkingFile->IsReadonly())
2612 sTaskTemp.Format(IDS_ASKFORSAVE_SAVERIGHT, (LPCTSTR)m_pwndRightView->m_pWorkingFile->GetFilename());
2613 else
2614 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS));
2615 taskdlg.AddCommandControl(202, sTaskTemp); // right
2616 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEALL2))); // both
2617 taskdlg.SetDefaultCommandControl(203);
2619 taskdlg.AddCommandControl(IDNO, sNoSave); // none
2620 taskdlg.AddCommandControl(IDCANCEL, sCancelAction); // cancel
2621 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2622 taskdlg.SetMainIcon(TD_WARNING_ICON);
2623 UINT ret = (UINT)taskdlg.DoModal(m_hWnd);
2624 switch (ret)
2626 case 201: // left
2627 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
2628 break;
2629 case 203: // both
2630 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
2631 case 202: // right
2632 m_pwndRightView->SaveFile();
2633 break;
2635 if (ret != IDCANCEL && (eReason == CHFSR_CLOSE || eReason == CHFSR_OPEN))
2636 DeleteBaseTheirsMineOnClose();
2637 return ret;
2639 else
2641 // only secondary (left) view
2643 // only right view - 1.7 implementation is used
2645 else if (CBaseView::IsViewGood(m_pwndLeftView))
2647 // only one view - only one to save
2648 // 1.7 FileSave don't support this mode
2649 if (HasUnsavedEdits(m_pwndLeftView))
2651 CTaskDialog taskdlg(sTitle,
2652 sSubTitle,
2653 sAppName,
2655 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
2656 CString sTask3;
2657 if (m_Data.m_mergedFile.InUse())
2658 sTask3.Format(IDS_ASKFORSAVE_TASK3, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
2659 else
2660 sTask3.LoadString(IDS_ASKFORSAVE_TASK6);
2661 taskdlg.AddCommandControl(IDYES, sTask3);
2662 taskdlg.AddCommandControl(IDNO, sNoSave);
2663 taskdlg.AddCommandControl(IDCANCEL, sCancelAction);
2664 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2665 taskdlg.SetDefaultCommandControl(IDYES);
2666 taskdlg.SetMainIcon(TD_WARNING_ICON);
2667 if ((UINT)taskdlg.DoModal(m_hWnd) == IDYES)
2669 if (m_pwndLeftView->SaveFile()<0)
2670 return IDCANCEL;
2673 if (eReason == CHFSR_CLOSE || eReason == CHFSR_OPEN)
2674 DeleteBaseTheirsMineOnClose();
2675 return IDNO;
2677 else
2679 if (eReason == CHFSR_CLOSE || eReason == CHFSR_OPEN)
2680 DeleteBaseTheirsMineOnClose();
2681 return IDNO; // nothing to save
2684 // 1.7 implementation
2685 UINT ret = IDNO;
2686 if (HasUnsavedEdits())
2688 CTaskDialog taskdlg(sTitle,
2689 sSubTitle,
2690 sAppName,
2692 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
2693 CString sTask3;
2694 if (m_Data.m_mergedFile.InUse())
2695 sTask3.Format(IDS_ASKFORSAVE_TASK3, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
2696 else
2697 sTask3.LoadString(IDS_ASKFORSAVE_TASK6);
2698 taskdlg.AddCommandControl(IDYES, sTask3);
2699 taskdlg.AddCommandControl(IDNO, sNoSave);
2700 taskdlg.AddCommandControl(IDCANCEL, sCancelAction);
2701 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2702 taskdlg.SetDefaultCommandControl(IDYES);
2703 taskdlg.SetMainIcon(TD_WARNING_ICON);
2704 ret = (UINT)taskdlg.DoModal(m_hWnd);
2706 if (ret == IDYES)
2708 if (!FileSave())
2709 ret = IDCANCEL;
2713 if (ret != IDCANCEL && (eReason == CHFSR_CLOSE || eReason == CHFSR_OPEN))
2714 DeleteBaseTheirsMineOnClose();
2716 return ret;
2719 void CMainFrame::DeleteBaseTheirsMineOnClose()
2721 if (!m_bDeleteBaseTheirsMineOnClose)
2722 return;
2724 m_bDeleteBaseTheirsMineOnClose = false;
2726 DeleteFile(m_Data.m_baseFile.GetFilename());
2727 DeleteFile(m_Data.m_theirFile.GetFilename());
2728 DeleteFile(m_Data.m_yourFile.GetFilename());
2731 bool CMainFrame::HasUnsavedEdits() const
2733 return HasUnsavedEdits(m_pwndBottomView) || HasUnsavedEdits(m_pwndRightView) || m_bSaveRequired;
2736 bool CMainFrame::HasUnsavedEdits(const CBaseView* view)
2738 if (!CBaseView::IsViewGood(view))
2739 return false;
2740 return view->IsModified();
2743 bool CMainFrame::HasMarkedBlocks() const
2745 return CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->HasMarkedBlocks();
2748 bool CMainFrame::IsViewGood(const CBaseView* view)
2750 return CBaseView::IsViewGood(view);
2753 void CMainFrame::OnViewInlinediffword()
2755 m_bInlineWordDiff = !m_bInlineWordDiff;
2756 if (m_pwndLeftView)
2758 m_pwndLeftView->SetInlineWordDiff(m_bInlineWordDiff);
2759 m_pwndLeftView->BuildAllScreen2ViewVector();
2760 m_pwndLeftView->DocumentUpdated();
2762 if (m_pwndRightView)
2764 m_pwndRightView->SetInlineWordDiff(m_bInlineWordDiff);
2765 m_pwndRightView->BuildAllScreen2ViewVector();
2766 m_pwndRightView->DocumentUpdated();
2768 if (m_pwndBottomView)
2770 m_pwndBottomView->SetInlineWordDiff(m_bInlineWordDiff);
2771 m_pwndBottomView->BuildAllScreen2ViewVector();
2772 m_pwndBottomView->DocumentUpdated();
2774 m_wndLineDiffBar.DocumentUpdated();
2777 void CMainFrame::OnUpdateViewInlinediffword(CCmdUI *pCmdUI)
2779 pCmdUI->Enable(m_bInlineDiff && IsViewGood(m_pwndLeftView) && IsViewGood(m_pwndRightView));
2780 pCmdUI->SetCheck(m_bInlineWordDiff);
2783 void CMainFrame::OnViewInlinediff()
2785 m_bInlineDiff = !m_bInlineDiff;
2786 if (m_pwndLeftView)
2788 m_pwndLeftView->SetInlineDiff(m_bInlineDiff);
2789 m_pwndLeftView->BuildAllScreen2ViewVector();
2790 m_pwndLeftView->DocumentUpdated();
2792 if (m_pwndRightView)
2794 m_pwndRightView->SetInlineDiff(m_bInlineDiff);
2795 m_pwndRightView->BuildAllScreen2ViewVector();
2796 m_pwndRightView->DocumentUpdated();
2798 if (m_pwndBottomView)
2800 m_pwndBottomView->SetInlineDiff(m_bInlineDiff);
2801 m_pwndBottomView->BuildAllScreen2ViewVector();
2802 m_pwndBottomView->DocumentUpdated();
2804 m_wndLineDiffBar.DocumentUpdated();
2807 void CMainFrame::OnUpdateViewInlinediff(CCmdUI *pCmdUI)
2809 pCmdUI->Enable(IsViewGood(m_pwndLeftView) && IsViewGood(m_pwndRightView));
2810 pCmdUI->SetCheck(m_bInlineDiff);
2813 void CMainFrame::OnUpdateEditCreateunifieddifffile(CCmdUI *pCmdUI)
2815 // "create unified diff file" is only available if two files
2816 // are diffed, not three.
2817 bool bEnabled = true;
2818 if (!IsViewGood(m_pwndLeftView))
2819 bEnabled = false;
2820 else if (!IsViewGood(m_pwndRightView))
2821 bEnabled = false;
2822 else if (IsViewGood(m_pwndBottomView)) //no negation here
2823 bEnabled = false;
2824 pCmdUI->Enable(bEnabled);
2827 void CMainFrame::OnEditCreateunifieddifffile()
2829 CString origFile, modifiedFile;
2830 // the original file is the one on the left
2831 if (m_pwndLeftView)
2832 origFile = m_pwndLeftView->m_sFullFilePath;
2833 if (m_pwndRightView)
2834 modifiedFile = m_pwndRightView->m_sFullFilePath;
2835 if (origFile.IsEmpty() || modifiedFile.IsEmpty())
2836 return;
2838 CString outputFile;
2839 if(!TryGetFileName(outputFile))
2840 return;
2842 CRegStdDWORD regContextLines(L"Software\\TortoiseGitMerge\\ContextLines", (DWORD)-1);
2843 CAppUtils::CreateUnifiedDiff(origFile, modifiedFile, outputFile, regContextLines, true);
2846 void CMainFrame::OnUpdateViewLinediffbar(CCmdUI *pCmdUI)
2848 pCmdUI->SetCheck(m_bLineDiff);
2849 pCmdUI->Enable();
2852 void CMainFrame::OnViewLinediffbar()
2854 m_bLineDiff = !m_bLineDiff;
2855 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2856 m_wndLineDiffBar.DocumentUpdated();
2857 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2858 m_wndLocatorBar.DocumentUpdated();
2861 void CMainFrame::OnUpdateViewLocatorbar(CCmdUI *pCmdUI)
2863 pCmdUI->SetCheck(m_bLocatorBar);
2864 pCmdUI->Enable();
2867 void CMainFrame::OnUpdateViewBars(CCmdUI * pCmdUI)
2869 pCmdUI->Enable();
2872 void CMainFrame::OnViewLocatorbar()
2874 m_bLocatorBar = !m_bLocatorBar;
2875 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2876 m_wndLocatorBar.DocumentUpdated();
2877 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2878 m_wndLineDiffBar.DocumentUpdated();
2881 void CMainFrame::OnViewComparewhitespaces()
2883 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2884 return;
2885 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
2886 regIgnoreWS = 0;
2887 LoadViews(-1);
2890 void CMainFrame::OnUpdateViewComparewhitespaces(CCmdUI *pCmdUI)
2892 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
2893 DWORD dwIgnoreWS = regIgnoreWS;
2894 pCmdUI->SetCheck(dwIgnoreWS == 0);
2897 void CMainFrame::OnViewIgnorewhitespacechanges()
2899 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2900 return;
2901 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
2902 regIgnoreWS = 2;
2903 LoadViews(-1);
2906 void CMainFrame::OnUpdateViewIgnorewhitespacechanges(CCmdUI *pCmdUI)
2908 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
2909 DWORD dwIgnoreWS = regIgnoreWS;
2910 pCmdUI->SetCheck(dwIgnoreWS == 2);
2913 void CMainFrame::OnViewIgnoreallwhitespacechanges()
2915 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2916 return;
2917 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
2918 regIgnoreWS = 1;
2919 LoadViews(-1);
2922 void CMainFrame::OnUpdateViewIgnoreallwhitespacechanges(CCmdUI *pCmdUI)
2924 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
2925 DWORD dwIgnoreWS = regIgnoreWS;
2926 pCmdUI->SetCheck(dwIgnoreWS == 1);
2929 void CMainFrame::OnViewMovedBlocks()
2931 m_bViewMovedBlocks = !(DWORD)m_regViewModedBlocks;
2932 m_regViewModedBlocks = m_bViewMovedBlocks;
2933 LoadViews(-1);
2936 void CMainFrame::OnUpdateViewMovedBlocks(CCmdUI *pCmdUI)
2938 pCmdUI->SetCheck(m_bViewMovedBlocks);
2939 BOOL bEnable = TRUE;
2940 if (IsViewGood(m_pwndBottomView))
2942 bEnable = FALSE;
2944 pCmdUI->Enable(bEnable);
2947 bool CMainFrame::HasConflictsWontKeep()
2949 const int nConflictLine = CheckResolved();
2950 if (nConflictLine < 0)
2951 return false;
2952 if (!m_pwndBottomView)
2953 return false;
2955 CString sTemp;
2956 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
2957 CTaskDialog taskdlg(sTemp,
2958 CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK2)),
2959 L"TortoiseGitMerge",
2961 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
2962 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK3)));
2963 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK4)));
2964 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2965 taskdlg.SetDefaultCommandControl(2);
2966 taskdlg.SetMainIcon(TD_ERROR_ICON);
2967 if (taskdlg.DoModal(m_hWnd) == 1)
2968 return false;
2970 m_pwndBottomView->GoToLine(nConflictLine);
2971 return true;
2974 bool CMainFrame::TryGetFileName(CString& result)
2976 return CCommonAppUtils::FileOpenSave(result, nullptr, IDS_SAVEASTITLE, IDS_COMMONFILEFILTER, false, m_hWnd);
2979 CBaseView* CMainFrame::GetActiveBaseView() const
2981 CView* activeView = GetActiveView();
2982 CBaseView* activeBase = dynamic_cast<CBaseView*>( activeView );
2983 return activeBase;
2986 void CMainFrame::SetWindowTitle()
2988 // try to find a suitable window title
2989 CString sYour = m_Data.m_yourFile.GetDescriptiveName();
2990 if (sYour.Find(L" - ") >= 0)
2991 sYour = sYour.Left(sYour.Find(L" - "));
2992 if (sYour.Find(L" : ") >= 0)
2993 sYour = sYour.Left(sYour.Find(L" : "));
2994 CString sTheir = m_Data.m_theirFile.GetDescriptiveName();
2995 if (sTheir.IsEmpty())
2996 sTheir = m_Data.m_baseFile.GetDescriptiveName();
2997 if (sTheir.Find(L" - ") >= 0)
2998 sTheir = sTheir.Left(sTheir.Find(L" - "));
2999 if (sTheir.Find(L" : ") >= 0)
3000 sTheir = sTheir.Left(sTheir.Find(L" : "));
3002 if (!sYour.IsEmpty() && !sTheir.IsEmpty())
3004 if (sYour.CompareNoCase(sTheir)==0)
3005 SetWindowText(sYour + L" - TortoiseGitMerge");
3006 else if ((sYour.GetLength() < 10) &&
3007 (sTheir.GetLength() < 10))
3008 SetWindowText(sYour + L" - " + sTheir + L" - TortoiseGitMerge");
3009 else
3011 // we have two very long descriptive texts here, which
3012 // means we have to find a way to use them as a window
3013 // title in a shorter way.
3014 // for simplicity, we just use the one from "yourfile"
3015 SetWindowText(sYour + L" - TortoiseGitMerge");
3018 else if (!sYour.IsEmpty())
3019 SetWindowText(sYour + L" - TortoiseGitMerge");
3020 else if (!sTheir.IsEmpty())
3021 SetWindowText(sTheir + L" - TortoiseGitMerge");
3022 else
3023 SetWindowText(L"TortoiseGitMerge");
3026 void CMainFrame::OnTimer(UINT_PTR nIDEvent)
3028 switch (nIDEvent)
3030 case IDT_RELOADCHECKTIMER:
3031 KillTimer(nIDEvent);
3032 CheckForReload();
3033 break;
3036 __super::OnTimer(nIDEvent);
3039 void CMainFrame::LoadIgnoreCommentData()
3041 static bool bLoaded = false;
3042 if (bLoaded)
3043 return;
3044 CString sPath = CPathUtils::GetAppDataDirectory() + L"ignorecomments.txt";
3045 if (!PathFileExists(sPath))
3047 // ignore comments file does not exist (yet), so create a default one
3048 HRSRC hRes = FindResource(nullptr, MAKEINTRESOURCE(IDR_IGNORECOMMENTSTXT), L"config");
3049 if (hRes)
3051 HGLOBAL hResourceLoaded = LoadResource(nullptr, hRes);
3052 if (hResourceLoaded)
3054 char * lpResLock = (char *) LockResource(hResourceLoaded);
3055 DWORD dwSizeRes = SizeofResource(nullptr, hRes);
3056 if (lpResLock)
3058 HANDLE hFile = CreateFile(sPath, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
3059 if (hFile != INVALID_HANDLE_VALUE)
3061 DWORD dwWritten = 0;
3062 WriteFile(hFile, lpResLock, dwSizeRes, &dwWritten, nullptr);
3063 CloseHandle(hFile);
3072 CStdioFile file;
3073 if (file.Open(sPath, CFile::modeRead))
3075 CString sLine;
3076 while (file.ReadString(sLine))
3078 int eqpos = sLine.Find('=');
3079 if (eqpos >= 0)
3081 CString sExts = sLine.Left(eqpos);
3082 CString sComments = sLine.Mid(eqpos+1);
3084 int pos = sComments.Find(',');
3085 CString sLineStart = sComments.Left(pos);
3086 pos = sComments.Find(',', pos);
3087 int pos2 = sComments.Find(',', pos+1);
3088 CString sBlockStart = sComments.Mid(pos+1, pos2-pos-1);
3089 CString sBlockEnd = sComments.Mid(pos2+1);
3091 auto commentTuple = std::make_tuple(sLineStart, sBlockStart, sBlockEnd);
3093 pos = 0;
3094 CString temp;
3095 for (;;)
3097 temp = sExts.Tokenize(L",", pos);
3098 if (temp.IsEmpty())
3100 break;
3102 ASSERT(m_IgnoreCommentsMap.find(temp) == m_IgnoreCommentsMap.end());
3103 m_IgnoreCommentsMap[temp] = commentTuple;
3109 catch (CFileException* e)
3111 e->Delete();
3113 bLoaded = true;
3116 void CMainFrame::OnViewIgnorecomments()
3118 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3119 return;
3120 m_regIgnoreComments = !DWORD(m_regIgnoreComments);
3121 LoadViews(-1);
3124 void CMainFrame::OnUpdateViewIgnorecomments(CCmdUI *pCmdUI)
3126 // only enable if we have comments defined for this file extension
3127 CString sExt = CPathUtils::GetFileExtFromPath(m_Data.m_baseFile.GetFilename()).MakeLower();
3128 sExt.TrimLeft(L".");
3129 auto sC = m_IgnoreCommentsMap.find(sExt);
3130 if (sC == m_IgnoreCommentsMap.end())
3132 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_yourFile.GetFilename()).MakeLower();
3133 sExt.TrimLeft(L".");
3134 sC = m_IgnoreCommentsMap.find(sExt);
3135 if (sC == m_IgnoreCommentsMap.end())
3137 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_theirFile.GetFilename()).MakeLower();
3138 sExt.TrimLeft(L".");
3139 sC = m_IgnoreCommentsMap.find(sExt);
3142 pCmdUI->Enable(sC != m_IgnoreCommentsMap.end());
3144 pCmdUI->SetCheck(DWORD(m_regIgnoreComments) != 0);
3148 void CMainFrame::OnRegexfilter(UINT cmd)
3150 if ((cmd == ID_REGEXFILTER)||(cmd == (ID_REGEXFILTER+1)))
3152 CRegexFiltersDlg dlg(this);
3153 dlg.SetIniFile(&m_regexIni);
3154 if (dlg.DoModal() == IDOK)
3156 FILE* pFile = nullptr;
3157 _wfopen_s(&pFile, CPathUtils::GetAppDataDirectory() + L"regexfilters.ini", L"wb");
3158 m_regexIni.SaveFile(pFile);
3159 fclose(pFile);
3161 BuildRegexSubitems();
3163 else
3165 if (cmd == (UINT)m_regexIndex && !m_bUseRibbons)
3167 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3168 return;
3169 m_Data.SetRegexTokens(std::wregex(), L"");
3170 m_regexIndex = -1;
3171 LoadViews(-1);
3173 else if (cmd != (UINT)m_regexIndex)
3175 CSimpleIni::TNamesDepend sections;
3176 m_regexIni.GetAllSections(sections);
3177 int index = ID_REGEXFILTER + 2;
3178 m_regexIndex = -1;
3179 for (const auto& section : sections)
3181 if (cmd == (UINT)index)
3183 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3184 break;
3187 std::wregex rx(m_regexIni.GetValue(section.pItem, L"regex", L""));
3188 m_Data.SetRegexTokens(rx, m_regexIni.GetValue(section.pItem, L"replace", L""));
3190 catch (std::exception &ex)
3192 MessageBox(L"Regex is invalid!\r\n" + CString(ex.what()));
3194 m_regexIndex = index;
3197 LoadViews(-1);
3199 catch (const std::regex_error& ex)
3201 MessageBox(L"Regexp error caught:\r\n" + CString(ex.what()) + L"\r\nTrying to recover by unsetting it again.");
3202 m_Data.SetRegexTokens(std::wregex(), L"");
3203 m_regexIndex = -1;
3204 LoadViews(-1);
3206 break;
3208 ++index;
3214 void CMainFrame::OnUpdateViewRegexFilter( CCmdUI *pCmdUI )
3216 pCmdUI->Enable();
3217 pCmdUI->SetCheck(pCmdUI->m_nID == (UINT)m_regexIndex);
3220 void CMainFrame::BuildRegexSubitems(CMFCPopupMenu* pMenuPopup)
3222 CString sIniPath = CPathUtils::GetAppDataDirectory() + L"regexfilters.ini";
3223 if (!PathFileExists(sIniPath))
3225 // ini file does not exist (yet), so create a default one
3226 HRSRC hRes = FindResource(nullptr, MAKEINTRESOURCE(IDR_REGEXFILTERINI), L"config");
3227 if (hRes)
3229 HGLOBAL hResourceLoaded = LoadResource(nullptr, hRes);
3230 if (hResourceLoaded)
3232 char * lpResLock = (char *)LockResource(hResourceLoaded);
3233 DWORD dwSizeRes = SizeofResource(nullptr, hRes);
3234 if (lpResLock)
3236 HANDLE hFile = CreateFile(sIniPath, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
3237 if (hFile != INVALID_HANDLE_VALUE)
3239 DWORD dwWritten = 0;
3240 WriteFile(hFile, lpResLock, dwSizeRes, &dwWritten, nullptr);
3241 CloseHandle(hFile);
3248 m_regexIni.LoadFile(sIniPath);
3249 CSimpleIni::TNamesDepend sections;
3250 m_regexIni.GetAllSections(sections);
3252 if (m_bUseRibbons)
3254 std::list<CNativeRibbonDynamicItemInfo> items;
3255 int cmdIndex = 2;
3256 items.push_back(CNativeRibbonDynamicItemInfo(ID_REGEX_NO_FILTER, CString(MAKEINTRESOURCE(ID_REGEX_NO_FILTER)), IDB_REGEX_FILTER));
3257 for (const auto& section : sections)
3259 items.emplace_back(ID_REGEXFILTER + cmdIndex, section.pItem, IDB_REGEX_FILTER);
3260 cmdIndex++;
3263 m_pRibbonApp->SetItems(ID_REGEXFILTER, items);
3265 else if (pMenuPopup)
3267 int iIndex = -1;
3268 if (!CMFCToolBar::IsCustomizeMode() &&
3269 (iIndex = pMenuPopup->GetMenuBar()->CommandToIndex(ID_REGEXFILTER)) >= 0)
3271 if (!sections.empty())
3272 pMenuPopup->InsertSeparator(iIndex + 1); // insert the separator at the end
3273 int cmdIndex = 2;
3274 for (const auto& section : sections)
3276 pMenuPopup->InsertItem(CMFCToolBarMenuButton(ID_REGEXFILTER + cmdIndex, nullptr, -1, (LPCWSTR)section.pItem), iIndex + cmdIndex);
3277 cmdIndex++;
3283 void CMainFrame::FillEncodingButton( CMFCRibbonButton * pButton, int start )
3285 pButton->SetDefaultCommand(FALSE);
3286 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::ASCII, L"ASCII" ));
3287 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::BINARY, L"BINARY" ));
3288 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_LE, L"UTF-16LE" ));
3289 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_LEBOM, L"UTF-16LE BOM"));
3290 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_BE, L"UTF-16BE" ));
3291 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_BEBOM, L"UTF-16BE BOM"));
3292 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF32_LE, L"UTF-32LE" ));
3293 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF32_BE, L"UTF-32BE" ));
3294 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF8, L"UTF-8" ));
3295 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF8BOM, L"UTF-8 BOM" ));
3298 void CMainFrame::FillEOLButton( CMFCRibbonButton * pButton, int start )
3300 pButton->SetDefaultCommand(FALSE);
3301 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LF , L"LF" ));
3302 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_CRLF, L"CRLF"));
3303 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LFCR, L"LRCR"));
3304 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_CR , L"CR" ));
3305 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_VT , L"VT" ));
3306 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_FF , L"FF" ));
3307 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_NEL , L"NEL" ));
3308 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LS , L"LS" ));
3309 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_PS , L"PS" ));
3312 void CMainFrame::FillTabModeButton(CMFCRibbonButton * pButton, int start)
3314 pButton->SetDefaultCommand(FALSE);
3315 pButton->AddSubItem(new CMFCRibbonButton(start + TABMODE_NONE , L"Tab"));
3316 pButton->AddSubItem(new CMFCRibbonButton(start + TABMODE_USESPACES , L"Space"));
3317 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3318 pButton->AddSubItem(new CMFCRibbonButton(start + TABMODE_SMARTINDENT , L"Smart tab char"));
3319 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3320 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON1, L"1"));
3321 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON2, L"2"));
3322 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON4, L"4"));
3323 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON8, L"8"));
3324 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3325 pButton->AddSubItem(new CMFCRibbonButton(start + ENABLEEDITORCONFIG, L"EditorConfig"));
3328 bool CMainFrame::AdjustUnicodeTypeForLoad(CFileTextLines::UnicodeType& type)
3330 switch (type)
3332 case CFileTextLines::UnicodeType::AUTOTYPE:
3333 case CFileTextLines::UnicodeType::BINARY:
3334 return false;
3336 case CFileTextLines::UnicodeType::ASCII:
3337 case CFileTextLines::UnicodeType::UTF16_LE:
3338 case CFileTextLines::UnicodeType::UTF16_BE:
3339 case CFileTextLines::UnicodeType::UTF32_LE:
3340 case CFileTextLines::UnicodeType::UTF32_BE:
3341 case CFileTextLines::UnicodeType::UTF8:
3342 return true;
3344 case CFileTextLines::UnicodeType::UTF16_LEBOM:
3345 type = CFileTextLines::UnicodeType::UTF16_LE;
3346 return true;
3348 case CFileTextLines::UnicodeType::UTF16_BEBOM:
3349 type = CFileTextLines::UnicodeType::UTF16_BE;
3350 return true;
3352 case CFileTextLines::UnicodeType::UTF8BOM:
3353 type = CFileTextLines::UnicodeType::UTF8;
3354 return true;
3356 return false;
3359 void CMainFrame::OnEncodingLeft( UINT cmd )
3361 if (m_pwndLeftView)
3363 if (GetKeyState(VK_CONTROL) & 0x8000)
3365 // reload with selected encoding
3366 auto saveparams = m_Data.m_arBaseFile.GetSaveParams();
3367 saveparams.m_UnicodeType = CFileTextLines::UnicodeType(cmd - ID_INDICATOR_LEFTENCODINGSTART);
3368 if (AdjustUnicodeTypeForLoad(saveparams.m_UnicodeType))
3370 m_Data.m_arBaseFile.SetSaveParams(saveparams);
3371 m_Data.m_arBaseFile.KeepEncoding();
3372 LoadViews();
3375 else
3377 m_pwndLeftView->SetTextType(CFileTextLines::UnicodeType(cmd - ID_INDICATOR_LEFTENCODINGSTART));
3378 m_pwndLeftView->RefreshViews();
3383 void CMainFrame::OnEncodingRight( UINT cmd )
3385 if (m_pwndRightView)
3387 if (GetKeyState(VK_CONTROL) & 0x8000)
3389 // reload with selected encoding
3390 auto saveparams = m_Data.m_arYourFile.GetSaveParams();
3391 saveparams.m_UnicodeType = CFileTextLines::UnicodeType(cmd - ID_INDICATOR_RIGHTENCODINGSTART);
3392 if (AdjustUnicodeTypeForLoad(saveparams.m_UnicodeType))
3394 m_Data.m_arYourFile.SetSaveParams(saveparams);
3395 m_Data.m_arYourFile.KeepEncoding();
3396 LoadViews();
3399 else
3401 m_pwndRightView->SetTextType(CFileTextLines::UnicodeType(cmd - ID_INDICATOR_RIGHTENCODINGSTART));
3402 m_pwndRightView->RefreshViews();
3407 void CMainFrame::OnEncodingBottom( UINT cmd )
3409 if (m_pwndBottomView)
3411 if (GetKeyState(VK_CONTROL) & 0x8000)
3413 // reload with selected encoding
3414 auto saveparams = m_Data.m_arTheirFile.GetSaveParams();
3415 saveparams.m_UnicodeType = CFileTextLines::UnicodeType(cmd - ID_INDICATOR_BOTTOMENCODINGSTART);
3416 if (AdjustUnicodeTypeForLoad(saveparams.m_UnicodeType))
3418 m_Data.m_arTheirFile.SetSaveParams(saveparams);
3419 m_Data.m_arTheirFile.KeepEncoding();
3420 LoadViews();
3423 else
3425 m_pwndBottomView->SetTextType(CFileTextLines::UnicodeType(cmd - ID_INDICATOR_BOTTOMENCODINGSTART));
3426 m_pwndBottomView->RefreshViews();
3431 void CMainFrame::OnEOLLeft( UINT cmd )
3433 if (m_pwndLeftView)
3435 m_pwndLeftView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_LEFTEOLSTART));
3436 m_pwndLeftView->RefreshViews();
3440 void CMainFrame::OnEOLRight( UINT cmd )
3442 if (m_pwndRightView)
3444 m_pwndRightView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_RIGHTEOLSTART));
3445 m_pwndRightView->RefreshViews();
3449 void CMainFrame::OnEOLBottom( UINT cmd )
3451 if (m_pwndBottomView)
3453 m_pwndBottomView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_BOTTOMEOLSTART));
3454 m_pwndBottomView->RefreshViews();
3458 void CMainFrame::OnTabModeLeft( UINT cmd )
3460 OnTabMode(m_pwndLeftView, (int)cmd - ID_INDICATOR_LEFTTABMODESTART);
3463 void CMainFrame::OnTabModeRight( UINT cmd )
3465 OnTabMode(m_pwndRightView, (int)cmd - ID_INDICATOR_RIGHTTABMODESTART);
3468 void CMainFrame::OnTabModeBottom( UINT cmd )
3470 OnTabMode(m_pwndBottomView, (int)cmd - ID_INDICATOR_BOTTOMTABMODESTART);
3473 void CMainFrame::OnTabMode(CBaseView *view, int cmd)
3475 if (!view)
3476 return;
3477 int nTabMode = view->GetTabMode();
3478 if (cmd == TABMODE_NONE || cmd == TABMODE_USESPACES)
3479 view->SetTabMode((nTabMode & (~TABMODE_USESPACES)) | (cmd & TABMODE_USESPACES));
3480 else if (cmd == TABMODE_SMARTINDENT) // Toggle
3481 view->SetTabMode((nTabMode & (~TABMODE_SMARTINDENT)) | ((nTabMode & TABMODE_SMARTINDENT) ? 0 : TABMODE_SMARTINDENT));
3482 else if (cmd == TABSIZEBUTTON1)
3483 view->SetTabSize(1);
3484 else if (cmd == TABSIZEBUTTON2)
3485 view->SetTabSize(2);
3486 else if (cmd == TABSIZEBUTTON4)
3487 view->SetTabSize(4);
3488 else if (cmd == TABSIZEBUTTON8)
3489 view->SetTabSize(8);
3490 else if (cmd == ENABLEEDITORCONFIG)
3491 view->SetEditorConfigEnabled(!view->GetEditorConfigEnabled());
3492 view->RefreshViews();
3495 void CMainFrame::OnUpdateEncodingLeft( CCmdUI *pCmdUI )
3497 if (m_pwndLeftView)
3499 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_LEFTENCODINGSTART) == m_pwndLeftView->GetTextType());
3500 pCmdUI->Enable(m_pwndLeftView->IsWritable() || (GetKeyState(VK_CONTROL)&0x8000));
3502 else
3503 pCmdUI->Enable(FALSE);
3506 void CMainFrame::OnUpdateEncodingRight( CCmdUI *pCmdUI )
3508 if (m_pwndRightView)
3510 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_RIGHTENCODINGSTART) == m_pwndRightView->GetTextType());
3511 pCmdUI->Enable(m_pwndRightView->IsWritable() || (GetKeyState(VK_CONTROL) & 0x8000));
3513 else
3514 pCmdUI->Enable(FALSE);
3517 void CMainFrame::OnUpdateEncodingBottom( CCmdUI *pCmdUI )
3519 if (m_pwndBottomView)
3521 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_BOTTOMENCODINGSTART) == m_pwndBottomView->GetTextType());
3522 pCmdUI->Enable(m_pwndBottomView->IsWritable() || (GetKeyState(VK_CONTROL) & 0x8000));
3524 else
3525 pCmdUI->Enable(FALSE);
3528 void CMainFrame::OnUpdateEOLLeft( CCmdUI *pCmdUI )
3530 if (m_pwndLeftView)
3532 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_LEFTEOLSTART) == m_pwndLeftView->GetLineEndings());
3533 pCmdUI->Enable(m_pwndLeftView->IsWritable());
3535 else
3536 pCmdUI->Enable(FALSE);
3539 void CMainFrame::OnUpdateEOLRight( CCmdUI *pCmdUI )
3541 if (m_pwndRightView)
3543 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_RIGHTEOLSTART) == m_pwndRightView->GetLineEndings());
3544 pCmdUI->Enable(m_pwndRightView->IsWritable());
3546 else
3547 pCmdUI->Enable(FALSE);
3550 void CMainFrame::OnUpdateEOLBottom( CCmdUI *pCmdUI )
3552 if (m_pwndBottomView)
3554 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_BOTTOMEOLSTART) == m_pwndBottomView->GetLineEndings());
3555 pCmdUI->Enable(m_pwndBottomView->IsWritable());
3557 else
3558 pCmdUI->Enable(FALSE);
3561 void CMainFrame::OnUpdateTabModeLeft(CCmdUI *pCmdUI)
3563 OnUpdateTabMode(m_pwndLeftView, pCmdUI, ID_INDICATOR_LEFTTABMODESTART);
3566 void CMainFrame::OnUpdateTabModeRight(CCmdUI *pCmdUI)
3568 OnUpdateTabMode(m_pwndRightView, pCmdUI, ID_INDICATOR_RIGHTTABMODESTART);
3571 void CMainFrame::OnUpdateTabModeBottom(CCmdUI *pCmdUI)
3573 OnUpdateTabMode(m_pwndBottomView, pCmdUI, ID_INDICATOR_BOTTOMTABMODESTART);
3576 void CMainFrame::OnUpdateTabMode(CBaseView *view, CCmdUI *pCmdUI, int startid)
3578 if (view)
3580 int cmd = (int)pCmdUI->m_nID - startid;
3581 if (cmd == TABMODE_NONE)
3582 pCmdUI->SetCheck((view->GetTabMode() & TABMODE_USESPACES) == TABMODE_NONE);
3583 else if (cmd == TABMODE_USESPACES)
3584 pCmdUI->SetCheck(view->GetTabMode() & TABMODE_USESPACES);
3585 else if (cmd == TABMODE_SMARTINDENT)
3586 pCmdUI->SetCheck(view->GetTabMode() & TABMODE_SMARTINDENT);
3587 else if (cmd == TABSIZEBUTTON1)
3588 pCmdUI->SetCheck(view->GetTabSize() == 1);
3589 else if (cmd == TABSIZEBUTTON2)
3590 pCmdUI->SetCheck(view->GetTabSize() == 2);
3591 else if (cmd == TABSIZEBUTTON4)
3592 pCmdUI->SetCheck(view->GetTabSize() == 4);
3593 else if (cmd == TABSIZEBUTTON8)
3594 pCmdUI->SetCheck(view->GetTabSize() == 8);
3595 else if (cmd == ENABLEEDITORCONFIG)
3596 pCmdUI->SetCheck(view->GetEditorConfigEnabled());
3597 pCmdUI->Enable(view->IsWritable());
3598 if (cmd == ENABLEEDITORCONFIG)
3599 pCmdUI->Enable(view->IsWritable() && view->GetEditorConfigLoaded());
3601 else
3602 pCmdUI->Enable(FALSE);
3605 BOOL CMainFrame::OnShowPopupMenu(CMFCPopupMenu* pMenuPopup)
3607 __super::OnShowPopupMenu(pMenuPopup);
3609 if (!pMenuPopup)
3610 return TRUE;
3612 int iIndex = -1;
3613 if (!CMFCToolBar::IsCustomizeMode() &&
3614 (iIndex = pMenuPopup->GetMenuBar()->CommandToIndex(ID_REGEXFILTER)) >= 0)
3616 BuildRegexSubitems(pMenuPopup);
3619 return TRUE;
3622 LRESULT CMainFrame::OnIdleUpdateCmdUI(WPARAM wParam, LPARAM lParam)
3624 __super::OnIdleUpdateCmdUI(wParam, lParam);
3626 if (m_pRibbonApp)
3628 BOOL bDisableIfNoHandler = (BOOL)wParam;
3629 m_pRibbonApp->UpdateCmdUI(bDisableIfNoHandler);
3631 return 0;
3634 void CMainFrame::OnUpdateThreeWayActions(CCmdUI * pCmdUI)
3636 pCmdUI->Enable();
3639 void CMainFrame::OnRegexNoFilter()
3641 if (CheckForSave(CHFSR_OPTIONS) == IDCANCEL)
3642 return;
3643 m_Data.SetRegexTokens(std::wregex(), L"");
3644 m_regexIndex = -1;
3645 LoadViews(-1);
3648 void CMainFrame::OnUpdateRegexNoFilter(CCmdUI * pCmdUI)
3650 pCmdUI->SetCheck(m_regexIndex < 0);