TGitMerge: Don't use theirs/mine
[TortoiseGit.git] / src / TortoiseMerge / MainFrm.cpp
blob8dd8e7882825b2ab810bc5913cd8616d0757bb55
1 // TortoiseGitMerge - a Diff/Patch program
3 // Copyright (C) 2008-2017 - TortoiseGit
4 // Copyright (C) 2004-2015 - TortoiseSVN
5 // Copyright (C) 2012-2014 - Sven Strickroth <email@cs-ware.de>
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software Foundation,
19 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "stdafx.h"
22 #include "TortoiseMerge.h"
23 #include "CustomMFCRibbonButton.h"
24 #include "OpenDlg.h"
25 #include "SysProgressDlg.h"
26 #include "Settings.h"
27 #include "MessageBox.h"
28 #include "AppUtils.h"
29 #include "PathUtils.h"
30 #include "MainFrm.h"
31 #include "LeftView.h"
32 #include "RightView.h"
33 #include "BottomView.h"
34 #include "DiffColors.h"
35 #include "SelectFileFilter.h"
36 #include "FormatMessageWrapper.h"
37 #include "TaskbarUUID.h"
38 #include "RegexFiltersDlg.h"
40 #ifdef _DEBUG
41 #define new DEBUG_NEW
42 #endif
44 CCustomMFCRibbonButton button1;
46 // CMainFrame
47 #define IDT_RELOADCHECKTIMER 123
49 IMPLEMENT_DYNCREATE(CMainFrame, CFrameWndEx)
51 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)
52 ON_WM_CREATE()
53 ON_COMMAND_RANGE(ID_VIEW_APPLOOK_WIN7, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnApplicationLook)
54 ON_UPDATE_COMMAND_UI_RANGE(IDC_STYLEBUTTON, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnUpdateApplicationLook)
55 // Global help commands
56 ON_COMMAND(ID_HELP_FINDER, CFrameWndEx::OnHelpFinder)
57 ON_COMMAND(ID_HELP, CFrameWndEx::OnHelp)
58 ON_COMMAND(ID_CONTEXT_HELP, CFrameWndEx::OnContextHelp)
59 ON_COMMAND(ID_DEFAULT_HELP, CFrameWndEx::OnHelpFinder)
60 ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
61 ON_COMMAND(ID_VIEW_WHITESPACES, OnViewWhitespaces)
62 ON_WM_SIZE()
63 ON_COMMAND(ID_FILE_SAVE, OnFileSave)
64 ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
65 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave)
66 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_AS, OnUpdateFileSaveAs)
67 ON_COMMAND(ID_VIEW_ONEWAYDIFF, OnViewOnewaydiff)
68 ON_UPDATE_COMMAND_UI(ID_VIEW_ONEWAYDIFF, OnUpdateViewOnewaydiff)
69 ON_UPDATE_COMMAND_UI(ID_VIEW_WHITESPACES, OnUpdateViewWhitespaces)
70 ON_COMMAND(ID_VIEW_OPTIONS, OnViewOptions)
71 ON_WM_CLOSE()
72 ON_WM_ACTIVATE()
73 ON_COMMAND(ID_FILE_RELOAD, OnFileReload)
74 ON_COMMAND(ID_VIEW_LINEDOWN, OnViewLinedown)
75 ON_COMMAND(ID_VIEW_LINEUP, OnViewLineup)
76 ON_COMMAND(ID_VIEW_MOVEDBLOCKS, OnViewMovedBlocks)
77 ON_UPDATE_COMMAND_UI(ID_VIEW_MOVEDBLOCKS, OnUpdateViewMovedBlocks)
78 ON_UPDATE_COMMAND_UI(ID_EDIT_MARKASRESOLVED, OnUpdateMergeMarkasresolved)
79 ON_COMMAND(ID_EDIT_MARKASRESOLVED, OnMergeMarkasresolved)
80 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTCONFLICT, OnUpdateMergeNextconflict)
81 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSCONFLICT, OnUpdateMergePreviousconflict)
82 ON_WM_MOVE()
83 ON_WM_MOVING()
84 ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
85 ON_COMMAND(ID_VIEW_SWITCHLEFT, OnViewSwitchleft)
86 ON_UPDATE_COMMAND_UI(ID_VIEW_SWITCHLEFT, OnUpdateViewSwitchleft)
87 ON_COMMAND(ID_VIEW_LINELEFT, &CMainFrame::OnViewLineleft)
88 ON_COMMAND(ID_VIEW_LINERIGHT, &CMainFrame::OnViewLineright)
89 ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWFILELIST, &CMainFrame::OnUpdateViewShowfilelist)
90 ON_COMMAND(ID_VIEW_SHOWFILELIST, &CMainFrame::OnViewShowfilelist)
91 ON_COMMAND(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnEditUseTheirs)
92 ON_COMMAND(ID_EDIT_USEMYBLOCK, &CMainFrame::OnEditUseMine)
93 ON_COMMAND(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnEditUseTheirsThenMine)
94 ON_COMMAND(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnEditUseMineThenTheirs)
95 ON_COMMAND(ID_EDIT_UNDO, &CMainFrame::OnEditUndo)
96 ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, &CMainFrame::OnUpdateEditUndo)
97 ON_COMMAND(ID_EDIT_REDO, &CMainFrame::OnEditRedo)
98 ON_UPDATE_COMMAND_UI(ID_EDIT_REDO, &CMainFrame::OnUpdateEditRedo)
99 ON_COMMAND(ID_EDIT_ENABLE, &CMainFrame::OnEditEnable)
100 ON_UPDATE_COMMAND_UI(ID_EDIT_ENABLE, &CMainFrame::OnUpdateEditEnable)
101 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnUpdateEditUseminethentheirblock)
102 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMYBLOCK, &CMainFrame::OnUpdateEditUsemyblock)
103 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnUpdateEditUsetheirblock)
104 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnUpdateEditUsetheirthenmyblock)
105 ON_COMMAND(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnViewInlinediffword)
106 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnUpdateViewInlinediffword)
107 ON_COMMAND(ID_VIEW_INLINEDIFF, &CMainFrame::OnViewInlinediff)
108 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFF, &CMainFrame::OnUpdateViewInlinediff)
109 ON_UPDATE_COMMAND_UI(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnUpdateEditCreateunifieddifffile)
110 ON_COMMAND(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnEditCreateunifieddifffile)
111 ON_UPDATE_COMMAND_UI(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnUpdateViewLinediffbar)
112 ON_COMMAND(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnViewLinediffbar)
113 ON_UPDATE_COMMAND_UI(ID_VIEW_BARS, &CMainFrame::OnUpdateViewBars)
114 ON_UPDATE_COMMAND_UI(ID_VIEW_LOCATORBAR, &CMainFrame::OnUpdateViewLocatorbar)
115 ON_COMMAND(ID_VIEW_LOCATORBAR, &CMainFrame::OnViewLocatorbar)
116 ON_COMMAND(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnEditUseleftblock)
117 ON_UPDATE_COMMAND_UI(ID_USEBLOCKS, &CMainFrame::OnUpdateUseBlock)
118 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnUpdateEditUseleftblock)
119 ON_COMMAND(ID_EDIT_USELEFTFILE, &CMainFrame::OnEditUseleftfile)
120 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTFILE, &CMainFrame::OnUpdateEditUseleftfile)
121 ON_COMMAND(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnEditUseblockfromleftbeforeright)
122 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnUpdateEditUseblockfromleftbeforeright)
123 ON_COMMAND(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnEditUseblockfromrightbeforeleft)
124 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnUpdateEditUseblockfromrightbeforeleft)
125 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTDIFFERENCE, &CMainFrame::OnUpdateNavigateNextdifference)
126 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSDIFFERENCE, &CMainFrame::OnUpdateNavigatePreviousdifference)
127 ON_COMMAND(ID_VIEW_COLLAPSED, &CMainFrame::OnViewCollapsed)
128 ON_UPDATE_COMMAND_UI(ID_VIEW_COLLAPSED, &CMainFrame::OnUpdateViewCollapsed)
129 ON_COMMAND(ID_VIEW_COMPAREWHITESPACES, &CMainFrame::OnViewComparewhitespaces)
130 ON_UPDATE_COMMAND_UI(ID_VIEW_COMPAREWHITESPACES, &CMainFrame::OnUpdateViewComparewhitespaces)
131 ON_COMMAND(ID_VIEW_IGNOREWHITESPACECHANGES, &CMainFrame::OnViewIgnorewhitespacechanges)
132 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREWHITESPACECHANGES, &CMainFrame::OnUpdateViewIgnorewhitespacechanges)
133 ON_COMMAND(ID_VIEW_IGNOREALLWHITESPACECHANGES, &CMainFrame::OnViewIgnoreallwhitespacechanges)
134 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREALLWHITESPACECHANGES, &CMainFrame::OnUpdateViewIgnoreallwhitespacechanges)
135 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTINLINEDIFF, &CMainFrame::OnUpdateNavigateNextinlinediff)
136 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVINLINEDIFF, &CMainFrame::OnUpdateNavigatePrevinlinediff)
137 ON_COMMAND(ID_VIEW_WRAPLONGLINES, &CMainFrame::OnViewWraplonglines)
138 ON_UPDATE_COMMAND_UI(ID_VIEW_WRAPLONGLINES, &CMainFrame::OnUpdateViewWraplonglines)
139 ON_REGISTERED_MESSAGE( TaskBarButtonCreated, CMainFrame::OnTaskbarButtonCreated )
140 ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, &CMainFrame::OnUpdateEditPaste)
141 ON_COMMAND(ID_INDICATOR_LEFTVIEW, &CMainFrame::OnIndicatorLeftview)
142 ON_COMMAND(ID_INDICATOR_RIGHTVIEW, &CMainFrame::OnIndicatorRightview)
143 ON_COMMAND(ID_INDICATOR_BOTTOMVIEW, &CMainFrame::OnIndicatorBottomview)
144 ON_WM_TIMER()
145 ON_COMMAND(ID_VIEW_IGNORECOMMENTS, &CMainFrame::OnViewIgnorecomments)
146 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNORECOMMENTS, &CMainFrame::OnUpdateViewIgnorecomments)
147 ON_COMMAND_RANGE(ID_REGEXFILTER, ID_REGEXFILTER+400, &CMainFrame::OnRegexfilter)
148 ON_UPDATE_COMMAND_UI_RANGE(ID_REGEXFILTER, ID_REGEXFILTER+400, &CMainFrame::OnUpdateViewRegexFilter)
149 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOENCODING, &CMainFrame::OnDummyEnabled)
150 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOENCODING, &CMainFrame::OnDummyEnabled)
151 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOENCODING, &CMainFrame::OnDummyEnabled)
152 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOEOL, &CMainFrame::OnDummyEnabled)
153 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOEOL, &CMainFrame::OnDummyEnabled)
154 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOEOL, &CMainFrame::OnDummyEnabled)
155 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOTABMODE, &CMainFrame::OnDummyEnabled)
156 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOTABMODE, &CMainFrame::OnDummyEnabled)
157 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOTABMODE, &CMainFrame::OnDummyEnabled)
158 ON_COMMAND_RANGE(ID_INDICATOR_LEFTENCODINGSTART, ID_INDICATOR_LEFTENCODINGSTART+19, &CMainFrame::OnEncodingLeft)
159 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTENCODINGSTART, ID_INDICATOR_RIGHTENCODINGSTART+19, &CMainFrame::OnEncodingRight)
160 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMENCODINGSTART, ID_INDICATOR_BOTTOMENCODINGSTART+19, &CMainFrame::OnEncodingBottom)
161 ON_COMMAND_RANGE(ID_INDICATOR_LEFTEOLSTART, ID_INDICATOR_LEFTEOLSTART+19, &CMainFrame::OnEOLLeft)
162 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTEOLSTART, ID_INDICATOR_RIGHTEOLSTART+19, &CMainFrame::OnEOLRight)
163 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMEOLSTART, ID_INDICATOR_BOTTOMEOLSTART+19, &CMainFrame::OnEOLBottom)
164 ON_COMMAND_RANGE(ID_INDICATOR_LEFTTABMODESTART, ID_INDICATOR_LEFTTABMODESTART+19, &CMainFrame::OnTabModeLeft)
165 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTTABMODESTART, ID_INDICATOR_RIGHTTABMODESTART+19, &CMainFrame::OnTabModeRight)
166 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMTABMODESTART, ID_INDICATOR_BOTTOMTABMODESTART+19, &CMainFrame::OnTabModeBottom)
167 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTENCODINGSTART, ID_INDICATOR_LEFTENCODINGSTART+19, &CMainFrame::OnUpdateEncodingLeft)
168 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTENCODINGSTART, ID_INDICATOR_RIGHTENCODINGSTART+19, &CMainFrame::OnUpdateEncodingRight)
169 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMENCODINGSTART, ID_INDICATOR_BOTTOMENCODINGSTART+19, &CMainFrame::OnUpdateEncodingBottom)
170 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTEOLSTART, ID_INDICATOR_LEFTEOLSTART+19, &CMainFrame::OnUpdateEOLLeft)
171 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTEOLSTART, ID_INDICATOR_RIGHTEOLSTART+19, &CMainFrame::OnUpdateEOLRight)
172 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMEOLSTART, ID_INDICATOR_BOTTOMEOLSTART+19, &CMainFrame::OnUpdateEOLBottom)
173 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTTABMODESTART, ID_INDICATOR_LEFTTABMODESTART+19, &CMainFrame::OnUpdateTabModeLeft)
174 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTTABMODESTART, ID_INDICATOR_RIGHTTABMODESTART+19, &CMainFrame::OnUpdateTabModeRight)
175 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMTABMODESTART, ID_INDICATOR_BOTTOMTABMODESTART+19, &CMainFrame::OnUpdateTabModeBottom)
176 ON_WM_NCCALCSIZE()
177 END_MESSAGE_MAP()
179 static UINT indicators[] =
181 ID_SEPARATOR, // status line indicator
182 ID_INDICATOR_LEFTVIEW,
183 ID_INDICATOR_RIGHTVIEW,
184 ID_INDICATOR_BOTTOMVIEW,
185 ID_INDICATOR_CAPS,
186 ID_INDICATOR_NUM,
187 ID_INDICATOR_SCRL
191 // CMainFrame construction/destruction
193 CMainFrame::CMainFrame()
194 : m_bInitSplitter(FALSE)
195 , m_bReversedPatch(FALSE)
196 , m_bHasConflicts(false)
197 , m_bInlineWordDiff(true)
198 , m_bLineDiff(true)
199 , m_bLocatorBar(true)
200 , m_nMoveMovesToIgnore(0)
201 , m_pwndLeftView(nullptr)
202 , m_pwndRightView(nullptr)
203 , m_pwndBottomView(nullptr)
204 , m_bReadOnly(false)
205 , m_bBlame(false)
206 , m_bCheckReload(false)
207 , m_bSaveRequired(false)
208 , m_bSaveRequiredOnConflicts(false)
209 , m_bDeleteBaseTheirsMineOnClose(false)
210 , resolveMsgWnd(0)
211 , resolveMsgWParam(0)
212 , resolveMsgLParam(0)
213 , m_regWrapLines(L"Software\\TortoiseGitMerge\\WrapLines", 0)
214 , m_regViewModedBlocks(L"Software\\TortoiseGitMerge\\ViewMovedBlocks", TRUE)
215 , m_regOneWay(L"Software\\TortoiseGitMerge\\OnePane")
216 , m_regCollapsed(L"Software\\TortoiseGitMerge\\Collapsed", 0)
217 , m_regInlineDiff(L"Software\\TortoiseGitMerge\\DisplayBinDiff", TRUE)
218 , m_regUseRibbons(L"Software\\TortoiseGitMerge\\UseRibbons", TRUE)
219 , m_regIgnoreComments(L"Software\\TortoiseGitMerge\\IgnoreComments", FALSE)
220 , m_regexIndex(-1)
222 m_bOneWay = (0 != ((DWORD)m_regOneWay));
223 theApp.m_nAppLook = theApp.GetInt(L"ApplicationLook", ID_VIEW_APPLOOK_VS_2005);
224 m_bCollapsed = !!(DWORD)m_regCollapsed;
225 m_bViewMovedBlocks = !!(DWORD)m_regViewModedBlocks;
226 m_bWrapLines = !!(DWORD)m_regWrapLines;
227 m_bInlineDiff = !!m_regInlineDiff;
228 m_bUseRibbons = !!m_regUseRibbons;
229 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
232 CMainFrame::~CMainFrame()
236 LRESULT CMainFrame::OnTaskbarButtonCreated(WPARAM /*wParam*/, LPARAM /*lParam*/)
238 SetUUIDOverlayIcon(m_hWnd);
239 return 0;
243 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
245 if (CFrameWndEx::OnCreate(lpCreateStruct) == -1)
246 return -1;
248 OnApplicationLook(theApp.m_nAppLook);
250 if (m_bUseRibbons)
252 m_wndRibbonBar.Create(this);
253 m_wndRibbonBar.LoadFromResource(IDR_RIBBON);
255 // enable the dialog launch button on the view panel
256 CMFCRibbonCategory * pMainCat = m_wndRibbonBar.GetCategory(1);
257 if (pMainCat)
259 CMFCRibbonPanel * pPanel = pMainCat->GetPanel(0);
260 if (pPanel)
261 pPanel->EnableLaunchButton(ID_VIEW_OPTIONS);
263 // now replace all buttons with our custom button class
264 for (int i = 0; i < m_wndRibbonBar.GetCategoryCount(); ++i)
266 CMFCRibbonCategory * pCat = m_wndRibbonBar.GetCategory(i);
267 for (int j = 0; j < pCat->GetPanelCount(); ++j)
269 CMFCRibbonPanel * pPanel = pCat->GetPanel(j);
270 CList<UINT, UINT> lstItems;
271 pPanel->GetItemIDsList(lstItems);
272 while (!lstItems.IsEmpty())
274 UINT id = lstItems.GetHead();
275 lstItems.RemoveHead();
276 CMFCRibbonButton * pButton = dynamic_cast<CMFCRibbonButton*>(pPanel->FindByID(id));
277 if (pButton)
279 CCustomMFCRibbonButton * c = new CCustomMFCRibbonButton(id, pButton->GetText());
280 pPanel->ReplaceByID(id, c);
285 BuildRegexSubitems();
286 if (!m_wndRibbonStatusBar.Create(this))
288 TRACE0("Failed to create ribbon status bar\n");
289 return -1; // fail to create
291 m_wndRibbonStatusBar.AddElement(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(AFX_IDS_IDLEMESSAGE)), TRUE), L"");
293 CString sTooltip(MAKEINTRESOURCE(IDS_ENCODING_COMBO_TOOLTIP));
294 auto apBtnGroupLeft = std::make_unique<CMFCRibbonButtonsGroup>();
295 apBtnGroupLeft->SetID(ID_INDICATOR_LEFTVIEW);
296 apBtnGroupLeft->AddButton(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(IDS_STATUSBAR_LEFTVIEW)), TRUE));
297 CMFCRibbonButton * pButton = new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOENCODING, L"");
298 pButton->SetToolTipText(sTooltip);
299 FillEncodingButton(pButton, ID_INDICATOR_LEFTENCODINGSTART);
300 apBtnGroupLeft->AddButton(pButton);
301 pButton = new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOEOL, L"");
302 FillEOLButton(pButton, ID_INDICATOR_LEFTEOLSTART);
303 apBtnGroupLeft->AddButton(pButton);
304 pButton = new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOTABMODE, L"");
305 FillTabModeButton(pButton, ID_INDICATOR_LEFTTABMODESTART);
306 apBtnGroupLeft->AddButton(pButton);
307 apBtnGroupLeft->AddButton(new CMFCRibbonStatusBarPane(ID_INDICATOR_LEFTVIEW, L"", TRUE));
308 m_wndRibbonStatusBar.AddExtendedElement(apBtnGroupLeft.release(), L"");
310 auto apBtnGroupRight = std::make_unique<CMFCRibbonButtonsGroup>();
311 apBtnGroupRight->SetID(ID_INDICATOR_RIGHTVIEW);
312 apBtnGroupRight->AddButton(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(IDS_STATUSBAR_RIGHTVIEW)), TRUE));
313 pButton = new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOENCODING, L"");
314 pButton->SetToolTipText(sTooltip);
315 FillEncodingButton(pButton, ID_INDICATOR_RIGHTENCODINGSTART);
316 apBtnGroupRight->AddButton(pButton);
317 pButton = new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOEOL, L"");
318 FillEOLButton(pButton, ID_INDICATOR_RIGHTEOLSTART);
319 apBtnGroupRight->AddButton(pButton);
320 pButton = new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOTABMODE, L"");
321 FillTabModeButton(pButton, ID_INDICATOR_RIGHTTABMODESTART);
322 apBtnGroupRight->AddButton(pButton);
323 apBtnGroupRight->AddButton(new CMFCRibbonStatusBarPane(ID_INDICATOR_RIGHTVIEW, L"", TRUE));
324 m_wndRibbonStatusBar.AddExtendedElement(apBtnGroupRight.release(), L"");
326 else
328 if (!m_wndMenuBar.Create(this))
330 TRACE0("Failed to create menubar\n");
331 return -1; // fail to create
333 m_wndMenuBar.SetPaneStyle(m_wndMenuBar.GetPaneStyle() | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY);
335 // prevent the menu bar from taking the focus on activation
336 CMFCPopupMenu::SetForceMenuFocus(FALSE);
337 if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
339 TRACE0("Failed to create toolbar\n");
340 return -1; // fail to create
342 m_wndToolBar.SetWindowText(L"Main");
343 if (!m_wndStatusBar.Create(this) ||
344 !m_wndStatusBar.SetIndicators(indicators,
345 _countof(indicators)))
347 TRACE0("Failed to create status bar\n");
348 return -1; // fail to create
350 m_wndStatusBar.EnablePaneDoubleClick();
353 if (!m_wndLocatorBar.Create(this, IDD_DIFFLOCATOR,
354 CBRS_ALIGN_LEFT | CBRS_SIZE_FIXED, ID_VIEW_LOCATORBAR))
356 TRACE0("Failed to create dialogbar\n");
357 return -1; // fail to create
359 if (!m_wndLineDiffBar.Create(this, IDD_LINEDIFF,
360 CBRS_ALIGN_BOTTOM | CBRS_SIZE_FIXED, ID_VIEW_LINEDIFFBAR))
362 TRACE0("Failed to create dialogbar\n");
363 return -1; // fail to create
365 m_wndLocatorBar.m_pMainFrm = this;
366 m_wndLineDiffBar.m_pMainFrm = this;
368 EnableDocking(CBRS_ALIGN_ANY);
369 if (!m_bUseRibbons)
371 m_wndMenuBar.EnableDocking(CBRS_ALIGN_TOP);
372 m_wndToolBar.EnableDocking(CBRS_ALIGN_TOP);
373 DockPane(&m_wndMenuBar);
374 DockPane(&m_wndToolBar);
376 DockPane(&m_wndLocatorBar);
377 DockPane(&m_wndLineDiffBar);
378 ShowPane(&m_wndLocatorBar, true, false, true);
379 ShowPane(&m_wndLineDiffBar, true, false, true);
381 m_wndLocatorBar.EnableGripper(FALSE);
382 m_wndLineDiffBar.EnableGripper(FALSE);
384 return 0;
387 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
389 if( !CFrameWndEx::PreCreateWindow(cs) )
390 return FALSE;
391 return TRUE;
394 void CMainFrame::OnApplicationLook(UINT id)
396 CWaitCursor wait;
398 theApp.m_nAppLook = id;
400 switch (theApp.m_nAppLook)
402 case ID_VIEW_APPLOOK_WIN_2000:
403 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManager));
404 m_wndRibbonBar.SetWindows7Look(FALSE);
405 break;
407 case ID_VIEW_APPLOOK_OFF_XP:
408 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOfficeXP));
409 m_wndRibbonBar.SetWindows7Look(FALSE);
410 break;
412 case ID_VIEW_APPLOOK_WIN_XP:
413 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
414 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
415 m_wndRibbonBar.SetWindows7Look(FALSE);
416 break;
418 case ID_VIEW_APPLOOK_OFF_2003:
419 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2003));
420 CDockingManager::SetDockingMode(DT_SMART);
421 m_wndRibbonBar.SetWindows7Look(FALSE);
422 break;
424 case ID_VIEW_APPLOOK_VS_2005:
425 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2005));
426 CDockingManager::SetDockingMode(DT_SMART);
427 m_wndRibbonBar.SetWindows7Look(FALSE);
428 break;
430 case ID_VIEW_APPLOOK_VS_2008:
431 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2008));
432 CDockingManager::SetDockingMode(DT_SMART);
433 m_wndRibbonBar.SetWindows7Look(FALSE);
434 break;
436 case ID_VIEW_APPLOOK_WIN7:
437 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows7));
438 CDockingManager::SetDockingMode(DT_SMART);
439 m_wndRibbonBar.SetWindows7Look(TRUE);
440 break;
442 default:
443 switch (theApp.m_nAppLook)
445 case ID_VIEW_APPLOOK_OFF_2007_BLUE:
446 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_LunaBlue);
447 break;
449 case ID_VIEW_APPLOOK_OFF_2007_BLACK:
450 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_ObsidianBlack);
451 break;
453 case ID_VIEW_APPLOOK_OFF_2007_SILVER:
454 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Silver);
455 break;
457 case ID_VIEW_APPLOOK_OFF_2007_AQUA:
458 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Aqua);
459 break;
462 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));
463 CDockingManager::SetDockingMode(DT_SMART);
464 m_wndRibbonBar.SetWindows7Look(FALSE);
467 RedrawWindow(nullptr, nullptr, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_FRAME | RDW_ERASE);
469 theApp.WriteInt(L"ApplicationLook", theApp.m_nAppLook);
472 void CMainFrame::OnUpdateApplicationLook(CCmdUI* pCmdUI)
474 pCmdUI->Enable();
475 pCmdUI->SetRadio(theApp.m_nAppLook == pCmdUI->m_nID);
479 // CMainFrame diagnostics
481 #ifdef _DEBUG
482 void CMainFrame::AssertValid() const
484 CFrameWndEx::AssertValid();
487 void CMainFrame::Dump(CDumpContext& dc) const
489 CFrameWndEx::Dump(dc);
492 #endif //_DEBUG
495 // CMainFrame message handlers
498 BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)
500 CRect cr;
501 GetClientRect( &cr);
504 // split into three panes:
505 // -------------
506 // | | |
507 // | | |
508 // |------------
509 // | |
510 // | |
511 // |------------
513 // create a splitter with 2 rows, 1 column
514 if (!m_wndSplitter.CreateStatic(this, 2, 1))
516 TRACE0("Failed to CreateStaticSplitter\n");
517 return FALSE;
520 // add the second splitter pane - which is a nested splitter with 2 columns
521 if (!m_wndSplitter2.CreateStatic(
522 &m_wndSplitter, // our parent window is the first splitter
523 1, 2, // the new splitter is 1 row, 2 columns
524 WS_CHILD | WS_VISIBLE | WS_BORDER, // style, WS_BORDER is needed
525 m_wndSplitter.IdFromRowCol(0, 0)
526 // new splitter is in the first row, 1st column of first splitter
529 TRACE0("Failed to create nested splitter\n");
530 return FALSE;
532 // add the first splitter pane - the default view in row 0
533 if (!m_wndSplitter.CreateView(1, 0,
534 RUNTIME_CLASS(CBottomView), CSize(cr.Width(), cr.Height()), pContext))
536 TRACE0("Failed to create first pane\n");
537 return FALSE;
539 m_pwndBottomView = static_cast<CBottomView*>(m_wndSplitter.GetPane(1, 0));
540 m_pwndBottomView->m_pwndLocator = &m_wndLocatorBar;
541 m_pwndBottomView->m_pwndLineDiffBar = &m_wndLineDiffBar;
542 if (m_bUseRibbons)
543 m_pwndBottomView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
544 else
545 m_pwndBottomView->m_pwndStatusBar = &m_wndStatusBar;
546 m_pwndBottomView->m_pMainFrame = this;
548 // now create the two views inside the nested splitter
550 if (!m_wndSplitter2.CreateView(0, 0,
551 RUNTIME_CLASS(CLeftView), CSize(cr.Width()/2, cr.Height()/2), pContext))
553 TRACE0("Failed to create second pane\n");
554 return FALSE;
556 m_pwndLeftView = static_cast<CLeftView*>(m_wndSplitter2.GetPane(0, 0));
557 m_pwndLeftView->m_pwndLocator = &m_wndLocatorBar;
558 m_pwndLeftView->m_pwndLineDiffBar = &m_wndLineDiffBar;
559 if (m_bUseRibbons)
560 m_pwndLeftView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
561 else
562 m_pwndLeftView->m_pwndStatusBar = &m_wndStatusBar;
563 m_pwndLeftView->m_pMainFrame = this;
565 if (!m_wndSplitter2.CreateView(0, 1,
566 RUNTIME_CLASS(CRightView), CSize(cr.Width()/2, cr.Height()/2), pContext))
568 TRACE0("Failed to create third pane\n");
569 return FALSE;
571 m_pwndRightView = static_cast<CRightView*>(m_wndSplitter2.GetPane(0, 1));
572 m_pwndRightView->m_pwndLocator = &m_wndLocatorBar;
573 m_pwndRightView->m_pwndLineDiffBar = &m_wndLineDiffBar;
574 if (m_bUseRibbons)
575 m_pwndRightView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
576 else
577 m_pwndRightView->m_pwndStatusBar = &m_wndStatusBar;
578 m_pwndRightView->m_pMainFrame = this;
579 m_bInitSplitter = TRUE;
581 m_dlgFilePatches.Create(IDD_FILEPATCHES, this);
582 UpdateLayout();
583 return TRUE;
586 // Callback function
587 BOOL CMainFrame::PatchFile(CString sFilePath, bool /*bContentMods*/, bool bPropMods, CString sVersion, BOOL bAutoPatch)
589 //"dry run" was successful, so save the patched file somewhere...
590 CString sTempFile = CTempFiles::Instance().GetTempFilePathString();
591 CString sRejectedFile, sBasePath;
592 if (m_Patch.GetPatchResult(sFilePath, sTempFile, sRejectedFile, sBasePath) < 0)
594 MessageBox(m_Patch.GetErrorMessage(), nullptr, MB_ICONERROR);
595 return FALSE;
597 sFilePath = m_Patch.GetTargetPath() + L'\\' + sFilePath;
598 sFilePath.Replace('/', '\\');
599 if (sBasePath.IsEmpty())
600 sBasePath = sFilePath;
601 if (m_bReversedPatch)
603 m_Data.m_baseFile.SetFileName(sTempFile);
604 CString temp;
605 temp.Format(L"%s %s", (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
606 m_Data.m_baseFile.SetDescriptiveName(temp);
607 m_Data.m_yourFile.SetFileName(sFilePath);
608 temp.Format(L"%s %s", (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchOriginal);
609 m_Data.m_yourFile.SetDescriptiveName(temp);
610 m_Data.m_theirFile.SetOutOfUse();
611 m_Data.m_mergedFile.SetOutOfUse();
613 else
615 if ((!PathFileExists(sBasePath))||(PathIsDirectory(sBasePath)))
617 m_Data.m_baseFile.SetFileName(CTempFiles::Instance().GetTempFilePathString());
618 m_Data.m_baseFile.CreateEmptyFile();
620 else
622 m_Data.m_baseFile.SetFileName(sBasePath);
624 CString sDescription;
625 sDescription.Format(L"%s %s", (LPCTSTR)CPathUtils::GetFileNameFromPath(sBasePath), (LPCTSTR)m_Data.m_sPatchOriginal);
626 m_Data.m_baseFile.SetDescriptiveName(sDescription);
627 if (sBasePath == sFilePath)
629 m_Data.m_yourFile.SetFileName(sTempFile);
630 CString temp;
631 temp.Format(L"%s %s", (LPCTSTR)CPathUtils::GetFileNameFromPath(sBasePath), (LPCTSTR)m_Data.m_sPatchPatched);
632 m_Data.m_yourFile.SetDescriptiveName(temp);
633 m_Data.m_theirFile.SetOutOfUse();
635 else
637 if (!PathFileExists(sFilePath) || PathIsDirectory(sFilePath))
639 m_Data.m_yourFile.SetFileName(CTempFiles::Instance().GetTempFilePathString());
640 m_Data.m_yourFile.CreateEmptyFile();
641 CString temp;
642 temp.Format(L"%s %s", (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)CString(MAKEINTRESOURCE(IDS_NOTFOUNDVIEWTITLEINDICATOR)));
643 m_Data.m_yourFile.SetDescriptiveName(temp);
645 else
646 m_Data.m_yourFile.SetFileName(sFilePath);
647 m_Data.m_theirFile.SetFileName(sTempFile);
648 CString temp;
649 temp.Format(L"%s %s", (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
650 m_Data.m_theirFile.SetDescriptiveName(temp);
652 m_Data.m_mergedFile.SetFileName(sFilePath);
653 m_Data.m_bPatchRequired = bPropMods;
655 TRACE(L"comparing %s\nwith the patched result %s\n", (LPCTSTR)sFilePath, (LPCTSTR)sTempFile);
657 LoadViews();
658 if (!sRejectedFile.IsEmpty())
660 #if 0 // TGIT TODO
661 // start TortoiseUDiff with the rejected hunks
662 CString sTitle;
663 sTitle.Format(IDS_TITLE_REJECTEDHUNKS, (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath));
664 CAppUtils::StartUnifiedDiffViewer(sRejectedFile, sTitle);
665 #endif
667 if (bAutoPatch)
669 if (sBasePath != sFilePath && HasConflictsWontKeep())
670 return FALSE;
672 PatchSave();
674 return TRUE;
677 // Callback function
678 BOOL CMainFrame::DiffFiles(CString sURL1, CString sRev1, CString sURL2, CString sRev2)
680 CString tempfile1 = CTempFiles::Instance().GetTempFilePathString();
681 CString tempfile2 = CTempFiles::Instance().GetTempFilePathString();
683 ASSERT(tempfile1.Compare(tempfile2));
685 CString sTemp;
686 CSysProgressDlg progDlg;
687 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev1);
688 progDlg.SetLine(1, sTemp, true);
689 progDlg.SetLine(2, sURL1, true);
690 sTemp.LoadString(IDS_GETVERSIONOFFILETITLE);
691 progDlg.SetTitle(sTemp);
692 progDlg.SetShowProgressBar(true);
693 progDlg.SetTime(FALSE);
694 progDlg.SetProgress(1,100);
695 progDlg.ShowModeless(this);
696 if (!CAppUtils::GetVersionedFile(sURL1, sRev1, tempfile1, &progDlg, m_hWnd))
698 progDlg.Stop();
699 CString sErrMsg;
700 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev1, (LPCTSTR)sURL1);
701 MessageBox(sErrMsg, nullptr, MB_ICONERROR);
702 return FALSE;
704 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev2);
705 progDlg.SetLine(1, sTemp, true);
706 progDlg.SetLine(2, sURL2, true);
707 progDlg.SetProgress(50, 100);
708 if (!CAppUtils::GetVersionedFile(sURL2, sRev2, tempfile2, &progDlg, m_hWnd))
710 progDlg.Stop();
711 CString sErrMsg;
712 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev2, (LPCTSTR)sURL2);
713 MessageBox(sErrMsg, nullptr, MB_ICONERROR);
714 return FALSE;
716 progDlg.SetProgress(100,100);
717 progDlg.Stop();
718 CString temp;
719 temp.Format(L"%s Revision %s", (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL1), (LPCTSTR)sRev1);
720 m_Data.m_baseFile.SetFileName(tempfile1);
721 m_Data.m_baseFile.SetDescriptiveName(temp);
722 temp.Format(L"%s Revision %s", (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL2), (LPCTSTR)sRev2);
723 m_Data.m_yourFile.SetFileName(tempfile2);
724 m_Data.m_yourFile.SetDescriptiveName(temp);
726 LoadViews();
728 return TRUE;
731 void CMainFrame::OnFileOpen()
733 if (CheckForSave(CHFSR_OPEN)==IDCANCEL)
734 return;
735 return OnFileOpen(false);
738 void CMainFrame::OnFileOpen(bool fillyours)
740 COpenDlg dlg;
741 if (fillyours)
742 dlg.m_sBaseFile = m_Data.m_yourFile.GetFilename();
743 if (dlg.DoModal() != IDOK)
745 return;
747 m_dlgFilePatches.ShowWindow(SW_HIDE);
748 m_dlgFilePatches.Init(nullptr, nullptr, CString(), nullptr);
749 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,
750 (LPCTSTR)dlg.m_sUnifiedDiffFile, (LPCTSTR)dlg.m_sPatchDirectory);
751 m_Data.m_baseFile.SetFileName(dlg.m_sBaseFile);
752 m_Data.m_theirFile.SetFileName(dlg.m_sTheirFile);
753 m_Data.m_yourFile.SetFileName(dlg.m_sYourFile);
754 m_Data.m_sDiffFile = dlg.m_sUnifiedDiffFile;
755 m_Data.m_sPatchPath = dlg.m_sPatchDirectory;
756 m_Data.m_mergedFile.SetOutOfUse();
757 CCrashReport::Instance().AddFile2(dlg.m_sBaseFile, nullptr, L"Basefile", CR_AF_MAKE_FILE_COPY);
758 CCrashReport::Instance().AddFile2(dlg.m_sTheirFile, nullptr, L"Theirfile", CR_AF_MAKE_FILE_COPY);
759 CCrashReport::Instance().AddFile2(dlg.m_sYourFile, nullptr, L"Yourfile", CR_AF_MAKE_FILE_COPY);
760 CCrashReport::Instance().AddFile2(dlg.m_sUnifiedDiffFile, nullptr, L"Difffile", CR_AF_MAKE_FILE_COPY);
762 if (!m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && m_Data.IsYourFileInUse())
764 // a diff between two files means "Yours" against "Base", not "Theirs" against "Yours"
765 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
767 if (m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && !m_Data.IsYourFileInUse())
769 // a diff between two files means "Yours" against "Base", not "Theirs" against "Base"
770 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
772 m_bSaveRequired = false;
774 LoadViews();
777 void CMainFrame::ClearViewNamesAndPaths()
779 m_pwndLeftView->m_sWindowName.Empty();
780 m_pwndLeftView->m_sFullFilePath.Empty();
781 m_pwndLeftView->m_sReflectedName.Empty();
782 m_pwndRightView->m_sWindowName.Empty();
783 m_pwndRightView->m_sFullFilePath.Empty();
784 m_pwndRightView->m_sReflectedName.Empty();
785 m_pwndBottomView->m_sWindowName.Empty();
786 m_pwndBottomView->m_sFullFilePath.Empty();
787 m_pwndBottomView->m_sReflectedName.Empty();
790 bool CMainFrame::LoadViews(int line)
792 LoadIgnoreCommentData();
793 m_Data.SetBlame(m_bBlame);
794 m_Data.SetMovedBlocks(m_bViewMovedBlocks);
795 m_bHasConflicts = false;
796 CBaseView* pwndActiveView = m_pwndLeftView;
797 int nOldLine = m_pwndRightView ? m_pwndRightView->m_nTopLine : -1;
798 int nOldLineNumber =
799 m_pwndRightView && m_pwndRightView->m_pViewData ?
800 m_pwndRightView->m_pViewData->GetLineNumber(m_pwndRightView->m_nTopLine) : -1;
801 POINT ptOldCaretPos = {-1, -1};
802 if (m_pwndRightView && m_pwndRightView->IsTarget())
803 ptOldCaretPos = m_pwndRightView->GetCaretPosition();
804 if (m_pwndBottomView && m_pwndBottomView->IsTarget())
805 ptOldCaretPos = m_pwndBottomView->GetCaretPosition();
806 CString sExt = CPathUtils::GetFileExtFromPath(m_Data.m_baseFile.GetFilename()).MakeLower();
807 sExt.TrimLeft(L".");
808 auto sC = m_IgnoreCommentsMap.find(sExt);
809 if (sC == m_IgnoreCommentsMap.end())
811 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_yourFile.GetFilename()).MakeLower();
812 sC = m_IgnoreCommentsMap.find(sExt);
813 if (sC == m_IgnoreCommentsMap.end())
815 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_theirFile.GetFilename()).MakeLower();
816 sC = m_IgnoreCommentsMap.find(sExt);
819 if (sC != m_IgnoreCommentsMap.end())
820 m_Data.SetCommentTokens(std::get<0>(sC->second), std::get<1>(sC->second), std::get<2>(sC->second));
821 else
822 m_Data.SetCommentTokens(L"", L"", L"");
823 if (!m_Data.Load())
825 m_pwndLeftView->BuildAllScreen2ViewVector();
826 m_pwndLeftView->DocumentUpdated();
827 m_pwndRightView->DocumentUpdated();
828 m_pwndBottomView->DocumentUpdated();
829 m_wndLocatorBar.DocumentUpdated();
830 m_wndLineDiffBar.DocumentUpdated();
831 ::MessageBox(m_hWnd, m_Data.GetError(), L"TortoiseGitMerge", MB_ICONERROR);
832 m_Data.m_mergedFile.SetOutOfUse();
833 m_bSaveRequired = false;
834 return false;
836 SetWindowTitle();
837 m_pwndLeftView->BuildAllScreen2ViewVector();
838 m_pwndLeftView->DocumentUpdated();
839 m_pwndRightView->DocumentUpdated();
840 m_pwndBottomView->DocumentUpdated();
841 m_wndLocatorBar.DocumentUpdated();
842 m_wndLineDiffBar.DocumentUpdated();
844 m_pwndLeftView->SetWritable(false);
845 m_pwndLeftView->SetWritableIsChangable(false);
846 m_pwndLeftView->SetTarget(false);
847 m_pwndRightView->SetWritable(false);
848 m_pwndRightView->SetWritableIsChangable(false);
849 m_pwndRightView->SetTarget(false);
850 m_pwndBottomView->SetWritable(false);
851 m_pwndBottomView->SetWritableIsChangable(false);
852 m_pwndBottomView->SetTarget(false);
854 if (!m_Data.IsBaseFileInUse())
856 CSysProgressDlg progDlg;
857 if (m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
859 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
861 else if ((!m_Data.m_sDiffFile.IsEmpty())&&(!m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg)))
863 progDlg.Stop();
864 ClearViewNamesAndPaths();
865 MessageBox(m_Patch.GetErrorMessage(), nullptr, MB_ICONERROR);
866 m_bSaveRequired = false;
867 return false;
869 progDlg.Stop();
870 if (m_Patch.GetNumberOfFiles() > 0)
872 CString betterpatchpath = m_Patch.CheckPatchPath(m_Data.m_sPatchPath);
873 if (betterpatchpath.CompareNoCase(m_Data.m_sPatchPath)!=0)
875 CString msg;
876 msg.Format(IDS_WARNBETTERPATCHPATHFOUND, (LPCTSTR)m_Data.m_sPatchPath, (LPCTSTR)betterpatchpath);
877 CTaskDialog taskdlg(msg,
878 CString(MAKEINTRESOURCE(IDS_WARNBETTERPATCHPATHFOUND_TASK2)),
879 L"TortoiseGitMerge",
881 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
882 CString task3;
883 WCHAR t3[MAX_PATH] = { 0 };
884 CString cp = betterpatchpath.Left(MAX_PATH - 1);
885 PathCompactPathEx(t3, cp, 50, 0);
886 task3.Format(IDS_WARNBETTERPATCHPATHFOUND_TASK3, t3);
887 taskdlg.AddCommandControl(1, task3);
888 CString task4;
889 WCHAR t4[MAX_PATH] = { 0 };
890 cp = m_Data.m_sPatchPath.Left(MAX_PATH - 1);
891 PathCompactPathEx(t4, cp, 50, 0);
892 task4.Format(IDS_WARNBETTERPATCHPATHFOUND_TASK4, t4);
893 taskdlg.AddCommandControl(2, task4);
894 taskdlg.SetDefaultCommandControl(1);
895 taskdlg.SetMainIcon(TD_INFORMATION_ICON);
896 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
897 if (taskdlg.DoModal(m_hWnd) == 1)
899 m_Data.m_sPatchPath = betterpatchpath;
900 m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg);
903 m_dlgFilePatches.Init(&m_Patch, this, m_Data.m_sPatchPath, this);
904 m_dlgFilePatches.ShowWindow(SW_SHOW);
905 ClearViewNamesAndPaths();
906 if (!m_wndSplitter.IsRowHidden(1))
907 m_wndSplitter.HideRow(1);
908 m_pwndLeftView->SetHidden(FALSE);
909 m_pwndRightView->SetHidden(FALSE);
910 m_pwndBottomView->SetHidden(TRUE);
913 if (m_Data.IsBaseFileInUse() && !m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
915 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
917 if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && !m_Data.IsTheirFileInUse())
919 //diff between YOUR and BASE
920 if (m_bOneWay)
922 pwndActiveView = m_pwndLeftView;
923 if (!m_wndSplitter2.IsColumnHidden(1))
924 m_wndSplitter2.HideColumn(1);
926 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseBoth;
927 m_pwndLeftView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
928 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
929 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName() + L" - " + m_Data.m_yourFile.GetWindowName();
930 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename() + L" - " + m_Data.m_yourFile.GetFilename();
931 m_pwndLeftView->m_sReflectedName = m_Data.m_yourFile.GetReflectedName();
932 m_pwndLeftView->m_pWorkingFile = &m_Data.m_yourFile;
933 m_pwndLeftView->SetTarget();
934 m_pwndLeftView->SetWritableIsChangable(true);
936 m_pwndRightView->m_pViewData = nullptr;
937 m_pwndRightView->m_pWorkingFile = nullptr;
938 m_pwndBottomView->m_pViewData = nullptr;
939 m_pwndBottomView->m_pWorkingFile = nullptr;
941 if (!m_wndSplitter.IsRowHidden(1))
942 m_wndSplitter.HideRow(1);
943 m_pwndLeftView->SetHidden(FALSE);
944 m_pwndRightView->SetHidden(TRUE);
945 m_pwndBottomView->SetHidden(TRUE);
946 ::SetWindowPos(m_pwndLeftView->m_hWnd, nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
948 else
950 pwndActiveView = m_pwndRightView;
951 if (m_wndSplitter2.IsColumnHidden(1))
952 m_wndSplitter2.ShowColumn();
954 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseLeft;
955 m_pwndLeftView->SetTextType(m_Data.m_arBaseFile.GetUnicodeType());
956 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arBaseFile.GetLineEndings());
957 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName();
958 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename();
959 m_pwndLeftView->m_sConvertedFilePath = m_Data.m_baseFile.GetConvertedFileName();
960 m_pwndLeftView->m_sReflectedName = m_Data.m_baseFile.GetReflectedName();
961 m_pwndLeftView->m_pWorkingFile = &m_Data.m_baseFile;
962 m_pwndLeftView->SetWritableIsChangable(true);
964 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseRight;
965 m_pwndRightView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
966 m_pwndRightView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
967 m_pwndRightView->m_sWindowName = m_Data.m_yourFile.GetWindowName();
968 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
969 m_pwndRightView->m_sConvertedFilePath = m_Data.m_yourFile.GetConvertedFileName();
970 m_pwndRightView->m_sReflectedName = m_Data.m_yourFile.GetReflectedName();
971 m_pwndRightView->m_pWorkingFile = &m_Data.m_yourFile;
972 m_pwndRightView->SetWritable();
973 m_pwndRightView->SetTarget();
975 m_pwndBottomView->m_pViewData = nullptr;
976 m_pwndBottomView->m_pWorkingFile = nullptr;
978 if (!m_wndSplitter.IsRowHidden(1))
979 m_wndSplitter.HideRow(1);
980 m_pwndLeftView->SetHidden(FALSE);
981 m_pwndRightView->SetHidden(FALSE);
982 m_pwndBottomView->SetHidden(TRUE);
984 bool hasMods, hasConflicts, hasWhitespaceMods;
985 pwndActiveView->CheckModifications(hasMods, hasConflicts, hasWhitespaceMods);
986 if (!hasMods && !hasConflicts)
988 // files appear identical, show a dialog informing the user that there are or might
989 // be other differences
990 bool hasEncodingDiff = m_Data.m_arBaseFile.GetUnicodeType() != m_Data.m_arYourFile.GetUnicodeType();
991 bool hasEOLDiff = m_Data.m_arBaseFile.GetLineEndings() != m_Data.m_arYourFile.GetLineEndings();
992 if (hasWhitespaceMods || hasEncodingDiff || hasEOLDiff)
994 // text is identical, but the files do not match
995 CString sWarning(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_MAIN));
996 CString sWhitespace(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_WHITESPACE));
997 CString sEncoding(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_ENCODING));
998 CString sEOL(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_EOL));
999 if (hasWhitespaceMods)
1001 sWarning += L"\r\n";
1002 sWarning += sWhitespace;
1004 if (hasEncodingDiff)
1006 sWarning += L"\r\n";
1007 sWarning += sEncoding;
1008 sWarning += L" (";
1009 sWarning += m_Data.m_arBaseFile.GetEncodingName(m_Data.m_arBaseFile.GetUnicodeType());
1010 sWarning += L", ";
1011 sWarning += m_Data.m_arYourFile.GetEncodingName(m_Data.m_arYourFile.GetUnicodeType());
1012 sWarning += L")";
1014 if (hasEOLDiff)
1016 sWarning += L"\r\n";
1017 sWarning += sEOL;
1019 AfxMessageBox(sWarning, MB_ICONINFORMATION);
1023 else if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
1025 //diff between THEIR, YOUR and BASE
1026 m_pwndBottomView->SetWritable();
1027 m_pwndBottomView->SetTarget();
1028 pwndActiveView = m_pwndBottomView;
1030 m_pwndLeftView->m_pViewData = &m_Data.m_TheirBaseBoth;
1031 m_pwndLeftView->SetTextType(m_Data.m_arTheirFile.GetUnicodeType());
1032 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arTheirFile.GetLineEndings());
1033 m_pwndLeftView->m_sWindowName = m_Data.m_theirFile.GetWindowName(IDS_VIEWTITLE_THEIRS);
1034 m_pwndLeftView->m_sFullFilePath = m_Data.m_theirFile.GetFilename();
1035 m_pwndLeftView->m_sConvertedFilePath = m_Data.m_theirFile.GetConvertedFileName();
1036 m_pwndLeftView->m_sReflectedName = m_Data.m_theirFile.GetReflectedName();
1037 m_pwndLeftView->m_pWorkingFile = &m_Data.m_theirFile;
1039 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseBoth;
1040 m_pwndRightView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
1041 m_pwndRightView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
1042 m_pwndRightView->m_sWindowName = m_Data.m_yourFile.GetWindowName(IDS_VIEWTITLE_MINE);
1043 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
1044 m_pwndRightView->m_sConvertedFilePath = m_Data.m_yourFile.GetConvertedFileName();
1045 m_pwndRightView->m_sReflectedName = m_Data.m_yourFile.GetReflectedName();
1046 m_pwndRightView->m_pWorkingFile = &m_Data.m_yourFile;
1048 m_pwndBottomView->m_pViewData = &m_Data.m_Diff3;
1049 m_pwndBottomView->SetTextType(m_Data.m_arTheirFile.GetUnicodeType());
1050 m_pwndBottomView->SetLineEndingStyle(m_Data.m_arTheirFile.GetLineEndings());
1051 m_pwndBottomView->m_sWindowName.LoadString(IDS_VIEWTITLE_MERGED);
1052 m_pwndBottomView->m_sWindowName += L" - " + m_Data.m_mergedFile.GetWindowName();
1053 m_pwndBottomView->m_sFullFilePath = m_Data.m_mergedFile.GetFilename();
1054 m_pwndBottomView->m_sConvertedFilePath = m_Data.m_mergedFile.GetConvertedFileName();
1055 m_pwndBottomView->m_sReflectedName = m_Data.m_mergedFile.GetReflectedName();
1056 m_pwndBottomView->m_pWorkingFile = &m_Data.m_mergedFile;
1058 if (m_wndSplitter2.IsColumnHidden(1))
1059 m_wndSplitter2.ShowColumn();
1060 if (m_wndSplitter.IsRowHidden(1))
1061 m_wndSplitter.ShowRow();
1062 m_pwndLeftView->SetHidden(FALSE);
1063 m_pwndRightView->SetHidden(FALSE);
1064 m_pwndBottomView->SetHidden(FALSE);
1065 // in three pane view, hide the line diff bar
1066 m_wndLineDiffBar.ShowPane(false, false, true);
1067 m_wndLineDiffBar.DocumentUpdated();
1069 if (!m_Data.m_mergedFile.InUse())
1071 m_Data.m_mergedFile.SetFileName(m_Data.m_yourFile.GetFilename());
1073 m_pwndLeftView->BuildAllScreen2ViewVector();
1074 m_pwndLeftView->DocumentUpdated();
1075 m_pwndRightView->DocumentUpdated();
1076 m_pwndBottomView->DocumentUpdated();
1077 m_wndLocatorBar.DocumentUpdated();
1078 m_wndLineDiffBar.DocumentUpdated();
1079 UpdateLayout();
1080 SetActiveView(pwndActiveView);
1082 if ((line >= -1) && m_pwndRightView->m_pViewData)
1084 int n = line == -1 ? min( nOldLineNumber, nOldLine ) : line;
1085 if (n >= 0)
1087 n = m_pwndRightView->m_pViewData->FindLineNumber(n);
1088 if (m_bCollapsed)
1090 // adjust the goto-line position if we're collapsed
1091 int step = m_pwndRightView->m_nTopLine > n ? -1 : 1;
1092 int skip = 0;
1093 for (int i = m_pwndRightView->m_nTopLine; i != n; i += step)
1095 if (m_pwndRightView->m_pViewData->GetHideState(i) == HIDESTATE_HIDDEN)
1096 ++skip;
1098 if (m_pwndRightView->m_pViewData->GetHideState(n) == HIDESTATE_HIDDEN)
1099 OnViewTextFoldUnfold();
1100 else
1101 n = n + (skip * step * -1);
1104 if (n < 0)
1105 n = nOldLine;
1107 m_pwndRightView->ScrollAllToLine(n);
1108 POINT p;
1109 p.x = 0;
1110 p.y = n;
1111 if ((ptOldCaretPos.x >= 0) || (ptOldCaretPos.y >= 0))
1112 p = ptOldCaretPos;
1113 m_pwndLeftView->SetCaretPosition(p);
1114 m_pwndRightView->SetCaretPosition(p);
1115 m_pwndBottomView->SetCaretPosition(p);
1116 m_pwndBottomView->ScrollToChar(0);
1117 m_pwndLeftView->ScrollToChar(0);
1118 m_pwndRightView->ScrollToChar(0);
1120 else
1122 CRegDWORD regFirstDiff = CRegDWORD(L"Software\\TortoiseGitMerge\\FirstDiffOnLoad", TRUE);
1123 CRegDWORD regFirstConflict = CRegDWORD(L"Software\\TortoiseGitMerge\\FirstConflictOnLoad", TRUE);
1124 bool bGoFirstDiff = (0 != (DWORD)regFirstDiff);
1125 bool bGoFirstConflict = (0 != (DWORD)regFirstConflict);
1126 if (bGoFirstConflict && (CheckResolved()>=0))
1128 pwndActiveView->GoToFirstConflict();
1129 // Ignore the first few Mouse Move messages, so that the line diff stays on
1130 // the first diff line until the user actually moves the mouse
1131 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1133 else if (bGoFirstDiff)
1135 pwndActiveView->GoToFirstDifference();
1136 // Ignore the first few Mouse Move messages, so that the line diff stays on
1137 // the first diff line until the user actually moves the mouse
1138 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1140 else
1142 // Avoid incorrect rendering of active pane.
1143 m_pwndBottomView->ScrollToChar(0);
1144 m_pwndLeftView->ScrollToChar(0);
1145 m_pwndRightView->ScrollToChar(0);
1148 CheckResolved();
1149 if (m_bHasConflicts && !m_bSaveRequiredOnConflicts)
1150 m_bSaveRequired = false;
1151 CUndo::GetInstance().Clear();
1152 return true;
1155 void CMainFrame::UpdateLayout()
1157 if (m_bInitSplitter)
1159 m_wndSplitter.CenterSplitter();
1160 m_wndSplitter2.CenterSplitter();
1164 void CMainFrame::OnSize(UINT nType, int cx, int cy)
1166 CFrameWndEx::OnSize(nType, cx, cy);
1167 if (m_bInitSplitter && nType != SIZE_MINIMIZED)
1169 if (m_wndSplitter.GetSafeHwnd())
1171 if (m_wndSplitter.HasOldRowSize() && (m_wndSplitter.GetOldRowCount() == 2))
1173 int oldTotal = m_wndSplitter.GetOldRowSize(0) + m_wndSplitter.GetOldRowSize(1);
1174 if (oldTotal)
1176 int cxCur0, cxCur1, cxMin0, cxMin1;
1177 m_wndSplitter.GetRowInfo(0, cxCur0, cxMin0);
1178 m_wndSplitter.GetRowInfo(1, cxCur1, cxMin1);
1179 cxCur0 = m_wndSplitter.GetOldRowSize(0) * (cxCur0 + cxCur1) / oldTotal;
1180 cxCur1 = m_wndSplitter.GetOldRowSize(1) * (cxCur0 + cxCur1) / oldTotal;
1181 m_wndSplitter.SetRowInfo(0, cxCur0, 0);
1182 m_wndSplitter.SetRowInfo(1, cxCur1, 0);
1183 m_wndSplitter.RecalcLayout();
1187 if (m_wndSplitter2.HasOldColSize() && (m_wndSplitter2.GetOldColCount() == 2))
1189 int oldTotal = m_wndSplitter2.GetOldColSize(0) + m_wndSplitter2.GetOldColSize(1);
1190 if (oldTotal)
1192 int cyCur0, cyCur1, cyMin0, cyMin1;
1193 m_wndSplitter2.GetColumnInfo(0, cyCur0, cyMin0);
1194 m_wndSplitter2.GetColumnInfo(1, cyCur1, cyMin1);
1195 cyCur0 = m_wndSplitter2.GetOldColSize(0) * (cyCur0 + cyCur1) / oldTotal;
1196 cyCur1 = m_wndSplitter2.GetOldColSize(1) * (cyCur0 + cyCur1) / oldTotal;
1197 m_wndSplitter2.SetColumnInfo(0, cyCur0, 0);
1198 m_wndSplitter2.SetColumnInfo(1, cyCur1, 0);
1199 m_wndSplitter2.RecalcLayout();
1204 if ((nType == SIZE_RESTORED)&&m_bCheckReload)
1206 m_bCheckReload = false;
1207 CheckForReload();
1211 void CMainFrame::OnViewWhitespaces()
1213 CRegDWORD regViewWhitespaces = CRegDWORD(L"Software\\TortoiseGitMerge\\ViewWhitespaces", 1);
1214 BOOL bViewWhitespaces = regViewWhitespaces;
1215 if (m_pwndLeftView)
1216 bViewWhitespaces = m_pwndLeftView->m_bViewWhitespace;
1218 bViewWhitespaces = !bViewWhitespaces;
1219 regViewWhitespaces = bViewWhitespaces;
1220 if (m_pwndLeftView)
1222 m_pwndLeftView->m_bViewWhitespace = bViewWhitespaces;
1223 m_pwndLeftView->Invalidate();
1225 if (m_pwndRightView)
1227 m_pwndRightView->m_bViewWhitespace = bViewWhitespaces;
1228 m_pwndRightView->Invalidate();
1230 if (m_pwndBottomView)
1232 m_pwndBottomView->m_bViewWhitespace = bViewWhitespaces;
1233 m_pwndBottomView->Invalidate();
1237 void CMainFrame::OnUpdateViewWhitespaces(CCmdUI *pCmdUI)
1239 if (m_pwndLeftView)
1240 pCmdUI->SetCheck(m_pwndLeftView->m_bViewWhitespace);
1243 void CMainFrame::OnViewCollapsed()
1245 m_regCollapsed = !(DWORD)m_regCollapsed;
1246 m_bCollapsed = !!(DWORD)m_regCollapsed;
1248 OnViewTextFoldUnfold();
1249 m_wndLocatorBar.Invalidate();
1252 void CMainFrame::OnUpdateViewCollapsed(CCmdUI *pCmdUI)
1254 pCmdUI->SetCheck(m_bCollapsed);
1257 void CMainFrame::OnViewWraplonglines()
1259 m_bWrapLines = !(DWORD)m_regWrapLines;
1260 m_regWrapLines = m_bWrapLines;
1262 if (m_pwndLeftView) m_pwndLeftView ->WrapChanged();
1263 if (m_pwndRightView) m_pwndRightView ->WrapChanged();
1264 if (m_pwndBottomView) m_pwndBottomView->WrapChanged();
1265 OnViewTextFoldUnfold();
1266 m_wndLocatorBar.DocumentUpdated();
1269 void CMainFrame::OnViewTextFoldUnfold()
1271 OnViewTextFoldUnfold(m_pwndLeftView);
1272 OnViewTextFoldUnfold(m_pwndRightView);
1273 OnViewTextFoldUnfold(m_pwndBottomView);
1276 void CMainFrame::OnViewTextFoldUnfold(CBaseView* view)
1278 if (view == 0)
1279 return;
1280 view->BuildAllScreen2ViewVector();
1281 view->UpdateCaret();
1282 view->Invalidate();
1283 view->EnsureCaretVisible();
1286 void CMainFrame::OnUpdateViewWraplonglines(CCmdUI *pCmdUI)
1288 pCmdUI->SetCheck(m_bWrapLines);
1291 void CMainFrame::OnViewOnewaydiff()
1293 if (CheckForSave(CHFSR_RELOAD)==IDCANCEL)
1294 return;
1295 m_bOneWay = !m_bOneWay;
1296 ShowDiffBar(!m_bOneWay);
1297 LoadViews(-1);
1300 void CMainFrame::ShowDiffBar(bool bShow)
1302 if (bShow)
1304 // restore the line diff bar
1305 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
1306 m_wndLineDiffBar.DocumentUpdated();
1307 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
1308 m_wndLocatorBar.DocumentUpdated();
1310 else
1312 // in one way view, hide the line diff bar
1313 m_wndLineDiffBar.ShowPane(false, false, true);
1314 m_wndLineDiffBar.DocumentUpdated();
1318 int CMainFrame::CheckResolved()
1320 //only in three way diffs can be conflicts!
1321 m_bHasConflicts = true;
1322 if (IsViewGood(m_pwndBottomView))
1324 CViewData* viewdata = m_pwndBottomView->m_pViewData;
1325 if (viewdata)
1327 for (int i=0; i<viewdata->GetCount(); i++)
1329 const DiffStates state = viewdata->GetState(i);
1330 if ((DIFFSTATE_CONFLICTED == state)||(DIFFSTATE_CONFLICTED_IGNORED == state))
1331 return i;
1335 m_bHasConflicts = false;
1336 return -1;
1339 int CMainFrame::SaveFile(const CString& sFilePath)
1341 CBaseView* pView = nullptr;
1342 CViewData* pViewData = nullptr;
1343 CFileTextLines * pOriginFile = &m_Data.m_arBaseFile;
1344 if (IsViewGood(m_pwndBottomView))
1346 pView = m_pwndBottomView;
1347 pViewData = m_pwndBottomView->m_pViewData;
1349 else if (IsViewGood(m_pwndRightView))
1351 pView = m_pwndRightView;
1352 pViewData = m_pwndRightView->m_pViewData;
1353 if (m_Data.IsYourFileInUse())
1354 pOriginFile = &m_Data.m_arYourFile;
1355 else if (m_Data.IsTheirFileInUse())
1356 pOriginFile = &m_Data.m_arTheirFile;
1358 else
1360 // nothing to save!
1361 return 1;
1363 Invalidate();
1364 if ((pViewData)&&(pOriginFile))
1366 CFileTextLines file;
1367 pOriginFile->CopySettings(&file);
1368 CFileTextLines::SaveParams saveParams;
1369 saveParams.m_LineEndings = pView->GetLineEndings();
1370 saveParams.m_UnicodeType = pView->GetTextType();
1371 file.SetSaveParams(saveParams);
1372 for (int i=0; i<pViewData->GetCount(); i++)
1374 //only copy non-removed lines
1375 DiffStates state = pViewData->GetState(i);
1376 switch (state)
1378 case DIFFSTATE_CONFLICTED:
1379 case DIFFSTATE_CONFLICTED_IGNORED:
1381 int first = i;
1382 int last = i;
1385 last++;
1386 } while((last<pViewData->GetCount()) && ((pViewData->GetState(last)==DIFFSTATE_CONFLICTED)||(pViewData->GetState(last)==DIFFSTATE_CONFLICTED_IGNORED)));
1387 // TortoiseGitMerge changes here
1388 file.Add(L"<<<<<<< .mine", m_pwndRightView->GetLineEndings());
1389 for (int j=first; j<last; j++)
1391 EOL lineending = m_pwndRightView->m_pViewData->GetLineEnding(j);
1392 if (lineending == EOL_NOENDING)
1393 lineending = m_pwndRightView->GetLineEndings();
1394 file.Add(m_pwndRightView->m_pViewData->GetLine(j), lineending);
1396 file.Add(L"=======", m_pwndRightView->GetLineEndings());
1397 for (int j=first; j<last; j++)
1399 EOL lineending = m_pwndLeftView->m_pViewData->GetLineEnding(j);
1400 if (lineending == EOL_NOENDING)
1401 lineending = m_pwndLeftView->GetLineEndings();
1402 file.Add(m_pwndLeftView->m_pViewData->GetLine(j), lineending);
1404 file.Add(L">>>>>>> .theirs", m_pwndRightView->GetLineEndings());
1405 i = last-1;
1407 break;
1408 case DIFFSTATE_EMPTY:
1409 case DIFFSTATE_CONFLICTEMPTY:
1410 case DIFFSTATE_IDENTICALREMOVED:
1411 case DIFFSTATE_REMOVED:
1412 case DIFFSTATE_THEIRSREMOVED:
1413 case DIFFSTATE_YOURSREMOVED:
1414 case DIFFSTATE_CONFLICTRESOLVEDEMPTY:
1415 // do not save removed lines
1416 break;
1417 default:
1418 file.Add(pViewData->GetLine(i), pViewData->GetLineEnding(i));
1419 break;
1422 if (!file.Save(sFilePath, false, false))
1424 CMessageBox::Show(m_hWnd, file.GetErrorString(), L"TortoiseGitMerge", MB_ICONERROR);
1425 return -1;
1427 if (sFilePath == m_Data.m_baseFile.GetFilename())
1429 m_Data.m_baseFile.StoreFileAttributes();
1431 if (sFilePath == m_Data.m_theirFile.GetFilename())
1433 m_Data.m_theirFile.StoreFileAttributes();
1435 if (sFilePath == m_Data.m_yourFile.GetFilename())
1437 m_Data.m_yourFile.StoreFileAttributes();
1439 /*if (sFilePath == m_Data.m_mergedFile.GetFilename())
1441 m_Data.m_mergedFile.StoreFileAttributes();
1442 }//*/
1443 m_dlgFilePatches.SetFileStatusAsPatched(sFilePath);
1444 if (IsViewGood(m_pwndBottomView))
1445 m_pwndBottomView->SetModified(FALSE);
1446 else if (IsViewGood(m_pwndRightView))
1447 m_pwndRightView->SetModified(FALSE);
1448 CUndo::GetInstance().MarkAsOriginalState(
1449 false,
1450 IsViewGood(m_pwndRightView) && (pViewData == m_pwndRightView->m_pViewData),
1451 IsViewGood(m_pwndBottomView) && (pViewData == m_pwndBottomView->m_pViewData));
1452 if (file.GetCount() == 1 && file.GetAt(0).IsEmpty() && file.GetLineEnding(0) == EOL_NOENDING)
1453 return 0;
1454 return file.GetCount();
1456 return 1;
1459 void CMainFrame::OnFileSave()
1461 // when multiple files are set as writable we have to ask what file to save
1462 int nEditableViewCount =
1463 (CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsWritable() ? 1 : 0)
1464 + (CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsWritable() ? 1 : 0)
1465 + (CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsWritable() ? 1 : 0);
1466 bool bLeftIsModified = CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsModified();
1467 bool bRightIsModified = CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsModified();
1468 bool bBottomIsModified = CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsModified();
1469 int nModifiedViewCount =
1470 (bLeftIsModified ? 1 : 0)
1471 + (bRightIsModified ? 1 : 0)
1472 + (bBottomIsModified ? 1 : 0);
1473 if (nEditableViewCount>1)
1475 if (nModifiedViewCount == 1)
1477 if (bLeftIsModified)
1478 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1479 else
1480 FileSave();
1482 else if (nModifiedViewCount>0)
1484 // both views
1485 CTaskDialog taskdlg(CString(MAKEINTRESOURCE(IDS_SAVE_MORE)),
1486 CString(MAKEINTRESOURCE(IDS_SAVE)),
1487 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1489 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
1490 CString sTaskTemp;
1491 if (m_pwndLeftView->m_pWorkingFile->InUse() && !m_pwndLeftView->m_pWorkingFile->IsReadonly())
1492 sTaskTemp.Format(IDS_ASKFORSAVE_SAVELEFT, (LPCTSTR)m_pwndLeftView->m_pWorkingFile->GetFilename());
1493 else
1494 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS));
1495 taskdlg.AddCommandControl(201, sTaskTemp, bLeftIsModified);// left
1496 if (bLeftIsModified)
1497 taskdlg.SetDefaultCommandControl(201);
1498 if (m_pwndRightView->m_pWorkingFile->InUse() && !m_pwndRightView->m_pWorkingFile->IsReadonly())
1499 sTaskTemp.Format(IDS_ASKFORSAVE_SAVERIGHT, (LPCTSTR)m_pwndRightView->m_pWorkingFile->GetFilename());
1500 else
1501 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS));
1502 taskdlg.AddCommandControl(202, sTaskTemp, bRightIsModified); // right
1503 if (bRightIsModified)
1504 taskdlg.SetDefaultCommandControl(202);
1505 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEALL2)), nModifiedViewCount>1); // both
1506 if (nModifiedViewCount > 1)
1507 taskdlg.SetDefaultCommandControl(203);
1508 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1509 taskdlg.SetMainIcon(TD_WARNING_ICON);
1510 UINT ret = (UINT)taskdlg.DoModal(m_hWnd);
1511 switch (ret)
1513 case 201: // left
1514 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1515 break;
1516 case 203: // both
1517 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1518 case 202: // right
1519 m_pwndRightView->SaveFile();
1520 break;
1524 else
1526 // only target view was modified
1527 FileSave();
1531 void CMainFrame::PatchSave()
1533 bool bDoesNotExist = !PathFileExists(m_Data.m_mergedFile.GetFilename());
1534 if (m_Data.m_bPatchRequired)
1536 m_Patch.PatchPath(m_Data.m_mergedFile.GetFilename());
1538 if (!PathIsDirectory(m_Data.m_mergedFile.GetFilename()))
1540 int saveret = SaveFile(m_Data.m_mergedFile.GetFilename());
1541 if (saveret==0)
1543 // file was saved with 0 lines, remove it.
1544 m_Patch.RemoveFile(m_Data.m_mergedFile.GetFilename());
1545 // just in case
1546 DeleteFile(m_Data.m_mergedFile.GetFilename());
1548 m_Data.m_mergedFile.StoreFileAttributes();
1549 if (m_Data.m_mergedFile.GetFilename() == m_Data.m_yourFile.GetFilename())
1550 m_Data.m_yourFile.StoreFileAttributes();
1551 if (bDoesNotExist && (DWORD(CRegDWORD(L"Software\\TortoiseGitMerge\\AutoAdd", TRUE))))
1553 // call TortoiseProc to add the new file to version control
1554 CString cmd = L"/command:add /noui /path:\"";
1555 cmd += m_Data.m_mergedFile.GetFilename() + L'"';
1556 CAppUtils::RunTortoiseGitProc(cmd);
1561 bool CMainFrame::FileSave(bool bCheckResolved /*=true*/)
1563 if (HasMarkedBlocks())
1565 CString sTitle(MAKEINTRESOURCE(IDS_WARNMARKEDBLOCKS));
1566 CString sSubTitle(MAKEINTRESOURCE(IDS_ASKFORSAVE_MARKEDBLOCKS));
1567 CString sAppName(MAKEINTRESOURCE(IDS_APPNAME));
1568 CTaskDialog taskdlg(sTitle,
1569 sSubTitle,
1570 sAppName,
1572 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
1573 taskdlg.AddCommandControl(10, CString(MAKEINTRESOURCE(IDS_MARKEDBLOCKSSAVEINCLUDE)));
1574 taskdlg.AddCommandControl(11, CString(MAKEINTRESOURCE(IDS_MARKEDBLOCKSSAVEEXCLUDE)));
1575 taskdlg.AddCommandControl(12, CString(MAKEINTRESOURCE(IDS_MARKEDBLCOKSSAVEIGNORE)));
1576 taskdlg.AddCommandControl(IDCANCEL, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_CANCEL_OPEN)));
1577 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1578 taskdlg.SetDefaultCommandControl(10);
1579 taskdlg.SetMainIcon(TD_WARNING_ICON);
1580 UINT ret = (UINT)taskdlg.DoModal(m_hWnd);
1581 if (ret == 10)
1582 m_pwndRightView->LeaveOnlyMarkedBlocks();
1583 else if (ret == 11)
1584 m_pwndRightView->UseViewFileOfMarked();
1585 else if (ret == 12)
1586 m_pwndRightView->UseViewFileExceptEdited();
1587 else
1588 return false;
1591 if (!m_Data.m_mergedFile.InUse())
1592 return FileSaveAs(bCheckResolved);
1593 // check if the file has the readonly attribute set
1594 bool bDoesNotExist = false;
1595 DWORD fAttribs = GetFileAttributes(m_Data.m_mergedFile.GetFilename());
1596 if ((fAttribs != INVALID_FILE_ATTRIBUTES)&&(fAttribs & FILE_ATTRIBUTE_READONLY))
1597 return FileSaveAs(bCheckResolved);
1598 if (fAttribs == INVALID_FILE_ATTRIBUTES)
1600 bDoesNotExist = (GetLastError() == ERROR_FILE_NOT_FOUND);
1602 if (bCheckResolved && HasConflictsWontKeep())
1603 return false;
1605 if (((DWORD)CRegDWORD(L"Software\\TortoiseGitMerge\\Backup")) != 0)
1607 MoveFileEx(m_Data.m_mergedFile.GetFilename(), m_Data.m_mergedFile.GetFilename() + L".bak", MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
1609 if (m_Data.m_bPatchRequired)
1611 m_Patch.PatchPath(m_Data.m_mergedFile.GetFilename());
1613 int saveret = SaveFile(m_Data.m_mergedFile.GetFilename());
1614 if (saveret==0)
1616 // file was saved with 0 lines!
1617 // ask the user if the file should be deleted
1618 CString msg;
1619 msg.Format(IDS_DELETEWHENEMPTY, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1620 CTaskDialog taskdlg(msg,
1621 CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK2)),
1622 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1624 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
1625 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK3)));
1626 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK4)));
1627 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1628 taskdlg.SetDefaultCommandControl(1);
1629 taskdlg.SetMainIcon(TD_WARNING_ICON);
1630 if (taskdlg.DoModal(m_hWnd) == 1)
1632 m_Patch.RemoveFile(m_Data.m_mergedFile.GetFilename());
1633 DeleteFile(m_Data.m_mergedFile.GetFilename());
1636 else if (saveret < 0)
1638 // error while saving the file
1639 return false;
1642 // if we're in conflict resolve mode (three pane view), check if there are no more conflicts
1643 // and if there aren't, ask to mark the file as resolved
1644 if (IsViewGood(m_pwndBottomView) && !m_bHasConflicts && bCheckResolved)
1646 CString projectRoot;
1647 if (GitAdminDir::HasAdminDir(m_Data.m_mergedFile.GetFilename(), false, &projectRoot))
1649 CString subpath = m_Data.m_mergedFile.GetFilename();
1650 subpath.Replace(L'\\', L'/');
1651 if (subpath.GetLength() >= projectRoot.GetLength())
1653 if (subpath[projectRoot.GetLength()] == L'/')
1654 subpath = subpath.Right(subpath.GetLength() - projectRoot.GetLength() - 1);
1655 else
1656 subpath = subpath.Right(subpath.GetLength() - projectRoot.GetLength());
1659 CAutoRepository repository(projectRoot);
1660 bool hasConflictInIndex = false;
1663 if (!repository)
1664 break;
1666 CAutoIndex index;
1667 if (git_repository_index(index.GetPointer(), repository))
1668 break;
1670 CStringA path = CUnicodeUtils::GetMulti(subpath, CP_UTF8);
1671 hasConflictInIndex = git_index_get_bypath(index, path, 1) || git_index_get_bypath(index, path, 2);
1672 } while(0);
1674 if (hasConflictInIndex)
1676 CString msg;
1677 msg.Format(IDS_MARKASRESOLVED, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1678 CTaskDialog taskdlg(msg,
1679 CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK2)),
1680 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1682 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
1683 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK3)));
1684 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK4)));
1685 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1686 taskdlg.SetDefaultCommandControl(1);
1687 taskdlg.SetMainIcon(TD_WARNING_ICON);
1688 if (taskdlg.DoModal(m_hWnd) == 1)
1689 MarkAsResolved();
1694 m_bSaveRequired = false;
1695 m_Data.m_mergedFile.StoreFileAttributes();
1697 if (bDoesNotExist && (DWORD(CRegDWORD(L"Software\\TortoiseGitMerge\\AutoAdd", TRUE))))
1699 // call TortoiseProc to add the new file to version control
1700 CString cmd = L"/command:add /noui /path:\"";
1701 cmd += m_Data.m_mergedFile.GetFilename() + L'"';
1702 if(!CAppUtils::RunTortoiseGitProc(cmd))
1703 return false;
1705 return true;
1708 void CMainFrame::OnFileSaveAs()
1710 // ask what file to save as
1711 bool bHaveConflict = (CheckResolved() >= 0);
1712 CTaskDialog taskdlg(
1713 CString(MAKEINTRESOURCE(bHaveConflict ? IDS_ASKFORSAVEAS_MORECONFLICT : IDS_ASKFORSAVEAS_MORE)),
1714 CString(MAKEINTRESOURCE(IDS_ASKFORSAVEAS)),
1715 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1717 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
1718 // default can be last view (target) as was in 1.7 or actual (where is cursor) as is in most text editor
1719 if (IsViewGood(m_pwndLeftView))
1721 taskdlg.AddCommandControl(201, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS))); // left
1722 taskdlg.SetDefaultCommandControl(201);
1724 if (IsViewGood(m_pwndRightView))
1726 taskdlg.AddCommandControl(202, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS))); // right
1727 taskdlg.SetDefaultCommandControl(202);
1729 if (IsViewGood(m_pwndBottomView))
1731 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEBOTTOMAS))); // bottom
1732 taskdlg.SetDefaultCommandControl(203);
1734 if (bHaveConflict)
1736 taskdlg.AddCommandControl(204, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_NEEDRESOLVE))); // resolve
1737 taskdlg.SetDefaultCommandControl(204);
1739 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1740 taskdlg.SetMainIcon(bHaveConflict ? TD_WARNING_ICON : TD_INFORMATION_ICON);
1741 int nCommand = (int)taskdlg.DoModal(m_hWnd);
1742 CString sFileName;
1743 switch (nCommand)
1745 case 201: // left
1746 if (TryGetFileName(sFileName))
1748 // in 2, 3 view display we want to keep removed lines
1749 m_pwndLeftView->SaveFileTo(sFileName, IsViewGood(m_pwndRightView) ? SAVE_REMOVEDLINES : 0);
1751 break;
1752 case 202: // right
1753 if (TryGetFileName(sFileName))
1755 m_pwndRightView->SaveFileTo(sFileName);
1757 break;
1758 case 203: // bottom
1759 FileSaveAs();
1760 break;
1761 case 204: // continue resolving
1762 if (IsViewGood(m_pwndBottomView))
1764 m_pwndBottomView->GoToLine(CheckResolved());
1766 break;
1770 bool CMainFrame::FileSaveAs(bool bCheckResolved /*=true*/)
1772 if (bCheckResolved && HasConflictsWontKeep())
1773 return false;
1775 CString fileName;
1776 if(!TryGetFileName(fileName))
1777 return false;
1779 SaveFile(fileName);
1780 return true;
1783 void CMainFrame::OnUpdateFileSave(CCmdUI *pCmdUI)
1785 BOOL bEnable = FALSE;
1786 if (m_Data.m_mergedFile.InUse())
1788 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1789 bEnable = TRUE;
1790 else if ( (IsViewGood(m_pwndRightView)&&(m_pwndRightView->m_pViewData)) &&
1791 (m_pwndRightView->IsModified() || (m_Data.m_yourFile.GetWindowName().Right(9).Compare(L": patched") == 0)))
1792 bEnable = TRUE;
1793 else if (IsViewGood(m_pwndLeftView)
1794 && (m_pwndLeftView->m_pViewData)
1795 && (m_pwndLeftView->IsModified()))
1796 bEnable = TRUE;
1798 pCmdUI->Enable(bEnable);
1801 void CMainFrame::OnUpdateFileSaveAs(CCmdUI *pCmdUI)
1803 // any file is open we can save it as
1804 BOOL bEnable = FALSE;
1805 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1806 bEnable = TRUE;
1807 else if (IsViewGood(m_pwndRightView)&&(m_pwndRightView->m_pViewData))
1808 bEnable = TRUE;
1809 else if (IsViewGood(m_pwndLeftView)&&(m_pwndLeftView->m_pViewData))
1810 bEnable = TRUE;
1811 pCmdUI->Enable(bEnable);
1814 void CMainFrame::OnUpdateViewOnewaydiff(CCmdUI *pCmdUI)
1816 pCmdUI->SetCheck(!m_bOneWay);
1817 BOOL bEnable = TRUE;
1818 if (IsViewGood(m_pwndBottomView))
1820 bEnable = FALSE;
1822 pCmdUI->Enable(bEnable);
1825 void CMainFrame::OnViewOptions()
1827 CString sTemp;
1828 sTemp.LoadString(IDS_SETTINGSTITLE);
1829 CSettings dlg(sTemp);
1830 dlg.DoModal();
1831 if (dlg.IsReloadNeeded())
1833 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
1834 return;
1835 CDiffColors::GetInstance().LoadRegistry();
1836 LoadViews();
1837 return;
1839 CDiffColors::GetInstance().LoadRegistry();
1840 if (m_pwndBottomView)
1841 m_pwndBottomView->Invalidate();
1842 if (m_pwndLeftView)
1843 m_pwndLeftView->Invalidate();
1844 if (m_pwndRightView)
1845 m_pwndRightView->Invalidate();
1848 void CMainFrame::OnClose()
1850 if (!IsWindowEnabled())
1851 return; // just in case someone sends a WM_CLOSE to the main window while another window (dialog,...) is open
1852 if (CheckForSave(CHFSR_CLOSE)!=IDCANCEL)
1854 WINDOWPLACEMENT wp;
1856 // before it is destroyed, save the position of the window
1857 wp.length = sizeof wp;
1859 if (GetWindowPlacement(&wp))
1862 if (IsIconic())
1863 // never restore to Iconic state
1864 wp.showCmd = SW_SHOW ;
1866 if ((wp.flags & WPF_RESTORETOMAXIMIZED) != 0)
1867 // if maximized and maybe iconic restore maximized state
1868 wp.showCmd = SW_SHOWMAXIMIZED ;
1870 // and write it
1871 WriteWindowPlacement(&wp);
1873 __super::OnClose();
1877 void CMainFrame::OnActivate(UINT nValue, CWnd* /*pwnd*/, BOOL /*bActivated?*/)
1879 if (nValue != 0) // activated
1881 if (IsIconic())
1883 m_bCheckReload = TRUE;
1885 else
1887 // use a timer to give other messages time to get processed
1888 // first, like e.g. the WM_CLOSE message in case the user
1889 // clicked the close button and that brought the window
1890 // to the front - in that case checking for reload wouldn't
1891 // do any good.
1892 SetTimer(IDT_RELOADCHECKTIMER, 300, nullptr);
1897 void CMainFrame::OnViewLinedown()
1899 OnViewLineUpDown(1);
1902 void CMainFrame::OnViewLineup()
1904 OnViewLineUpDown(-1);
1907 void CMainFrame::OnViewLineUpDown(int direction)
1909 if (m_pwndLeftView)
1910 m_pwndLeftView->ScrollToLine(m_pwndLeftView->m_nTopLine+direction);
1911 if (m_pwndRightView)
1912 m_pwndRightView->ScrollToLine(m_pwndRightView->m_nTopLine+direction);
1913 if (m_pwndBottomView)
1914 m_pwndBottomView->ScrollToLine(m_pwndBottomView->m_nTopLine+direction);
1915 m_wndLocatorBar.Invalidate();
1916 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1919 void CMainFrame::OnViewLineleft()
1921 OnViewLineLeftRight(-1);
1924 void CMainFrame::OnViewLineright()
1926 OnViewLineLeftRight(1);
1929 void CMainFrame::OnViewLineLeftRight(int direction)
1931 if (m_pwndLeftView)
1932 m_pwndLeftView->ScrollSide(direction);
1933 if (m_pwndRightView)
1934 m_pwndRightView->ScrollSide(direction);
1935 if (m_pwndBottomView)
1936 m_pwndBottomView->ScrollSide(direction);
1939 void CMainFrame::OnEditUseTheirs()
1941 if (m_pwndBottomView)
1942 m_pwndBottomView->UseTheirTextBlock();
1944 void CMainFrame::OnUpdateEditUsetheirblock(CCmdUI *pCmdUI)
1946 pCmdUI->Enable(m_pwndBottomView && m_pwndBottomView->HasSelection());
1949 void CMainFrame::OnEditUseMine()
1951 if (m_pwndBottomView)
1952 m_pwndBottomView->UseMyTextBlock();
1954 void CMainFrame::OnUpdateEditUsemyblock(CCmdUI *pCmdUI)
1956 OnUpdateEditUsetheirblock(pCmdUI);
1959 void CMainFrame::OnEditUseTheirsThenMine()
1961 if (m_pwndBottomView)
1962 m_pwndBottomView->UseTheirAndYourBlock();
1965 void CMainFrame::OnUpdateEditUsetheirthenmyblock(CCmdUI *pCmdUI)
1967 OnUpdateEditUsetheirblock(pCmdUI);
1970 void CMainFrame::OnEditUseMineThenTheirs()
1972 if (m_pwndBottomView)
1973 m_pwndBottomView->UseYourAndTheirBlock();
1976 void CMainFrame::OnUpdateEditUseminethentheirblock(CCmdUI *pCmdUI)
1978 OnUpdateEditUsetheirblock(pCmdUI);
1981 void CMainFrame::OnEditUseleftblock()
1983 if (m_pwndBottomView->IsWindowVisible())
1984 m_pwndBottomView->UseRightBlock();
1985 else
1986 m_pwndRightView->UseLeftBlock();
1989 void CMainFrame::OnUpdateEditUseleftblock(CCmdUI *pCmdUI)
1991 pCmdUI->Enable(IsViewGood(m_pwndRightView) && m_pwndRightView->IsTarget() && m_pwndRightView->HasSelection());
1994 void CMainFrame::OnUpdateUseBlock(CCmdUI *pCmdUI)
1996 pCmdUI->Enable(TRUE);
1999 void CMainFrame::OnEditUseleftfile()
2001 if (m_pwndBottomView->IsWindowVisible())
2002 m_pwndBottomView->UseRightFile();
2003 else
2004 m_pwndRightView->UseLeftFile();
2007 void CMainFrame::OnUpdateEditUseleftfile(CCmdUI *pCmdUI)
2009 pCmdUI->Enable(IsViewGood(m_pwndRightView) && m_pwndRightView->IsTarget());
2012 void CMainFrame::OnEditUseblockfromleftbeforeright()
2014 if (m_pwndRightView)
2015 m_pwndRightView->UseBothLeftFirst();
2018 void CMainFrame::OnUpdateEditUseblockfromleftbeforeright(CCmdUI *pCmdUI)
2020 OnUpdateEditUseleftblock(pCmdUI);
2023 void CMainFrame::OnEditUseblockfromrightbeforeleft()
2025 if (m_pwndRightView)
2026 m_pwndRightView->UseBothRightFirst();
2029 void CMainFrame::OnUpdateEditUseblockfromrightbeforeleft(CCmdUI *pCmdUI)
2031 OnUpdateEditUseleftblock(pCmdUI);
2034 void CMainFrame::OnFileReload()
2036 if (CheckForSave(CHFSR_RELOAD)==IDCANCEL)
2037 return;
2038 CDiffColors::GetInstance().LoadRegistry();
2039 LoadViews(-1);
2042 void CMainFrame::ActivateFrame(int nCmdShow)
2044 // nCmdShow is the normal show mode this frame should be in
2045 // translate default nCmdShow (-1)
2046 if (nCmdShow == -1)
2048 if (!IsWindowVisible())
2049 nCmdShow = SW_SHOWNORMAL;
2050 else if (IsIconic())
2051 nCmdShow = SW_RESTORE;
2054 // bring to top before showing
2055 BringToTop(nCmdShow);
2057 if (nCmdShow != -1)
2059 // show the window as specified
2060 WINDOWPLACEMENT wp;
2062 if ( !ReadWindowPlacement(&wp) )
2064 ShowWindow(nCmdShow);
2066 else
2068 if ( nCmdShow != SW_SHOWNORMAL )
2069 wp.showCmd = nCmdShow;
2071 SetWindowPlacement(&wp);
2074 // and finally, bring to top after showing
2075 BringToTop(nCmdShow);
2079 BOOL CMainFrame::ReadWindowPlacement(WINDOWPLACEMENT * pwp)
2081 CRegString placement = CRegString(L"Software\\TortoiseGitMerge\\WindowPos");
2082 CString sPlacement = placement;
2083 if (sPlacement.IsEmpty())
2084 return FALSE;
2085 int nRead = swscanf_s(sPlacement, L"%u,%u,%d,%d,%d,%d,%d,%d,%d,%d",
2086 &pwp->flags, &pwp->showCmd,
2087 &pwp->ptMinPosition.x, &pwp->ptMinPosition.y,
2088 &pwp->ptMaxPosition.x, &pwp->ptMaxPosition.y,
2089 &pwp->rcNormalPosition.left, &pwp->rcNormalPosition.top,
2090 &pwp->rcNormalPosition.right, &pwp->rcNormalPosition.bottom);
2091 if ( nRead != 10 )
2092 return FALSE;
2093 pwp->length = sizeof(WINDOWPLACEMENT);
2095 return TRUE;
2098 void CMainFrame::WriteWindowPlacement(WINDOWPLACEMENT * pwp)
2100 CRegString placement(L"Software\\TortoiseGitMerge\\WindowPos");
2101 TCHAR szBuffer[_countof("-32767")*8 + sizeof("65535")*2];
2103 swprintf_s(szBuffer, L"%u,%u,%d,%d,%d,%d,%d,%d,%d,%d",
2104 pwp->flags, pwp->showCmd,
2105 pwp->ptMinPosition.x, pwp->ptMinPosition.y,
2106 pwp->ptMaxPosition.x, pwp->ptMaxPosition.y,
2107 pwp->rcNormalPosition.left, pwp->rcNormalPosition.top,
2108 pwp->rcNormalPosition.right, pwp->rcNormalPosition.bottom);
2109 placement = szBuffer;
2112 void CMainFrame::OnUpdateMergeMarkasresolved(CCmdUI *pCmdUI)
2114 if (!pCmdUI)
2115 return;
2116 BOOL bEnable = FALSE;
2117 if ((!m_bReadOnly)&&(m_Data.m_mergedFile.InUse()))
2119 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
2121 bEnable = TRUE;
2124 pCmdUI->Enable(bEnable);
2127 void CMainFrame::OnMergeMarkasresolved()
2129 if(HasConflictsWontKeep())
2130 return;
2132 // now check if the file has already been saved and if not, save it.
2133 if (m_Data.m_mergedFile.InUse())
2135 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
2137 if (!FileSave(false))
2138 return;
2139 m_bSaveRequired = false;
2142 MarkAsResolved();
2145 BOOL CMainFrame::MarkAsResolved()
2147 if (m_bReadOnly)
2148 return FALSE;
2149 if (!IsViewGood(m_pwndBottomView))
2150 return FALSE;
2152 CString cmd = L"/command:resolve /path:\"";
2153 cmd += m_Data.m_mergedFile.GetFilename();
2154 cmd += L"\" /closeonend:1 /noquestion /skipcheck /silent";
2155 if (resolveMsgWnd)
2157 CString s;
2158 s.Format(L" /resolvemsghwnd:%I64d /resolvemsgwparam:%I64d /resolvemsglparam:%I64d", (__int64)resolveMsgWnd, (__int64)resolveMsgWParam, (__int64)resolveMsgLParam);
2159 cmd += s;
2161 if(!CAppUtils::RunTortoiseGitProc(cmd))
2162 return FALSE;
2163 m_bSaveRequired = false;
2164 return TRUE;
2167 void CMainFrame::OnUpdateMergeNextconflict(CCmdUI *pCmdUI)
2169 BOOL bShow = FALSE;
2170 if (HasNextConflict(m_pwndBottomView))
2171 bShow = TRUE;
2172 else if (HasNextConflict(m_pwndRightView))
2173 bShow = TRUE;
2174 else if (HasNextConflict(m_pwndLeftView))
2175 bShow = TRUE;
2176 pCmdUI->Enable(bShow);
2179 bool CMainFrame::HasNextConflict(CBaseView* view)
2181 if (view == 0)
2182 return false;
2183 if (!view->IsTarget())
2184 return false;
2185 return view->HasNextConflict();
2188 void CMainFrame::OnUpdateMergePreviousconflict(CCmdUI *pCmdUI)
2190 BOOL bShow = FALSE;
2191 if (HasPrevConflict(m_pwndBottomView))
2192 bShow = TRUE;
2193 else if (HasPrevConflict(m_pwndRightView))
2194 bShow = TRUE;
2195 else if (HasPrevConflict(m_pwndLeftView))
2196 bShow = TRUE;
2197 pCmdUI->Enable(bShow);
2200 bool CMainFrame::HasPrevConflict(CBaseView* view)
2202 if (view == 0)
2203 return false;
2204 if (!view->IsTarget())
2205 return false;
2206 return view->HasPrevConflict();
2209 void CMainFrame::OnUpdateNavigateNextdifference(CCmdUI *pCmdUI)
2211 CBaseView* baseView = GetActiveBaseView();
2212 BOOL bShow = FALSE;
2213 if (baseView != 0)
2214 bShow = baseView->HasNextDiff();
2215 pCmdUI->Enable(bShow);
2218 void CMainFrame::OnUpdateNavigatePreviousdifference(CCmdUI *pCmdUI)
2220 CBaseView* baseView = GetActiveBaseView();
2221 BOOL bShow = FALSE;
2222 if (baseView != 0)
2223 bShow = baseView->HasPrevDiff();
2224 pCmdUI->Enable(bShow);
2227 void CMainFrame::OnUpdateNavigateNextinlinediff(CCmdUI *pCmdUI)
2229 BOOL bShow = FALSE;
2230 if (HasNextInlineDiff(m_pwndBottomView))
2231 bShow = TRUE;
2232 else if (HasNextInlineDiff(m_pwndRightView))
2233 bShow = TRUE;
2234 else if (HasNextInlineDiff(m_pwndLeftView))
2235 bShow = TRUE;
2236 pCmdUI->Enable(bShow);
2239 bool CMainFrame::HasNextInlineDiff(CBaseView* view)
2241 if (view == 0)
2242 return false;
2243 if (!view->IsTarget())
2244 return false;
2245 return view->HasNextInlineDiff();
2248 void CMainFrame::OnUpdateNavigatePrevinlinediff(CCmdUI *pCmdUI)
2250 BOOL bShow = FALSE;
2251 if (HasPrevInlineDiff(m_pwndBottomView))
2252 bShow = TRUE;
2253 else if (HasPrevInlineDiff(m_pwndRightView))
2254 bShow = TRUE;
2255 else if (HasPrevInlineDiff(m_pwndLeftView))
2256 bShow = TRUE;
2257 pCmdUI->Enable(bShow);
2260 bool CMainFrame::HasPrevInlineDiff(CBaseView* view)
2262 if (view == 0)
2263 return false;
2264 if (!view->IsTarget())
2265 return false;
2266 return view->HasPrevInlineDiff();
2269 void CMainFrame::OnMoving(UINT fwSide, LPRECT pRect)
2271 // if the pathfilelist dialog is attached to the mainframe,
2272 // move it along with the mainframe
2273 if (::IsWindow(m_dlgFilePatches.m_hWnd))
2275 RECT patchrect;
2276 m_dlgFilePatches.GetWindowRect(&patchrect);
2277 if (::IsWindow(m_hWnd))
2279 RECT thisrect;
2280 GetWindowRect(&thisrect);
2281 if (patchrect.right == thisrect.left)
2283 m_dlgFilePatches.SetWindowPos(nullptr, patchrect.left - (thisrect.left - pRect->left), patchrect.top - (thisrect.top - pRect->top),
2284 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
2288 __super::OnMoving(fwSide, pRect);
2291 void CMainFrame::OnUpdateEditCopy(CCmdUI *pCmdUI)
2293 BOOL bShow = FALSE;
2294 if ((m_pwndBottomView)&&(m_pwndBottomView->HasSelection()))
2295 bShow = TRUE;
2296 else if ((m_pwndRightView)&&(m_pwndRightView->HasSelection()))
2297 bShow = TRUE;
2298 else if ((m_pwndLeftView)&&(m_pwndLeftView->HasSelection()))
2299 bShow = TRUE;
2300 pCmdUI->Enable(bShow);
2303 void CMainFrame::OnUpdateEditPaste(CCmdUI *pCmdUI)
2305 BOOL bWritable = FALSE;
2306 if ((m_pwndBottomView)&&(m_pwndBottomView->IsWritable()))
2307 bWritable = TRUE;
2308 else if ((m_pwndRightView)&&(m_pwndRightView->IsWritable()))
2309 bWritable = TRUE;
2310 else if ((m_pwndLeftView)&&(m_pwndLeftView->IsWritable()))
2311 bWritable = TRUE;
2312 pCmdUI->Enable(bWritable && ::IsClipboardFormatAvailable(CF_TEXT));
2315 void CMainFrame::OnViewSwitchleft()
2317 if (CheckForSave(CHFSR_SWITCH)!=IDCANCEL)
2319 CWorkingFile file = m_Data.m_baseFile;
2320 m_Data.m_baseFile = m_Data.m_yourFile;
2321 m_Data.m_yourFile = file;
2322 if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_yourFile.GetFilename())==0)
2324 m_Data.m_mergedFile = m_Data.m_baseFile;
2326 else if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_baseFile.GetFilename())==0)
2328 m_Data.m_mergedFile = m_Data.m_yourFile;
2330 LoadViews();
2334 void CMainFrame::OnUpdateViewSwitchleft(CCmdUI *pCmdUI)
2336 BOOL bEnable = !IsViewGood(m_pwndBottomView);
2337 pCmdUI->Enable(bEnable);
2340 void CMainFrame::OnUpdateViewShowfilelist(CCmdUI *pCmdUI)
2342 BOOL bEnable = m_dlgFilePatches.HasFiles();
2343 pCmdUI->Enable(bEnable);
2344 pCmdUI->SetCheck(m_dlgFilePatches.IsWindowVisible());
2347 void CMainFrame::OnViewShowfilelist()
2349 m_dlgFilePatches.ShowWindow(m_dlgFilePatches.IsWindowVisible() ? SW_HIDE : SW_SHOW);
2352 void CMainFrame::OnEditUndo()
2354 if (CUndo::GetInstance().CanUndo())
2356 CUndo::GetInstance().Undo(m_pwndLeftView, m_pwndRightView, m_pwndBottomView);
2360 void CMainFrame::OnUpdateEditUndo(CCmdUI *pCmdUI)
2362 pCmdUI->Enable(CUndo::GetInstance().CanUndo());
2365 void CMainFrame::OnEditRedo()
2367 if (CUndo::GetInstance().CanRedo())
2369 CUndo::GetInstance().Redo(m_pwndLeftView, m_pwndRightView, m_pwndBottomView);
2373 void CMainFrame::OnUpdateEditRedo(CCmdUI *pCmdUI)
2375 pCmdUI->Enable(CUndo::GetInstance().CanRedo());
2378 void CMainFrame::OnEditEnable()
2380 CBaseView * pView = GetActiveBaseView();
2381 if (pView && pView->IsReadonlyChangable())
2383 bool isReadOnly = pView->IsReadonly();
2384 pView->SetReadonly(!isReadOnly);
2388 void CMainFrame::OnUpdateEditEnable(CCmdUI *pCmdUI)
2390 CBaseView * pView = GetActiveBaseView();
2391 if (pView)
2393 pCmdUI->Enable(pView->IsReadonlyChangable() || !pView->IsReadonly());
2394 pCmdUI->SetCheck(!pView->IsReadonly());
2396 else
2398 pCmdUI->Enable(FALSE);
2402 void CMainFrame::OnIndicatorLeftview()
2404 if (m_bUseRibbons)
2405 return;
2406 if (IsViewGood(m_pwndLeftView))
2408 m_pwndLeftView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_LEFTVIEW);
2412 void CMainFrame::OnIndicatorRightview()
2414 if (m_bUseRibbons)
2415 return;
2416 if (IsViewGood(m_pwndRightView))
2418 m_pwndRightView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_RIGHTVIEW);
2422 void CMainFrame::OnIndicatorBottomview()
2424 if (m_bUseRibbons)
2425 return;
2426 if (IsViewGood(m_pwndBottomView))
2428 m_pwndBottomView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_BOTTOMVIEW);
2432 int CMainFrame::CheckForReload()
2434 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
2435 if (bLock)
2437 return IDNO;
2439 bLock = true;
2440 bool bSourceChanged =
2441 m_Data.m_baseFile.HasSourceFileChanged()
2442 || m_Data.m_yourFile.HasSourceFileChanged()
2443 || m_Data.m_theirFile.HasSourceFileChanged()
2444 /*|| m_Data.m_mergedFile.HasSourceFileChanged()*/;
2445 if (!bSourceChanged)
2447 bLock = false;
2448 return IDNO;
2451 CString msg = HasUnsavedEdits() ? CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDELOOSECHANGES)) : CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE));
2452 CTaskDialog taskdlg(msg,
2453 CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE_TASK2)),
2454 L"TortoiseGitMerge",
2456 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
2457 CString sTask3;
2458 if (HasUnsavedEdits())
2459 sTask3.LoadString(IDS_WARNMODIFIEDOUTSIDE_TASK3);
2460 else
2461 sTask3.LoadString(IDS_WARNMODIFIEDOUTSIDE_TASK4);
2462 taskdlg.AddCommandControl(IDYES, sTask3);
2463 taskdlg.AddCommandControl(IDNO, CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE_TASK5)));
2464 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2465 taskdlg.SetDefaultCommandControl(IDYES);
2466 taskdlg.SetMainIcon(TD_WARNING_ICON);
2467 UINT ret = (UINT)taskdlg.DoModal(m_hWnd);
2468 if (ret == IDYES)
2470 CDiffColors::GetInstance().LoadRegistry();
2471 LoadViews(-1);
2473 else
2475 if (IsViewGood(m_pwndBottomView)) // three pane view
2477 /*if (m_Data.m_sourceFile.HasSourceFileChanged())
2478 m_pwndBottomView->SetModified();
2479 if (m_Data.m_mergedFile.HasSourceFileChanged())
2480 m_pwndBottomView->SetModified();//*/
2481 if (m_Data.m_yourFile.HasSourceFileChanged())
2482 m_pwndRightView->SetModified();
2483 if (m_Data.m_theirFile.HasSourceFileChanged())
2484 m_pwndLeftView->SetModified();
2486 else if (IsViewGood(m_pwndRightView)) // two pane view
2488 if (m_Data.m_baseFile.HasSourceFileChanged())
2489 m_pwndLeftView->SetModified();
2490 if (m_Data.m_yourFile.HasSourceFileChanged())
2491 m_pwndRightView->SetModified();
2493 else
2495 if (m_Data.m_yourFile.HasSourceFileChanged())
2496 m_pwndLeftView->SetModified();
2499 // no reload just store updated file time
2500 m_Data.m_baseFile.StoreFileAttributes();
2501 m_Data.m_theirFile.StoreFileAttributes();
2502 m_Data.m_yourFile.StoreFileAttributes();
2503 //m_Data.m_mergedFile.StoreFileAttributes();
2505 bLock = false;
2506 return ret;
2509 int CMainFrame::CheckForSave(ECheckForSaveReason eReason)
2511 int idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2512 int idNoSave = IDS_ASKFORSAVE_TASK7;
2513 int idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2514 switch (eReason)
2516 case CHFSR_CLOSE:
2517 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2518 idNoSave = IDS_ASKFORSAVE_TASK4;
2519 idCancelAction = IDS_ASKFORSAVE_TASK5;
2520 break;
2521 case CHFSR_SWITCH:
2522 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2523 //idNoSave = IDS_ASKFORSAVE_TASK7;
2524 idCancelAction = IDS_ASKFORSAVE_TASK8;
2525 break;
2526 case CHFSR_RELOAD:
2527 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2528 //idNoSave = IDS_ASKFORSAVE_TASK7;
2529 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2530 break;
2531 case CHFSR_OPTIONS:
2532 idTitle = IDS_WARNMODIFIEDLOOSECHANGESOPTIONS;
2533 //idNoSave = IDS_ASKFORSAVE_TASK7;
2534 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPTIONS;
2535 break;
2536 case CHFSR_OPEN:
2537 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2538 idNoSave = IDS_ASKFORSAVE_NOSAVE_OPEN;
2539 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2540 break;
2543 CString sTitle(MAKEINTRESOURCE(idTitle));
2544 CString sSubTitle(MAKEINTRESOURCE(IDS_ASKFORSAVE_TASK2));
2545 CString sNoSave(MAKEINTRESOURCE(idNoSave));
2546 CString sCancelAction(MAKEINTRESOURCE(idCancelAction));
2547 CString sAppName(MAKEINTRESOURCE(IDS_APPNAME));
2549 // TODO simplify logic, reduce code duplication
2550 if (CBaseView::IsViewGood(m_pwndBottomView))
2552 // three-way diff - by design only bottom can be changed
2553 // use 1.7 way to do that
2555 else if (CBaseView::IsViewGood(m_pwndRightView))
2557 // two-way diff -
2558 // 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
2559 if (HasUnsavedEdits(m_pwndLeftView))
2561 // both views
2562 CTaskDialog taskdlg(sTitle,
2563 sSubTitle,
2564 sAppName,
2566 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
2567 CString sTaskTemp;
2568 if (m_pwndLeftView->m_pWorkingFile->InUse() && !m_pwndLeftView->m_pWorkingFile->IsReadonly())
2569 sTaskTemp.Format(IDS_ASKFORSAVE_SAVELEFT, (LPCTSTR)m_pwndLeftView->m_pWorkingFile->GetFilename());
2570 else
2571 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS));
2572 taskdlg.AddCommandControl(201, sTaskTemp); // left
2573 taskdlg.SetDefaultCommandControl(201);
2574 if (HasUnsavedEdits(m_pwndRightView))
2576 if (m_pwndRightView->m_pWorkingFile->InUse() && !m_pwndRightView->m_pWorkingFile->IsReadonly())
2577 sTaskTemp.Format(IDS_ASKFORSAVE_SAVERIGHT, (LPCTSTR)m_pwndRightView->m_pWorkingFile->GetFilename());
2578 else
2579 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS));
2580 taskdlg.AddCommandControl(202, sTaskTemp); // right
2581 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEALL2))); // both
2582 taskdlg.SetDefaultCommandControl(203);
2584 taskdlg.AddCommandControl(IDNO, sNoSave); // none
2585 taskdlg.AddCommandControl(IDCANCEL, sCancelAction); // cancel
2586 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2587 taskdlg.SetMainIcon(TD_WARNING_ICON);
2588 UINT ret = (UINT)taskdlg.DoModal(m_hWnd);
2589 switch (ret)
2591 case 201: // left
2592 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
2593 break;
2594 case 203: // both
2595 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
2596 case 202: // right
2597 m_pwndRightView->SaveFile();
2598 break;
2600 if (ret != IDCANCEL && (eReason == CHFSR_CLOSE || eReason == CHFSR_OPEN))
2601 DeleteBaseTheirsMineOnClose();
2602 return ret;
2604 else
2606 // only secondary (left) view
2608 // only right view - 1.7 implementation is used
2610 else if (CBaseView::IsViewGood(m_pwndLeftView))
2612 // only one view - only one to save
2613 // 1.7 FileSave don't support this mode
2614 if (HasUnsavedEdits(m_pwndLeftView))
2616 CTaskDialog taskdlg(sTitle,
2617 sSubTitle,
2618 sAppName,
2620 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
2621 CString sTask3;
2622 if (m_Data.m_mergedFile.InUse())
2623 sTask3.Format(IDS_ASKFORSAVE_TASK3, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
2624 else
2625 sTask3.LoadString(IDS_ASKFORSAVE_TASK6);
2626 taskdlg.AddCommandControl(IDYES, sTask3);
2627 taskdlg.AddCommandControl(IDNO, sNoSave);
2628 taskdlg.AddCommandControl(IDCANCEL, sCancelAction);
2629 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2630 taskdlg.SetDefaultCommandControl(IDYES);
2631 taskdlg.SetMainIcon(TD_WARNING_ICON);
2632 if ((UINT)taskdlg.DoModal(m_hWnd) == IDYES)
2634 if (m_pwndLeftView->SaveFile()<0)
2635 return IDCANCEL;
2638 if (eReason == CHFSR_CLOSE || eReason == CHFSR_OPEN)
2639 DeleteBaseTheirsMineOnClose();
2640 return IDNO;
2642 else
2644 if (eReason == CHFSR_CLOSE || eReason == CHFSR_OPEN)
2645 DeleteBaseTheirsMineOnClose();
2646 return IDNO; // nothing to save
2649 // 1.7 implementation
2650 UINT ret = IDNO;
2651 if (HasUnsavedEdits())
2653 CTaskDialog taskdlg(sTitle,
2654 sSubTitle,
2655 sAppName,
2657 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
2658 CString sTask3;
2659 if (m_Data.m_mergedFile.InUse())
2660 sTask3.Format(IDS_ASKFORSAVE_TASK3, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
2661 else
2662 sTask3.LoadString(IDS_ASKFORSAVE_TASK6);
2663 taskdlg.AddCommandControl(IDYES, sTask3);
2664 taskdlg.AddCommandControl(IDNO, sNoSave);
2665 taskdlg.AddCommandControl(IDCANCEL, sCancelAction);
2666 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2667 taskdlg.SetDefaultCommandControl(IDYES);
2668 taskdlg.SetMainIcon(TD_WARNING_ICON);
2669 ret = (UINT)taskdlg.DoModal(m_hWnd);
2671 if (ret == IDYES)
2673 if (!FileSave())
2674 ret = IDCANCEL;
2678 if (ret != IDCANCEL && (eReason == CHFSR_CLOSE || eReason == CHFSR_OPEN))
2679 DeleteBaseTheirsMineOnClose();
2681 return ret;
2684 void CMainFrame::DeleteBaseTheirsMineOnClose()
2686 if (!m_bDeleteBaseTheirsMineOnClose)
2687 return;
2689 m_bDeleteBaseTheirsMineOnClose = false;
2691 DeleteFile(m_Data.m_baseFile.GetFilename());
2692 DeleteFile(m_Data.m_theirFile.GetFilename());
2693 DeleteFile(m_Data.m_yourFile.GetFilename());
2696 bool CMainFrame::HasUnsavedEdits() const
2698 return HasUnsavedEdits(m_pwndBottomView) || HasUnsavedEdits(m_pwndRightView) || m_bSaveRequired;
2701 bool CMainFrame::HasUnsavedEdits(const CBaseView* view)
2703 if (!CBaseView::IsViewGood(view))
2704 return false;
2705 return view->IsModified();
2708 bool CMainFrame::HasMarkedBlocks() const
2710 return CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->HasMarkedBlocks();
2713 bool CMainFrame::IsViewGood(const CBaseView* view)
2715 return CBaseView::IsViewGood(view);
2718 void CMainFrame::OnViewInlinediffword()
2720 m_bInlineWordDiff = !m_bInlineWordDiff;
2721 if (m_pwndLeftView)
2723 m_pwndLeftView->SetInlineWordDiff(m_bInlineWordDiff);
2724 m_pwndLeftView->BuildAllScreen2ViewVector();
2725 m_pwndLeftView->DocumentUpdated();
2727 if (m_pwndRightView)
2729 m_pwndRightView->SetInlineWordDiff(m_bInlineWordDiff);
2730 m_pwndRightView->BuildAllScreen2ViewVector();
2731 m_pwndRightView->DocumentUpdated();
2733 if (m_pwndBottomView)
2735 m_pwndBottomView->SetInlineWordDiff(m_bInlineWordDiff);
2736 m_pwndBottomView->BuildAllScreen2ViewVector();
2737 m_pwndBottomView->DocumentUpdated();
2739 m_wndLineDiffBar.DocumentUpdated();
2742 void CMainFrame::OnUpdateViewInlinediffword(CCmdUI *pCmdUI)
2744 pCmdUI->Enable(m_bInlineDiff && IsViewGood(m_pwndLeftView) && IsViewGood(m_pwndRightView));
2745 pCmdUI->SetCheck(m_bInlineWordDiff);
2748 void CMainFrame::OnViewInlinediff()
2750 m_bInlineDiff = !m_bInlineDiff;
2751 if (m_pwndLeftView)
2753 m_pwndLeftView->SetInlineDiff(m_bInlineDiff);
2754 m_pwndLeftView->BuildAllScreen2ViewVector();
2755 m_pwndLeftView->DocumentUpdated();
2757 if (m_pwndRightView)
2759 m_pwndRightView->SetInlineDiff(m_bInlineDiff);
2760 m_pwndRightView->BuildAllScreen2ViewVector();
2761 m_pwndRightView->DocumentUpdated();
2763 if (m_pwndBottomView)
2765 m_pwndBottomView->SetInlineDiff(m_bInlineDiff);
2766 m_pwndBottomView->BuildAllScreen2ViewVector();
2767 m_pwndBottomView->DocumentUpdated();
2769 m_wndLineDiffBar.DocumentUpdated();
2772 void CMainFrame::OnUpdateViewInlinediff(CCmdUI *pCmdUI)
2774 pCmdUI->Enable(IsViewGood(m_pwndLeftView) && IsViewGood(m_pwndRightView));
2775 pCmdUI->SetCheck(m_bInlineDiff);
2778 void CMainFrame::OnUpdateEditCreateunifieddifffile(CCmdUI *pCmdUI)
2780 // "create unified diff file" is only available if two files
2781 // are diffed, not three.
2782 bool bEnabled = true;
2783 if (!IsViewGood(m_pwndLeftView))
2784 bEnabled = false;
2785 else if (!IsViewGood(m_pwndRightView))
2786 bEnabled = false;
2787 else if (IsViewGood(m_pwndBottomView)) //no negation here
2788 bEnabled = false;
2789 pCmdUI->Enable(bEnabled);
2792 void CMainFrame::OnEditCreateunifieddifffile()
2794 CString origFile, modifiedFile;
2795 // the original file is the one on the left
2796 if (m_pwndLeftView)
2797 origFile = m_pwndLeftView->m_sFullFilePath;
2798 if (m_pwndRightView)
2799 modifiedFile = m_pwndRightView->m_sFullFilePath;
2800 if (origFile.IsEmpty() || modifiedFile.IsEmpty())
2801 return;
2803 CString outputFile;
2804 if(!TryGetFileName(outputFile))
2805 return;
2807 CRegStdDWORD regContextLines(L"Software\\TortoiseGitMerge\\ContextLines", (DWORD)-1);
2808 CAppUtils::CreateUnifiedDiff(origFile, modifiedFile, outputFile, regContextLines, true);
2811 void CMainFrame::OnUpdateViewLinediffbar(CCmdUI *pCmdUI)
2813 pCmdUI->SetCheck(m_bLineDiff);
2814 pCmdUI->Enable();
2817 void CMainFrame::OnViewLinediffbar()
2819 m_bLineDiff = !m_bLineDiff;
2820 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2821 m_wndLineDiffBar.DocumentUpdated();
2822 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2823 m_wndLocatorBar.DocumentUpdated();
2826 void CMainFrame::OnUpdateViewLocatorbar(CCmdUI *pCmdUI)
2828 pCmdUI->SetCheck(m_bLocatorBar);
2829 pCmdUI->Enable();
2832 void CMainFrame::OnUpdateViewBars(CCmdUI * pCmdUI)
2834 pCmdUI->Enable();
2837 void CMainFrame::OnViewLocatorbar()
2839 m_bLocatorBar = !m_bLocatorBar;
2840 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2841 m_wndLocatorBar.DocumentUpdated();
2842 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2843 m_wndLineDiffBar.DocumentUpdated();
2846 void CMainFrame::OnViewComparewhitespaces()
2848 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2849 return;
2850 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
2851 regIgnoreWS = 0;
2852 LoadViews(-1);
2855 void CMainFrame::OnUpdateViewComparewhitespaces(CCmdUI *pCmdUI)
2857 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
2858 DWORD dwIgnoreWS = regIgnoreWS;
2859 pCmdUI->SetCheck(dwIgnoreWS == 0);
2862 void CMainFrame::OnViewIgnorewhitespacechanges()
2864 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2865 return;
2866 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
2867 regIgnoreWS = 2;
2868 LoadViews(-1);
2871 void CMainFrame::OnUpdateViewIgnorewhitespacechanges(CCmdUI *pCmdUI)
2873 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
2874 DWORD dwIgnoreWS = regIgnoreWS;
2875 pCmdUI->SetCheck(dwIgnoreWS == 2);
2878 void CMainFrame::OnViewIgnoreallwhitespacechanges()
2880 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2881 return;
2882 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
2883 regIgnoreWS = 1;
2884 LoadViews(-1);
2887 void CMainFrame::OnUpdateViewIgnoreallwhitespacechanges(CCmdUI *pCmdUI)
2889 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
2890 DWORD dwIgnoreWS = regIgnoreWS;
2891 pCmdUI->SetCheck(dwIgnoreWS == 1);
2894 void CMainFrame::OnViewMovedBlocks()
2896 m_bViewMovedBlocks = !(DWORD)m_regViewModedBlocks;
2897 m_regViewModedBlocks = m_bViewMovedBlocks;
2898 LoadViews(-1);
2901 void CMainFrame::OnUpdateViewMovedBlocks(CCmdUI *pCmdUI)
2903 pCmdUI->SetCheck(m_bViewMovedBlocks);
2904 BOOL bEnable = TRUE;
2905 if (IsViewGood(m_pwndBottomView))
2907 bEnable = FALSE;
2909 pCmdUI->Enable(bEnable);
2912 bool CMainFrame::HasConflictsWontKeep()
2914 const int nConflictLine = CheckResolved();
2915 if (nConflictLine < 0)
2916 return false;
2917 if (!m_pwndBottomView)
2918 return false;
2920 CString sTemp;
2921 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
2922 CTaskDialog taskdlg(sTemp,
2923 CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK2)),
2924 L"TortoiseGitMerge",
2926 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
2927 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK3)));
2928 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK4)));
2929 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2930 taskdlg.SetDefaultCommandControl(2);
2931 taskdlg.SetMainIcon(TD_ERROR_ICON);
2932 if (taskdlg.DoModal(m_hWnd) == 1)
2933 return false;
2935 m_pwndBottomView->GoToLine(nConflictLine);
2936 return true;
2939 bool CMainFrame::TryGetFileName(CString& result)
2941 return CCommonAppUtils::FileOpenSave(result, nullptr, IDS_SAVEASTITLE, IDS_COMMONFILEFILTER, false, m_hWnd);
2944 CBaseView* CMainFrame::GetActiveBaseView() const
2946 CView* activeView = GetActiveView();
2947 CBaseView* activeBase = dynamic_cast<CBaseView*>( activeView );
2948 return activeBase;
2951 void CMainFrame::SetWindowTitle()
2953 // try to find a suitable window title
2954 CString sYour = m_Data.m_yourFile.GetDescriptiveName();
2955 if (sYour.Find(L" - ") >= 0)
2956 sYour = sYour.Left(sYour.Find(L" - "));
2957 if (sYour.Find(L" : ") >= 0)
2958 sYour = sYour.Left(sYour.Find(L" : "));
2959 CString sTheir = m_Data.m_theirFile.GetDescriptiveName();
2960 if (sTheir.IsEmpty())
2961 sTheir = m_Data.m_baseFile.GetDescriptiveName();
2962 if (sTheir.Find(L" - ") >= 0)
2963 sTheir = sTheir.Left(sTheir.Find(L" - "));
2964 if (sTheir.Find(L" : ") >= 0)
2965 sTheir = sTheir.Left(sTheir.Find(L" : "));
2967 if (!sYour.IsEmpty() && !sTheir.IsEmpty())
2969 if (sYour.CompareNoCase(sTheir)==0)
2970 SetWindowText(sYour + L" - TortoiseGitMerge");
2971 else if ((sYour.GetLength() < 10) &&
2972 (sTheir.GetLength() < 10))
2973 SetWindowText(sYour + L" - " + sTheir + L" - TortoiseGitMerge");
2974 else
2976 // we have two very long descriptive texts here, which
2977 // means we have to find a way to use them as a window
2978 // title in a shorter way.
2979 // for simplicity, we just use the one from "yourfile"
2980 SetWindowText(sYour + L" - TortoiseGitMerge");
2983 else if (!sYour.IsEmpty())
2984 SetWindowText(sYour + L" - TortoiseGitMerge");
2985 else if (!sTheir.IsEmpty())
2986 SetWindowText(sTheir + L" - TortoiseGitMerge");
2987 else
2988 SetWindowText(L"TortoiseGitMerge");
2991 void CMainFrame::OnTimer(UINT_PTR nIDEvent)
2993 switch (nIDEvent)
2995 case IDT_RELOADCHECKTIMER:
2996 KillTimer(nIDEvent);
2997 CheckForReload();
2998 break;
3001 __super::OnTimer(nIDEvent);
3004 void CMainFrame::LoadIgnoreCommentData()
3006 static bool bLoaded = false;
3007 if (bLoaded)
3008 return;
3009 CString sPath = CPathUtils::GetAppDataDirectory() + L"ignorecomments.txt";
3010 if (!PathFileExists(sPath))
3012 // ignore comments file does not exist (yet), so create a default one
3013 HRSRC hRes = FindResource(nullptr, MAKEINTRESOURCE(IDR_IGNORECOMMENTSTXT), L"config");
3014 if (hRes)
3016 HGLOBAL hResourceLoaded = LoadResource(nullptr, hRes);
3017 if (hResourceLoaded)
3019 char * lpResLock = (char *) LockResource(hResourceLoaded);
3020 DWORD dwSizeRes = SizeofResource(nullptr, hRes);
3021 if (lpResLock)
3023 HANDLE hFile = CreateFile(sPath, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
3024 if (hFile != INVALID_HANDLE_VALUE)
3026 DWORD dwWritten = 0;
3027 WriteFile(hFile, lpResLock, dwSizeRes, &dwWritten, nullptr);
3028 CloseHandle(hFile);
3037 CStdioFile file;
3038 if (file.Open(sPath, CFile::modeRead))
3040 CString sLine;
3041 while (file.ReadString(sLine))
3043 int eqpos = sLine.Find('=');
3044 if (eqpos >= 0)
3046 CString sExts = sLine.Left(eqpos);
3047 CString sComments = sLine.Mid(eqpos+1);
3049 int pos = sComments.Find(',');
3050 CString sLineStart = sComments.Left(pos);
3051 pos = sComments.Find(',', pos);
3052 int pos2 = sComments.Find(',', pos+1);
3053 CString sBlockStart = sComments.Mid(pos+1, pos2-pos-1);
3054 CString sBlockEnd = sComments.Mid(pos2+1);
3056 auto commentTuple = std::make_tuple(sLineStart, sBlockStart, sBlockEnd);
3058 pos = 0;
3059 CString temp;
3060 for (;;)
3062 temp = sExts.Tokenize(L",", pos);
3063 if (temp.IsEmpty())
3065 break;
3067 ASSERT(m_IgnoreCommentsMap.find(temp) == m_IgnoreCommentsMap.end());
3068 m_IgnoreCommentsMap[temp] = commentTuple;
3074 catch (CFileException* e)
3076 e->Delete();
3078 bLoaded = true;
3081 void CMainFrame::OnViewIgnorecomments()
3083 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3084 return;
3085 m_regIgnoreComments = !DWORD(m_regIgnoreComments);
3086 LoadViews(-1);
3089 void CMainFrame::OnUpdateViewIgnorecomments(CCmdUI *pCmdUI)
3091 // only enable if we have comments defined for this file extension
3092 CString sExt = CPathUtils::GetFileExtFromPath(m_Data.m_baseFile.GetFilename()).MakeLower();
3093 sExt.TrimLeft(L".");
3094 auto sC = m_IgnoreCommentsMap.find(sExt);
3095 if (sC == m_IgnoreCommentsMap.end())
3097 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_yourFile.GetFilename()).MakeLower();
3098 sExt.TrimLeft(L".");
3099 sC = m_IgnoreCommentsMap.find(sExt);
3100 if (sC == m_IgnoreCommentsMap.end())
3102 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_theirFile.GetFilename()).MakeLower();
3103 sExt.TrimLeft(L".");
3104 sC = m_IgnoreCommentsMap.find(sExt);
3107 pCmdUI->Enable(sC != m_IgnoreCommentsMap.end());
3109 pCmdUI->SetCheck(DWORD(m_regIgnoreComments) != 0);
3113 void CMainFrame::OnRegexfilter(UINT cmd)
3115 if ((cmd == ID_REGEXFILTER)||(cmd == (ID_REGEXFILTER+1)))
3117 CRegexFiltersDlg dlg(this);
3118 dlg.SetIniFile(&m_regexIni);
3119 if (dlg.DoModal() == IDOK)
3121 FILE* pFile = nullptr;
3122 _wfopen_s(&pFile, CPathUtils::GetAppDataDirectory() + L"regexfilters.ini", L"wb");
3123 m_regexIni.SaveFile(pFile);
3124 fclose(pFile);
3126 BuildRegexSubitems();
3128 else
3130 if (cmd == (UINT)m_regexIndex)
3132 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3133 return;
3134 m_Data.SetRegexTokens(std::wregex(), L"");
3135 m_regexIndex = -1;
3136 LoadViews(-1);
3138 else
3140 CSimpleIni::TNamesDepend sections;
3141 m_regexIni.GetAllSections(sections);
3142 int index = ID_REGEXFILTER + 2;
3143 m_regexIndex = -1;
3144 for (const auto& section : sections)
3146 if (cmd == (UINT)index)
3148 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3149 break;
3152 std::wregex rx(m_regexIni.GetValue(section.pItem, L"regex", L""));
3153 m_Data.SetRegexTokens(rx, m_regexIni.GetValue(section.pItem, L"replace", L""));
3155 catch (std::exception &ex)
3157 MessageBox(L"Regex is invalid!\r\n" + CString(ex.what()));
3159 m_regexIndex = index;
3160 LoadViews(-1);
3161 break;
3163 ++index;
3169 void CMainFrame::OnUpdateViewRegexFilter( CCmdUI *pCmdUI )
3171 pCmdUI->Enable();
3172 pCmdUI->SetCheck(pCmdUI->m_nID == (UINT)m_regexIndex);
3175 void CMainFrame::BuildRegexSubitems(CMFCPopupMenu* pMenuPopup)
3177 CString sIniPath = CPathUtils::GetAppDataDirectory() + L"regexfilters.ini";
3178 if (!PathFileExists(sIniPath))
3180 // ini file does not exist (yet), so create a default one
3181 HRSRC hRes = FindResource(nullptr, MAKEINTRESOURCE(IDR_REGEXFILTERINI), L"config");
3182 if (hRes)
3184 HGLOBAL hResourceLoaded = LoadResource(nullptr, hRes);
3185 if (hResourceLoaded)
3187 char * lpResLock = (char *)LockResource(hResourceLoaded);
3188 DWORD dwSizeRes = SizeofResource(nullptr, hRes);
3189 if (lpResLock)
3191 HANDLE hFile = CreateFile(sIniPath, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
3192 if (hFile != INVALID_HANDLE_VALUE)
3194 DWORD dwWritten = 0;
3195 WriteFile(hFile, lpResLock, dwSizeRes, &dwWritten, nullptr);
3196 CloseHandle(hFile);
3203 m_regexIni.LoadFile(sIniPath);
3204 CSimpleIni::TNamesDepend sections;
3205 m_regexIni.GetAllSections(sections);
3207 if (m_bUseRibbons)
3209 CArray<CMFCRibbonBaseElement*, CMFCRibbonBaseElement*> arButtons;
3210 m_wndRibbonBar.GetElementsByID(ID_REGEXFILTER, arButtons);
3211 if (arButtons.GetCount() == 1)
3213 CMFCRibbonButton * pButton = (CMFCRibbonButton*)arButtons.GetAt(0);
3214 if (pButton)
3216 pButton->RemoveAllSubItems();
3217 pButton->AddSubItem(new CMFCRibbonButton(ID_REGEXFILTER + 1, CString(MAKEINTRESOURCE(IDS_CONFIGUREREGEXES)), 47, 47));
3219 if (!sections.empty())
3220 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3221 int cmdIndex = 2;
3222 for (const auto& section : sections)
3224 pButton->AddSubItem(new CMFCRibbonButton(ID_REGEXFILTER + cmdIndex, section.pItem, 46, 46));
3225 cmdIndex++;
3230 else if (pMenuPopup)
3232 int iIndex = -1;
3233 if (!CMFCToolBar::IsCustomizeMode() &&
3234 (iIndex = pMenuPopup->GetMenuBar()->CommandToIndex(ID_REGEXFILTER)) >= 0)
3236 if (!sections.empty())
3237 pMenuPopup->InsertSeparator(iIndex + 1); // insert the separator at the end
3238 int cmdIndex = 2;
3239 for (const auto& section : sections)
3241 pMenuPopup->InsertItem(CMFCToolBarMenuButton(ID_REGEXFILTER + cmdIndex, nullptr, -1, (LPCWSTR)section.pItem), iIndex + cmdIndex);
3242 cmdIndex++;
3248 void CMainFrame::FillEncodingButton( CMFCRibbonButton * pButton, int start )
3250 pButton->SetDefaultCommand(FALSE);
3251 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::ASCII, L"ASCII" ));
3252 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::BINARY, L"BINARY" ));
3253 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_LE, L"UTF-16LE" ));
3254 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_LEBOM, L"UTF-16LE BOM"));
3255 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_BE, L"UTF-16BE" ));
3256 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_BEBOM, L"UTF-16BE BOM"));
3257 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF32_LE, L"UTF-32LE" ));
3258 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF32_BE, L"UTF-32BE" ));
3259 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF8, L"UTF-8" ));
3260 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF8BOM, L"UTF-8 BOM" ));
3263 void CMainFrame::FillEOLButton( CMFCRibbonButton * pButton, int start )
3265 pButton->SetDefaultCommand(FALSE);
3266 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LF , L"LF" ));
3267 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_CRLF, L"CRLF"));
3268 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LFCR, L"LRCR"));
3269 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_CR , L"CR" ));
3270 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_VT , L"VT" ));
3271 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_FF , L"FF" ));
3272 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_NEL , L"NEL" ));
3273 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LS , L"LS" ));
3274 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_PS , L"PS" ));
3277 void CMainFrame::FillTabModeButton(CMFCRibbonButton * pButton, int start)
3279 pButton->SetDefaultCommand(FALSE);
3280 pButton->AddSubItem(new CMFCRibbonButton(start + TABMODE_NONE , L"Tab"));
3281 pButton->AddSubItem(new CMFCRibbonButton(start + TABMODE_USESPACES , L"Space"));
3282 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3283 pButton->AddSubItem(new CMFCRibbonButton(start + TABMODE_SMARTINDENT , L"Smart tab char"));
3284 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3285 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON1, L"1"));
3286 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON2, L"2"));
3287 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON4, L"4"));
3288 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON8, L"8"));
3289 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3290 pButton->AddSubItem(new CMFCRibbonButton(start + ENABLEEDITORCONFIG, L"EditorConfig"));
3293 bool CMainFrame::AdjustUnicodeTypeForLoad(CFileTextLines::UnicodeType& type)
3295 switch (type)
3297 case CFileTextLines::UnicodeType::AUTOTYPE:
3298 case CFileTextLines::UnicodeType::BINARY:
3299 return false;
3301 case CFileTextLines::UnicodeType::ASCII:
3302 case CFileTextLines::UnicodeType::UTF16_LE:
3303 case CFileTextLines::UnicodeType::UTF16_BE:
3304 case CFileTextLines::UnicodeType::UTF32_LE:
3305 case CFileTextLines::UnicodeType::UTF32_BE:
3306 case CFileTextLines::UnicodeType::UTF8:
3307 return true;
3309 case CFileTextLines::UnicodeType::UTF16_LEBOM:
3310 type = CFileTextLines::UnicodeType::UTF16_LE;
3311 return true;
3313 case CFileTextLines::UnicodeType::UTF16_BEBOM:
3314 type = CFileTextLines::UnicodeType::UTF16_BE;
3315 return true;
3317 case CFileTextLines::UnicodeType::UTF8BOM:
3318 type = CFileTextLines::UnicodeType::UTF8;
3319 return true;
3321 return false;
3324 void CMainFrame::OnEncodingLeft( UINT cmd )
3326 if (m_pwndLeftView)
3328 if (GetKeyState(VK_CONTROL) & 0x8000)
3330 // reload with selected encoding
3331 auto saveparams = m_Data.m_arBaseFile.GetSaveParams();
3332 saveparams.m_UnicodeType = CFileTextLines::UnicodeType(cmd - ID_INDICATOR_LEFTENCODINGSTART);
3333 if (AdjustUnicodeTypeForLoad(saveparams.m_UnicodeType))
3335 m_Data.m_arBaseFile.SetSaveParams(saveparams);
3336 m_Data.m_arBaseFile.KeepEncoding();
3337 LoadViews();
3340 else
3342 m_pwndLeftView->SetTextType(CFileTextLines::UnicodeType(cmd - ID_INDICATOR_LEFTENCODINGSTART));
3343 m_pwndLeftView->RefreshViews();
3348 void CMainFrame::OnEncodingRight( UINT cmd )
3350 if (m_pwndRightView)
3352 if (GetKeyState(VK_CONTROL) & 0x8000)
3354 // reload with selected encoding
3355 auto saveparams = m_Data.m_arYourFile.GetSaveParams();
3356 saveparams.m_UnicodeType = CFileTextLines::UnicodeType(cmd - ID_INDICATOR_RIGHTENCODINGSTART);
3357 if (AdjustUnicodeTypeForLoad(saveparams.m_UnicodeType))
3359 m_Data.m_arYourFile.SetSaveParams(saveparams);
3360 m_Data.m_arYourFile.KeepEncoding();
3361 LoadViews();
3364 else
3366 m_pwndRightView->SetTextType(CFileTextLines::UnicodeType(cmd - ID_INDICATOR_RIGHTENCODINGSTART));
3367 m_pwndRightView->RefreshViews();
3372 void CMainFrame::OnEncodingBottom( UINT cmd )
3374 if (m_pwndBottomView)
3376 if (GetKeyState(VK_CONTROL) & 0x8000)
3378 // reload with selected encoding
3379 auto saveparams = m_Data.m_arTheirFile.GetSaveParams();
3380 saveparams.m_UnicodeType = CFileTextLines::UnicodeType(cmd - ID_INDICATOR_BOTTOMENCODINGSTART);
3381 if (AdjustUnicodeTypeForLoad(saveparams.m_UnicodeType))
3383 m_Data.m_arTheirFile.SetSaveParams(saveparams);
3384 m_Data.m_arTheirFile.KeepEncoding();
3385 LoadViews();
3388 else
3390 m_pwndBottomView->SetTextType(CFileTextLines::UnicodeType(cmd - ID_INDICATOR_BOTTOMENCODINGSTART));
3391 m_pwndBottomView->RefreshViews();
3396 void CMainFrame::OnEOLLeft( UINT cmd )
3398 if (m_pwndLeftView)
3400 m_pwndLeftView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_LEFTEOLSTART));
3401 m_pwndLeftView->RefreshViews();
3405 void CMainFrame::OnEOLRight( UINT cmd )
3407 if (m_pwndRightView)
3409 m_pwndRightView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_RIGHTEOLSTART));
3410 m_pwndRightView->RefreshViews();
3414 void CMainFrame::OnEOLBottom( UINT cmd )
3416 if (m_pwndBottomView)
3418 m_pwndBottomView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_BOTTOMEOLSTART));
3419 m_pwndBottomView->RefreshViews();
3423 void CMainFrame::OnTabModeLeft( UINT cmd )
3425 OnTabMode(m_pwndLeftView, (int)cmd - ID_INDICATOR_LEFTTABMODESTART);
3428 void CMainFrame::OnTabModeRight( UINT cmd )
3430 OnTabMode(m_pwndRightView, (int)cmd - ID_INDICATOR_RIGHTTABMODESTART);
3433 void CMainFrame::OnTabModeBottom( UINT cmd )
3435 OnTabMode(m_pwndBottomView, (int)cmd - ID_INDICATOR_BOTTOMTABMODESTART);
3438 void CMainFrame::OnTabMode(CBaseView *view, int cmd)
3440 if (!view)
3441 return;
3442 int nTabMode = view->GetTabMode();
3443 if (cmd == TABMODE_NONE || cmd == TABMODE_USESPACES)
3444 view->SetTabMode((nTabMode & (~TABMODE_USESPACES)) | (cmd & TABMODE_USESPACES));
3445 else if (cmd == TABMODE_SMARTINDENT) // Toggle
3446 view->SetTabMode((nTabMode & (~TABMODE_SMARTINDENT)) | ((nTabMode & TABMODE_SMARTINDENT) ? 0 : TABMODE_SMARTINDENT));
3447 else if (cmd == TABSIZEBUTTON1)
3448 view->SetTabSize(1);
3449 else if (cmd == TABSIZEBUTTON2)
3450 view->SetTabSize(2);
3451 else if (cmd == TABSIZEBUTTON4)
3452 view->SetTabSize(4);
3453 else if (cmd == TABSIZEBUTTON8)
3454 view->SetTabSize(8);
3455 else if (cmd == ENABLEEDITORCONFIG)
3456 view->SetEditorConfigEnabled(!view->GetEditorConfigEnabled());
3457 view->RefreshViews();
3460 void CMainFrame::OnUpdateEncodingLeft( CCmdUI *pCmdUI )
3462 if (m_pwndLeftView)
3464 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_LEFTENCODINGSTART) == m_pwndLeftView->GetTextType());
3465 pCmdUI->Enable(m_pwndLeftView->IsWritable() || (GetKeyState(VK_CONTROL)&0x8000));
3467 else
3468 pCmdUI->Enable(FALSE);
3471 void CMainFrame::OnUpdateEncodingRight( CCmdUI *pCmdUI )
3473 if (m_pwndRightView)
3475 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_RIGHTENCODINGSTART) == m_pwndRightView->GetTextType());
3476 pCmdUI->Enable(m_pwndRightView->IsWritable() || (GetKeyState(VK_CONTROL) & 0x8000));
3478 else
3479 pCmdUI->Enable(FALSE);
3482 void CMainFrame::OnUpdateEncodingBottom( CCmdUI *pCmdUI )
3484 if (m_pwndBottomView)
3486 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_BOTTOMENCODINGSTART) == m_pwndBottomView->GetTextType());
3487 pCmdUI->Enable(m_pwndBottomView->IsWritable() || (GetKeyState(VK_CONTROL) & 0x8000));
3489 else
3490 pCmdUI->Enable(FALSE);
3493 void CMainFrame::OnUpdateEOLLeft( CCmdUI *pCmdUI )
3495 if (m_pwndLeftView)
3497 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_LEFTEOLSTART) == m_pwndLeftView->GetLineEndings());
3498 pCmdUI->Enable(m_pwndLeftView->IsWritable());
3500 else
3501 pCmdUI->Enable(FALSE);
3504 void CMainFrame::OnUpdateEOLRight( CCmdUI *pCmdUI )
3506 if (m_pwndRightView)
3508 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_RIGHTEOLSTART) == m_pwndRightView->GetLineEndings());
3509 pCmdUI->Enable(m_pwndRightView->IsWritable());
3511 else
3512 pCmdUI->Enable(FALSE);
3515 void CMainFrame::OnUpdateEOLBottom( CCmdUI *pCmdUI )
3517 if (m_pwndBottomView)
3519 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_BOTTOMEOLSTART) == m_pwndBottomView->GetLineEndings());
3520 pCmdUI->Enable(m_pwndBottomView->IsWritable());
3522 else
3523 pCmdUI->Enable(FALSE);
3526 void CMainFrame::OnUpdateTabModeLeft(CCmdUI *pCmdUI)
3528 OnUpdateTabMode(m_pwndLeftView, pCmdUI, ID_INDICATOR_LEFTTABMODESTART);
3531 void CMainFrame::OnUpdateTabModeRight(CCmdUI *pCmdUI)
3533 OnUpdateTabMode(m_pwndRightView, pCmdUI, ID_INDICATOR_RIGHTTABMODESTART);
3536 void CMainFrame::OnUpdateTabModeBottom(CCmdUI *pCmdUI)
3538 OnUpdateTabMode(m_pwndBottomView, pCmdUI, ID_INDICATOR_BOTTOMTABMODESTART);
3541 void CMainFrame::OnUpdateTabMode(CBaseView *view, CCmdUI *pCmdUI, int startid)
3543 if (view)
3545 int cmd = (int)pCmdUI->m_nID - startid;
3546 if (cmd == TABMODE_NONE)
3547 pCmdUI->SetCheck((view->GetTabMode() & TABMODE_USESPACES) == TABMODE_NONE);
3548 else if (cmd == TABMODE_USESPACES)
3549 pCmdUI->SetCheck(view->GetTabMode() & TABMODE_USESPACES);
3550 else if (cmd == TABMODE_SMARTINDENT)
3551 pCmdUI->SetCheck(view->GetTabMode() & TABMODE_SMARTINDENT);
3552 else if (cmd == TABSIZEBUTTON1)
3553 pCmdUI->SetCheck(view->GetTabSize() == 1);
3554 else if (cmd == TABSIZEBUTTON2)
3555 pCmdUI->SetCheck(view->GetTabSize() == 2);
3556 else if (cmd == TABSIZEBUTTON4)
3557 pCmdUI->SetCheck(view->GetTabSize() == 4);
3558 else if (cmd == TABSIZEBUTTON8)
3559 pCmdUI->SetCheck(view->GetTabSize() == 8);
3560 else if (cmd == ENABLEEDITORCONFIG)
3561 pCmdUI->SetCheck(view->GetEditorConfigEnabled());
3562 pCmdUI->Enable(view->IsWritable());
3563 if (cmd == ENABLEEDITORCONFIG)
3564 pCmdUI->Enable(view->IsWritable() && view->GetEditorConfigLoaded());
3566 else
3567 pCmdUI->Enable(FALSE);
3570 BOOL CMainFrame::OnShowPopupMenu(CMFCPopupMenu* pMenuPopup)
3572 __super::OnShowPopupMenu(pMenuPopup);
3574 if (!pMenuPopup)
3575 return TRUE;
3577 int iIndex = -1;
3578 if (!CMFCToolBar::IsCustomizeMode() &&
3579 (iIndex = pMenuPopup->GetMenuBar()->CommandToIndex(ID_REGEXFILTER)) >= 0)
3581 BuildRegexSubitems(pMenuPopup);
3584 return TRUE;
3587 void CMainFrame::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
3589 __super::OnNcCalcSize(bCalcValidRects, lpncsp);
3591 // the original OnNcCalcSize handler extends the client are over the window borders if DWM composition is enabled,
3592 // but that leads to ugly gaps when the window is maximized and the task bar is set
3593 // to auto-hide. Seems Windows tries to adjust a maximized window itself to ensure that
3594 // the window either covers everything (fullscreen window) or does not cover the last pixel
3595 // on the side where the task bar is. But that adjustment doesn't work properly if the window
3596 // does not have borders.
3597 // So: to work around this problem, we undo what the original OnNcCalcSize() handler has done
3598 // if the window is maximized, the task bar is set to auto-hide and DWM composition is enabled.
3599 // problem reported here: https://developercommunity.visualstudio.com/content/problem/44368/maximizing-mfc-ribbon-app-is-wrong-when-task-bar-i.html
3600 if (GetRibbonBar()->GetSafeHwnd() && ((GetRibbonBar()->IsWindowVisible()) || !IsWindowVisible()) && GetRibbonBar()->IsReplaceFrameCaption())
3602 if (GetGlobalData()->IsDwmCompositionEnabled() && (GetStyle() & WS_MAXIMIZE))
3604 int nShellAutohideBars = GetGlobalData()->GetShellAutohideBars();
3605 if (nShellAutohideBars)
3607 CSize szSystemBorder(afxGlobalUtils.GetSystemBorders(this));
3608 lpncsp->rgrc[0].left -= szSystemBorder.cx;
3609 lpncsp->rgrc[0].right += szSystemBorder.cx;
3610 lpncsp->rgrc[0].bottom += szSystemBorder.cy;