Update editorconfig
[TortoiseGit.git] / src / TortoiseMerge / MainFrm.cpp
blobc33c7b49e21d8d09715fde9df4aa18fb8886a2c4
1 // TortoiseGitMerge - a Diff/Patch program
3 // Copyright (C) 2008-2016 - 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 END_MESSAGE_MAP()
178 static UINT indicators[] =
180 ID_SEPARATOR, // status line indicator
181 ID_INDICATOR_LEFTVIEW,
182 ID_INDICATOR_RIGHTVIEW,
183 ID_INDICATOR_BOTTOMVIEW,
184 ID_INDICATOR_CAPS,
185 ID_INDICATOR_NUM,
186 ID_INDICATOR_SCRL
190 // CMainFrame construction/destruction
192 CMainFrame::CMainFrame()
193 : m_bInitSplitter(FALSE)
194 , m_bReversedPatch(FALSE)
195 , m_bHasConflicts(false)
196 , m_bInlineWordDiff(true)
197 , m_bLineDiff(true)
198 , m_bLocatorBar(true)
199 , m_nMoveMovesToIgnore(0)
200 , m_pwndLeftView(NULL)
201 , m_pwndRightView(NULL)
202 , m_pwndBottomView(NULL)
203 , m_bReadOnly(false)
204 , m_bBlame(false)
205 , m_bCheckReload(false)
206 , m_bSaveRequired(false)
207 , m_bSaveRequiredOnConflicts(false)
208 , m_bDeleteBaseTheirsMineOnClose(false)
209 , resolveMsgWnd(0)
210 , resolveMsgWParam(0)
211 , resolveMsgLParam(0)
212 , m_regWrapLines(L"Software\\TortoiseGitMerge\\WrapLines", 0)
213 , m_regViewModedBlocks(L"Software\\TortoiseGitMerge\\ViewMovedBlocks", TRUE)
214 , m_regOneWay(L"Software\\TortoiseGitMerge\\OnePane")
215 , m_regCollapsed(L"Software\\TortoiseGitMerge\\Collapsed", 0)
216 , m_regInlineDiff(L"Software\\TortoiseGitMerge\\DisplayBinDiff", TRUE)
217 , m_regUseRibbons(L"Software\\TortoiseGitMerge\\UseRibbons", TRUE)
218 , m_regIgnoreComments(_T("Software\\TortoiseGitMerge\\IgnoreComments"), FALSE)
219 , m_regexIndex(-1)
221 m_bOneWay = (0 != ((DWORD)m_regOneWay));
222 theApp.m_nAppLook = theApp.GetInt(_T("ApplicationLook"), ID_VIEW_APPLOOK_VS_2005);
223 m_bCollapsed = !!(DWORD)m_regCollapsed;
224 m_bViewMovedBlocks = !!(DWORD)m_regViewModedBlocks;
225 m_bWrapLines = !!(DWORD)m_regWrapLines;
226 m_bInlineDiff = !!m_regInlineDiff;
227 m_bUseRibbons = !!m_regUseRibbons;
228 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
231 CMainFrame::~CMainFrame()
235 LRESULT CMainFrame::OnTaskbarButtonCreated(WPARAM /*wParam*/, LPARAM /*lParam*/)
237 SetUUIDOverlayIcon(m_hWnd);
238 return 0;
242 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
244 if (CFrameWndEx::OnCreate(lpCreateStruct) == -1)
245 return -1;
247 OnApplicationLook(theApp.m_nAppLook);
249 if (m_bUseRibbons)
251 m_wndRibbonBar.Create(this);
252 m_wndRibbonBar.LoadFromResource(IDR_RIBBON);
254 // enable the dialog launch button on the view panel
255 CMFCRibbonCategory * pMainCat = m_wndRibbonBar.GetCategory(1);
256 if (pMainCat)
258 CMFCRibbonPanel * pPanel = pMainCat->GetPanel(0);
259 if (pPanel)
260 pPanel->EnableLaunchButton(ID_VIEW_OPTIONS);
262 // now replace all buttons with our custom button class
263 for (int i = 0; i < m_wndRibbonBar.GetCategoryCount(); ++i)
265 CMFCRibbonCategory * pCat = m_wndRibbonBar.GetCategory(i);
266 for (int j = 0; j < pCat->GetPanelCount(); ++j)
268 CMFCRibbonPanel * pPanel = pCat->GetPanel(j);
269 CList<UINT, UINT> lstItems;
270 pPanel->GetItemIDsList(lstItems);
271 while (!lstItems.IsEmpty())
273 UINT id = lstItems.GetHead();
274 lstItems.RemoveHead();
275 CMFCRibbonButton * pButton = dynamic_cast<CMFCRibbonButton*>(pPanel->FindByID(id));
276 if (pButton)
278 CCustomMFCRibbonButton * c = new CCustomMFCRibbonButton(id, pButton->GetText());
279 pPanel->ReplaceByID(id, c);
284 BuildRegexSubitems();
285 if (!m_wndRibbonStatusBar.Create(this))
287 TRACE0("Failed to create ribbon status bar\n");
288 return -1; // fail to create
290 m_wndRibbonStatusBar.AddElement(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(AFX_IDS_IDLEMESSAGE)), TRUE), L"");
292 CString sTooltip(MAKEINTRESOURCE(IDS_ENCODING_COMBO_TOOLTIP));
293 auto apBtnGroupLeft = std::make_unique<CMFCRibbonButtonsGroup>();
294 apBtnGroupLeft->SetID(ID_INDICATOR_LEFTVIEW);
295 apBtnGroupLeft->AddButton(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(IDS_STATUSBAR_LEFTVIEW)), TRUE));
296 CMFCRibbonButton * pButton = new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOENCODING, L"");
297 pButton->SetToolTipText(sTooltip);
298 FillEncodingButton(pButton, ID_INDICATOR_LEFTENCODINGSTART);
299 apBtnGroupLeft->AddButton(pButton);
300 pButton = new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOEOL, L"");
301 FillEOLButton(pButton, ID_INDICATOR_LEFTEOLSTART);
302 apBtnGroupLeft->AddButton(pButton);
303 pButton = new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOTABMODE, L"");
304 FillTabModeButton(pButton, ID_INDICATOR_LEFTTABMODESTART);
305 apBtnGroupLeft->AddButton(pButton);
306 apBtnGroupLeft->AddButton(new CMFCRibbonStatusBarPane(ID_INDICATOR_LEFTVIEW, L"", TRUE));
307 m_wndRibbonStatusBar.AddExtendedElement(apBtnGroupLeft.release(), L"");
309 auto apBtnGroupRight = std::make_unique<CMFCRibbonButtonsGroup>();
310 apBtnGroupRight->SetID(ID_INDICATOR_RIGHTVIEW);
311 apBtnGroupRight->AddButton(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(IDS_STATUSBAR_RIGHTVIEW)), TRUE));
312 pButton = new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOENCODING, L"");
313 pButton->SetToolTipText(sTooltip);
314 FillEncodingButton(pButton, ID_INDICATOR_RIGHTENCODINGSTART);
315 apBtnGroupRight->AddButton(pButton);
316 pButton = new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOEOL, L"");
317 FillEOLButton(pButton, ID_INDICATOR_RIGHTEOLSTART);
318 apBtnGroupRight->AddButton(pButton);
319 pButton = new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOTABMODE, L"");
320 FillTabModeButton(pButton, ID_INDICATOR_RIGHTTABMODESTART);
321 apBtnGroupRight->AddButton(pButton);
322 apBtnGroupRight->AddButton(new CMFCRibbonStatusBarPane(ID_INDICATOR_RIGHTVIEW, L"", TRUE));
323 m_wndRibbonStatusBar.AddExtendedElement(apBtnGroupRight.release(), L"");
325 else
327 if (!m_wndMenuBar.Create(this))
329 TRACE0("Failed to create menubar\n");
330 return -1; // fail to create
332 m_wndMenuBar.SetPaneStyle(m_wndMenuBar.GetPaneStyle() | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY);
334 // prevent the menu bar from taking the focus on activation
335 CMFCPopupMenu::SetForceMenuFocus(FALSE);
336 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))
338 TRACE0("Failed to create toolbar\n");
339 return -1; // fail to create
341 m_wndToolBar.SetWindowText(_T("Main"));
342 if (!m_wndStatusBar.Create(this) ||
343 !m_wndStatusBar.SetIndicators(indicators,
344 _countof(indicators)))
346 TRACE0("Failed to create status bar\n");
347 return -1; // fail to create
349 m_wndStatusBar.EnablePaneDoubleClick();
352 if (!m_wndLocatorBar.Create(this, IDD_DIFFLOCATOR,
353 CBRS_ALIGN_LEFT | CBRS_SIZE_FIXED, ID_VIEW_LOCATORBAR))
355 TRACE0("Failed to create dialogbar\n");
356 return -1; // fail to create
358 if (!m_wndLineDiffBar.Create(this, IDD_LINEDIFF,
359 CBRS_ALIGN_BOTTOM | CBRS_SIZE_FIXED, ID_VIEW_LINEDIFFBAR))
361 TRACE0("Failed to create dialogbar\n");
362 return -1; // fail to create
364 m_wndLocatorBar.m_pMainFrm = this;
365 m_wndLineDiffBar.m_pMainFrm = this;
367 EnableDocking(CBRS_ALIGN_ANY);
368 if (!m_bUseRibbons)
370 m_wndMenuBar.EnableDocking(CBRS_ALIGN_TOP);
371 m_wndToolBar.EnableDocking(CBRS_ALIGN_TOP);
372 DockPane(&m_wndMenuBar);
373 DockPane(&m_wndToolBar);
375 DockPane(&m_wndLocatorBar);
376 DockPane(&m_wndLineDiffBar);
377 ShowPane(&m_wndLocatorBar, true, false, true);
378 ShowPane(&m_wndLineDiffBar, true, false, true);
380 m_wndLocatorBar.EnableGripper(FALSE);
381 m_wndLineDiffBar.EnableGripper(FALSE);
383 return 0;
386 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
388 if( !CFrameWndEx::PreCreateWindow(cs) )
389 return FALSE;
390 return TRUE;
393 void CMainFrame::OnApplicationLook(UINT id)
395 CWaitCursor wait;
397 theApp.m_nAppLook = id;
399 switch (theApp.m_nAppLook)
401 case ID_VIEW_APPLOOK_WIN_2000:
402 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManager));
403 m_wndRibbonBar.SetWindows7Look(FALSE);
404 break;
406 case ID_VIEW_APPLOOK_OFF_XP:
407 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOfficeXP));
408 m_wndRibbonBar.SetWindows7Look(FALSE);
409 break;
411 case ID_VIEW_APPLOOK_WIN_XP:
412 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
413 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
414 m_wndRibbonBar.SetWindows7Look(FALSE);
415 break;
417 case ID_VIEW_APPLOOK_OFF_2003:
418 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2003));
419 CDockingManager::SetDockingMode(DT_SMART);
420 m_wndRibbonBar.SetWindows7Look(FALSE);
421 break;
423 case ID_VIEW_APPLOOK_VS_2005:
424 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2005));
425 CDockingManager::SetDockingMode(DT_SMART);
426 m_wndRibbonBar.SetWindows7Look(FALSE);
427 break;
429 case ID_VIEW_APPLOOK_VS_2008:
430 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2008));
431 CDockingManager::SetDockingMode(DT_SMART);
432 m_wndRibbonBar.SetWindows7Look(FALSE);
433 break;
435 case ID_VIEW_APPLOOK_WIN7:
436 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows7));
437 CDockingManager::SetDockingMode(DT_SMART);
438 m_wndRibbonBar.SetWindows7Look(TRUE);
439 break;
441 default:
442 switch (theApp.m_nAppLook)
444 case ID_VIEW_APPLOOK_OFF_2007_BLUE:
445 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_LunaBlue);
446 break;
448 case ID_VIEW_APPLOOK_OFF_2007_BLACK:
449 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_ObsidianBlack);
450 break;
452 case ID_VIEW_APPLOOK_OFF_2007_SILVER:
453 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Silver);
454 break;
456 case ID_VIEW_APPLOOK_OFF_2007_AQUA:
457 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Aqua);
458 break;
461 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));
462 CDockingManager::SetDockingMode(DT_SMART);
463 m_wndRibbonBar.SetWindows7Look(FALSE);
466 RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_FRAME | RDW_ERASE);
468 theApp.WriteInt(_T("ApplicationLook"), theApp.m_nAppLook);
471 void CMainFrame::OnUpdateApplicationLook(CCmdUI* pCmdUI)
473 pCmdUI->Enable();
474 pCmdUI->SetRadio(theApp.m_nAppLook == pCmdUI->m_nID);
478 // CMainFrame diagnostics
480 #ifdef _DEBUG
481 void CMainFrame::AssertValid() const
483 CFrameWndEx::AssertValid();
486 void CMainFrame::Dump(CDumpContext& dc) const
488 CFrameWndEx::Dump(dc);
491 #endif //_DEBUG
494 // CMainFrame message handlers
497 BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)
499 CRect cr;
500 GetClientRect( &cr);
503 // split into three panes:
504 // -------------
505 // | | |
506 // | | |
507 // |------------
508 // | |
509 // | |
510 // |------------
512 // create a splitter with 2 rows, 1 column
513 if (!m_wndSplitter.CreateStatic(this, 2, 1))
515 TRACE0("Failed to CreateStaticSplitter\n");
516 return FALSE;
519 // add the second splitter pane - which is a nested splitter with 2 columns
520 if (!m_wndSplitter2.CreateStatic(
521 &m_wndSplitter, // our parent window is the first splitter
522 1, 2, // the new splitter is 1 row, 2 columns
523 WS_CHILD | WS_VISIBLE | WS_BORDER, // style, WS_BORDER is needed
524 m_wndSplitter.IdFromRowCol(0, 0)
525 // new splitter is in the first row, 1st column of first splitter
528 TRACE0("Failed to create nested splitter\n");
529 return FALSE;
531 // add the first splitter pane - the default view in row 0
532 if (!m_wndSplitter.CreateView(1, 0,
533 RUNTIME_CLASS(CBottomView), CSize(cr.Width(), cr.Height()), pContext))
535 TRACE0("Failed to create first pane\n");
536 return FALSE;
538 m_pwndBottomView = static_cast<CBottomView*>(m_wndSplitter.GetPane(1, 0));
539 m_pwndBottomView->m_pwndLocator = &m_wndLocatorBar;
540 m_pwndBottomView->m_pwndLineDiffBar = &m_wndLineDiffBar;
541 if (m_bUseRibbons)
542 m_pwndBottomView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
543 else
544 m_pwndBottomView->m_pwndStatusBar = &m_wndStatusBar;
545 m_pwndBottomView->m_pMainFrame = this;
547 // now create the two views inside the nested splitter
549 if (!m_wndSplitter2.CreateView(0, 0,
550 RUNTIME_CLASS(CLeftView), CSize(cr.Width()/2, cr.Height()/2), pContext))
552 TRACE0("Failed to create second pane\n");
553 return FALSE;
555 m_pwndLeftView = static_cast<CLeftView*>(m_wndSplitter2.GetPane(0, 0));
556 m_pwndLeftView->m_pwndLocator = &m_wndLocatorBar;
557 m_pwndLeftView->m_pwndLineDiffBar = &m_wndLineDiffBar;
558 if (m_bUseRibbons)
559 m_pwndLeftView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
560 else
561 m_pwndLeftView->m_pwndStatusBar = &m_wndStatusBar;
562 m_pwndLeftView->m_pMainFrame = this;
564 if (!m_wndSplitter2.CreateView(0, 1,
565 RUNTIME_CLASS(CRightView), CSize(cr.Width()/2, cr.Height()/2), pContext))
567 TRACE0("Failed to create third pane\n");
568 return FALSE;
570 m_pwndRightView = static_cast<CRightView*>(m_wndSplitter2.GetPane(0, 1));
571 m_pwndRightView->m_pwndLocator = &m_wndLocatorBar;
572 m_pwndRightView->m_pwndLineDiffBar = &m_wndLineDiffBar;
573 if (m_bUseRibbons)
574 m_pwndRightView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
575 else
576 m_pwndRightView->m_pwndStatusBar = &m_wndStatusBar;
577 m_pwndRightView->m_pMainFrame = this;
578 m_bInitSplitter = TRUE;
580 m_dlgFilePatches.Create(IDD_FILEPATCHES, this);
581 UpdateLayout();
582 return TRUE;
585 // Callback function
586 BOOL CMainFrame::PatchFile(CString sFilePath, bool /*bContentMods*/, bool bPropMods, CString sVersion, BOOL bAutoPatch)
588 CString sDummy;
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(), NULL, MB_ICONERROR);
595 return FALSE;
597 sFilePath = m_Patch.GetTargetPath() + _T("\\") + 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(_T("%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(_T("%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(_T("%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(_T("%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(_T("%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(_T("%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(_T("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.SetAnimation(IDR_DOWNLOAD);
694 progDlg.SetTime(FALSE);
695 progDlg.SetProgress(1,100);
696 progDlg.ShowModeless(this);
697 if (!CAppUtils::GetVersionedFile(sURL1, sRev1, tempfile1, &progDlg, m_hWnd))
699 progDlg.Stop();
700 CString sErrMsg;
701 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev1, (LPCTSTR)sURL1);
702 MessageBox(sErrMsg, NULL, MB_ICONERROR);
703 return FALSE;
705 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev2);
706 progDlg.SetLine(1, sTemp, true);
707 progDlg.SetLine(2, sURL2, true);
708 progDlg.SetProgress(50, 100);
709 if (!CAppUtils::GetVersionedFile(sURL2, sRev2, tempfile2, &progDlg, m_hWnd))
711 progDlg.Stop();
712 CString sErrMsg;
713 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev2, (LPCTSTR)sURL2);
714 MessageBox(sErrMsg, NULL, MB_ICONERROR);
715 return FALSE;
717 progDlg.SetProgress(100,100);
718 progDlg.Stop();
719 CString temp;
720 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL1), (LPCTSTR)sRev1);
721 m_Data.m_baseFile.SetFileName(tempfile1);
722 m_Data.m_baseFile.SetDescriptiveName(temp);
723 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL2), (LPCTSTR)sRev2);
724 m_Data.m_yourFile.SetFileName(tempfile2);
725 m_Data.m_yourFile.SetDescriptiveName(temp);
727 LoadViews();
729 return TRUE;
732 void CMainFrame::OnFileOpen()
734 if (CheckForSave(CHFSR_OPEN)==IDCANCEL)
735 return;
736 return OnFileOpen(false);
739 void CMainFrame::OnFileOpen(bool fillyours)
741 COpenDlg dlg;
742 if (fillyours)
743 dlg.m_sBaseFile = m_Data.m_yourFile.GetFilename();
744 if (dlg.DoModal() != IDOK)
746 return;
748 m_dlgFilePatches.ShowWindow(SW_HIDE);
749 m_dlgFilePatches.Init(NULL, NULL, CString(), NULL);
750 TRACE(_T("got the files:\n %s\n %s\n %s\n %s\n %s\n"), (LPCTSTR)dlg.m_sBaseFile, (LPCTSTR)dlg.m_sTheirFile, (LPCTSTR)dlg.m_sYourFile,
751 (LPCTSTR)dlg.m_sUnifiedDiffFile, (LPCTSTR)dlg.m_sPatchDirectory);
752 m_Data.m_baseFile.SetFileName(dlg.m_sBaseFile);
753 m_Data.m_theirFile.SetFileName(dlg.m_sTheirFile);
754 m_Data.m_yourFile.SetFileName(dlg.m_sYourFile);
755 m_Data.m_sDiffFile = dlg.m_sUnifiedDiffFile;
756 m_Data.m_sPatchPath = dlg.m_sPatchDirectory;
757 m_Data.m_mergedFile.SetOutOfUse();
758 CCrashReport::Instance().AddFile2(dlg.m_sBaseFile, NULL, _T("Basefile"), CR_AF_MAKE_FILE_COPY);
759 CCrashReport::Instance().AddFile2(dlg.m_sTheirFile, NULL, _T("Theirfile"), CR_AF_MAKE_FILE_COPY);
760 CCrashReport::Instance().AddFile2(dlg.m_sYourFile, NULL, _T("Yourfile"), CR_AF_MAKE_FILE_COPY);
761 CCrashReport::Instance().AddFile2(dlg.m_sUnifiedDiffFile, NULL, _T("Difffile"), CR_AF_MAKE_FILE_COPY);
763 if (!m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && m_Data.IsYourFileInUse())
765 // a diff between two files means "Yours" against "Base", not "Theirs" against "Yours"
766 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
768 if (m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && !m_Data.IsYourFileInUse())
770 // a diff between two files means "Yours" against "Base", not "Theirs" against "Base"
771 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
773 m_bSaveRequired = false;
775 LoadViews();
778 void CMainFrame::ClearViewNamesAndPaths()
780 m_pwndLeftView->m_sWindowName.Empty();
781 m_pwndLeftView->m_sFullFilePath.Empty();
782 m_pwndLeftView->m_sReflectedName.Empty();
783 m_pwndRightView->m_sWindowName.Empty();
784 m_pwndRightView->m_sFullFilePath.Empty();
785 m_pwndRightView->m_sReflectedName.Empty();
786 m_pwndBottomView->m_sWindowName.Empty();
787 m_pwndBottomView->m_sFullFilePath.Empty();
788 m_pwndBottomView->m_sReflectedName.Empty();
791 bool CMainFrame::LoadViews(int line)
793 LoadIgnoreCommentData();
794 m_Data.SetBlame(m_bBlame);
795 m_Data.SetMovedBlocks(m_bViewMovedBlocks);
796 m_bHasConflicts = false;
797 CBaseView* pwndActiveView = m_pwndLeftView;
798 int nOldLine = m_pwndRightView ? m_pwndRightView->m_nTopLine : -1;
799 int nOldLineNumber =
800 m_pwndRightView && m_pwndRightView->m_pViewData ?
801 m_pwndRightView->m_pViewData->GetLineNumber(m_pwndRightView->m_nTopLine) : -1;
802 POINT ptOldCaretPos = {-1, -1};
803 if (m_pwndRightView && m_pwndRightView->IsTarget())
804 ptOldCaretPos = m_pwndRightView->GetCaretPosition();
805 if (m_pwndBottomView && m_pwndBottomView->IsTarget())
806 ptOldCaretPos = m_pwndBottomView->GetCaretPosition();
807 CString sExt = CPathUtils::GetFileExtFromPath(m_Data.m_baseFile.GetFilename()).MakeLower();
808 sExt.TrimLeft(L".");
809 auto sC = m_IgnoreCommentsMap.find(sExt);
810 if (sC == m_IgnoreCommentsMap.end())
812 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_yourFile.GetFilename()).MakeLower();
813 sC = m_IgnoreCommentsMap.find(sExt);
814 if (sC == m_IgnoreCommentsMap.end())
816 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_theirFile.GetFilename()).MakeLower();
817 sC = m_IgnoreCommentsMap.find(sExt);
820 if (sC != m_IgnoreCommentsMap.end())
821 m_Data.SetCommentTokens(std::get<0>(sC->second), std::get<1>(sC->second), std::get<2>(sC->second));
822 else
823 m_Data.SetCommentTokens(L"", L"", L"");
824 if (!m_Data.Load())
826 m_pwndLeftView->BuildAllScreen2ViewVector();
827 m_pwndLeftView->DocumentUpdated();
828 m_pwndRightView->DocumentUpdated();
829 m_pwndBottomView->DocumentUpdated();
830 m_wndLocatorBar.DocumentUpdated();
831 m_wndLineDiffBar.DocumentUpdated();
832 ::MessageBox(m_hWnd, m_Data.GetError(), _T("TortoiseGitMerge"), MB_ICONERROR);
833 m_Data.m_mergedFile.SetOutOfUse();
834 m_bSaveRequired = false;
835 return false;
837 SetWindowTitle();
838 m_pwndLeftView->BuildAllScreen2ViewVector();
839 m_pwndLeftView->DocumentUpdated();
840 m_pwndRightView->DocumentUpdated();
841 m_pwndBottomView->DocumentUpdated();
842 m_wndLocatorBar.DocumentUpdated();
843 m_wndLineDiffBar.DocumentUpdated();
845 m_pwndLeftView->SetWritable(false);
846 m_pwndLeftView->SetWritableIsChangable(false);
847 m_pwndLeftView->SetTarget(false);
848 m_pwndRightView->SetWritable(false);
849 m_pwndRightView->SetWritableIsChangable(false);
850 m_pwndRightView->SetTarget(false);
851 m_pwndBottomView->SetWritable(false);
852 m_pwndBottomView->SetWritableIsChangable(false);
853 m_pwndBottomView->SetTarget(false);
855 if (!m_Data.IsBaseFileInUse())
857 CSysProgressDlg progDlg;
858 if (m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
860 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
862 else if ((!m_Data.m_sDiffFile.IsEmpty())&&(!m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg)))
864 progDlg.Stop();
865 ClearViewNamesAndPaths();
866 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
867 m_bSaveRequired = false;
868 return false;
870 progDlg.Stop();
871 if (m_Patch.GetNumberOfFiles() > 0)
873 CString betterpatchpath = m_Patch.CheckPatchPath(m_Data.m_sPatchPath);
874 if (betterpatchpath.CompareNoCase(m_Data.m_sPatchPath)!=0)
876 CString msg;
877 msg.Format(IDS_WARNBETTERPATCHPATHFOUND, (LPCTSTR)m_Data.m_sPatchPath, (LPCTSTR)betterpatchpath);
878 CTaskDialog taskdlg(msg,
879 CString(MAKEINTRESOURCE(IDS_WARNBETTERPATCHPATHFOUND_TASK2)),
880 L"TortoiseGitMerge",
882 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
883 CString task3;
884 WCHAR t3[MAX_PATH] = { 0 };
885 CString cp = betterpatchpath.Left(MAX_PATH - 1);
886 PathCompactPathEx(t3, cp, 50, 0);
887 task3.Format(IDS_WARNBETTERPATCHPATHFOUND_TASK3, t3);
888 taskdlg.AddCommandControl(1, task3);
889 CString task4;
890 WCHAR t4[MAX_PATH] = { 0 };
891 cp = m_Data.m_sPatchPath.Left(MAX_PATH - 1);
892 PathCompactPathEx(t4, cp, 50, 0);
893 task4.Format(IDS_WARNBETTERPATCHPATHFOUND_TASK4, t4);
894 taskdlg.AddCommandControl(2, task4);
895 taskdlg.SetDefaultCommandControl(1);
896 taskdlg.SetMainIcon(TD_INFORMATION_ICON);
897 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
898 if (taskdlg.DoModal(m_hWnd) == 1)
900 m_Data.m_sPatchPath = betterpatchpath;
901 m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg);
904 m_dlgFilePatches.Init(&m_Patch, this, m_Data.m_sPatchPath, this);
905 m_dlgFilePatches.ShowWindow(SW_SHOW);
906 ClearViewNamesAndPaths();
907 if (!m_wndSplitter.IsRowHidden(1))
908 m_wndSplitter.HideRow(1);
909 m_pwndLeftView->SetHidden(FALSE);
910 m_pwndRightView->SetHidden(FALSE);
911 m_pwndBottomView->SetHidden(TRUE);
914 if (m_Data.IsBaseFileInUse() && !m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
916 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
918 if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && !m_Data.IsTheirFileInUse())
920 //diff between YOUR and BASE
921 if (m_bOneWay)
923 pwndActiveView = m_pwndLeftView;
924 if (!m_wndSplitter2.IsColumnHidden(1))
925 m_wndSplitter2.HideColumn(1);
927 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseBoth;
928 m_pwndLeftView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
929 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
930 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName() + _T(" - ") + m_Data.m_yourFile.GetWindowName();
931 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename() + _T(" - ") + m_Data.m_yourFile.GetFilename();
932 m_pwndLeftView->m_sReflectedName = m_Data.m_yourFile.GetReflectedName();
933 m_pwndLeftView->m_pWorkingFile = &m_Data.m_yourFile;
934 m_pwndLeftView->SetTarget();
935 m_pwndLeftView->SetWritableIsChangable(true);
937 m_pwndRightView->m_pViewData = NULL;
938 m_pwndRightView->m_pWorkingFile = NULL;
939 m_pwndBottomView->m_pViewData = NULL;
940 m_pwndBottomView->m_pWorkingFile = NULL;
942 if (!m_wndSplitter.IsRowHidden(1))
943 m_wndSplitter.HideRow(1);
944 m_pwndLeftView->SetHidden(FALSE);
945 m_pwndRightView->SetHidden(TRUE);
946 m_pwndBottomView->SetHidden(TRUE);
947 ::SetWindowPos(m_pwndLeftView->m_hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
949 else
951 pwndActiveView = m_pwndRightView;
952 if (m_wndSplitter2.IsColumnHidden(1))
953 m_wndSplitter2.ShowColumn();
955 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseLeft;
956 m_pwndLeftView->SetTextType(m_Data.m_arBaseFile.GetUnicodeType());
957 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arBaseFile.GetLineEndings());
958 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName();
959 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename();
960 m_pwndLeftView->m_sConvertedFilePath = m_Data.m_baseFile.GetConvertedFileName();
961 m_pwndLeftView->m_sReflectedName = m_Data.m_baseFile.GetReflectedName();
962 m_pwndLeftView->m_pWorkingFile = &m_Data.m_baseFile;
963 m_pwndLeftView->SetWritableIsChangable(true);
965 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseRight;
966 m_pwndRightView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
967 m_pwndRightView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
968 m_pwndRightView->m_sWindowName = m_Data.m_yourFile.GetWindowName();
969 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
970 m_pwndRightView->m_sConvertedFilePath = m_Data.m_yourFile.GetConvertedFileName();
971 m_pwndRightView->m_sReflectedName = m_Data.m_yourFile.GetReflectedName();
972 m_pwndRightView->m_pWorkingFile = &m_Data.m_yourFile;
973 m_pwndRightView->SetWritable();
974 m_pwndRightView->SetTarget();
976 m_pwndBottomView->m_pViewData = NULL;
977 m_pwndBottomView->m_pWorkingFile = NULL;
979 if (!m_wndSplitter.IsRowHidden(1))
980 m_wndSplitter.HideRow(1);
981 m_pwndLeftView->SetHidden(FALSE);
982 m_pwndRightView->SetHidden(FALSE);
983 m_pwndBottomView->SetHidden(TRUE);
985 bool hasMods, hasConflicts, hasWhitespaceMods;
986 pwndActiveView->CheckModifications(hasMods, hasConflicts, hasWhitespaceMods);
987 if (!hasMods && !hasConflicts)
989 // files appear identical, show a dialog informing the user that there are or might
990 // be other differences
991 bool hasEncodingDiff = m_Data.m_arBaseFile.GetUnicodeType() != m_Data.m_arYourFile.GetUnicodeType();
992 bool hasEOLDiff = m_Data.m_arBaseFile.GetLineEndings() != m_Data.m_arYourFile.GetLineEndings();
993 if (hasWhitespaceMods || hasEncodingDiff || hasEOLDiff)
995 // text is identical, but the files do not match
996 CString sWarning(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_MAIN));
997 CString sWhitespace(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_WHITESPACE));
998 CString sEncoding(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_ENCODING));
999 CString sEOL(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_EOL));
1000 if (hasWhitespaceMods)
1002 sWarning += L"\r\n";
1003 sWarning += sWhitespace;
1005 if (hasEncodingDiff)
1007 sWarning += L"\r\n";
1008 sWarning += sEncoding;
1009 sWarning += L" (";
1010 sWarning += m_Data.m_arBaseFile.GetEncodingName(m_Data.m_arBaseFile.GetUnicodeType());
1011 sWarning += L", ";
1012 sWarning += m_Data.m_arYourFile.GetEncodingName(m_Data.m_arYourFile.GetUnicodeType());
1013 sWarning += L")";
1015 if (hasEOLDiff)
1017 sWarning += L"\r\n";
1018 sWarning += sEOL;
1020 AfxMessageBox(sWarning, MB_ICONINFORMATION);
1024 else if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
1026 //diff between THEIR, YOUR and BASE
1027 m_pwndBottomView->SetWritable();
1028 m_pwndBottomView->SetTarget();
1029 pwndActiveView = m_pwndBottomView;
1031 m_pwndLeftView->m_pViewData = &m_Data.m_TheirBaseBoth;
1032 m_pwndLeftView->SetTextType(m_Data.m_arTheirFile.GetUnicodeType());
1033 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arTheirFile.GetLineEndings());
1034 m_pwndLeftView->m_sWindowName.LoadString(IDS_VIEWTITLE_THEIRS);
1035 m_pwndLeftView->m_sWindowName += _T(" - ") + m_Data.m_theirFile.GetWindowName();
1036 m_pwndLeftView->m_sFullFilePath = m_Data.m_theirFile.GetFilename();
1037 m_pwndLeftView->m_sConvertedFilePath = m_Data.m_theirFile.GetConvertedFileName();
1038 m_pwndLeftView->m_sReflectedName = m_Data.m_theirFile.GetReflectedName();
1039 m_pwndLeftView->m_pWorkingFile = &m_Data.m_theirFile;
1041 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseBoth;
1042 m_pwndRightView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
1043 m_pwndRightView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
1044 m_pwndRightView->m_sWindowName.LoadString(IDS_VIEWTITLE_MINE);
1045 m_pwndRightView->m_sWindowName += _T(" - ") + m_Data.m_yourFile.GetWindowName();
1046 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
1047 m_pwndRightView->m_sConvertedFilePath = m_Data.m_yourFile.GetConvertedFileName();
1048 m_pwndRightView->m_sReflectedName = m_Data.m_yourFile.GetReflectedName();
1049 m_pwndRightView->m_pWorkingFile = &m_Data.m_yourFile;
1051 m_pwndBottomView->m_pViewData = &m_Data.m_Diff3;
1052 m_pwndBottomView->SetTextType(m_Data.m_arTheirFile.GetUnicodeType());
1053 m_pwndBottomView->SetLineEndingStyle(m_Data.m_arTheirFile.GetLineEndings());
1054 m_pwndBottomView->m_sWindowName.LoadString(IDS_VIEWTITLE_MERGED);
1055 m_pwndBottomView->m_sWindowName += _T(" - ") + m_Data.m_mergedFile.GetWindowName();
1056 m_pwndBottomView->m_sFullFilePath = m_Data.m_mergedFile.GetFilename();
1057 m_pwndBottomView->m_sConvertedFilePath = m_Data.m_mergedFile.GetConvertedFileName();
1058 m_pwndBottomView->m_sReflectedName = m_Data.m_mergedFile.GetReflectedName();
1059 m_pwndBottomView->m_pWorkingFile = &m_Data.m_mergedFile;
1061 if (m_wndSplitter2.IsColumnHidden(1))
1062 m_wndSplitter2.ShowColumn();
1063 if (m_wndSplitter.IsRowHidden(1))
1064 m_wndSplitter.ShowRow();
1065 m_pwndLeftView->SetHidden(FALSE);
1066 m_pwndRightView->SetHidden(FALSE);
1067 m_pwndBottomView->SetHidden(FALSE);
1068 // in three pane view, hide the line diff bar
1069 m_wndLineDiffBar.ShowPane(false, false, true);
1070 m_wndLineDiffBar.DocumentUpdated();
1072 if (!m_Data.m_mergedFile.InUse())
1074 m_Data.m_mergedFile.SetFileName(m_Data.m_yourFile.GetFilename());
1076 m_pwndLeftView->BuildAllScreen2ViewVector();
1077 m_pwndLeftView->DocumentUpdated();
1078 m_pwndRightView->DocumentUpdated();
1079 m_pwndBottomView->DocumentUpdated();
1080 m_wndLocatorBar.DocumentUpdated();
1081 m_wndLineDiffBar.DocumentUpdated();
1082 UpdateLayout();
1083 SetActiveView(pwndActiveView);
1085 if ((line >= -1) && m_pwndRightView->m_pViewData)
1087 int n = line == -1 ? min( nOldLineNumber, nOldLine ) : line;
1088 if (n >= 0)
1089 n = m_pwndRightView->m_pViewData->FindLineNumber(n);
1090 if (n < 0)
1091 n = nOldLine;
1093 m_pwndRightView->ScrollAllToLine(n);
1094 POINT p;
1095 p.x = 0;
1096 p.y = n;
1097 if ((ptOldCaretPos.x >= 0) || (ptOldCaretPos.y >= 0))
1098 p = ptOldCaretPos;
1099 m_pwndLeftView->SetCaretPosition(p);
1100 m_pwndRightView->SetCaretPosition(p);
1101 m_pwndBottomView->SetCaretPosition(p);
1102 m_pwndBottomView->ScrollToChar(0);
1103 m_pwndLeftView->ScrollToChar(0);
1104 m_pwndRightView->ScrollToChar(0);
1106 else
1108 CRegDWORD regFirstDiff = CRegDWORD(_T("Software\\TortoiseGitMerge\\FirstDiffOnLoad"), TRUE);
1109 CRegDWORD regFirstConflict = CRegDWORD(_T("Software\\TortoiseGitMerge\\FirstConflictOnLoad"), TRUE);
1110 bool bGoFirstDiff = (0 != (DWORD)regFirstDiff);
1111 bool bGoFirstConflict = (0 != (DWORD)regFirstConflict);
1112 if (bGoFirstConflict && (CheckResolved()>=0))
1114 pwndActiveView->GoToFirstConflict();
1115 // Ignore the first few Mouse Move messages, so that the line diff stays on
1116 // the first diff line until the user actually moves the mouse
1117 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1119 else if (bGoFirstDiff)
1121 pwndActiveView->GoToFirstDifference();
1122 // Ignore the first few Mouse Move messages, so that the line diff stays on
1123 // the first diff line until the user actually moves the mouse
1124 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1126 else
1128 // Avoid incorrect rendering of active pane.
1129 m_pwndBottomView->ScrollToChar(0);
1130 m_pwndLeftView->ScrollToChar(0);
1131 m_pwndRightView->ScrollToChar(0);
1134 CheckResolved();
1135 if (m_bHasConflicts && !m_bSaveRequiredOnConflicts)
1136 m_bSaveRequired = false;
1137 CUndo::GetInstance().Clear();
1138 return true;
1141 void CMainFrame::UpdateLayout()
1143 if (m_bInitSplitter)
1145 m_wndSplitter.CenterSplitter();
1146 m_wndSplitter2.CenterSplitter();
1150 void CMainFrame::OnSize(UINT nType, int cx, int cy)
1152 CFrameWndEx::OnSize(nType, cx, cy);
1153 if (m_bInitSplitter && nType != SIZE_MINIMIZED)
1155 if (m_wndSplitter.GetSafeHwnd())
1157 if (m_wndSplitter.HasOldRowSize() && (m_wndSplitter.GetOldRowCount() == 2))
1159 int oldTotal = m_wndSplitter.GetOldRowSize(0) + m_wndSplitter.GetOldRowSize(1);
1160 if (oldTotal)
1162 int cxCur0, cxCur1, cxMin0, cxMin1;
1163 m_wndSplitter.GetRowInfo(0, cxCur0, cxMin0);
1164 m_wndSplitter.GetRowInfo(1, cxCur1, cxMin1);
1165 cxCur0 = m_wndSplitter.GetOldRowSize(0) * (cxCur0 + cxCur1) / oldTotal;
1166 cxCur1 = m_wndSplitter.GetOldRowSize(1) * (cxCur0 + cxCur1) / oldTotal;
1167 m_wndSplitter.SetRowInfo(0, cxCur0, 0);
1168 m_wndSplitter.SetRowInfo(1, cxCur1, 0);
1169 m_wndSplitter.RecalcLayout();
1173 if (m_wndSplitter2.HasOldColSize() && (m_wndSplitter2.GetOldColCount() == 2))
1175 int oldTotal = m_wndSplitter2.GetOldColSize(0) + m_wndSplitter2.GetOldColSize(1);
1176 if (oldTotal)
1178 int cyCur0, cyCur1, cyMin0, cyMin1;
1179 m_wndSplitter2.GetColumnInfo(0, cyCur0, cyMin0);
1180 m_wndSplitter2.GetColumnInfo(1, cyCur1, cyMin1);
1181 cyCur0 = m_wndSplitter2.GetOldColSize(0) * (cyCur0 + cyCur1) / oldTotal;
1182 cyCur1 = m_wndSplitter2.GetOldColSize(1) * (cyCur0 + cyCur1) / oldTotal;
1183 m_wndSplitter2.SetColumnInfo(0, cyCur0, 0);
1184 m_wndSplitter2.SetColumnInfo(1, cyCur1, 0);
1185 m_wndSplitter2.RecalcLayout();
1190 if ((nType == SIZE_RESTORED)&&m_bCheckReload)
1192 m_bCheckReload = false;
1193 CheckForReload();
1197 void CMainFrame::OnViewWhitespaces()
1199 CRegDWORD regViewWhitespaces = CRegDWORD(_T("Software\\TortoiseGitMerge\\ViewWhitespaces"), 1);
1200 BOOL bViewWhitespaces = regViewWhitespaces;
1201 if (m_pwndLeftView)
1202 bViewWhitespaces = m_pwndLeftView->m_bViewWhitespace;
1204 bViewWhitespaces = !bViewWhitespaces;
1205 regViewWhitespaces = bViewWhitespaces;
1206 if (m_pwndLeftView)
1208 m_pwndLeftView->m_bViewWhitespace = bViewWhitespaces;
1209 m_pwndLeftView->Invalidate();
1211 if (m_pwndRightView)
1213 m_pwndRightView->m_bViewWhitespace = bViewWhitespaces;
1214 m_pwndRightView->Invalidate();
1216 if (m_pwndBottomView)
1218 m_pwndBottomView->m_bViewWhitespace = bViewWhitespaces;
1219 m_pwndBottomView->Invalidate();
1223 void CMainFrame::OnUpdateViewWhitespaces(CCmdUI *pCmdUI)
1225 if (m_pwndLeftView)
1226 pCmdUI->SetCheck(m_pwndLeftView->m_bViewWhitespace);
1229 void CMainFrame::OnViewCollapsed()
1231 m_regCollapsed = !(DWORD)m_regCollapsed;
1232 m_bCollapsed = !!(DWORD)m_regCollapsed;
1234 OnViewTextFoldUnfold();
1235 m_wndLocatorBar.Invalidate();
1238 void CMainFrame::OnUpdateViewCollapsed(CCmdUI *pCmdUI)
1240 pCmdUI->SetCheck(m_bCollapsed);
1243 void CMainFrame::OnViewWraplonglines()
1245 m_bWrapLines = !(DWORD)m_regWrapLines;
1246 m_regWrapLines = m_bWrapLines;
1248 if (m_pwndLeftView) m_pwndLeftView ->WrapChanged();
1249 if (m_pwndRightView) m_pwndRightView ->WrapChanged();
1250 if (m_pwndBottomView) m_pwndBottomView->WrapChanged();
1251 OnViewTextFoldUnfold();
1252 m_wndLocatorBar.DocumentUpdated();
1255 void CMainFrame::OnViewTextFoldUnfold()
1257 OnViewTextFoldUnfold(m_pwndLeftView);
1258 OnViewTextFoldUnfold(m_pwndRightView);
1259 OnViewTextFoldUnfold(m_pwndBottomView);
1262 void CMainFrame::OnViewTextFoldUnfold(CBaseView* view)
1264 if (view == 0)
1265 return;
1266 view->BuildAllScreen2ViewVector();
1267 view->UpdateCaret();
1268 view->Invalidate();
1269 view->EnsureCaretVisible();
1272 void CMainFrame::OnUpdateViewWraplonglines(CCmdUI *pCmdUI)
1274 pCmdUI->SetCheck(m_bWrapLines);
1277 void CMainFrame::OnViewOnewaydiff()
1279 if (CheckForSave(CHFSR_RELOAD)==IDCANCEL)
1280 return;
1281 m_bOneWay = !m_bOneWay;
1282 ShowDiffBar(!m_bOneWay);
1283 LoadViews(-1);
1286 void CMainFrame::ShowDiffBar(bool bShow)
1288 if (bShow)
1290 // restore the line diff bar
1291 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
1292 m_wndLineDiffBar.DocumentUpdated();
1293 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
1294 m_wndLocatorBar.DocumentUpdated();
1296 else
1298 // in one way view, hide the line diff bar
1299 m_wndLineDiffBar.ShowPane(false, false, true);
1300 m_wndLineDiffBar.DocumentUpdated();
1304 int CMainFrame::CheckResolved()
1306 //only in three way diffs can be conflicts!
1307 m_bHasConflicts = true;
1308 if (IsViewGood(m_pwndBottomView))
1310 CViewData* viewdata = m_pwndBottomView->m_pViewData;
1311 if (viewdata)
1313 for (int i=0; i<viewdata->GetCount(); i++)
1315 const DiffStates state = viewdata->GetState(i);
1316 if ((DIFFSTATE_CONFLICTED == state)||(DIFFSTATE_CONFLICTED_IGNORED == state))
1317 return i;
1321 m_bHasConflicts = false;
1322 return -1;
1325 int CMainFrame::SaveFile(const CString& sFilePath)
1327 CBaseView * pView = NULL;
1328 CViewData * pViewData = NULL;
1329 CFileTextLines * pOriginFile = &m_Data.m_arBaseFile;
1330 if (IsViewGood(m_pwndBottomView))
1332 pView = m_pwndBottomView;
1333 pViewData = m_pwndBottomView->m_pViewData;
1335 else if (IsViewGood(m_pwndRightView))
1337 pView = m_pwndRightView;
1338 pViewData = m_pwndRightView->m_pViewData;
1339 if (m_Data.IsYourFileInUse())
1340 pOriginFile = &m_Data.m_arYourFile;
1341 else if (m_Data.IsTheirFileInUse())
1342 pOriginFile = &m_Data.m_arTheirFile;
1344 else
1346 // nothing to save!
1347 return 1;
1349 Invalidate();
1350 if ((pViewData)&&(pOriginFile))
1352 CFileTextLines file;
1353 pOriginFile->CopySettings(&file);
1354 CFileTextLines::SaveParams saveParams;
1355 saveParams.m_LineEndings = pView->GetLineEndings();
1356 saveParams.m_UnicodeType = pView->GetTextType();
1357 file.SetSaveParams(saveParams);
1358 for (int i=0; i<pViewData->GetCount(); i++)
1360 //only copy non-removed lines
1361 DiffStates state = pViewData->GetState(i);
1362 switch (state)
1364 case DIFFSTATE_CONFLICTED:
1365 case DIFFSTATE_CONFLICTED_IGNORED:
1367 int first = i;
1368 int last = i;
1371 last++;
1372 } while((last<pViewData->GetCount()) && ((pViewData->GetState(last)==DIFFSTATE_CONFLICTED)||(pViewData->GetState(last)==DIFFSTATE_CONFLICTED_IGNORED)));
1373 // TortoiseGitMerge changes here
1374 file.Add(_T("<<<<<<< .mine"), m_pwndRightView->GetLineEndings());
1375 for (int j=first; j<last; j++)
1377 EOL lineending = m_pwndRightView->m_pViewData->GetLineEnding(j);
1378 if (lineending == EOL_NOENDING)
1379 lineending = m_pwndRightView->GetLineEndings();
1380 file.Add(m_pwndRightView->m_pViewData->GetLine(j), lineending);
1382 file.Add(_T("======="), m_pwndRightView->GetLineEndings());
1383 for (int j=first; j<last; j++)
1385 EOL lineending = m_pwndLeftView->m_pViewData->GetLineEnding(j);
1386 if (lineending == EOL_NOENDING)
1387 lineending = m_pwndLeftView->GetLineEndings();
1388 file.Add(m_pwndLeftView->m_pViewData->GetLine(j), lineending);
1390 file.Add(_T(">>>>>>> .theirs"), m_pwndRightView->GetLineEndings());
1391 i = last-1;
1393 break;
1394 case DIFFSTATE_EMPTY:
1395 case DIFFSTATE_CONFLICTEMPTY:
1396 case DIFFSTATE_IDENTICALREMOVED:
1397 case DIFFSTATE_REMOVED:
1398 case DIFFSTATE_THEIRSREMOVED:
1399 case DIFFSTATE_YOURSREMOVED:
1400 case DIFFSTATE_CONFLICTRESOLVEDEMPTY:
1401 // do not save removed lines
1402 break;
1403 default:
1404 file.Add(pViewData->GetLine(i), pViewData->GetLineEnding(i));
1405 break;
1408 if (!file.Save(sFilePath, false, false))
1410 CMessageBox::Show(m_hWnd, file.GetErrorString(), _T("TortoiseGitMerge"), MB_ICONERROR);
1411 return -1;
1413 if (sFilePath == m_Data.m_baseFile.GetFilename())
1415 m_Data.m_baseFile.StoreFileAttributes();
1417 if (sFilePath == m_Data.m_theirFile.GetFilename())
1419 m_Data.m_theirFile.StoreFileAttributes();
1421 if (sFilePath == m_Data.m_yourFile.GetFilename())
1423 m_Data.m_yourFile.StoreFileAttributes();
1425 /*if (sFilePath == m_Data.m_mergedFile.GetFilename())
1427 m_Data.m_mergedFile.StoreFileAttributes();
1428 }//*/
1429 m_dlgFilePatches.SetFileStatusAsPatched(sFilePath);
1430 if (IsViewGood(m_pwndBottomView))
1431 m_pwndBottomView->SetModified(FALSE);
1432 else if (IsViewGood(m_pwndRightView))
1433 m_pwndRightView->SetModified(FALSE);
1434 CUndo::GetInstance().MarkAsOriginalState(
1435 false,
1436 IsViewGood(m_pwndRightView) && (pViewData == m_pwndRightView->m_pViewData),
1437 IsViewGood(m_pwndBottomView) && (pViewData == m_pwndBottomView->m_pViewData));
1438 if (file.GetCount() == 1 && file.GetAt(0).IsEmpty() && file.GetLineEnding(0) == EOL_NOENDING)
1439 return 0;
1440 return file.GetCount();
1442 return 1;
1445 void CMainFrame::OnFileSave()
1447 // when multiple files are set as writable we have to ask what file to save
1448 int nEditableViewCount =
1449 (CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsWritable() ? 1 : 0)
1450 + (CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsWritable() ? 1 : 0)
1451 + (CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsWritable() ? 1 : 0);
1452 bool bLeftIsModified = CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsModified();
1453 bool bRightIsModified = CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsModified();
1454 bool bBottomIsModified = CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsModified();
1455 int nModifiedViewCount =
1456 (bLeftIsModified ? 1 : 0)
1457 + (bRightIsModified ? 1 : 0)
1458 + (bBottomIsModified ? 1 : 0);
1459 if (nEditableViewCount>1)
1461 if (nModifiedViewCount == 1)
1463 if (bLeftIsModified)
1464 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1465 else
1466 FileSave();
1468 else if (nModifiedViewCount>0)
1470 // both views
1471 CTaskDialog taskdlg(CString(MAKEINTRESOURCE(IDS_SAVE_MORE)),
1472 CString(MAKEINTRESOURCE(IDS_SAVE)),
1473 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1475 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
1476 CString sTaskTemp;
1477 if (m_pwndLeftView->m_pWorkingFile->InUse() && !m_pwndLeftView->m_pWorkingFile->IsReadonly())
1478 sTaskTemp.Format(IDS_ASKFORSAVE_SAVELEFT, (LPCTSTR)m_pwndLeftView->m_pWorkingFile->GetFilename());
1479 else
1480 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS));
1481 taskdlg.AddCommandControl(201, sTaskTemp, bLeftIsModified);// left
1482 if (bLeftIsModified)
1483 taskdlg.SetDefaultCommandControl(201);
1484 if (m_pwndRightView->m_pWorkingFile->InUse() && !m_pwndRightView->m_pWorkingFile->IsReadonly())
1485 sTaskTemp.Format(IDS_ASKFORSAVE_SAVERIGHT, (LPCTSTR)m_pwndRightView->m_pWorkingFile->GetFilename());
1486 else
1487 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS));
1488 taskdlg.AddCommandControl(202, sTaskTemp, bRightIsModified); // right
1489 if (bRightIsModified)
1490 taskdlg.SetDefaultCommandControl(202);
1491 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEALL2)), nModifiedViewCount>1); // both
1492 if (nModifiedViewCount > 1)
1493 taskdlg.SetDefaultCommandControl(203);
1494 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1495 taskdlg.SetMainIcon(TD_WARNING_ICON);
1496 UINT ret = (UINT)taskdlg.DoModal(m_hWnd);
1497 switch (ret)
1499 case 201: // left
1500 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1501 break;
1502 case 203: // both
1503 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1504 case 202: // right
1505 m_pwndRightView->SaveFile();
1506 break;
1510 else
1512 // only target view was modified
1513 FileSave();
1517 void CMainFrame::PatchSave()
1519 bool bDoesNotExist = !PathFileExists(m_Data.m_mergedFile.GetFilename());
1520 if (m_Data.m_bPatchRequired)
1522 m_Patch.PatchPath(m_Data.m_mergedFile.GetFilename());
1524 if (!PathIsDirectory(m_Data.m_mergedFile.GetFilename()))
1526 int saveret = SaveFile(m_Data.m_mergedFile.GetFilename());
1527 if (saveret==0)
1529 // file was saved with 0 lines, remove it.
1530 m_Patch.RemoveFile(m_Data.m_mergedFile.GetFilename());
1531 // just in case
1532 DeleteFile(m_Data.m_mergedFile.GetFilename());
1534 m_Data.m_mergedFile.StoreFileAttributes();
1535 if (m_Data.m_mergedFile.GetFilename() == m_Data.m_yourFile.GetFilename())
1536 m_Data.m_yourFile.StoreFileAttributes();
1537 if ((bDoesNotExist)&&(DWORD(CRegDWORD(_T("Software\\TortoiseGitMerge\\AutoAdd"), TRUE))))
1539 // call TortoiseProc to add the new file to version control
1540 CString cmd = _T("/command:add /noui /path:\"");
1541 cmd += m_Data.m_mergedFile.GetFilename() + _T("\"");
1542 CAppUtils::RunTortoiseGitProc(cmd);
1547 bool CMainFrame::FileSave(bool bCheckResolved /*=true*/)
1549 if (HasMarkedBlocks())
1551 CString sTitle(MAKEINTRESOURCE(IDS_WARNMARKEDBLOCKS));
1552 CString sSubTitle(MAKEINTRESOURCE(IDS_ASKFORSAVE_MARKEDBLOCKS));
1553 CString sAppName(MAKEINTRESOURCE(IDS_APPNAME));
1554 CTaskDialog taskdlg(sTitle,
1555 sSubTitle,
1556 sAppName,
1558 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
1559 taskdlg.AddCommandControl(10, CString(MAKEINTRESOURCE(IDS_MARKEDBLOCKSSAVEINCLUDE)));
1560 taskdlg.AddCommandControl(11, CString(MAKEINTRESOURCE(IDS_MARKEDBLOCKSSAVEEXCLUDE)));
1561 taskdlg.AddCommandControl(12, CString(MAKEINTRESOURCE(IDS_MARKEDBLCOKSSAVEIGNORE)));
1562 taskdlg.AddCommandControl(IDCANCEL, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_CANCEL_OPEN)));
1563 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1564 taskdlg.SetDefaultCommandControl(10);
1565 taskdlg.SetMainIcon(TD_WARNING_ICON);
1566 UINT ret = (UINT)taskdlg.DoModal(m_hWnd);
1567 if (ret == 10)
1568 m_pwndRightView->LeaveOnlyMarkedBlocks();
1569 else if (ret == 11)
1570 m_pwndRightView->UseViewFileOfMarked();
1571 else if (ret == 12)
1572 m_pwndRightView->UseViewFileExceptEdited();
1573 else
1574 return false;
1577 if (!m_Data.m_mergedFile.InUse())
1578 return FileSaveAs(bCheckResolved);
1579 // check if the file has the readonly attribute set
1580 bool bDoesNotExist = false;
1581 DWORD fAttribs = GetFileAttributes(m_Data.m_mergedFile.GetFilename());
1582 if ((fAttribs != INVALID_FILE_ATTRIBUTES)&&(fAttribs & FILE_ATTRIBUTE_READONLY))
1583 return FileSaveAs(bCheckResolved);
1584 if (fAttribs == INVALID_FILE_ATTRIBUTES)
1586 bDoesNotExist = (GetLastError() == ERROR_FILE_NOT_FOUND);
1588 if (bCheckResolved && HasConflictsWontKeep())
1589 return false;
1591 if (((DWORD)CRegDWORD(_T("Software\\TortoiseGitMerge\\Backup"))) != 0)
1593 MoveFileEx(m_Data.m_mergedFile.GetFilename(), m_Data.m_mergedFile.GetFilename() + _T(".bak"), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
1595 if (m_Data.m_bPatchRequired)
1597 m_Patch.PatchPath(m_Data.m_mergedFile.GetFilename());
1599 int saveret = SaveFile(m_Data.m_mergedFile.GetFilename());
1600 if (saveret==0)
1602 // file was saved with 0 lines!
1603 // ask the user if the file should be deleted
1604 CString msg;
1605 msg.Format(IDS_DELETEWHENEMPTY, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1606 CTaskDialog taskdlg(msg,
1607 CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK2)),
1608 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1610 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
1611 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK3)));
1612 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK4)));
1613 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1614 taskdlg.SetDefaultCommandControl(1);
1615 taskdlg.SetMainIcon(TD_WARNING_ICON);
1616 if (taskdlg.DoModal(m_hWnd) == 1)
1618 m_Patch.RemoveFile(m_Data.m_mergedFile.GetFilename());
1619 DeleteFile(m_Data.m_mergedFile.GetFilename());
1622 else if (saveret < 0)
1624 // error while saving the file
1625 return false;
1628 // if we're in conflict resolve mode (three pane view), check if there are no more conflicts
1629 // and if there aren't, ask to mark the file as resolved
1630 if (IsViewGood(m_pwndBottomView) && !m_bHasConflicts && bCheckResolved)
1632 CString projectRoot;
1633 if (GitAdminDir::HasAdminDir(m_Data.m_mergedFile.GetFilename(), false, &projectRoot))
1635 CString subpath = m_Data.m_mergedFile.GetFilename();
1636 subpath.Replace(_T('\\'), _T('/'));
1637 if (subpath.GetLength() >= projectRoot.GetLength())
1639 if (subpath[projectRoot.GetLength()] == _T('/'))
1640 subpath = subpath.Right(subpath.GetLength() - projectRoot.GetLength() - 1);
1641 else
1642 subpath = subpath.Right(subpath.GetLength() - projectRoot.GetLength());
1645 CAutoRepository repository(projectRoot);
1646 bool hasConflictInIndex = false;
1649 if (!repository)
1650 break;
1652 CAutoIndex index;
1653 if (git_repository_index(index.GetPointer(), repository))
1654 break;
1656 CStringA path = CUnicodeUtils::GetMulti(subpath, CP_UTF8);
1657 const git_index_entry * entry = git_index_get_bypath(index, path, 1);
1658 hasConflictInIndex = entry != nullptr;
1659 } while(0);
1661 if (hasConflictInIndex)
1663 CString msg;
1664 msg.Format(IDS_MARKASRESOLVED, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1665 CTaskDialog taskdlg(msg,
1666 CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK2)),
1667 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1669 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
1670 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK3)));
1671 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK4)));
1672 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1673 taskdlg.SetDefaultCommandControl(1);
1674 taskdlg.SetMainIcon(TD_WARNING_ICON);
1675 if (taskdlg.DoModal(m_hWnd) == 1)
1676 MarkAsResolved();
1681 m_bSaveRequired = false;
1682 m_Data.m_mergedFile.StoreFileAttributes();
1684 if ((bDoesNotExist)&&(DWORD(CRegDWORD(_T("Software\\TortoiseGitMerge\\AutoAdd"), TRUE))))
1686 // call TortoiseProc to add the new file to version control
1687 CString cmd = _T("/command:add /noui /path:\"");
1688 cmd += m_Data.m_mergedFile.GetFilename() + _T("\"");
1689 if(!CAppUtils::RunTortoiseGitProc(cmd))
1690 return false;
1692 return true;
1695 void CMainFrame::OnFileSaveAs()
1697 // ask what file to save as
1698 bool bHaveConflict = (CheckResolved() >= 0);
1699 CTaskDialog taskdlg(
1700 CString(MAKEINTRESOURCE(bHaveConflict ? IDS_ASKFORSAVEAS_MORECONFLICT : IDS_ASKFORSAVEAS_MORE)),
1701 CString(MAKEINTRESOURCE(IDS_ASKFORSAVEAS)),
1702 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1704 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
1705 // default can be last view (target) as was in 1.7 or actual (where is cursor) as is in most text editor
1706 if (IsViewGood(m_pwndLeftView))
1708 taskdlg.AddCommandControl(201, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS))); // left
1709 taskdlg.SetDefaultCommandControl(201);
1711 if (IsViewGood(m_pwndRightView))
1713 taskdlg.AddCommandControl(202, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS))); // right
1714 taskdlg.SetDefaultCommandControl(202);
1716 if (IsViewGood(m_pwndBottomView))
1718 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEBOTTOMAS))); // bottom
1719 taskdlg.SetDefaultCommandControl(203);
1721 if (bHaveConflict)
1723 taskdlg.AddCommandControl(204, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_NEEDRESOLVE))); // resolve
1724 taskdlg.SetDefaultCommandControl(204);
1726 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1727 taskdlg.SetMainIcon(bHaveConflict ? TD_WARNING_ICON : TD_INFORMATION_ICON);
1728 int nCommand = (int)taskdlg.DoModal(m_hWnd);
1729 CString sFileName;
1730 switch (nCommand)
1732 case 201: // left
1733 if (TryGetFileName(sFileName))
1735 // in 2, 3 view display we want to keep removed lines
1736 m_pwndLeftView->SaveFileTo(sFileName, IsViewGood(m_pwndRightView) ? SAVE_REMOVEDLINES : 0);
1738 break;
1739 case 202: // right
1740 if (TryGetFileName(sFileName))
1742 m_pwndRightView->SaveFileTo(sFileName);
1744 break;
1745 case 203: // bottom
1746 FileSaveAs();
1747 break;
1748 case 204: // continue resolving
1749 if (IsViewGood(m_pwndBottomView))
1751 m_pwndBottomView->GoToLine(CheckResolved());
1753 break;
1757 bool CMainFrame::FileSaveAs(bool bCheckResolved /*=true*/)
1759 if (bCheckResolved && HasConflictsWontKeep())
1760 return false;
1762 CString fileName;
1763 if(!TryGetFileName(fileName))
1764 return false;
1766 SaveFile(fileName);
1767 return true;
1770 void CMainFrame::OnUpdateFileSave(CCmdUI *pCmdUI)
1772 BOOL bEnable = FALSE;
1773 if (m_Data.m_mergedFile.InUse())
1775 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1776 bEnable = TRUE;
1777 else if ( (IsViewGood(m_pwndRightView)&&(m_pwndRightView->m_pViewData)) &&
1778 (m_pwndRightView->IsModified() || (m_Data.m_yourFile.GetWindowName().Right(9).Compare(_T(": patched"))==0)) )
1779 bEnable = TRUE;
1780 else if (IsViewGood(m_pwndLeftView)
1781 && (m_pwndLeftView->m_pViewData)
1782 && (m_pwndLeftView->IsModified()))
1783 bEnable = TRUE;
1785 pCmdUI->Enable(bEnable);
1788 void CMainFrame::OnUpdateFileSaveAs(CCmdUI *pCmdUI)
1790 // any file is open we can save it as
1791 BOOL bEnable = FALSE;
1792 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1793 bEnable = TRUE;
1794 else if (IsViewGood(m_pwndRightView)&&(m_pwndRightView->m_pViewData))
1795 bEnable = TRUE;
1796 else if (IsViewGood(m_pwndLeftView)&&(m_pwndLeftView->m_pViewData))
1797 bEnable = TRUE;
1798 pCmdUI->Enable(bEnable);
1801 void CMainFrame::OnUpdateViewOnewaydiff(CCmdUI *pCmdUI)
1803 pCmdUI->SetCheck(!m_bOneWay);
1804 BOOL bEnable = TRUE;
1805 if (IsViewGood(m_pwndBottomView))
1807 bEnable = FALSE;
1809 pCmdUI->Enable(bEnable);
1812 void CMainFrame::OnViewOptions()
1814 CString sTemp;
1815 sTemp.LoadString(IDS_SETTINGSTITLE);
1816 CSettings dlg(sTemp);
1817 dlg.DoModal();
1818 if (dlg.IsReloadNeeded())
1820 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
1821 return;
1822 CDiffColors::GetInstance().LoadRegistry();
1823 LoadViews();
1824 return;
1826 CDiffColors::GetInstance().LoadRegistry();
1827 if (m_pwndBottomView)
1828 m_pwndBottomView->Invalidate();
1829 if (m_pwndLeftView)
1830 m_pwndLeftView->Invalidate();
1831 if (m_pwndRightView)
1832 m_pwndRightView->Invalidate();
1835 void CMainFrame::OnClose()
1837 if (!IsWindowEnabled())
1838 return; // just in case someone sends a WM_CLOSE to the main window while another window (dialog,...) is open
1839 if (CheckForSave(CHFSR_CLOSE)!=IDCANCEL)
1841 WINDOWPLACEMENT wp;
1843 // before it is destroyed, save the position of the window
1844 wp.length = sizeof wp;
1846 if (GetWindowPlacement(&wp))
1849 if (IsIconic())
1850 // never restore to Iconic state
1851 wp.showCmd = SW_SHOW ;
1853 if ((wp.flags & WPF_RESTORETOMAXIMIZED) != 0)
1854 // if maximized and maybe iconic restore maximized state
1855 wp.showCmd = SW_SHOWMAXIMIZED ;
1857 // and write it
1858 WriteWindowPlacement(&wp);
1860 __super::OnClose();
1864 void CMainFrame::OnActivate(UINT nValue, CWnd* /*pwnd*/, BOOL /*bActivated?*/)
1866 if (nValue != 0) // activated
1868 if (IsIconic())
1870 m_bCheckReload = TRUE;
1872 else
1874 // use a timer to give other messages time to get processed
1875 // first, like e.g. the WM_CLOSE message in case the user
1876 // clicked the close button and that brought the window
1877 // to the front - in that case checking for reload wouldn't
1878 // do any good.
1879 SetTimer(IDT_RELOADCHECKTIMER, 300, NULL);
1884 void CMainFrame::OnViewLinedown()
1886 OnViewLineUpDown(1);
1889 void CMainFrame::OnViewLineup()
1891 OnViewLineUpDown(-1);
1894 void CMainFrame::OnViewLineUpDown(int direction)
1896 if (m_pwndLeftView)
1897 m_pwndLeftView->ScrollToLine(m_pwndLeftView->m_nTopLine+direction);
1898 if (m_pwndRightView)
1899 m_pwndRightView->ScrollToLine(m_pwndRightView->m_nTopLine+direction);
1900 if (m_pwndBottomView)
1901 m_pwndBottomView->ScrollToLine(m_pwndBottomView->m_nTopLine+direction);
1902 m_wndLocatorBar.Invalidate();
1903 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1906 void CMainFrame::OnViewLineleft()
1908 OnViewLineLeftRight(-1);
1911 void CMainFrame::OnViewLineright()
1913 OnViewLineLeftRight(1);
1916 void CMainFrame::OnViewLineLeftRight(int direction)
1918 if (m_pwndLeftView)
1919 m_pwndLeftView->ScrollSide(direction);
1920 if (m_pwndRightView)
1921 m_pwndRightView->ScrollSide(direction);
1922 if (m_pwndBottomView)
1923 m_pwndBottomView->ScrollSide(direction);
1926 void CMainFrame::OnEditUseTheirs()
1928 if (m_pwndBottomView)
1929 m_pwndBottomView->UseTheirTextBlock();
1931 void CMainFrame::OnUpdateEditUsetheirblock(CCmdUI *pCmdUI)
1933 pCmdUI->Enable(m_pwndBottomView && m_pwndBottomView->HasSelection());
1936 void CMainFrame::OnEditUseMine()
1938 if (m_pwndBottomView)
1939 m_pwndBottomView->UseMyTextBlock();
1941 void CMainFrame::OnUpdateEditUsemyblock(CCmdUI *pCmdUI)
1943 OnUpdateEditUsetheirblock(pCmdUI);
1946 void CMainFrame::OnEditUseTheirsThenMine()
1948 if (m_pwndBottomView)
1949 m_pwndBottomView->UseTheirAndYourBlock();
1952 void CMainFrame::OnUpdateEditUsetheirthenmyblock(CCmdUI *pCmdUI)
1954 OnUpdateEditUsetheirblock(pCmdUI);
1957 void CMainFrame::OnEditUseMineThenTheirs()
1959 if (m_pwndBottomView)
1960 m_pwndBottomView->UseYourAndTheirBlock();
1963 void CMainFrame::OnUpdateEditUseminethentheirblock(CCmdUI *pCmdUI)
1965 OnUpdateEditUsetheirblock(pCmdUI);
1968 void CMainFrame::OnEditUseleftblock()
1970 if (m_pwndBottomView->IsWindowVisible())
1971 m_pwndBottomView->UseRightBlock();
1972 else
1973 m_pwndRightView->UseLeftBlock();
1976 void CMainFrame::OnUpdateEditUseleftblock(CCmdUI *pCmdUI)
1978 pCmdUI->Enable(IsViewGood(m_pwndRightView) && m_pwndRightView->IsTarget() && m_pwndRightView->HasSelection());
1981 void CMainFrame::OnUpdateUseBlock(CCmdUI *pCmdUI)
1983 pCmdUI->Enable(TRUE);
1986 void CMainFrame::OnEditUseleftfile()
1988 if (m_pwndBottomView->IsWindowVisible())
1989 m_pwndBottomView->UseRightFile();
1990 else
1991 m_pwndRightView->UseLeftFile();
1994 void CMainFrame::OnUpdateEditUseleftfile(CCmdUI *pCmdUI)
1996 pCmdUI->Enable(IsViewGood(m_pwndRightView) && m_pwndRightView->IsTarget());
1999 void CMainFrame::OnEditUseblockfromleftbeforeright()
2001 if (m_pwndRightView)
2002 m_pwndRightView->UseBothLeftFirst();
2005 void CMainFrame::OnUpdateEditUseblockfromleftbeforeright(CCmdUI *pCmdUI)
2007 OnUpdateEditUseleftblock(pCmdUI);
2010 void CMainFrame::OnEditUseblockfromrightbeforeleft()
2012 if (m_pwndRightView)
2013 m_pwndRightView->UseBothRightFirst();
2016 void CMainFrame::OnUpdateEditUseblockfromrightbeforeleft(CCmdUI *pCmdUI)
2018 OnUpdateEditUseleftblock(pCmdUI);
2021 void CMainFrame::OnFileReload()
2023 if (CheckForSave(CHFSR_RELOAD)==IDCANCEL)
2024 return;
2025 CDiffColors::GetInstance().LoadRegistry();
2026 LoadViews(-1);
2029 void CMainFrame::ActivateFrame(int nCmdShow)
2031 // nCmdShow is the normal show mode this frame should be in
2032 // translate default nCmdShow (-1)
2033 if (nCmdShow == -1)
2035 if (!IsWindowVisible())
2036 nCmdShow = SW_SHOWNORMAL;
2037 else if (IsIconic())
2038 nCmdShow = SW_RESTORE;
2041 // bring to top before showing
2042 BringToTop(nCmdShow);
2044 if (nCmdShow != -1)
2046 // show the window as specified
2047 WINDOWPLACEMENT wp;
2049 if ( !ReadWindowPlacement(&wp) )
2051 ShowWindow(nCmdShow);
2053 else
2055 if ( nCmdShow != SW_SHOWNORMAL )
2056 wp.showCmd = nCmdShow;
2058 SetWindowPlacement(&wp);
2061 // and finally, bring to top after showing
2062 BringToTop(nCmdShow);
2066 BOOL CMainFrame::ReadWindowPlacement(WINDOWPLACEMENT * pwp)
2068 CRegString placement = CRegString(_T("Software\\TortoiseGitMerge\\WindowPos"));
2069 CString sPlacement = placement;
2070 if (sPlacement.IsEmpty())
2071 return FALSE;
2072 int nRead = _stscanf_s(sPlacement, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
2073 &pwp->flags, &pwp->showCmd,
2074 &pwp->ptMinPosition.x, &pwp->ptMinPosition.y,
2075 &pwp->ptMaxPosition.x, &pwp->ptMaxPosition.y,
2076 &pwp->rcNormalPosition.left, &pwp->rcNormalPosition.top,
2077 &pwp->rcNormalPosition.right, &pwp->rcNormalPosition.bottom);
2078 if ( nRead != 10 )
2079 return FALSE;
2080 pwp->length = sizeof(WINDOWPLACEMENT);
2082 return TRUE;
2085 void CMainFrame::WriteWindowPlacement(WINDOWPLACEMENT * pwp)
2087 CRegString placement(L"Software\\TortoiseGitMerge\\WindowPos");
2088 TCHAR szBuffer[_countof("-32767")*8 + sizeof("65535")*2];
2090 _stprintf_s(szBuffer, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
2091 pwp->flags, pwp->showCmd,
2092 pwp->ptMinPosition.x, pwp->ptMinPosition.y,
2093 pwp->ptMaxPosition.x, pwp->ptMaxPosition.y,
2094 pwp->rcNormalPosition.left, pwp->rcNormalPosition.top,
2095 pwp->rcNormalPosition.right, pwp->rcNormalPosition.bottom);
2096 placement = szBuffer;
2099 void CMainFrame::OnUpdateMergeMarkasresolved(CCmdUI *pCmdUI)
2101 if (pCmdUI == NULL)
2102 return;
2103 BOOL bEnable = FALSE;
2104 if ((!m_bReadOnly)&&(m_Data.m_mergedFile.InUse()))
2106 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
2108 bEnable = TRUE;
2111 pCmdUI->Enable(bEnable);
2114 void CMainFrame::OnMergeMarkasresolved()
2116 if(HasConflictsWontKeep())
2117 return;
2119 // now check if the file has already been saved and if not, save it.
2120 if (m_Data.m_mergedFile.InUse())
2122 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
2124 if (!FileSave(false))
2125 return;
2126 m_bSaveRequired = false;
2129 MarkAsResolved();
2132 BOOL CMainFrame::MarkAsResolved()
2134 if (m_bReadOnly)
2135 return FALSE;
2136 if (!IsViewGood(m_pwndBottomView))
2137 return FALSE;
2139 CString cmd = _T("/command:resolve /path:\"");
2140 cmd += m_Data.m_mergedFile.GetFilename();
2141 cmd += _T("\" /closeonend:1 /noquestion /skipcheck /silent");
2142 if (resolveMsgWnd)
2144 CString s;
2145 s.Format(L" /resolvemsghwnd:%I64d /resolvemsgwparam:%I64d /resolvemsglparam:%I64d", (__int64)resolveMsgWnd, (__int64)resolveMsgWParam, (__int64)resolveMsgLParam);
2146 cmd += s;
2148 if(!CAppUtils::RunTortoiseGitProc(cmd))
2149 return FALSE;
2150 m_bSaveRequired = false;
2151 return TRUE;
2154 void CMainFrame::OnUpdateMergeNextconflict(CCmdUI *pCmdUI)
2156 BOOL bShow = FALSE;
2157 if (HasNextConflict(m_pwndBottomView))
2158 bShow = TRUE;
2159 else if (HasNextConflict(m_pwndRightView))
2160 bShow = TRUE;
2161 else if (HasNextConflict(m_pwndLeftView))
2162 bShow = TRUE;
2163 pCmdUI->Enable(bShow);
2166 bool CMainFrame::HasNextConflict(CBaseView* view)
2168 if (view == 0)
2169 return false;
2170 if (!view->IsTarget())
2171 return false;
2172 return view->HasNextConflict();
2175 void CMainFrame::OnUpdateMergePreviousconflict(CCmdUI *pCmdUI)
2177 BOOL bShow = FALSE;
2178 if (HasPrevConflict(m_pwndBottomView))
2179 bShow = TRUE;
2180 else if (HasPrevConflict(m_pwndRightView))
2181 bShow = TRUE;
2182 else if (HasPrevConflict(m_pwndLeftView))
2183 bShow = TRUE;
2184 pCmdUI->Enable(bShow);
2187 bool CMainFrame::HasPrevConflict(CBaseView* view)
2189 if (view == 0)
2190 return false;
2191 if (!view->IsTarget())
2192 return false;
2193 return view->HasPrevConflict();
2196 void CMainFrame::OnUpdateNavigateNextdifference(CCmdUI *pCmdUI)
2198 CBaseView* baseView = GetActiveBaseView();
2199 BOOL bShow = FALSE;
2200 if (baseView != 0)
2201 bShow = baseView->HasNextDiff();
2202 pCmdUI->Enable(bShow);
2205 void CMainFrame::OnUpdateNavigatePreviousdifference(CCmdUI *pCmdUI)
2207 CBaseView* baseView = GetActiveBaseView();
2208 BOOL bShow = FALSE;
2209 if (baseView != 0)
2210 bShow = baseView->HasPrevDiff();
2211 pCmdUI->Enable(bShow);
2214 void CMainFrame::OnUpdateNavigateNextinlinediff(CCmdUI *pCmdUI)
2216 BOOL bShow = FALSE;
2217 if (HasNextInlineDiff(m_pwndBottomView))
2218 bShow = TRUE;
2219 else if (HasNextInlineDiff(m_pwndRightView))
2220 bShow = TRUE;
2221 else if (HasNextInlineDiff(m_pwndLeftView))
2222 bShow = TRUE;
2223 pCmdUI->Enable(bShow);
2226 bool CMainFrame::HasNextInlineDiff(CBaseView* view)
2228 if (view == 0)
2229 return false;
2230 if (!view->IsTarget())
2231 return false;
2232 return view->HasNextInlineDiff();
2235 void CMainFrame::OnUpdateNavigatePrevinlinediff(CCmdUI *pCmdUI)
2237 BOOL bShow = FALSE;
2238 if (HasPrevInlineDiff(m_pwndBottomView))
2239 bShow = TRUE;
2240 else if (HasPrevInlineDiff(m_pwndRightView))
2241 bShow = TRUE;
2242 else if (HasPrevInlineDiff(m_pwndLeftView))
2243 bShow = TRUE;
2244 pCmdUI->Enable(bShow);
2247 bool CMainFrame::HasPrevInlineDiff(CBaseView* view)
2249 if (view == 0)
2250 return false;
2251 if (!view->IsTarget())
2252 return false;
2253 return view->HasPrevInlineDiff();
2256 void CMainFrame::OnMoving(UINT fwSide, LPRECT pRect)
2258 // if the pathfilelist dialog is attached to the mainframe,
2259 // move it along with the mainframe
2260 if (::IsWindow(m_dlgFilePatches.m_hWnd))
2262 RECT patchrect;
2263 m_dlgFilePatches.GetWindowRect(&patchrect);
2264 if (::IsWindow(m_hWnd))
2266 RECT thisrect;
2267 GetWindowRect(&thisrect);
2268 if (patchrect.right == thisrect.left)
2270 m_dlgFilePatches.SetWindowPos(NULL, patchrect.left - (thisrect.left - pRect->left), patchrect.top - (thisrect.top - pRect->top),
2271 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
2275 __super::OnMoving(fwSide, pRect);
2278 void CMainFrame::OnUpdateEditCopy(CCmdUI *pCmdUI)
2280 BOOL bShow = FALSE;
2281 if ((m_pwndBottomView)&&(m_pwndBottomView->HasSelection()))
2282 bShow = TRUE;
2283 else if ((m_pwndRightView)&&(m_pwndRightView->HasSelection()))
2284 bShow = TRUE;
2285 else if ((m_pwndLeftView)&&(m_pwndLeftView->HasSelection()))
2286 bShow = TRUE;
2287 pCmdUI->Enable(bShow);
2290 void CMainFrame::OnUpdateEditPaste(CCmdUI *pCmdUI)
2292 BOOL bWritable = FALSE;
2293 if ((m_pwndBottomView)&&(m_pwndBottomView->IsWritable()))
2294 bWritable = TRUE;
2295 else if ((m_pwndRightView)&&(m_pwndRightView->IsWritable()))
2296 bWritable = TRUE;
2297 else if ((m_pwndLeftView)&&(m_pwndLeftView->IsWritable()))
2298 bWritable = TRUE;
2299 pCmdUI->Enable(bWritable && ::IsClipboardFormatAvailable(CF_TEXT));
2302 void CMainFrame::OnViewSwitchleft()
2304 if (CheckForSave(CHFSR_SWITCH)!=IDCANCEL)
2306 CWorkingFile file = m_Data.m_baseFile;
2307 m_Data.m_baseFile = m_Data.m_yourFile;
2308 m_Data.m_yourFile = file;
2309 if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_yourFile.GetFilename())==0)
2311 m_Data.m_mergedFile = m_Data.m_baseFile;
2313 else if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_baseFile.GetFilename())==0)
2315 m_Data.m_mergedFile = m_Data.m_yourFile;
2317 LoadViews();
2321 void CMainFrame::OnUpdateViewSwitchleft(CCmdUI *pCmdUI)
2323 BOOL bEnable = !IsViewGood(m_pwndBottomView);
2324 pCmdUI->Enable(bEnable);
2327 void CMainFrame::OnUpdateViewShowfilelist(CCmdUI *pCmdUI)
2329 BOOL bEnable = m_dlgFilePatches.HasFiles();
2330 pCmdUI->Enable(bEnable);
2331 pCmdUI->SetCheck(m_dlgFilePatches.IsWindowVisible());
2334 void CMainFrame::OnViewShowfilelist()
2336 m_dlgFilePatches.ShowWindow(m_dlgFilePatches.IsWindowVisible() ? SW_HIDE : SW_SHOW);
2339 void CMainFrame::OnEditUndo()
2341 if (CUndo::GetInstance().CanUndo())
2343 CUndo::GetInstance().Undo(m_pwndLeftView, m_pwndRightView, m_pwndBottomView);
2347 void CMainFrame::OnUpdateEditUndo(CCmdUI *pCmdUI)
2349 pCmdUI->Enable(CUndo::GetInstance().CanUndo());
2352 void CMainFrame::OnEditRedo()
2354 if (CUndo::GetInstance().CanRedo())
2356 CUndo::GetInstance().Redo(m_pwndLeftView, m_pwndRightView, m_pwndBottomView);
2360 void CMainFrame::OnUpdateEditRedo(CCmdUI *pCmdUI)
2362 pCmdUI->Enable(CUndo::GetInstance().CanRedo());
2365 void CMainFrame::OnEditEnable()
2367 CBaseView * pView = GetActiveBaseView();
2368 if (pView && pView->IsReadonlyChangable())
2370 bool isReadOnly = pView->IsReadonly();
2371 pView->SetReadonly(!isReadOnly);
2375 void CMainFrame::OnUpdateEditEnable(CCmdUI *pCmdUI)
2377 CBaseView * pView = GetActiveBaseView();
2378 if (pView)
2380 pCmdUI->Enable(pView->IsReadonlyChangable() || !pView->IsReadonly());
2381 pCmdUI->SetCheck(!pView->IsReadonly());
2383 else
2385 pCmdUI->Enable(FALSE);
2389 void CMainFrame::OnIndicatorLeftview()
2391 if (m_bUseRibbons)
2392 return;
2393 if (IsViewGood(m_pwndLeftView))
2395 m_pwndLeftView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_LEFTVIEW);
2399 void CMainFrame::OnIndicatorRightview()
2401 if (m_bUseRibbons)
2402 return;
2403 if (IsViewGood(m_pwndRightView))
2405 m_pwndRightView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_RIGHTVIEW);
2409 void CMainFrame::OnIndicatorBottomview()
2411 if (m_bUseRibbons)
2412 return;
2413 if (IsViewGood(m_pwndBottomView))
2415 m_pwndBottomView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_BOTTOMVIEW);
2419 int CMainFrame::CheckForReload()
2421 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
2422 if (bLock)
2424 return IDNO;
2426 bLock = true;
2427 bool bSourceChanged =
2428 m_Data.m_baseFile.HasSourceFileChanged()
2429 || m_Data.m_yourFile.HasSourceFileChanged()
2430 || m_Data.m_theirFile.HasSourceFileChanged()
2431 /*|| m_Data.m_mergedFile.HasSourceFileChanged()*/;
2432 if (!bSourceChanged)
2434 bLock = false;
2435 return IDNO;
2438 CString msg = HasUnsavedEdits() ? CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDELOOSECHANGES)) : CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE));
2439 CTaskDialog taskdlg(msg,
2440 CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE_TASK2)),
2441 L"TortoiseGitMerge",
2443 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
2444 CString sTask3;
2445 if (HasUnsavedEdits())
2446 sTask3.LoadString(IDS_WARNMODIFIEDOUTSIDE_TASK3);
2447 else
2448 sTask3.LoadString(IDS_WARNMODIFIEDOUTSIDE_TASK4);
2449 taskdlg.AddCommandControl(IDYES, sTask3);
2450 taskdlg.AddCommandControl(IDNO, CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE_TASK5)));
2451 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2452 taskdlg.SetDefaultCommandControl(IDYES);
2453 taskdlg.SetMainIcon(TD_WARNING_ICON);
2454 UINT ret = (UINT)taskdlg.DoModal(m_hWnd);
2455 if (ret == IDYES)
2457 CDiffColors::GetInstance().LoadRegistry();
2458 LoadViews(-1);
2460 else
2462 if (IsViewGood(m_pwndBottomView)) // three pane view
2464 /*if (m_Data.m_sourceFile.HasSourceFileChanged())
2465 m_pwndBottomView->SetModified();
2466 if (m_Data.m_mergedFile.HasSourceFileChanged())
2467 m_pwndBottomView->SetModified();//*/
2468 if (m_Data.m_yourFile.HasSourceFileChanged())
2469 m_pwndRightView->SetModified();
2470 if (m_Data.m_theirFile.HasSourceFileChanged())
2471 m_pwndLeftView->SetModified();
2473 else if (IsViewGood(m_pwndRightView)) // two pane view
2475 if (m_Data.m_baseFile.HasSourceFileChanged())
2476 m_pwndLeftView->SetModified();
2477 if (m_Data.m_yourFile.HasSourceFileChanged())
2478 m_pwndRightView->SetModified();
2480 else
2482 if (m_Data.m_yourFile.HasSourceFileChanged())
2483 m_pwndLeftView->SetModified();
2486 // no reload just store updated file time
2487 m_Data.m_baseFile.StoreFileAttributes();
2488 m_Data.m_theirFile.StoreFileAttributes();
2489 m_Data.m_yourFile.StoreFileAttributes();
2490 //m_Data.m_mergedFile.StoreFileAttributes();
2492 bLock = false;
2493 return ret;
2496 int CMainFrame::CheckForSave(ECheckForSaveReason eReason)
2498 int idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2499 int idNoSave = IDS_ASKFORSAVE_TASK7;
2500 int idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2501 switch (eReason)
2503 case CHFSR_CLOSE:
2504 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2505 idNoSave = IDS_ASKFORSAVE_TASK4;
2506 idCancelAction = IDS_ASKFORSAVE_TASK5;
2507 break;
2508 case CHFSR_SWITCH:
2509 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2510 //idNoSave = IDS_ASKFORSAVE_TASK7;
2511 idCancelAction = IDS_ASKFORSAVE_TASK8;
2512 break;
2513 case CHFSR_RELOAD:
2514 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2515 //idNoSave = IDS_ASKFORSAVE_TASK7;
2516 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2517 break;
2518 case CHFSR_OPTIONS:
2519 idTitle = IDS_WARNMODIFIEDLOOSECHANGESOPTIONS;
2520 //idNoSave = IDS_ASKFORSAVE_TASK7;
2521 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPTIONS;
2522 break;
2523 case CHFSR_OPEN:
2524 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2525 idNoSave = IDS_ASKFORSAVE_NOSAVE_OPEN;
2526 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2527 break;
2530 CString sTitle(MAKEINTRESOURCE(idTitle));
2531 CString sSubTitle(MAKEINTRESOURCE(IDS_ASKFORSAVE_TASK2));
2532 CString sNoSave(MAKEINTRESOURCE(idNoSave));
2533 CString sCancelAction(MAKEINTRESOURCE(idCancelAction));
2534 CString sAppName(MAKEINTRESOURCE(IDS_APPNAME));
2536 // TODO simplify logic, reduce code duplication
2537 if (CBaseView::IsViewGood(m_pwndBottomView))
2539 // three-way diff - by design only bottom can be changed
2540 // use 1.7 way to do that
2542 else if (CBaseView::IsViewGood(m_pwndRightView))
2544 // two-way diff -
2545 // 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
2546 if (HasUnsavedEdits(m_pwndLeftView))
2548 // both views
2549 CTaskDialog taskdlg(sTitle,
2550 sSubTitle,
2551 sAppName,
2553 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
2554 CString sTaskTemp;
2555 if (m_pwndLeftView->m_pWorkingFile->InUse() && !m_pwndLeftView->m_pWorkingFile->IsReadonly())
2556 sTaskTemp.Format(IDS_ASKFORSAVE_SAVELEFT, (LPCTSTR)m_pwndLeftView->m_pWorkingFile->GetFilename());
2557 else
2558 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS));
2559 taskdlg.AddCommandControl(201, sTaskTemp); // left
2560 taskdlg.SetDefaultCommandControl(201);
2561 if (HasUnsavedEdits(m_pwndRightView))
2563 if (m_pwndRightView->m_pWorkingFile->InUse() && !m_pwndRightView->m_pWorkingFile->IsReadonly())
2564 sTaskTemp.Format(IDS_ASKFORSAVE_SAVERIGHT, (LPCTSTR)m_pwndRightView->m_pWorkingFile->GetFilename());
2565 else
2566 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS));
2567 taskdlg.AddCommandControl(202, sTaskTemp); // right
2568 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEALL2))); // both
2569 taskdlg.SetDefaultCommandControl(203);
2571 taskdlg.AddCommandControl(IDNO, sNoSave); // none
2572 taskdlg.AddCommandControl(IDCANCEL, sCancelAction); // cancel
2573 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2574 taskdlg.SetMainIcon(TD_WARNING_ICON);
2575 UINT ret = (UINT)taskdlg.DoModal(m_hWnd);
2576 switch (ret)
2578 case 201: // left
2579 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
2580 break;
2581 case 203: // both
2582 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
2583 case 202: // right
2584 m_pwndRightView->SaveFile();
2585 break;
2587 if (ret != IDCANCEL && (eReason == CHFSR_CLOSE || eReason == CHFSR_OPEN))
2588 DeleteBaseTheirsMineOnClose();
2589 return ret;
2591 else
2593 // only secondary (left) view
2595 // only right view - 1.7 implementation is used
2597 else if (CBaseView::IsViewGood(m_pwndLeftView))
2599 // only one view - only one to save
2600 // 1.7 FileSave don't support this mode
2601 if (HasUnsavedEdits(m_pwndLeftView))
2603 CTaskDialog taskdlg(sTitle,
2604 sSubTitle,
2605 sAppName,
2607 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
2608 CString sTask3;
2609 if (m_Data.m_mergedFile.InUse())
2610 sTask3.Format(IDS_ASKFORSAVE_TASK3, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
2611 else
2612 sTask3.LoadString(IDS_ASKFORSAVE_TASK6);
2613 taskdlg.AddCommandControl(IDYES, sTask3);
2614 taskdlg.AddCommandControl(IDNO, sNoSave);
2615 taskdlg.AddCommandControl(IDCANCEL, sCancelAction);
2616 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2617 taskdlg.SetDefaultCommandControl(IDYES);
2618 taskdlg.SetMainIcon(TD_WARNING_ICON);
2619 if ((UINT)taskdlg.DoModal(m_hWnd) == IDYES)
2621 if (m_pwndLeftView->SaveFile()<0)
2622 return IDCANCEL;
2625 if (eReason == CHFSR_CLOSE || eReason == CHFSR_OPEN)
2626 DeleteBaseTheirsMineOnClose();
2627 return IDNO;
2629 else
2631 if (eReason == CHFSR_CLOSE || eReason == CHFSR_OPEN)
2632 DeleteBaseTheirsMineOnClose();
2633 return IDNO; // nothing to save
2636 // 1.7 implementation
2637 UINT ret = IDNO;
2638 if (HasUnsavedEdits())
2640 CTaskDialog taskdlg(sTitle,
2641 sSubTitle,
2642 sAppName,
2644 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
2645 CString sTask3;
2646 if (m_Data.m_mergedFile.InUse())
2647 sTask3.Format(IDS_ASKFORSAVE_TASK3, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
2648 else
2649 sTask3.LoadString(IDS_ASKFORSAVE_TASK6);
2650 taskdlg.AddCommandControl(IDYES, sTask3);
2651 taskdlg.AddCommandControl(IDNO, sNoSave);
2652 taskdlg.AddCommandControl(IDCANCEL, sCancelAction);
2653 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2654 taskdlg.SetDefaultCommandControl(IDYES);
2655 taskdlg.SetMainIcon(TD_WARNING_ICON);
2656 ret = (UINT)taskdlg.DoModal(m_hWnd);
2658 if (ret == IDYES)
2660 if (!FileSave())
2661 ret = IDCANCEL;
2665 if (ret != IDCANCEL && (eReason == CHFSR_CLOSE || eReason == CHFSR_OPEN))
2666 DeleteBaseTheirsMineOnClose();
2668 return ret;
2671 void CMainFrame::DeleteBaseTheirsMineOnClose()
2673 if (!m_bDeleteBaseTheirsMineOnClose)
2674 return;
2676 m_bDeleteBaseTheirsMineOnClose = false;
2678 DeleteFile(m_Data.m_baseFile.GetFilename());
2679 DeleteFile(m_Data.m_theirFile.GetFilename());
2680 DeleteFile(m_Data.m_yourFile.GetFilename());
2683 bool CMainFrame::HasUnsavedEdits() const
2685 return HasUnsavedEdits(m_pwndBottomView) || HasUnsavedEdits(m_pwndRightView) || m_bSaveRequired;
2688 bool CMainFrame::HasUnsavedEdits(const CBaseView* view)
2690 if (!CBaseView::IsViewGood(view))
2691 return false;
2692 return view->IsModified();
2695 bool CMainFrame::HasMarkedBlocks() const
2697 return CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->HasMarkedBlocks();
2700 bool CMainFrame::IsViewGood(const CBaseView* view)
2702 return CBaseView::IsViewGood(view);
2705 void CMainFrame::OnViewInlinediffword()
2707 m_bInlineWordDiff = !m_bInlineWordDiff;
2708 if (m_pwndLeftView)
2710 m_pwndLeftView->SetInlineWordDiff(m_bInlineWordDiff);
2711 m_pwndLeftView->BuildAllScreen2ViewVector();
2712 m_pwndLeftView->DocumentUpdated();
2714 if (m_pwndRightView)
2716 m_pwndRightView->SetInlineWordDiff(m_bInlineWordDiff);
2717 m_pwndRightView->BuildAllScreen2ViewVector();
2718 m_pwndRightView->DocumentUpdated();
2720 if (m_pwndBottomView)
2722 m_pwndBottomView->SetInlineWordDiff(m_bInlineWordDiff);
2723 m_pwndBottomView->BuildAllScreen2ViewVector();
2724 m_pwndBottomView->DocumentUpdated();
2726 m_wndLineDiffBar.DocumentUpdated();
2729 void CMainFrame::OnUpdateViewInlinediffword(CCmdUI *pCmdUI)
2731 pCmdUI->Enable(m_bInlineDiff && IsViewGood(m_pwndLeftView) && IsViewGood(m_pwndRightView));
2732 pCmdUI->SetCheck(m_bInlineWordDiff);
2735 void CMainFrame::OnViewInlinediff()
2737 m_bInlineDiff = !m_bInlineDiff;
2738 if (m_pwndLeftView)
2740 m_pwndLeftView->SetInlineDiff(m_bInlineDiff);
2741 m_pwndLeftView->BuildAllScreen2ViewVector();
2742 m_pwndLeftView->DocumentUpdated();
2744 if (m_pwndRightView)
2746 m_pwndRightView->SetInlineDiff(m_bInlineDiff);
2747 m_pwndRightView->BuildAllScreen2ViewVector();
2748 m_pwndRightView->DocumentUpdated();
2750 if (m_pwndBottomView)
2752 m_pwndBottomView->SetInlineDiff(m_bInlineDiff);
2753 m_pwndBottomView->BuildAllScreen2ViewVector();
2754 m_pwndBottomView->DocumentUpdated();
2756 m_wndLineDiffBar.DocumentUpdated();
2759 void CMainFrame::OnUpdateViewInlinediff(CCmdUI *pCmdUI)
2761 pCmdUI->Enable(IsViewGood(m_pwndLeftView) && IsViewGood(m_pwndRightView));
2762 pCmdUI->SetCheck(m_bInlineDiff);
2765 void CMainFrame::OnUpdateEditCreateunifieddifffile(CCmdUI *pCmdUI)
2767 // "create unified diff file" is only available if two files
2768 // are diffed, not three.
2769 bool bEnabled = true;
2770 if (!IsViewGood(m_pwndLeftView))
2771 bEnabled = false;
2772 else if (!IsViewGood(m_pwndRightView))
2773 bEnabled = false;
2774 else if (IsViewGood(m_pwndBottomView)) //no negation here
2775 bEnabled = false;
2776 pCmdUI->Enable(bEnabled);
2779 void CMainFrame::OnEditCreateunifieddifffile()
2781 CString origFile, modifiedFile;
2782 // the original file is the one on the left
2783 if (m_pwndLeftView)
2784 origFile = m_pwndLeftView->m_sFullFilePath;
2785 if (m_pwndRightView)
2786 modifiedFile = m_pwndRightView->m_sFullFilePath;
2787 if (origFile.IsEmpty() || modifiedFile.IsEmpty())
2788 return;
2790 CString outputFile;
2791 if(!TryGetFileName(outputFile))
2792 return;
2794 CRegStdDWORD regContextLines(L"Software\\TortoiseGitMerge\\ContextLines", (DWORD)-1);
2795 CAppUtils::CreateUnifiedDiff(origFile, modifiedFile, outputFile, regContextLines, true);
2798 void CMainFrame::OnUpdateViewLinediffbar(CCmdUI *pCmdUI)
2800 pCmdUI->SetCheck(m_bLineDiff);
2801 pCmdUI->Enable();
2804 void CMainFrame::OnViewLinediffbar()
2806 m_bLineDiff = !m_bLineDiff;
2807 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2808 m_wndLineDiffBar.DocumentUpdated();
2809 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2810 m_wndLocatorBar.DocumentUpdated();
2813 void CMainFrame::OnUpdateViewLocatorbar(CCmdUI *pCmdUI)
2815 pCmdUI->SetCheck(m_bLocatorBar);
2816 pCmdUI->Enable();
2819 void CMainFrame::OnUpdateViewBars(CCmdUI * pCmdUI)
2821 pCmdUI->Enable();
2824 void CMainFrame::OnViewLocatorbar()
2826 m_bLocatorBar = !m_bLocatorBar;
2827 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2828 m_wndLocatorBar.DocumentUpdated();
2829 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2830 m_wndLineDiffBar.DocumentUpdated();
2833 void CMainFrame::OnViewComparewhitespaces()
2835 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2836 return;
2837 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
2838 regIgnoreWS = 0;
2839 LoadViews(-1);
2842 void CMainFrame::OnUpdateViewComparewhitespaces(CCmdUI *pCmdUI)
2844 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
2845 DWORD dwIgnoreWS = regIgnoreWS;
2846 pCmdUI->SetCheck(dwIgnoreWS == 0);
2849 void CMainFrame::OnViewIgnorewhitespacechanges()
2851 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2852 return;
2853 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
2854 regIgnoreWS = 2;
2855 LoadViews(-1);
2858 void CMainFrame::OnUpdateViewIgnorewhitespacechanges(CCmdUI *pCmdUI)
2860 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
2861 DWORD dwIgnoreWS = regIgnoreWS;
2862 pCmdUI->SetCheck(dwIgnoreWS == 2);
2865 void CMainFrame::OnViewIgnoreallwhitespacechanges()
2867 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2868 return;
2869 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
2870 regIgnoreWS = 1;
2871 LoadViews(-1);
2874 void CMainFrame::OnUpdateViewIgnoreallwhitespacechanges(CCmdUI *pCmdUI)
2876 CRegDWORD regIgnoreWS(L"Software\\TortoiseGitMerge\\IgnoreWS");
2877 DWORD dwIgnoreWS = regIgnoreWS;
2878 pCmdUI->SetCheck(dwIgnoreWS == 1);
2881 void CMainFrame::OnViewMovedBlocks()
2883 m_bViewMovedBlocks = !(DWORD)m_regViewModedBlocks;
2884 m_regViewModedBlocks = m_bViewMovedBlocks;
2885 LoadViews(-1);
2888 void CMainFrame::OnUpdateViewMovedBlocks(CCmdUI *pCmdUI)
2890 pCmdUI->SetCheck(m_bViewMovedBlocks);
2891 BOOL bEnable = TRUE;
2892 if (IsViewGood(m_pwndBottomView))
2894 bEnable = FALSE;
2896 pCmdUI->Enable(bEnable);
2899 bool CMainFrame::HasConflictsWontKeep()
2901 const int nConflictLine = CheckResolved();
2902 if (nConflictLine < 0)
2903 return false;
2904 if (m_pwndBottomView == nullptr)
2905 return false;
2907 CString sTemp;
2908 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
2909 CTaskDialog taskdlg(sTemp,
2910 CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK2)),
2911 L"TortoiseGitMerge",
2913 TDF_ENABLE_HYPERLINKS | TDF_USE_COMMAND_LINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW);
2914 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK3)));
2915 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK4)));
2916 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2917 taskdlg.SetDefaultCommandControl(2);
2918 taskdlg.SetMainIcon(TD_ERROR_ICON);
2919 if (taskdlg.DoModal(m_hWnd) == 1)
2920 return false;
2922 m_pwndBottomView->GoToLine(nConflictLine);
2923 return true;
2926 bool CMainFrame::TryGetFileName(CString& result)
2928 return CCommonAppUtils::FileOpenSave(result, NULL, IDS_SAVEASTITLE, IDS_COMMONFILEFILTER, false, m_hWnd);
2931 CBaseView* CMainFrame::GetActiveBaseView() const
2933 CView* activeView = GetActiveView();
2934 CBaseView* activeBase = dynamic_cast<CBaseView*>( activeView );
2935 return activeBase;
2938 void CMainFrame::SetWindowTitle()
2940 // try to find a suitable window title
2941 CString sYour = m_Data.m_yourFile.GetDescriptiveName();
2942 if (sYour.Find(_T(" - "))>=0)
2943 sYour = sYour.Left(sYour.Find(_T(" - ")));
2944 if (sYour.Find(_T(" : "))>=0)
2945 sYour = sYour.Left(sYour.Find(_T(" : ")));
2946 CString sTheir = m_Data.m_theirFile.GetDescriptiveName();
2947 if (sTheir.IsEmpty())
2948 sTheir = m_Data.m_baseFile.GetDescriptiveName();
2949 if (sTheir.Find(_T(" - "))>=0)
2950 sTheir = sTheir.Left(sTheir.Find(_T(" - ")));
2951 if (sTheir.Find(_T(" : "))>=0)
2952 sTheir = sTheir.Left(sTheir.Find(_T(" : ")));
2954 if (!sYour.IsEmpty() && !sTheir.IsEmpty())
2956 if (sYour.CompareNoCase(sTheir)==0)
2957 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
2958 else if ((sYour.GetLength() < 10) &&
2959 (sTheir.GetLength() < 10))
2960 SetWindowText(sYour + _T(" - ") + sTheir + _T(" - TortoiseGitMerge"));
2961 else
2963 // we have two very long descriptive texts here, which
2964 // means we have to find a way to use them as a window
2965 // title in a shorter way.
2966 // for simplicity, we just use the one from "yourfile"
2967 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
2970 else if (!sYour.IsEmpty())
2971 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
2972 else if (!sTheir.IsEmpty())
2973 SetWindowText(sTheir + _T(" - TortoiseGitMerge"));
2974 else
2975 SetWindowText(L"TortoiseGitMerge");
2978 void CMainFrame::OnTimer(UINT_PTR nIDEvent)
2980 switch (nIDEvent)
2982 case IDT_RELOADCHECKTIMER:
2983 KillTimer(nIDEvent);
2984 CheckForReload();
2985 break;
2988 __super::OnTimer(nIDEvent);
2991 void CMainFrame::LoadIgnoreCommentData()
2993 static bool bLoaded = false;
2994 if (bLoaded)
2995 return;
2996 CString sPath = CPathUtils::GetAppDataDirectory() + L"ignorecomments.txt";
2997 if (!PathFileExists(sPath))
2999 // ignore comments file does not exist (yet), so create a default one
3000 HRSRC hRes = FindResource(NULL, MAKEINTRESOURCE(IDR_IGNORECOMMENTSTXT), L"config");
3001 if (hRes)
3003 HGLOBAL hResourceLoaded = LoadResource(NULL, hRes);
3004 if (hResourceLoaded)
3006 char * lpResLock = (char *) LockResource(hResourceLoaded);
3007 DWORD dwSizeRes = SizeofResource(NULL, hRes);
3008 if (lpResLock)
3010 HANDLE hFile = CreateFile(sPath, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
3011 if (hFile != INVALID_HANDLE_VALUE)
3013 DWORD dwWritten = 0;
3014 WriteFile(hFile, lpResLock, dwSizeRes, &dwWritten, NULL);
3015 CloseHandle(hFile);
3024 CStdioFile file;
3025 if (file.Open(sPath, CFile::modeRead))
3027 CString sLine;
3028 while (file.ReadString(sLine))
3030 int eqpos = sLine.Find('=');
3031 if (eqpos >= 0)
3033 CString sExts = sLine.Left(eqpos);
3034 CString sComments = sLine.Mid(eqpos+1);
3036 int pos = sComments.Find(',');
3037 CString sLineStart = sComments.Left(pos);
3038 pos = sComments.Find(',', pos);
3039 int pos2 = sComments.Find(',', pos+1);
3040 CString sBlockStart = sComments.Mid(pos+1, pos2-pos-1);
3041 CString sBlockEnd = sComments.Mid(pos2+1);
3043 auto commentTuple = std::make_tuple(sLineStart, sBlockStart, sBlockEnd);
3045 pos = 0;
3046 CString temp;
3047 for (;;)
3049 temp = sExts.Tokenize(_T(","),pos);
3050 if (temp.IsEmpty())
3052 break;
3054 ASSERT(m_IgnoreCommentsMap.find(temp) == m_IgnoreCommentsMap.end());
3055 m_IgnoreCommentsMap[temp] = commentTuple;
3061 catch (CFileException* e)
3063 e->Delete();
3065 bLoaded = true;
3068 void CMainFrame::OnViewIgnorecomments()
3070 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3071 return;
3072 m_regIgnoreComments = !DWORD(m_regIgnoreComments);
3073 LoadViews(-1);
3076 void CMainFrame::OnUpdateViewIgnorecomments(CCmdUI *pCmdUI)
3078 // only enable if we have comments defined for this file extension
3079 CString sExt = CPathUtils::GetFileExtFromPath(m_Data.m_baseFile.GetFilename()).MakeLower();
3080 sExt.TrimLeft(L".");
3081 auto sC = m_IgnoreCommentsMap.find(sExt);
3082 if (sC == m_IgnoreCommentsMap.end())
3084 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_yourFile.GetFilename()).MakeLower();
3085 sExt.TrimLeft(L".");
3086 sC = m_IgnoreCommentsMap.find(sExt);
3087 if (sC == m_IgnoreCommentsMap.end())
3089 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_theirFile.GetFilename()).MakeLower();
3090 sExt.TrimLeft(L".");
3091 sC = m_IgnoreCommentsMap.find(sExt);
3094 pCmdUI->Enable(sC != m_IgnoreCommentsMap.end());
3096 pCmdUI->SetCheck(DWORD(m_regIgnoreComments) != 0);
3100 void CMainFrame::OnRegexfilter(UINT cmd)
3102 if ((cmd == ID_REGEXFILTER)||(cmd == (ID_REGEXFILTER+1)))
3104 CRegexFiltersDlg dlg(this);
3105 dlg.SetIniFile(&m_regexIni);
3106 if (dlg.DoModal() == IDOK)
3108 FILE * pFile = NULL;
3109 _tfopen_s(&pFile, CPathUtils::GetAppDataDirectory() + L"regexfilters.ini", _T("wb"));
3110 m_regexIni.SaveFile(pFile);
3111 fclose(pFile);
3113 BuildRegexSubitems();
3115 else
3117 if (cmd == (UINT)m_regexIndex)
3119 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3120 return;
3121 m_Data.SetRegexTokens(std::wregex(), L"");
3122 m_regexIndex = -1;
3123 LoadViews(-1);
3125 else
3127 CSimpleIni::TNamesDepend sections;
3128 m_regexIni.GetAllSections(sections);
3129 int index = ID_REGEXFILTER + 2;
3130 m_regexIndex = -1;
3131 for (const auto& section : sections)
3133 if (cmd == (UINT)index)
3135 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3136 break;
3139 std::wregex rx(m_regexIni.GetValue(section, L"regex", L""));
3140 m_Data.SetRegexTokens(rx, m_regexIni.GetValue(section, L"replace", L""));
3142 catch (std::exception &ex)
3144 MessageBox(_T("Regex is invalid!\r\n") + CString(ex.what()));
3146 m_regexIndex = index;
3147 LoadViews(-1);
3148 break;
3150 ++index;
3156 void CMainFrame::OnUpdateViewRegexFilter( CCmdUI *pCmdUI )
3158 pCmdUI->Enable();
3159 pCmdUI->SetCheck(pCmdUI->m_nID == (UINT)m_regexIndex);
3162 void CMainFrame::BuildRegexSubitems(CMFCPopupMenu* pMenuPopup)
3164 CString sIniPath = CPathUtils::GetAppDataDirectory() + L"regexfilters.ini";
3165 if (!PathFileExists(sIniPath))
3167 // ini file does not exist (yet), so create a default one
3168 HRSRC hRes = FindResource(NULL, MAKEINTRESOURCE(IDR_REGEXFILTERINI), L"config");
3169 if (hRes)
3171 HGLOBAL hResourceLoaded = LoadResource(NULL, hRes);
3172 if (hResourceLoaded)
3174 char * lpResLock = (char *)LockResource(hResourceLoaded);
3175 DWORD dwSizeRes = SizeofResource(NULL, hRes);
3176 if (lpResLock)
3178 HANDLE hFile = CreateFile(sIniPath, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
3179 if (hFile != INVALID_HANDLE_VALUE)
3181 DWORD dwWritten = 0;
3182 WriteFile(hFile, lpResLock, dwSizeRes, &dwWritten, NULL);
3183 CloseHandle(hFile);
3190 m_regexIni.LoadFile(sIniPath);
3191 CSimpleIni::TNamesDepend sections;
3192 m_regexIni.GetAllSections(sections);
3194 if (m_bUseRibbons)
3196 CArray<CMFCRibbonBaseElement*, CMFCRibbonBaseElement*> arButtons;
3197 m_wndRibbonBar.GetElementsByID(ID_REGEXFILTER, arButtons);
3198 if (arButtons.GetCount() == 1)
3200 CMFCRibbonButton * pButton = (CMFCRibbonButton*)arButtons.GetAt(0);
3201 if (pButton)
3203 pButton->RemoveAllSubItems();
3204 pButton->AddSubItem(new CMFCRibbonButton(ID_REGEXFILTER + 1, CString(MAKEINTRESOURCE(IDS_CONFIGUREREGEXES)), 47, 47));
3206 if (!sections.empty())
3207 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3208 int cmdIndex = 2;
3209 for (const auto& section : sections)
3211 pButton->AddSubItem(new CMFCRibbonButton(ID_REGEXFILTER + cmdIndex, section, 46, 46));
3212 cmdIndex++;
3217 else if (pMenuPopup)
3219 int iIndex = -1;
3220 if (!CMFCToolBar::IsCustomizeMode() &&
3221 (iIndex = pMenuPopup->GetMenuBar()->CommandToIndex(ID_REGEXFILTER)) >= 0)
3223 if (!sections.empty())
3224 pMenuPopup->InsertSeparator(iIndex + 1); // insert the separator at the end
3225 int cmdIndex = 2;
3226 for (const auto& section : sections)
3228 pMenuPopup->InsertItem(CMFCToolBarMenuButton(ID_REGEXFILTER + cmdIndex, NULL, -1, (LPCWSTR)section), iIndex + cmdIndex);
3229 cmdIndex++;
3235 void CMainFrame::FillEncodingButton( CMFCRibbonButton * pButton, int start )
3237 pButton->SetDefaultCommand(FALSE);
3238 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::ASCII, L"ASCII" ));
3239 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::BINARY, L"BINARY" ));
3240 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_LE, L"UTF-16LE" ));
3241 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_LEBOM, L"UTF-16LE BOM"));
3242 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_BE, L"UTF-16BE" ));
3243 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_BEBOM, L"UTF-16BE BOM"));
3244 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF32_LE, L"UTF-32LE" ));
3245 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF32_BE, L"UTF-32BE" ));
3246 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF8, L"UTF-8" ));
3247 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF8BOM, L"UTF-8 BOM" ));
3250 void CMainFrame::FillEOLButton( CMFCRibbonButton * pButton, int start )
3252 pButton->SetDefaultCommand(FALSE);
3253 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LF , L"LF" ));
3254 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_CRLF, L"CRLF"));
3255 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LFCR, L"LRCR"));
3256 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_CR , L"CR" ));
3257 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_VT , L"VT" ));
3258 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_FF , L"FF" ));
3259 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_NEL , L"NEL" ));
3260 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LS , L"LS" ));
3261 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_PS , L"PS" ));
3264 void CMainFrame::FillTabModeButton(CMFCRibbonButton * pButton, int start)
3266 pButton->SetDefaultCommand(FALSE);
3267 pButton->AddSubItem(new CMFCRibbonButton(start + TABMODE_NONE , L"Tab"));
3268 pButton->AddSubItem(new CMFCRibbonButton(start + TABMODE_USESPACES , L"Space"));
3269 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3270 pButton->AddSubItem(new CMFCRibbonButton(start + TABMODE_SMARTINDENT , L"Smart tab char"));
3271 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3272 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON1, L"1"));
3273 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON2, L"2"));
3274 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON4, L"4"));
3275 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON8, L"8"));
3276 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3277 pButton->AddSubItem(new CMFCRibbonButton(start + ENABLEEDITORCONFIG, L"EditorConfig"));
3280 bool CMainFrame::AdjustUnicodeTypeForLoad(CFileTextLines::UnicodeType& type)
3282 switch (type)
3284 case CFileTextLines::UnicodeType::AUTOTYPE:
3285 case CFileTextLines::UnicodeType::BINARY:
3286 return false;
3288 case CFileTextLines::UnicodeType::ASCII:
3289 case CFileTextLines::UnicodeType::UTF16_LE:
3290 case CFileTextLines::UnicodeType::UTF16_BE:
3291 case CFileTextLines::UnicodeType::UTF32_LE:
3292 case CFileTextLines::UnicodeType::UTF32_BE:
3293 case CFileTextLines::UnicodeType::UTF8:
3294 return true;
3296 case CFileTextLines::UnicodeType::UTF16_LEBOM:
3297 type = CFileTextLines::UnicodeType::UTF16_LE;
3298 return true;
3300 case CFileTextLines::UnicodeType::UTF16_BEBOM:
3301 type = CFileTextLines::UnicodeType::UTF16_BE;
3302 return true;
3304 case CFileTextLines::UnicodeType::UTF8BOM:
3305 type = CFileTextLines::UnicodeType::UTF8;
3306 return true;
3308 return false;
3311 void CMainFrame::OnEncodingLeft( UINT cmd )
3313 if (m_pwndLeftView)
3315 if (GetKeyState(VK_CONTROL) & 0x8000)
3317 // reload with selected encoding
3318 auto saveparams = m_Data.m_arBaseFile.GetSaveParams();
3319 saveparams.m_UnicodeType = CFileTextLines::UnicodeType(cmd - ID_INDICATOR_LEFTENCODINGSTART);
3320 if (AdjustUnicodeTypeForLoad(saveparams.m_UnicodeType))
3322 m_Data.m_arBaseFile.SetSaveParams(saveparams);
3323 m_Data.m_arBaseFile.KeepEncoding();
3324 LoadViews();
3327 else
3329 m_pwndLeftView->SetTextType(CFileTextLines::UnicodeType(cmd - ID_INDICATOR_LEFTENCODINGSTART));
3330 m_pwndLeftView->RefreshViews();
3335 void CMainFrame::OnEncodingRight( UINT cmd )
3337 if (m_pwndRightView)
3339 if (GetKeyState(VK_CONTROL) & 0x8000)
3341 // reload with selected encoding
3342 auto saveparams = m_Data.m_arYourFile.GetSaveParams();
3343 saveparams.m_UnicodeType = CFileTextLines::UnicodeType(cmd - ID_INDICATOR_RIGHTENCODINGSTART);
3344 if (AdjustUnicodeTypeForLoad(saveparams.m_UnicodeType))
3346 m_Data.m_arYourFile.SetSaveParams(saveparams);
3347 m_Data.m_arYourFile.KeepEncoding();
3348 LoadViews();
3351 else
3353 m_pwndRightView->SetTextType(CFileTextLines::UnicodeType(cmd - ID_INDICATOR_RIGHTENCODINGSTART));
3354 m_pwndRightView->RefreshViews();
3359 void CMainFrame::OnEncodingBottom( UINT cmd )
3361 if (m_pwndBottomView)
3363 if (GetKeyState(VK_CONTROL) & 0x8000)
3365 // reload with selected encoding
3366 auto saveparams = m_Data.m_arTheirFile.GetSaveParams();
3367 saveparams.m_UnicodeType = CFileTextLines::UnicodeType(cmd - ID_INDICATOR_BOTTOMENCODINGSTART);
3368 if (AdjustUnicodeTypeForLoad(saveparams.m_UnicodeType))
3370 m_Data.m_arTheirFile.SetSaveParams(saveparams);
3371 m_Data.m_arTheirFile.KeepEncoding();
3372 LoadViews();
3375 else
3377 m_pwndBottomView->SetTextType(CFileTextLines::UnicodeType(cmd - ID_INDICATOR_BOTTOMENCODINGSTART));
3378 m_pwndBottomView->RefreshViews();
3383 void CMainFrame::OnEOLLeft( UINT cmd )
3385 if (m_pwndLeftView)
3387 m_pwndLeftView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_LEFTEOLSTART));
3388 m_pwndLeftView->RefreshViews();
3392 void CMainFrame::OnEOLRight( UINT cmd )
3394 if (m_pwndRightView)
3396 m_pwndRightView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_RIGHTEOLSTART));
3397 m_pwndRightView->RefreshViews();
3401 void CMainFrame::OnEOLBottom( UINT cmd )
3403 if (m_pwndBottomView)
3405 m_pwndBottomView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_BOTTOMEOLSTART));
3406 m_pwndBottomView->RefreshViews();
3410 void CMainFrame::OnTabModeLeft( UINT cmd )
3412 OnTabMode(m_pwndLeftView, (int)cmd - ID_INDICATOR_LEFTTABMODESTART);
3415 void CMainFrame::OnTabModeRight( UINT cmd )
3417 OnTabMode(m_pwndRightView, (int)cmd - ID_INDICATOR_RIGHTTABMODESTART);
3420 void CMainFrame::OnTabModeBottom( UINT cmd )
3422 OnTabMode(m_pwndBottomView, (int)cmd - ID_INDICATOR_BOTTOMTABMODESTART);
3425 void CMainFrame::OnTabMode(CBaseView *view, int cmd)
3427 if (!view)
3428 return;
3429 int nTabMode = view->GetTabMode();
3430 if (cmd == TABMODE_NONE || cmd == TABMODE_USESPACES)
3431 view->SetTabMode((nTabMode & (~TABMODE_USESPACES)) | (cmd & TABMODE_USESPACES));
3432 else if (cmd == TABMODE_SMARTINDENT) // Toggle
3433 view->SetTabMode((nTabMode & (~TABMODE_SMARTINDENT)) | ((nTabMode & TABMODE_SMARTINDENT) ? 0 : TABMODE_SMARTINDENT));
3434 else if (cmd == TABSIZEBUTTON1)
3435 view->SetTabSize(1);
3436 else if (cmd == TABSIZEBUTTON2)
3437 view->SetTabSize(2);
3438 else if (cmd == TABSIZEBUTTON4)
3439 view->SetTabSize(4);
3440 else if (cmd == TABSIZEBUTTON8)
3441 view->SetTabSize(8);
3442 else if (cmd == ENABLEEDITORCONFIG)
3443 view->SetEditorConfigEnabled(!view->GetEditorConfigEnabled());
3444 view->RefreshViews();
3447 void CMainFrame::OnUpdateEncodingLeft( CCmdUI *pCmdUI )
3449 if (m_pwndLeftView)
3451 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_LEFTENCODINGSTART) == m_pwndLeftView->GetTextType());
3452 pCmdUI->Enable(m_pwndLeftView->IsWritable() || (GetKeyState(VK_CONTROL)&0x8000));
3454 else
3455 pCmdUI->Enable(FALSE);
3458 void CMainFrame::OnUpdateEncodingRight( CCmdUI *pCmdUI )
3460 if (m_pwndRightView)
3462 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_RIGHTENCODINGSTART) == m_pwndRightView->GetTextType());
3463 pCmdUI->Enable(m_pwndRightView->IsWritable() || (GetKeyState(VK_CONTROL) & 0x8000));
3465 else
3466 pCmdUI->Enable(FALSE);
3469 void CMainFrame::OnUpdateEncodingBottom( CCmdUI *pCmdUI )
3471 if (m_pwndBottomView)
3473 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_BOTTOMENCODINGSTART) == m_pwndBottomView->GetTextType());
3474 pCmdUI->Enable(m_pwndBottomView->IsWritable() || (GetKeyState(VK_CONTROL) & 0x8000));
3476 else
3477 pCmdUI->Enable(FALSE);
3480 void CMainFrame::OnUpdateEOLLeft( CCmdUI *pCmdUI )
3482 if (m_pwndLeftView)
3484 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_LEFTEOLSTART) == m_pwndLeftView->GetLineEndings());
3485 pCmdUI->Enable(m_pwndLeftView->IsWritable());
3487 else
3488 pCmdUI->Enable(FALSE);
3491 void CMainFrame::OnUpdateEOLRight( CCmdUI *pCmdUI )
3493 if (m_pwndRightView)
3495 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_RIGHTEOLSTART) == m_pwndRightView->GetLineEndings());
3496 pCmdUI->Enable(m_pwndRightView->IsWritable());
3498 else
3499 pCmdUI->Enable(FALSE);
3502 void CMainFrame::OnUpdateEOLBottom( CCmdUI *pCmdUI )
3504 if (m_pwndBottomView)
3506 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_BOTTOMEOLSTART) == m_pwndBottomView->GetLineEndings());
3507 pCmdUI->Enable(m_pwndBottomView->IsWritable());
3509 else
3510 pCmdUI->Enable(FALSE);
3513 void CMainFrame::OnUpdateTabModeLeft(CCmdUI *pCmdUI)
3515 OnUpdateTabMode(m_pwndLeftView, pCmdUI, ID_INDICATOR_LEFTTABMODESTART);
3518 void CMainFrame::OnUpdateTabModeRight(CCmdUI *pCmdUI)
3520 OnUpdateTabMode(m_pwndRightView, pCmdUI, ID_INDICATOR_RIGHTTABMODESTART);
3523 void CMainFrame::OnUpdateTabModeBottom(CCmdUI *pCmdUI)
3525 OnUpdateTabMode(m_pwndBottomView, pCmdUI, ID_INDICATOR_BOTTOMTABMODESTART);
3528 void CMainFrame::OnUpdateTabMode(CBaseView *view, CCmdUI *pCmdUI, int startid)
3530 if (view)
3532 int cmd = (int)pCmdUI->m_nID - startid;
3533 if (cmd == TABMODE_NONE)
3534 pCmdUI->SetCheck((view->GetTabMode() & TABMODE_USESPACES) == TABMODE_NONE);
3535 else if (cmd == TABMODE_USESPACES)
3536 pCmdUI->SetCheck(view->GetTabMode() & TABMODE_USESPACES);
3537 else if (cmd == TABMODE_SMARTINDENT)
3538 pCmdUI->SetCheck(view->GetTabMode() & TABMODE_SMARTINDENT);
3539 else if (cmd == TABSIZEBUTTON1)
3540 pCmdUI->SetCheck(view->GetTabSize() == 1);
3541 else if (cmd == TABSIZEBUTTON2)
3542 pCmdUI->SetCheck(view->GetTabSize() == 2);
3543 else if (cmd == TABSIZEBUTTON4)
3544 pCmdUI->SetCheck(view->GetTabSize() == 4);
3545 else if (cmd == TABSIZEBUTTON8)
3546 pCmdUI->SetCheck(view->GetTabSize() == 8);
3547 else if (cmd == ENABLEEDITORCONFIG)
3548 pCmdUI->SetCheck(view->GetEditorConfigEnabled());
3549 pCmdUI->Enable(view->IsWritable());
3550 if (cmd == ENABLEEDITORCONFIG)
3551 pCmdUI->Enable(view->IsWritable() && view->GetEditorConfigLoaded());
3553 else
3554 pCmdUI->Enable(FALSE);
3557 BOOL CMainFrame::OnShowPopupMenu(CMFCPopupMenu* pMenuPopup)
3559 __super::OnShowPopupMenu(pMenuPopup);
3561 if (pMenuPopup == NULL)
3563 return TRUE;
3566 int iIndex = -1;
3567 if (!CMFCToolBar::IsCustomizeMode() &&
3568 (iIndex = pMenuPopup->GetMenuBar()->CommandToIndex(ID_REGEXFILTER)) >= 0)
3570 BuildRegexSubitems(pMenuPopup);
3573 return TRUE;