If only one path is specified like it would happen if someone used the "open
[TortoiseGit.git] / src / TortoiseMerge / MainFrm.cpp
blobb13b2fcc0dd3904eea1e4c1d4791a85c6ab2f941
1 // TortoiseGitMerge - a Diff/Patch program
3 // Copyright (C) 2008-2014 - TortoiseGit
4 // Copyright (C) 2004-2014 - TortoiseSVN
5 // Copyright (C) 2012-2014 - Sven Strickroth <email@cs-ware.de>
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software Foundation,
19 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "stdafx.h"
22 #include "TortoiseMerge.h"
23 #include "CustomMFCRibbonButton.h"
24 #include "OpenDlg.h"
25 #include "SysProgressDlg.h"
26 #include "Settings.h"
27 #include "MessageBox.h"
28 #include "AppUtils.h"
29 #include "PathUtils.h"
30 #include "MainFrm.h"
31 #include "LeftView.h"
32 #include "RightView.h"
33 #include "BottomView.h"
34 #include "DiffColors.h"
35 #include "SelectFileFilter.h"
36 #include "FormatMessageWrapper.h"
37 #include "TaskbarUUID.h"
38 #include "git2.h"
39 #include "SmartLibgit2Ref.h" // needs to be included after git2.h
40 #include "RegexFiltersDlg.h"
41 #include "SysInfo.h"
43 #ifdef _DEBUG
44 #define new DEBUG_NEW
45 #endif
47 CCustomMFCRibbonButton button1;
49 // CMainFrame
50 const UINT TaskBarButtonCreated = RegisterWindowMessage(L"TaskbarButtonCreated");
51 #define IDT_RELOADCHECKTIMER 123
53 IMPLEMENT_DYNCREATE(CMainFrame, CFrameWndEx)
55 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)
56 ON_WM_CREATE()
57 ON_COMMAND_RANGE(ID_VIEW_APPLOOK_WIN7, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnApplicationLook)
58 ON_UPDATE_COMMAND_UI_RANGE(IDC_STYLEBUTTON, ID_VIEW_APPLOOK_OFF_2007_AQUA, &CMainFrame::OnUpdateApplicationLook)
59 // Global help commands
60 ON_COMMAND(ID_HELP_FINDER, CFrameWndEx::OnHelpFinder)
61 ON_COMMAND(ID_HELP, CFrameWndEx::OnHelp)
62 ON_COMMAND(ID_CONTEXT_HELP, CFrameWndEx::OnContextHelp)
63 ON_COMMAND(ID_DEFAULT_HELP, CFrameWndEx::OnHelpFinder)
64 ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
65 ON_COMMAND(ID_VIEW_WHITESPACES, OnViewWhitespaces)
66 ON_WM_SIZE()
67 ON_COMMAND(ID_FILE_SAVE, OnFileSave)
68 ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
69 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave)
70 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_AS, OnUpdateFileSaveAs)
71 ON_COMMAND(ID_VIEW_ONEWAYDIFF, OnViewOnewaydiff)
72 ON_UPDATE_COMMAND_UI(ID_VIEW_ONEWAYDIFF, OnUpdateViewOnewaydiff)
73 ON_UPDATE_COMMAND_UI(ID_VIEW_WHITESPACES, OnUpdateViewWhitespaces)
74 ON_COMMAND(ID_VIEW_OPTIONS, OnViewOptions)
75 ON_WM_CLOSE()
76 ON_WM_ACTIVATE()
77 ON_COMMAND(ID_FILE_RELOAD, OnFileReload)
78 ON_COMMAND(ID_VIEW_LINEDOWN, OnViewLinedown)
79 ON_COMMAND(ID_VIEW_LINEUP, OnViewLineup)
80 ON_COMMAND(ID_VIEW_MOVEDBLOCKS, OnViewMovedBlocks)
81 ON_UPDATE_COMMAND_UI(ID_VIEW_MOVEDBLOCKS, OnUpdateViewMovedBlocks)
82 ON_UPDATE_COMMAND_UI(ID_EDIT_MARKASRESOLVED, OnUpdateMergeMarkasresolved)
83 ON_COMMAND(ID_EDIT_MARKASRESOLVED, OnMergeMarkasresolved)
84 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTCONFLICT, OnUpdateMergeNextconflict)
85 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSCONFLICT, OnUpdateMergePreviousconflict)
86 ON_WM_MOVE()
87 ON_WM_MOVING()
88 ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
89 ON_COMMAND(ID_VIEW_SWITCHLEFT, OnViewSwitchleft)
90 ON_UPDATE_COMMAND_UI(ID_VIEW_SWITCHLEFT, OnUpdateViewSwitchleft)
91 ON_COMMAND(ID_VIEW_LINELEFT, &CMainFrame::OnViewLineleft)
92 ON_COMMAND(ID_VIEW_LINERIGHT, &CMainFrame::OnViewLineright)
93 ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWFILELIST, &CMainFrame::OnUpdateViewShowfilelist)
94 ON_COMMAND(ID_VIEW_SHOWFILELIST, &CMainFrame::OnViewShowfilelist)
95 ON_COMMAND(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnEditUseTheirs)
96 ON_COMMAND(ID_EDIT_USEMYBLOCK, &CMainFrame::OnEditUseMine)
97 ON_COMMAND(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnEditUseTheirsThenMine)
98 ON_COMMAND(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnEditUseMineThenTheirs)
99 ON_COMMAND(ID_EDIT_UNDO, &CMainFrame::OnEditUndo)
100 ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, &CMainFrame::OnUpdateEditUndo)
101 ON_COMMAND(ID_EDIT_ENABLE, &CMainFrame::OnEditEnable)
102 ON_UPDATE_COMMAND_UI(ID_EDIT_ENABLE, &CMainFrame::OnUpdateEditEnable)
103 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMINETHENTHEIRBLOCK, &CMainFrame::OnUpdateEditUseminethentheirblock)
104 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMYBLOCK, &CMainFrame::OnUpdateEditUsemyblock)
105 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRBLOCK, &CMainFrame::OnUpdateEditUsetheirblock)
106 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRTHENMYBLOCK, &CMainFrame::OnUpdateEditUsetheirthenmyblock)
107 ON_COMMAND(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnViewInlinediffword)
108 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFFWORD, &CMainFrame::OnUpdateViewInlinediffword)
109 ON_COMMAND(ID_VIEW_INLINEDIFF, &CMainFrame::OnViewInlinediff)
110 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFF, &CMainFrame::OnUpdateViewInlinediff)
111 ON_UPDATE_COMMAND_UI(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnUpdateEditCreateunifieddifffile)
112 ON_COMMAND(ID_EDIT_CREATEUNIFIEDDIFFFILE, &CMainFrame::OnEditCreateunifieddifffile)
113 ON_UPDATE_COMMAND_UI(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnUpdateViewLinediffbar)
114 ON_COMMAND(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnViewLinediffbar)
115 ON_UPDATE_COMMAND_UI(ID_VIEW_LOCATORBAR, &CMainFrame::OnUpdateViewLocatorbar)
116 ON_COMMAND(ID_VIEW_LOCATORBAR, &CMainFrame::OnViewLocatorbar)
117 ON_COMMAND(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnEditUseleftblock)
118 ON_UPDATE_COMMAND_UI(ID_USEBLOCKS, &CMainFrame::OnUpdateUseBlock)
119 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnUpdateEditUseleftblock)
120 ON_COMMAND(ID_EDIT_USELEFTFILE, &CMainFrame::OnEditUseleftfile)
121 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTFILE, &CMainFrame::OnUpdateEditUseleftfile)
122 ON_COMMAND(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnEditUseblockfromleftbeforeright)
123 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnUpdateEditUseblockfromleftbeforeright)
124 ON_COMMAND(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnEditUseblockfromrightbeforeleft)
125 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnUpdateEditUseblockfromrightbeforeleft)
126 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTDIFFERENCE, &CMainFrame::OnUpdateNavigateNextdifference)
127 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSDIFFERENCE, &CMainFrame::OnUpdateNavigatePreviousdifference)
128 ON_COMMAND(ID_VIEW_COLLAPSED, &CMainFrame::OnViewCollapsed)
129 ON_UPDATE_COMMAND_UI(ID_VIEW_COLLAPSED, &CMainFrame::OnUpdateViewCollapsed)
130 ON_COMMAND(ID_VIEW_COMPAREWHITESPACES, &CMainFrame::OnViewComparewhitespaces)
131 ON_UPDATE_COMMAND_UI(ID_VIEW_COMPAREWHITESPACES, &CMainFrame::OnUpdateViewComparewhitespaces)
132 ON_COMMAND(ID_VIEW_IGNOREWHITESPACECHANGES, &CMainFrame::OnViewIgnorewhitespacechanges)
133 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREWHITESPACECHANGES, &CMainFrame::OnUpdateViewIgnorewhitespacechanges)
134 ON_COMMAND(ID_VIEW_IGNOREALLWHITESPACECHANGES, &CMainFrame::OnViewIgnoreallwhitespacechanges)
135 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREALLWHITESPACECHANGES, &CMainFrame::OnUpdateViewIgnoreallwhitespacechanges)
136 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTINLINEDIFF, &CMainFrame::OnUpdateNavigateNextinlinediff)
137 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVINLINEDIFF, &CMainFrame::OnUpdateNavigatePrevinlinediff)
138 ON_COMMAND(ID_VIEW_WRAPLONGLINES, &CMainFrame::OnViewWraplonglines)
139 ON_UPDATE_COMMAND_UI(ID_VIEW_WRAPLONGLINES, &CMainFrame::OnUpdateViewWraplonglines)
140 ON_REGISTERED_MESSAGE( TaskBarButtonCreated, CMainFrame::OnTaskbarButtonCreated )
141 ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, &CMainFrame::OnUpdateEditPaste)
142 ON_COMMAND(ID_INDICATOR_LEFTVIEW, &CMainFrame::OnIndicatorLeftview)
143 ON_COMMAND(ID_INDICATOR_RIGHTVIEW, &CMainFrame::OnIndicatorRightview)
144 ON_COMMAND(ID_INDICATOR_BOTTOMVIEW, &CMainFrame::OnIndicatorBottomview)
145 ON_WM_TIMER()
146 ON_COMMAND(ID_VIEW_IGNORECOMMENTS, &CMainFrame::OnViewIgnorecomments)
147 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNORECOMMENTS, &CMainFrame::OnUpdateViewIgnorecomments)
148 ON_COMMAND_RANGE(ID_REGEXFILTER, ID_REGEXFILTER+400, &CMainFrame::OnRegexfilter)
149 ON_UPDATE_COMMAND_UI_RANGE(ID_REGEXFILTER, ID_REGEXFILTER+400, &CMainFrame::OnUpdateViewRegexFilter)
150 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOENCODING, &CMainFrame::OnDummyEnabled)
151 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOENCODING, &CMainFrame::OnDummyEnabled)
152 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOENCODING, &CMainFrame::OnDummyEnabled)
153 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOEOL, &CMainFrame::OnDummyEnabled)
154 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOEOL, &CMainFrame::OnDummyEnabled)
155 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOEOL, &CMainFrame::OnDummyEnabled)
156 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOTABMODE, &CMainFrame::OnDummyEnabled)
157 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOTABMODE, &CMainFrame::OnDummyEnabled)
158 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOTABMODE, &CMainFrame::OnDummyEnabled)
159 ON_COMMAND_RANGE(ID_INDICATOR_LEFTENCODINGSTART, ID_INDICATOR_LEFTENCODINGSTART+19, &CMainFrame::OnEncodingLeft)
160 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTENCODINGSTART, ID_INDICATOR_RIGHTENCODINGSTART+19, &CMainFrame::OnEncodingRight)
161 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMENCODINGSTART, ID_INDICATOR_BOTTOMENCODINGSTART+19, &CMainFrame::OnEncodingBottom)
162 ON_COMMAND_RANGE(ID_INDICATOR_LEFTEOLSTART, ID_INDICATOR_LEFTEOLSTART+19, &CMainFrame::OnEOLLeft)
163 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTEOLSTART, ID_INDICATOR_RIGHTEOLSTART+19, &CMainFrame::OnEOLRight)
164 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMEOLSTART, ID_INDICATOR_BOTTOMEOLSTART+19, &CMainFrame::OnEOLBottom)
165 ON_COMMAND_RANGE(ID_INDICATOR_LEFTTABMODESTART, ID_INDICATOR_LEFTTABMODESTART+19, &CMainFrame::OnTabModeLeft)
166 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTTABMODESTART, ID_INDICATOR_RIGHTTABMODESTART+19, &CMainFrame::OnTabModeRight)
167 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMTABMODESTART, ID_INDICATOR_BOTTOMTABMODESTART+19, &CMainFrame::OnTabModeBottom)
168 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTENCODINGSTART, ID_INDICATOR_LEFTENCODINGSTART+19, &CMainFrame::OnUpdateEncodingLeft)
169 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTENCODINGSTART, ID_INDICATOR_RIGHTENCODINGSTART+19, &CMainFrame::OnUpdateEncodingRight)
170 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMENCODINGSTART, ID_INDICATOR_BOTTOMENCODINGSTART+19, &CMainFrame::OnUpdateEncodingBottom)
171 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTEOLSTART, ID_INDICATOR_LEFTEOLSTART+19, &CMainFrame::OnUpdateEOLLeft)
172 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTEOLSTART, ID_INDICATOR_RIGHTEOLSTART+19, &CMainFrame::OnUpdateEOLRight)
173 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMEOLSTART, ID_INDICATOR_BOTTOMEOLSTART+19, &CMainFrame::OnUpdateEOLBottom)
174 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTTABMODESTART, ID_INDICATOR_LEFTTABMODESTART+19, &CMainFrame::OnUpdateTabModeLeft)
175 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTTABMODESTART, ID_INDICATOR_RIGHTTABMODESTART+19, &CMainFrame::OnUpdateTabModeRight)
176 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMTABMODESTART, ID_INDICATOR_BOTTOMTABMODESTART+19, &CMainFrame::OnUpdateTabModeBottom)
177 END_MESSAGE_MAP()
179 static UINT indicators[] =
181 ID_SEPARATOR, // status line indicator
182 ID_INDICATOR_LEFTVIEW,
183 ID_INDICATOR_RIGHTVIEW,
184 ID_INDICATOR_BOTTOMVIEW,
185 ID_INDICATOR_CAPS,
186 ID_INDICATOR_NUM,
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 , resolveMsgWnd(0)
209 , resolveMsgWParam(0)
210 , resolveMsgLParam(0)
211 , m_regWrapLines(L"Software\\TortoiseGitMerge\\WrapLines", 0)
212 , m_regViewModedBlocks(L"Software\\TortoiseGitMerge\\ViewMovedBlocks", TRUE)
213 , m_regOneWay(L"Software\\TortoiseGitMerge\\OnePane")
214 , m_regCollapsed(L"Software\\TortoiseGitMerge\\Collapsed", 0)
215 , m_regInlineDiff(L"Software\\TortoiseGitMerge\\DisplayBinDiff", TRUE)
216 , m_regUseRibbons(L"Software\\TortoiseGitMerge\\UseRibbons", TRUE)
217 , m_regUseTaskDialog(L"Software\\TortoiseGitMerge\\UseTaskDialog", 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 #if _WIN64
229 if (SysInfo::Instance().IsXP())
230 m_bUseRibbons = FALSE;
231 #endif
232 m_bUseTaskDialog = CTaskDialog::IsSupported() && (DWORD)m_regUseTaskDialog;
233 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
236 CMainFrame::~CMainFrame()
240 LRESULT CMainFrame::OnTaskbarButtonCreated(WPARAM /*wParam*/, LPARAM /*lParam*/)
242 SetUUIDOverlayIcon(m_hWnd);
243 return 0;
247 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
249 if (CFrameWndEx::OnCreate(lpCreateStruct) == -1)
250 return -1;
252 OnApplicationLook(theApp.m_nAppLook);
254 if (m_bUseRibbons)
256 m_wndRibbonBar.Create(this);
257 m_wndRibbonBar.LoadFromResource(IDR_RIBBON);
259 // enable the dialog launch button on the view panel
260 CMFCRibbonCategory * pMainCat = m_wndRibbonBar.GetCategory(1);
261 if (pMainCat)
263 CMFCRibbonPanel * pPanel = pMainCat->GetPanel(3);
264 if (pPanel)
265 pPanel->EnableLaunchButton(ID_VIEW_OPTIONS);
267 // now replace all buttons with our custom button class
268 for (int i = 0; i < m_wndRibbonBar.GetCategoryCount(); ++i)
270 CMFCRibbonCategory * pCat = m_wndRibbonBar.GetCategory(i);
271 for (int j = 0; j < pCat->GetPanelCount(); ++j)
273 CMFCRibbonPanel * pPanel = pCat->GetPanel(j);
274 CList<UINT, UINT> lstItems;
275 pPanel->GetItemIDsList(lstItems);
276 while (!lstItems.IsEmpty())
278 UINT id = lstItems.GetHead();
279 lstItems.RemoveHead();
280 CMFCRibbonButton * pButton = dynamic_cast<CMFCRibbonButton*>(pPanel->FindByID(id));
281 if (pButton)
283 CCustomMFCRibbonButton * c = new CCustomMFCRibbonButton(id, pButton->GetText());
284 pPanel->ReplaceByID(id, c);
289 BuildRegexSubitems();
290 if (!m_wndRibbonStatusBar.Create(this))
292 TRACE0("Failed to create ribbon status bar\n");
293 return -1; // fail to create
295 m_wndRibbonStatusBar.AddElement(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(AFX_IDS_IDLEMESSAGE)), TRUE), L"");
297 std::unique_ptr<CMFCRibbonButtonsGroup> apBtnGroupLeft(new CMFCRibbonButtonsGroup);
298 apBtnGroupLeft->SetID(ID_INDICATOR_LEFTVIEW);
299 apBtnGroupLeft->AddButton(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(IDS_STATUSBAR_LEFTVIEW)), TRUE));
300 CMFCRibbonButton * pButton = new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOENCODING, L"");
301 FillEncodingButton(pButton, ID_INDICATOR_LEFTENCODINGSTART);
302 apBtnGroupLeft->AddButton(pButton);
303 pButton = new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOEOL, L"");
304 FillEOLButton(pButton, ID_INDICATOR_LEFTEOLSTART);
305 apBtnGroupLeft->AddButton(pButton);
306 pButton = new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOTABMODE, L"");
307 FillTabModeButton(pButton, ID_INDICATOR_LEFTTABMODESTART);
308 apBtnGroupLeft->AddButton(pButton);
309 apBtnGroupLeft->AddButton(new CMFCRibbonStatusBarPane(ID_INDICATOR_LEFTVIEW, L"", TRUE));
310 m_wndRibbonStatusBar.AddExtendedElement(apBtnGroupLeft.release(), L"");
312 std::unique_ptr<CMFCRibbonButtonsGroup> apBtnGroupRight(new CMFCRibbonButtonsGroup);
313 apBtnGroupRight->SetID(ID_INDICATOR_RIGHTVIEW);
314 apBtnGroupRight->AddButton(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(IDS_STATUSBAR_RIGHTVIEW)), TRUE));
315 pButton = new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOENCODING, L"");
316 FillEncodingButton(pButton, ID_INDICATOR_RIGHTENCODINGSTART);
317 apBtnGroupRight->AddButton(pButton);
318 pButton = new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOEOL, L"");
319 FillEOLButton(pButton, ID_INDICATOR_RIGHTEOLSTART);
320 apBtnGroupRight->AddButton(pButton);
321 pButton = new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOTABMODE, L"");
322 FillTabModeButton(pButton, ID_INDICATOR_RIGHTTABMODESTART);
323 apBtnGroupRight->AddButton(pButton);
324 apBtnGroupRight->AddButton(new CMFCRibbonStatusBarPane(ID_INDICATOR_RIGHTVIEW, L"", TRUE));
325 m_wndRibbonStatusBar.AddExtendedElement(apBtnGroupRight.release(), L"");
327 else
329 if (!m_wndMenuBar.Create(this))
331 TRACE0("Failed to create menubar\n");
332 return -1; // fail to create
334 m_wndMenuBar.SetPaneStyle(m_wndMenuBar.GetPaneStyle() | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY);
336 // prevent the menu bar from taking the focus on activation
337 CMFCPopupMenu::SetForceMenuFocus(FALSE);
338 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))
340 TRACE0("Failed to create toolbar\n");
341 return -1; // fail to create
343 m_wndToolBar.SetWindowText(_T("Main"));
344 if (!m_wndStatusBar.Create(this) ||
345 !m_wndStatusBar.SetIndicators(indicators,
346 _countof(indicators)))
348 TRACE0("Failed to create status bar\n");
349 return -1; // fail to create
351 m_wndStatusBar.EnablePaneDoubleClick();
354 if (!m_wndLocatorBar.Create(this, IDD_DIFFLOCATOR,
355 CBRS_ALIGN_LEFT | CBRS_SIZE_FIXED, ID_VIEW_LOCATORBAR))
357 TRACE0("Failed to create dialogbar\n");
358 return -1; // fail to create
360 if (!m_wndLineDiffBar.Create(this, IDD_LINEDIFF,
361 CBRS_ALIGN_BOTTOM | CBRS_SIZE_FIXED, ID_VIEW_LINEDIFFBAR))
363 TRACE0("Failed to create dialogbar\n");
364 return -1; // fail to create
366 m_wndLocatorBar.m_pMainFrm = this;
367 m_wndLineDiffBar.m_pMainFrm = this;
369 EnableDocking(CBRS_ALIGN_ANY);
370 if (!m_bUseRibbons)
372 m_wndMenuBar.EnableDocking(CBRS_ALIGN_TOP);
373 m_wndToolBar.EnableDocking(CBRS_ALIGN_TOP);
374 DockPane(&m_wndMenuBar);
375 DockPane(&m_wndToolBar);
377 DockPane(&m_wndLocatorBar);
378 DockPane(&m_wndLineDiffBar);
379 ShowPane(&m_wndLocatorBar, true, false, true);
380 ShowPane(&m_wndLineDiffBar, true, false, true);
382 m_wndLocatorBar.EnableGripper(FALSE);
383 m_wndLineDiffBar.EnableGripper(FALSE);
385 return 0;
388 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
390 if( !CFrameWndEx::PreCreateWindow(cs) )
391 return FALSE;
392 return TRUE;
395 void CMainFrame::OnApplicationLook(UINT id)
397 CWaitCursor wait;
399 theApp.m_nAppLook = id;
401 switch (theApp.m_nAppLook)
403 case ID_VIEW_APPLOOK_WIN_2000:
404 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManager));
405 m_wndRibbonBar.SetWindows7Look(FALSE);
406 break;
408 case ID_VIEW_APPLOOK_OFF_XP:
409 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOfficeXP));
410 m_wndRibbonBar.SetWindows7Look(FALSE);
411 break;
413 case ID_VIEW_APPLOOK_WIN_XP:
414 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
415 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
416 m_wndRibbonBar.SetWindows7Look(FALSE);
417 break;
419 case ID_VIEW_APPLOOK_OFF_2003:
420 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2003));
421 CDockingManager::SetDockingMode(DT_SMART);
422 m_wndRibbonBar.SetWindows7Look(FALSE);
423 break;
425 case ID_VIEW_APPLOOK_VS_2005:
426 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2005));
427 CDockingManager::SetDockingMode(DT_SMART);
428 m_wndRibbonBar.SetWindows7Look(FALSE);
429 break;
431 case ID_VIEW_APPLOOK_VS_2008:
432 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2008));
433 CDockingManager::SetDockingMode(DT_SMART);
434 m_wndRibbonBar.SetWindows7Look(FALSE);
435 break;
437 case ID_VIEW_APPLOOK_WIN7:
438 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows7));
439 CDockingManager::SetDockingMode(DT_SMART);
440 m_wndRibbonBar.SetWindows7Look(TRUE);
441 break;
443 default:
444 switch (theApp.m_nAppLook)
446 case ID_VIEW_APPLOOK_OFF_2007_BLUE:
447 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_LunaBlue);
448 break;
450 case ID_VIEW_APPLOOK_OFF_2007_BLACK:
451 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_ObsidianBlack);
452 break;
454 case ID_VIEW_APPLOOK_OFF_2007_SILVER:
455 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Silver);
456 break;
458 case ID_VIEW_APPLOOK_OFF_2007_AQUA:
459 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Aqua);
460 break;
463 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));
464 CDockingManager::SetDockingMode(DT_SMART);
465 m_wndRibbonBar.SetWindows7Look(FALSE);
468 RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_FRAME | RDW_ERASE);
470 theApp.WriteInt(_T("ApplicationLook"), theApp.m_nAppLook);
473 void CMainFrame::OnUpdateApplicationLook(CCmdUI* pCmdUI)
475 pCmdUI->Enable();
476 pCmdUI->SetRadio(theApp.m_nAppLook == pCmdUI->m_nID);
480 // CMainFrame diagnostics
482 #ifdef _DEBUG
483 void CMainFrame::AssertValid() const
485 CFrameWndEx::AssertValid();
488 void CMainFrame::Dump(CDumpContext& dc) const
490 CFrameWndEx::Dump(dc);
493 #endif //_DEBUG
496 // CMainFrame message handlers
499 BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)
501 CRect cr;
502 GetClientRect( &cr);
505 // split into three panes:
506 // -------------
507 // | | |
508 // | | |
509 // |------------
510 // | |
511 // | |
512 // |------------
514 // create a splitter with 2 rows, 1 column
515 if (!m_wndSplitter.CreateStatic(this, 2, 1))
517 TRACE0("Failed to CreateStaticSplitter\n");
518 return FALSE;
521 // add the second splitter pane - which is a nested splitter with 2 columns
522 if (!m_wndSplitter2.CreateStatic(
523 &m_wndSplitter, // our parent window is the first splitter
524 1, 2, // the new splitter is 1 row, 2 columns
525 WS_CHILD | WS_VISIBLE | WS_BORDER, // style, WS_BORDER is needed
526 m_wndSplitter.IdFromRowCol(0, 0)
527 // new splitter is in the first row, 1st column of first splitter
530 TRACE0("Failed to create nested splitter\n");
531 return FALSE;
533 // add the first splitter pane - the default view in row 0
534 if (!m_wndSplitter.CreateView(1, 0,
535 RUNTIME_CLASS(CBottomView), CSize(cr.Width(), cr.Height()), pContext))
537 TRACE0("Failed to create first pane\n");
538 return FALSE;
540 m_pwndBottomView = (CBottomView *)m_wndSplitter.GetPane(1,0);
541 m_pwndBottomView->m_pwndLocator = &m_wndLocatorBar;
542 m_pwndBottomView->m_pwndLineDiffBar = &m_wndLineDiffBar;
543 if (m_bUseRibbons)
544 m_pwndBottomView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
545 else
546 m_pwndBottomView->m_pwndStatusBar = &m_wndStatusBar;
547 m_pwndBottomView->m_pMainFrame = this;
549 // now create the two views inside the nested splitter
551 if (!m_wndSplitter2.CreateView(0, 0,
552 RUNTIME_CLASS(CLeftView), CSize(cr.Width()/2, cr.Height()/2), pContext))
554 TRACE0("Failed to create second pane\n");
555 return FALSE;
557 m_pwndLeftView = (CLeftView *)m_wndSplitter2.GetPane(0,0);
558 m_pwndLeftView->m_pwndLocator = &m_wndLocatorBar;
559 m_pwndLeftView->m_pwndLineDiffBar = &m_wndLineDiffBar;
560 if (m_bUseRibbons)
561 m_pwndLeftView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
562 else
563 m_pwndLeftView->m_pwndStatusBar = &m_wndStatusBar;
564 m_pwndLeftView->m_pMainFrame = this;
566 if (!m_wndSplitter2.CreateView(0, 1,
567 RUNTIME_CLASS(CRightView), CSize(cr.Width()/2, cr.Height()/2), pContext))
569 TRACE0("Failed to create third pane\n");
570 return FALSE;
572 m_pwndRightView = (CRightView *)m_wndSplitter2.GetPane(0,1);
573 m_pwndRightView->m_pwndLocator = &m_wndLocatorBar;
574 m_pwndRightView->m_pwndLineDiffBar = &m_wndLineDiffBar;
575 if (m_bUseRibbons)
576 m_pwndRightView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
577 else
578 m_pwndRightView->m_pwndStatusBar = &m_wndStatusBar;
579 m_pwndRightView->m_pMainFrame = this;
580 m_bInitSplitter = TRUE;
582 m_dlgFilePatches.Create(IDD_FILEPATCHES, this);
583 UpdateLayout();
584 return TRUE;
587 // Callback function
588 BOOL CMainFrame::PatchFile(CString sFilePath, bool /*bContentMods*/, bool bPropMods, CString sVersion, BOOL bAutoPatch)
590 CString sDummy;
591 //"dry run" was successful, so save the patched file somewhere...
592 CString sTempFile = CTempFiles::Instance().GetTempFilePathString();
593 CString sRejectedFile, sBasePath;
594 if (m_Patch.GetPatchResult(sFilePath, sTempFile, sRejectedFile, sBasePath) < 0)
596 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
597 return FALSE;
599 sFilePath = m_Patch.GetTargetPath() + _T("\\") + sFilePath;
600 sFilePath.Replace('/', '\\');
601 if (sBasePath.IsEmpty())
602 sBasePath = sFilePath;
603 if (m_bReversedPatch)
605 m_Data.m_baseFile.SetFileName(sTempFile);
606 CString temp;
607 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
608 m_Data.m_baseFile.SetDescriptiveName(temp);
609 m_Data.m_yourFile.SetFileName(sFilePath);
610 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchOriginal);
611 m_Data.m_yourFile.SetDescriptiveName(temp);
612 m_Data.m_theirFile.SetOutOfUse();
613 m_Data.m_mergedFile.SetOutOfUse();
615 else
617 if ((!PathFileExists(sBasePath))||(PathIsDirectory(sBasePath)))
619 m_Data.m_baseFile.SetFileName(CTempFiles::Instance().GetTempFilePathString());
620 m_Data.m_baseFile.CreateEmptyFile();
622 else
624 m_Data.m_baseFile.SetFileName(sBasePath);
626 CString sDescription;
627 sDescription.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sBasePath), (LPCTSTR)m_Data.m_sPatchOriginal);
628 m_Data.m_baseFile.SetDescriptiveName(sDescription);
629 if (sBasePath == sFilePath)
631 m_Data.m_yourFile.SetFileName(sTempFile);
632 CString temp;
633 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sBasePath), (LPCTSTR)m_Data.m_sPatchPatched);
634 m_Data.m_yourFile.SetDescriptiveName(temp);
635 m_Data.m_theirFile.SetOutOfUse();
637 else
639 if (!PathFileExists(sFilePath) || PathIsDirectory(sFilePath))
641 m_Data.m_yourFile.SetFileName(CTempFiles::Instance().GetTempFilePathString());
642 m_Data.m_yourFile.CreateEmptyFile();
643 CString temp;
644 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), CString(MAKEINTRESOURCE(IDS_NOTFOUNDVIEWTITLEINDICATOR)));
645 m_Data.m_yourFile.SetDescriptiveName(temp);
647 else
648 m_Data.m_yourFile.SetFileName(sFilePath);
649 m_Data.m_theirFile.SetFileName(sTempFile);
650 CString temp;
651 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
652 m_Data.m_theirFile.SetDescriptiveName(temp);
654 m_Data.m_mergedFile.SetFileName(sFilePath);
655 m_Data.m_bPatchRequired = bPropMods;
657 TRACE(_T("comparing %s\nwith the patched result %s\n"), (LPCTSTR)sFilePath, (LPCTSTR)sTempFile);
659 LoadViews();
660 if (!sRejectedFile.IsEmpty())
662 #if 0 // TGIT TODO
663 // start TortoiseUDiff with the rejected hunks
664 CString sTitle;
665 sTitle.Format(IDS_TITLE_REJECTEDHUNKS, (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath));
666 CAppUtils::StartUnifiedDiffViewer(sRejectedFile, sTitle);
667 #endif
669 if (bAutoPatch)
671 if (sBasePath != sFilePath && HasConflictsWontKeep())
672 return FALSE;
674 PatchSave();
676 return TRUE;
679 // Callback function
680 BOOL CMainFrame::DiffFiles(CString sURL1, CString sRev1, CString sURL2, CString sRev2)
682 CString tempfile1 = CTempFiles::Instance().GetTempFilePathString();
683 CString tempfile2 = CTempFiles::Instance().GetTempFilePathString();
685 ASSERT(tempfile1.Compare(tempfile2));
687 CString sTemp;
688 CSysProgressDlg progDlg;
689 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev1);
690 progDlg.SetLine(1, sTemp, true);
691 progDlg.SetLine(2, sURL1, true);
692 sTemp.LoadString(IDS_GETVERSIONOFFILETITLE);
693 progDlg.SetTitle(sTemp);
694 progDlg.SetShowProgressBar(true);
695 progDlg.SetAnimation(IDR_DOWNLOAD);
696 progDlg.SetTime(FALSE);
697 progDlg.SetProgress(1,100);
698 progDlg.ShowModeless(this);
699 if (!CAppUtils::GetVersionedFile(sURL1, sRev1, tempfile1, &progDlg, m_hWnd))
701 progDlg.Stop();
702 CString sErrMsg;
703 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev1, (LPCTSTR)sURL1);
704 MessageBox(sErrMsg, NULL, MB_ICONERROR);
705 return FALSE;
707 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev2);
708 progDlg.SetLine(1, sTemp, true);
709 progDlg.SetLine(2, sURL2, true);
710 progDlg.SetProgress(50, 100);
711 if (!CAppUtils::GetVersionedFile(sURL2, sRev2, tempfile2, &progDlg, m_hWnd))
713 progDlg.Stop();
714 CString sErrMsg;
715 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev2, (LPCTSTR)sURL2);
716 MessageBox(sErrMsg, NULL, MB_ICONERROR);
717 return FALSE;
719 progDlg.SetProgress(100,100);
720 progDlg.Stop();
721 CString temp;
722 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL1), (LPCTSTR)sRev1);
723 m_Data.m_baseFile.SetFileName(tempfile1);
724 m_Data.m_baseFile.SetDescriptiveName(temp);
725 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL2), (LPCTSTR)sRev2);
726 m_Data.m_yourFile.SetFileName(tempfile2);
727 m_Data.m_yourFile.SetDescriptiveName(temp);
729 LoadViews();
731 return TRUE;
734 void CMainFrame::OnFileOpen()
736 if (CheckForSave(CHFSR_OPEN)==IDCANCEL)
737 return;
738 return OnFileOpen(false);
741 void CMainFrame::OnFileOpen(bool fillyours)
743 COpenDlg dlg;
744 if (fillyours)
745 dlg.m_sBaseFile = m_Data.m_yourFile.GetFilename();
746 if (dlg.DoModal() != IDOK)
748 return;
750 m_dlgFilePatches.ShowWindow(SW_HIDE);
751 m_dlgFilePatches.Init(NULL, NULL, CString(), NULL);
752 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,
753 (LPCTSTR)dlg.m_sUnifiedDiffFile, (LPCTSTR)dlg.m_sPatchDirectory);
754 m_Data.m_baseFile.SetFileName(dlg.m_sBaseFile);
755 m_Data.m_theirFile.SetFileName(dlg.m_sTheirFile);
756 m_Data.m_yourFile.SetFileName(dlg.m_sYourFile);
757 m_Data.m_sDiffFile = dlg.m_sUnifiedDiffFile;
758 m_Data.m_sPatchPath = dlg.m_sPatchDirectory;
759 m_Data.m_mergedFile.SetOutOfUse();
760 CCrashReport::Instance().AddFile2(dlg.m_sBaseFile, NULL, _T("Basefile"), CR_AF_MAKE_FILE_COPY);
761 CCrashReport::Instance().AddFile2(dlg.m_sTheirFile, NULL, _T("Theirfile"), CR_AF_MAKE_FILE_COPY);
762 CCrashReport::Instance().AddFile2(dlg.m_sYourFile, NULL, _T("Yourfile"), CR_AF_MAKE_FILE_COPY);
763 CCrashReport::Instance().AddFile2(dlg.m_sUnifiedDiffFile, NULL, _T("Difffile"), CR_AF_MAKE_FILE_COPY);
765 if (!m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && m_Data.IsYourFileInUse())
767 // a diff between two files means "Yours" against "Base", not "Theirs" against "Yours"
768 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
770 if (m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && !m_Data.IsYourFileInUse())
772 // a diff between two files means "Yours" against "Base", not "Theirs" against "Base"
773 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
775 m_bSaveRequired = false;
777 LoadViews();
780 void CMainFrame::ClearViewNamesAndPaths()
782 m_pwndLeftView->m_sWindowName.Empty();
783 m_pwndLeftView->m_sFullFilePath.Empty();
784 m_pwndLeftView->m_sReflectedName.Empty();
785 m_pwndRightView->m_sWindowName.Empty();
786 m_pwndRightView->m_sFullFilePath.Empty();
787 m_pwndRightView->m_sReflectedName.Empty();
788 m_pwndBottomView->m_sWindowName.Empty();
789 m_pwndBottomView->m_sFullFilePath.Empty();
790 m_pwndBottomView->m_sReflectedName.Empty();
793 bool CMainFrame::LoadViews(int line)
795 LoadIgnoreCommentData();
796 m_Data.SetBlame(m_bBlame);
797 m_Data.SetMovedBlocks(m_bViewMovedBlocks);
798 m_bHasConflicts = false;
799 CBaseView* pwndActiveView = m_pwndLeftView;
800 int nOldLine = m_pwndRightView ? m_pwndRightView->m_nTopLine : -1;
801 int nOldLineNumber =
802 m_pwndRightView && m_pwndRightView->m_pViewData ?
803 m_pwndRightView->m_pViewData->GetLineNumber(m_pwndRightView->m_nTopLine) : -1;
804 POINT ptOldCaretPos = {-1, -1};
805 if (m_pwndRightView && m_pwndRightView->IsTarget())
806 ptOldCaretPos = m_pwndRightView->GetCaretPosition();
807 if (m_pwndBottomView && m_pwndBottomView->IsTarget())
808 ptOldCaretPos = m_pwndBottomView->GetCaretPosition();
809 CString sExt = CPathUtils::GetFileExtFromPath(m_Data.m_baseFile.GetFilename()).MakeLower();
810 sExt.TrimLeft(L".");
811 auto sC = m_IgnoreCommentsMap.find(sExt);
812 if (sC == m_IgnoreCommentsMap.end())
814 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_yourFile.GetFilename()).MakeLower();
815 sC = m_IgnoreCommentsMap.find(sExt);
816 if (sC == m_IgnoreCommentsMap.end())
818 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_theirFile.GetFilename()).MakeLower();
819 sC = m_IgnoreCommentsMap.find(sExt);
822 if (sC != m_IgnoreCommentsMap.end())
823 m_Data.SetCommentTokens(std::get<0>(sC->second), std::get<1>(sC->second), std::get<2>(sC->second));
824 else
825 m_Data.SetCommentTokens(L"", L"", L"");
826 if (!m_Data.Load())
828 m_pwndLeftView->BuildAllScreen2ViewVector();
829 m_pwndLeftView->DocumentUpdated();
830 m_pwndRightView->DocumentUpdated();
831 m_pwndBottomView->DocumentUpdated();
832 m_wndLocatorBar.DocumentUpdated();
833 m_wndLineDiffBar.DocumentUpdated();
834 ::MessageBox(m_hWnd, m_Data.GetError(), _T("TortoiseGitMerge"), MB_ICONERROR);
835 m_Data.m_mergedFile.SetOutOfUse();
836 m_bSaveRequired = false;
837 return false;
839 SetWindowTitle();
840 m_pwndLeftView->BuildAllScreen2ViewVector();
841 m_pwndLeftView->DocumentUpdated();
842 m_pwndRightView->DocumentUpdated();
843 m_pwndBottomView->DocumentUpdated();
844 m_wndLocatorBar.DocumentUpdated();
845 m_wndLineDiffBar.DocumentUpdated();
847 m_pwndLeftView->SetWritable(false);
848 m_pwndLeftView->SetWritableIsChangable(false);
849 m_pwndLeftView->SetTarget(false);
850 m_pwndRightView->SetWritable(false);
851 m_pwndRightView->SetWritableIsChangable(false);
852 m_pwndRightView->SetTarget(false);
853 m_pwndBottomView->SetWritable(false);
854 m_pwndBottomView->SetWritableIsChangable(false);
855 m_pwndBottomView->SetTarget(false);
857 if (!m_Data.IsBaseFileInUse())
859 CSysProgressDlg progDlg;
860 if (m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
862 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
864 else if ((!m_Data.m_sDiffFile.IsEmpty())&&(!m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg)))
866 progDlg.Stop();
867 ClearViewNamesAndPaths();
868 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
869 m_bSaveRequired = false;
870 return false;
872 progDlg.Stop();
873 if (m_Patch.GetNumberOfFiles() > 0)
875 CString betterpatchpath = m_Patch.CheckPatchPath(m_Data.m_sPatchPath);
876 if (betterpatchpath.CompareNoCase(m_Data.m_sPatchPath)!=0)
878 CString msg;
879 msg.Format(IDS_WARNBETTERPATCHPATHFOUND, (LPCTSTR)m_Data.m_sPatchPath, (LPCTSTR)betterpatchpath);
880 if (m_bUseTaskDialog)
882 CTaskDialog taskdlg(msg,
883 CString(MAKEINTRESOURCE(IDS_WARNBETTERPATCHPATHFOUND_TASK2)),
884 L"TortoiseGitMerge",
886 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
887 CString task3;
888 WCHAR t3[MAX_PATH] = {0};
889 CString cp = betterpatchpath.Left(MAX_PATH-1);
890 PathCompactPathEx(t3, cp, 50, 0);
891 task3.Format(IDS_WARNBETTERPATCHPATHFOUND_TASK3, t3);
892 taskdlg.AddCommandControl(1, task3);
893 CString task4;
894 WCHAR t4[MAX_PATH] = {0};
895 cp = m_Data.m_sPatchPath.Left(MAX_PATH-1);
896 PathCompactPathEx(t4, cp, 50, 0);
897 task4.Format(IDS_WARNBETTERPATCHPATHFOUND_TASK4, t4);
898 taskdlg.AddCommandControl(2, task4);
899 taskdlg.SetDefaultCommandControl(1);
900 taskdlg.SetMainIcon(TD_INFORMATION_ICON);
901 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
902 if (taskdlg.DoModal(m_hWnd) == 1)
904 m_Data.m_sPatchPath = betterpatchpath;
905 m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg);
908 else if (::MessageBox(m_hWnd, msg, _T("TortoiseGitMerge"), MB_ICONQUESTION | MB_YESNO)==IDYES)
910 m_Data.m_sPatchPath = betterpatchpath;
911 m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg);
914 m_dlgFilePatches.Init(&m_Patch, this, m_Data.m_sPatchPath, this);
915 m_dlgFilePatches.ShowWindow(SW_SHOW);
916 ClearViewNamesAndPaths();
917 if (!m_wndSplitter.IsRowHidden(1))
918 m_wndSplitter.HideRow(1);
919 m_pwndLeftView->SetHidden(FALSE);
920 m_pwndRightView->SetHidden(FALSE);
921 m_pwndBottomView->SetHidden(TRUE);
924 if (m_Data.IsBaseFileInUse() && !m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
926 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
928 if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && !m_Data.IsTheirFileInUse())
930 //diff between YOUR and BASE
931 if (m_bOneWay)
933 pwndActiveView = m_pwndLeftView;
934 if (!m_wndSplitter2.IsColumnHidden(1))
935 m_wndSplitter2.HideColumn(1);
937 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseBoth;
938 m_pwndLeftView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
939 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
940 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName() + _T(" - ") + m_Data.m_yourFile.GetWindowName();
941 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename() + _T(" - ") + m_Data.m_yourFile.GetFilename();
942 m_pwndLeftView->m_sReflectedName = m_Data.m_yourFile.GetReflectedName();
943 m_pwndLeftView->m_pWorkingFile = &m_Data.m_yourFile;
944 m_pwndLeftView->SetTarget();
945 m_pwndLeftView->SetWritableIsChangable(true);
947 m_pwndRightView->m_pViewData = NULL;
948 m_pwndRightView->m_pWorkingFile = NULL;
949 m_pwndBottomView->m_pViewData = NULL;
950 m_pwndBottomView->m_pWorkingFile = NULL;
952 if (!m_wndSplitter.IsRowHidden(1))
953 m_wndSplitter.HideRow(1);
954 m_pwndLeftView->SetHidden(FALSE);
955 m_pwndRightView->SetHidden(TRUE);
956 m_pwndBottomView->SetHidden(TRUE);
957 ::SetWindowPos(m_pwndLeftView->m_hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
959 else
961 pwndActiveView = m_pwndRightView;
962 if (m_wndSplitter2.IsColumnHidden(1))
963 m_wndSplitter2.ShowColumn();
965 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseLeft;
966 m_pwndLeftView->SetTextType(m_Data.m_arBaseFile.GetUnicodeType());
967 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arBaseFile.GetLineEndings());
968 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName();
969 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename();
970 m_pwndLeftView->m_sConvertedFilePath = m_Data.m_baseFile.GetConvertedFileName();
971 m_pwndLeftView->m_sReflectedName = m_Data.m_baseFile.GetReflectedName();
972 m_pwndLeftView->m_pWorkingFile = &m_Data.m_baseFile;
973 m_pwndLeftView->SetWritableIsChangable(true);
975 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseRight;
976 m_pwndRightView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
977 m_pwndRightView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
978 m_pwndRightView->m_sWindowName = m_Data.m_yourFile.GetWindowName();
979 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
980 m_pwndRightView->m_sConvertedFilePath = m_Data.m_yourFile.GetConvertedFileName();
981 m_pwndRightView->m_sReflectedName = m_Data.m_yourFile.GetReflectedName();
982 m_pwndRightView->m_pWorkingFile = &m_Data.m_yourFile;
983 m_pwndRightView->SetWritable();
984 m_pwndRightView->SetTarget();
986 m_pwndBottomView->m_pViewData = NULL;
987 m_pwndBottomView->m_pWorkingFile = NULL;
989 if (!m_wndSplitter.IsRowHidden(1))
990 m_wndSplitter.HideRow(1);
991 m_pwndLeftView->SetHidden(FALSE);
992 m_pwndRightView->SetHidden(FALSE);
993 m_pwndBottomView->SetHidden(TRUE);
995 bool hasMods, hasConflicts, hasWhitespaceMods;
996 pwndActiveView->CheckModifications(hasMods, hasConflicts, hasWhitespaceMods);
997 if (!hasMods && !hasConflicts)
999 // files appear identical, show a dialog informing the user that there are or might
1000 // be other differences
1001 bool hasEncodingDiff = m_Data.m_arBaseFile.GetUnicodeType() != m_Data.m_arYourFile.GetUnicodeType();
1002 bool hasEOLDiff = m_Data.m_arBaseFile.GetLineEndings() != m_Data.m_arYourFile.GetLineEndings();
1003 if (hasWhitespaceMods || hasEncodingDiff || hasEOLDiff)
1005 // text is identical, but the files do not match
1006 CString sWarning(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_MAIN));
1007 CString sWhitespace(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_WHITESPACE));
1008 CString sEncoding(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_ENCODING));
1009 CString sEOL(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_EOL));
1010 if (hasWhitespaceMods)
1012 sWarning += L"\r\n";
1013 sWarning += sWhitespace;
1015 if (hasEncodingDiff)
1017 sWarning += L"\r\n";
1018 sWarning += sEncoding;
1019 sWarning += L" (";
1020 sWarning += m_Data.m_arBaseFile.GetEncodingName(m_Data.m_arBaseFile.GetUnicodeType());
1021 sWarning += L", ";
1022 sWarning += m_Data.m_arYourFile.GetEncodingName(m_Data.m_arYourFile.GetUnicodeType());
1023 sWarning += L")";
1025 if (hasEOLDiff)
1027 sWarning += L"\r\n";
1028 sWarning += sEOL;
1030 AfxMessageBox(sWarning, MB_ICONINFORMATION);
1034 else if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
1036 //diff between THEIR, YOUR and BASE
1037 m_pwndBottomView->SetWritable();
1038 m_pwndBottomView->SetTarget();
1039 pwndActiveView = m_pwndBottomView;
1041 m_pwndLeftView->m_pViewData = &m_Data.m_TheirBaseBoth;
1042 m_pwndLeftView->SetTextType(m_Data.m_arTheirFile.GetUnicodeType());
1043 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arTheirFile.GetLineEndings());
1044 m_pwndLeftView->m_sWindowName.LoadString(IDS_VIEWTITLE_THEIRS);
1045 m_pwndLeftView->m_sWindowName += _T(" - ") + m_Data.m_theirFile.GetWindowName();
1046 m_pwndLeftView->m_sFullFilePath = m_Data.m_theirFile.GetFilename();
1047 m_pwndLeftView->m_sConvertedFilePath = m_Data.m_theirFile.GetConvertedFileName();
1048 m_pwndLeftView->m_sReflectedName = m_Data.m_theirFile.GetReflectedName();
1049 m_pwndLeftView->m_pWorkingFile = &m_Data.m_theirFile;
1051 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseBoth;
1052 m_pwndRightView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
1053 m_pwndRightView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
1054 m_pwndRightView->m_sWindowName.LoadString(IDS_VIEWTITLE_MINE);
1055 m_pwndRightView->m_sWindowName += _T(" - ") + m_Data.m_yourFile.GetWindowName();
1056 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
1057 m_pwndRightView->m_sConvertedFilePath = m_Data.m_yourFile.GetConvertedFileName();
1058 m_pwndRightView->m_sReflectedName = m_Data.m_yourFile.GetReflectedName();
1059 m_pwndRightView->m_pWorkingFile = &m_Data.m_yourFile;
1061 m_pwndBottomView->m_pViewData = &m_Data.m_Diff3;
1062 m_pwndBottomView->SetTextType(m_Data.m_arTheirFile.GetUnicodeType());
1063 m_pwndBottomView->SetLineEndingStyle(m_Data.m_arTheirFile.GetLineEndings());
1064 m_pwndBottomView->m_sWindowName.LoadString(IDS_VIEWTITLE_MERGED);
1065 m_pwndBottomView->m_sWindowName += _T(" - ") + m_Data.m_mergedFile.GetWindowName();
1066 m_pwndBottomView->m_sFullFilePath = m_Data.m_mergedFile.GetFilename();
1067 m_pwndBottomView->m_sConvertedFilePath = m_Data.m_mergedFile.GetConvertedFileName();
1068 m_pwndBottomView->m_sReflectedName = m_Data.m_mergedFile.GetReflectedName();
1069 m_pwndBottomView->m_pWorkingFile = &m_Data.m_mergedFile;
1071 if (m_wndSplitter2.IsColumnHidden(1))
1072 m_wndSplitter2.ShowColumn();
1073 if (m_wndSplitter.IsRowHidden(1))
1074 m_wndSplitter.ShowRow();
1075 m_pwndLeftView->SetHidden(FALSE);
1076 m_pwndRightView->SetHidden(FALSE);
1077 m_pwndBottomView->SetHidden(FALSE);
1078 // in three pane view, hide the line diff bar
1079 m_wndLineDiffBar.ShowPane(false, false, true);
1080 m_wndLineDiffBar.DocumentUpdated();
1082 if (!m_Data.m_mergedFile.InUse())
1084 m_Data.m_mergedFile.SetFileName(m_Data.m_yourFile.GetFilename());
1086 m_pwndLeftView->BuildAllScreen2ViewVector();
1087 m_pwndLeftView->DocumentUpdated();
1088 m_pwndRightView->DocumentUpdated();
1089 m_pwndBottomView->DocumentUpdated();
1090 m_wndLocatorBar.DocumentUpdated();
1091 m_wndLineDiffBar.DocumentUpdated();
1092 UpdateLayout();
1093 SetActiveView(pwndActiveView);
1095 if ((line >= -1) && m_pwndRightView->m_pViewData)
1097 int n = line == -1 ? min( nOldLineNumber, nOldLine ) : line;
1098 if (n >= 0)
1099 n = m_pwndRightView->m_pViewData->FindLineNumber(n);
1100 if (n < 0)
1101 n = nOldLine;
1103 m_pwndRightView->ScrollAllToLine(n);
1104 POINT p;
1105 p.x = 0;
1106 p.y = n;
1107 if ((ptOldCaretPos.x >= 0) || (ptOldCaretPos.y >= 0))
1108 p = ptOldCaretPos;
1109 m_pwndLeftView->SetCaretPosition(p);
1110 m_pwndRightView->SetCaretPosition(p);
1111 m_pwndBottomView->SetCaretPosition(p);
1112 m_pwndBottomView->ScrollToChar(0);
1113 m_pwndLeftView->ScrollToChar(0);
1114 m_pwndRightView->ScrollToChar(0);
1116 else
1118 CRegDWORD regFirstDiff = CRegDWORD(_T("Software\\TortoiseGitMerge\\FirstDiffOnLoad"), TRUE);
1119 CRegDWORD regFirstConflict = CRegDWORD(_T("Software\\TortoiseGitMerge\\FirstConflictOnLoad"), TRUE);
1120 bool bGoFirstDiff = (0 != (DWORD)regFirstDiff);
1121 bool bGoFirstConflict = (0 != (DWORD)regFirstConflict);
1122 if (bGoFirstConflict && (CheckResolved()>=0))
1124 pwndActiveView->GoToFirstConflict();
1125 // Ignore the first few Mouse Move messages, so that the line diff stays on
1126 // the first diff line until the user actually moves the mouse
1127 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1129 else if (bGoFirstDiff)
1131 pwndActiveView->GoToFirstDifference();
1132 // Ignore the first few Mouse Move messages, so that the line diff stays on
1133 // the first diff line until the user actually moves the mouse
1134 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1136 else
1138 // Avoid incorrect rendering of active pane.
1139 m_pwndBottomView->ScrollToChar(0);
1140 m_pwndLeftView->ScrollToChar(0);
1141 m_pwndRightView->ScrollToChar(0);
1144 CheckResolved();
1145 if (m_bHasConflicts && !m_bSaveRequiredOnConflicts)
1146 m_bSaveRequired = false;
1147 CUndo::GetInstance().Clear();
1148 return true;
1151 void CMainFrame::UpdateLayout()
1153 if (m_bInitSplitter)
1155 m_wndSplitter.CenterSplitter();
1156 m_wndSplitter2.CenterSplitter();
1160 void CMainFrame::OnSize(UINT nType, int cx, int cy)
1162 CFrameWndEx::OnSize(nType, cx, cy);
1163 if (m_bInitSplitter && nType != SIZE_MINIMIZED)
1165 if (m_wndSplitter.GetSafeHwnd())
1167 if (m_wndSplitter.HasOldRowSize() && (m_wndSplitter.GetOldRowCount() == 2))
1169 int oldTotal = m_wndSplitter.GetOldRowSize(0) + m_wndSplitter.GetOldRowSize(1);
1170 if (oldTotal)
1172 int cxCur0, cxCur1, cxMin0, cxMin1;
1173 m_wndSplitter.GetRowInfo(0, cxCur0, cxMin0);
1174 m_wndSplitter.GetRowInfo(1, cxCur1, cxMin1);
1175 cxCur0 = m_wndSplitter.GetOldRowSize(0) * (cxCur0 + cxCur1) / oldTotal;
1176 cxCur1 = m_wndSplitter.GetOldRowSize(1) * (cxCur0 + cxCur1) / oldTotal;
1177 m_wndSplitter.SetRowInfo(0, cxCur0, 0);
1178 m_wndSplitter.SetRowInfo(1, cxCur1, 0);
1179 m_wndSplitter.RecalcLayout();
1183 if (m_wndSplitter2.HasOldColSize() && (m_wndSplitter2.GetOldColCount() == 2))
1185 int oldTotal = m_wndSplitter2.GetOldColSize(0) + m_wndSplitter2.GetOldColSize(1);
1186 if (oldTotal)
1188 int cyCur0, cyCur1, cyMin0, cyMin1;
1189 m_wndSplitter2.GetColumnInfo(0, cyCur0, cyMin0);
1190 m_wndSplitter2.GetColumnInfo(1, cyCur1, cyMin1);
1191 cyCur0 = m_wndSplitter2.GetOldColSize(0) * (cyCur0 + cyCur1) / oldTotal;
1192 cyCur1 = m_wndSplitter2.GetOldColSize(1) * (cyCur0 + cyCur1) / oldTotal;
1193 m_wndSplitter2.SetColumnInfo(0, cyCur0, 0);
1194 m_wndSplitter2.SetColumnInfo(1, cyCur1, 0);
1195 m_wndSplitter2.RecalcLayout();
1200 if ((nType == SIZE_RESTORED)&&m_bCheckReload)
1202 m_bCheckReload = false;
1203 CheckForReload();
1205 #if _MSC_VER < 1800
1206 // workaround for ribbon interface when the task bar is on the left or top
1207 // The bug has been fixed in VS2013
1208 // http://connect.microsoft.com/VisualStudio/feedback/details/791229/cmfcribbonbar-app-does-not-maximize-correctly-if-windows-7-taskbar-is-docked-on-left
1209 if (nType == SIZE_MAXIMIZED)
1211 HMONITOR hMon = MonitorFromWindow(this->m_hWnd, MONITOR_DEFAULTTONEAREST);
1212 MONITORINFOEX mix;
1213 mix.cbSize = sizeof(MONITORINFOEX);
1214 bool primary = true; // assume primary monitor
1215 CRect rect(0, 0, 0, 0);
1216 if (GetMonitorInfo(hMon, &mix))
1218 primary = (mix.dwFlags == MONITORINFOF_PRIMARY);
1219 rect = mix.rcWork;
1221 else
1223 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
1225 if (primary)
1227 WINDOWPLACEMENT wp;
1228 GetWindowPlacement(&wp);
1229 if (wp.ptMaxPosition.x || wp.ptMaxPosition.y)
1231 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
1232 SetWindowPlacement(&wp);
1235 else
1237 MoveWindow(rect);
1240 #endif
1243 void CMainFrame::OnViewWhitespaces()
1245 CRegDWORD regViewWhitespaces = CRegDWORD(_T("Software\\TortoiseGitMerge\\ViewWhitespaces"), 1);
1246 BOOL bViewWhitespaces = regViewWhitespaces;
1247 if (m_pwndLeftView)
1248 bViewWhitespaces = m_pwndLeftView->m_bViewWhitespace;
1250 bViewWhitespaces = !bViewWhitespaces;
1251 regViewWhitespaces = bViewWhitespaces;
1252 if (m_pwndLeftView)
1254 m_pwndLeftView->m_bViewWhitespace = bViewWhitespaces;
1255 m_pwndLeftView->Invalidate();
1257 if (m_pwndRightView)
1259 m_pwndRightView->m_bViewWhitespace = bViewWhitespaces;
1260 m_pwndRightView->Invalidate();
1262 if (m_pwndBottomView)
1264 m_pwndBottomView->m_bViewWhitespace = bViewWhitespaces;
1265 m_pwndBottomView->Invalidate();
1269 void CMainFrame::OnUpdateViewWhitespaces(CCmdUI *pCmdUI)
1271 if (m_pwndLeftView)
1272 pCmdUI->SetCheck(m_pwndLeftView->m_bViewWhitespace);
1275 void CMainFrame::OnViewCollapsed()
1277 m_regCollapsed = !(DWORD)m_regCollapsed;
1278 m_bCollapsed = !!(DWORD)m_regCollapsed;
1280 OnViewTextFoldUnfold();
1281 m_wndLocatorBar.Invalidate();
1284 void CMainFrame::OnUpdateViewCollapsed(CCmdUI *pCmdUI)
1286 pCmdUI->SetCheck(m_bCollapsed);
1289 void CMainFrame::OnViewWraplonglines()
1291 m_bWrapLines = !(DWORD)m_regWrapLines;
1292 m_regWrapLines = m_bWrapLines;
1294 if (m_pwndLeftView) m_pwndLeftView ->WrapChanged();
1295 if (m_pwndRightView) m_pwndRightView ->WrapChanged();
1296 if (m_pwndBottomView) m_pwndBottomView->WrapChanged();
1297 OnViewTextFoldUnfold();
1298 m_wndLocatorBar.DocumentUpdated();
1301 void CMainFrame::OnViewTextFoldUnfold()
1303 OnViewTextFoldUnfold(m_pwndLeftView);
1304 OnViewTextFoldUnfold(m_pwndRightView);
1305 OnViewTextFoldUnfold(m_pwndBottomView);
1308 void CMainFrame::OnViewTextFoldUnfold(CBaseView* view)
1310 if (view == 0)
1311 return;
1312 view->BuildAllScreen2ViewVector();
1313 view->UpdateCaret();
1314 view->Invalidate();
1315 view->EnsureCaretVisible();
1318 void CMainFrame::OnUpdateViewWraplonglines(CCmdUI *pCmdUI)
1320 pCmdUI->SetCheck(m_bWrapLines);
1323 void CMainFrame::OnViewOnewaydiff()
1325 if (CheckForSave(CHFSR_RELOAD)==IDCANCEL)
1326 return;
1327 m_bOneWay = !m_bOneWay;
1328 ShowDiffBar(!m_bOneWay);
1329 LoadViews(-1);
1332 void CMainFrame::ShowDiffBar(bool bShow)
1334 if (bShow)
1336 // restore the line diff bar
1337 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
1338 m_wndLineDiffBar.DocumentUpdated();
1339 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
1340 m_wndLocatorBar.DocumentUpdated();
1342 else
1344 // in one way view, hide the line diff bar
1345 m_wndLineDiffBar.ShowPane(false, false, true);
1346 m_wndLineDiffBar.DocumentUpdated();
1350 int CMainFrame::CheckResolved()
1352 //only in three way diffs can be conflicts!
1353 m_bHasConflicts = true;
1354 if (IsViewGood(m_pwndBottomView))
1356 CViewData* viewdata = m_pwndBottomView->m_pViewData;
1357 if (viewdata)
1359 for (int i=0; i<viewdata->GetCount(); i++)
1361 const DiffStates state = viewdata->GetState(i);
1362 if ((DIFFSTATE_CONFLICTED == state)||(DIFFSTATE_CONFLICTED_IGNORED == state))
1363 return i;
1367 m_bHasConflicts = false;
1368 return -1;
1371 int CMainFrame::SaveFile(const CString& sFilePath)
1373 CBaseView * pView = NULL;
1374 CViewData * pViewData = NULL;
1375 CFileTextLines * pOriginFile = &m_Data.m_arBaseFile;
1376 if (IsViewGood(m_pwndBottomView))
1378 pView = m_pwndBottomView;
1379 pViewData = m_pwndBottomView->m_pViewData;
1381 else if (IsViewGood(m_pwndRightView))
1383 pView = m_pwndRightView;
1384 pViewData = m_pwndRightView->m_pViewData;
1385 if (m_Data.IsYourFileInUse())
1386 pOriginFile = &m_Data.m_arYourFile;
1387 else if (m_Data.IsTheirFileInUse())
1388 pOriginFile = &m_Data.m_arTheirFile;
1390 else
1392 // nothing to save!
1393 return 1;
1395 Invalidate();
1396 if ((pViewData)&&(pOriginFile))
1398 CFileTextLines file;
1399 pOriginFile->CopySettings(&file);
1400 CFileTextLines::SaveParams saveParams;
1401 saveParams.m_LineEndings = pView->GetLineEndings();
1402 saveParams.m_UnicodeType = pView->GetTextType();
1403 file.SetSaveParams(saveParams);
1404 for (int i=0; i<pViewData->GetCount(); i++)
1406 //only copy non-removed lines
1407 DiffStates state = pViewData->GetState(i);
1408 switch (state)
1410 case DIFFSTATE_CONFLICTED:
1411 case DIFFSTATE_CONFLICTED_IGNORED:
1413 int first = i;
1414 int last = i;
1417 last++;
1418 } while((last<pViewData->GetCount()) && ((pViewData->GetState(last)==DIFFSTATE_CONFLICTED)||(pViewData->GetState(last)==DIFFSTATE_CONFLICTED_IGNORED)));
1419 // TortoiseGitMerge changes here
1420 file.Add(_T("<<<<<<< .mine"), m_pwndRightView->GetLineEndings());
1421 for (int j=first; j<last; j++)
1423 EOL lineending = m_pwndRightView->m_pViewData->GetLineEnding(j);
1424 if (lineending == EOL_NOENDING)
1425 lineending = m_pwndRightView->GetLineEndings();
1426 file.Add(m_pwndRightView->m_pViewData->GetLine(j), lineending);
1428 file.Add(_T("======="), m_pwndRightView->GetLineEndings());
1429 for (int j=first; j<last; j++)
1431 EOL lineending = m_pwndLeftView->m_pViewData->GetLineEnding(j);
1432 if (lineending == EOL_NOENDING)
1433 lineending = m_pwndLeftView->GetLineEndings();
1434 file.Add(m_pwndLeftView->m_pViewData->GetLine(j), lineending);
1436 file.Add(_T(">>>>>>> .theirs"), m_pwndRightView->GetLineEndings());
1437 i = last-1;
1439 break;
1440 case DIFFSTATE_EMPTY:
1441 case DIFFSTATE_CONFLICTEMPTY:
1442 case DIFFSTATE_IDENTICALREMOVED:
1443 case DIFFSTATE_REMOVED:
1444 case DIFFSTATE_THEIRSREMOVED:
1445 case DIFFSTATE_YOURSREMOVED:
1446 case DIFFSTATE_CONFLICTRESOLVEDEMPTY:
1447 // do not save removed lines
1448 break;
1449 default:
1450 file.Add(pViewData->GetLine(i), pViewData->GetLineEnding(i));
1451 break;
1454 if (!file.Save(sFilePath, false, false))
1456 CMessageBox::Show(m_hWnd, file.GetErrorString(), _T("TortoiseGitMerge"), MB_ICONERROR);
1457 return -1;
1459 if (sFilePath == m_Data.m_baseFile.GetFilename())
1461 m_Data.m_baseFile.StoreFileAttributes();
1463 if (sFilePath == m_Data.m_theirFile.GetFilename())
1465 m_Data.m_theirFile.StoreFileAttributes();
1467 if (sFilePath == m_Data.m_yourFile.GetFilename())
1469 m_Data.m_yourFile.StoreFileAttributes();
1471 /*if (sFilePath == m_Data.m_mergedFile.GetFilename())
1473 m_Data.m_mergedFile.StoreFileAttributes();
1474 }//*/
1475 m_dlgFilePatches.SetFileStatusAsPatched(sFilePath);
1476 if (IsViewGood(m_pwndBottomView))
1477 m_pwndBottomView->SetModified(FALSE);
1478 else if (IsViewGood(m_pwndRightView))
1479 m_pwndRightView->SetModified(FALSE);
1480 CUndo::GetInstance().MarkAsOriginalState(
1481 false,
1482 IsViewGood(m_pwndRightView) && (pViewData == m_pwndRightView->m_pViewData),
1483 IsViewGood(m_pwndBottomView) && (pViewData == m_pwndBottomView->m_pViewData));
1484 if (file.GetCount() == 1 && file.GetAt(0).IsEmpty() && file.GetLineEnding(0) == EOL_NOENDING)
1485 return 0;
1486 return file.GetCount();
1488 return 1;
1491 void CMainFrame::OnFileSave()
1493 // when multiple files are set as writable we have to ask what file to save
1494 int nEditableViewCount =
1495 (CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsWritable() ? 1 : 0)
1496 + (CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsWritable() ? 1 : 0)
1497 + (CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsWritable() ? 1 : 0);
1498 bool bLeftIsModified = CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsModified();
1499 bool bRightIsModified = CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsModified();
1500 bool bBottomIsModified = CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsModified();
1501 int nModifiedViewCount =
1502 (bLeftIsModified ? 1 : 0)
1503 + (bRightIsModified ? 1 : 0)
1504 + (bBottomIsModified ? 1 : 0);
1505 if (nEditableViewCount>1)
1507 if (nModifiedViewCount == 1)
1509 if (bLeftIsModified)
1510 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1511 else
1512 FileSave();
1514 else if (nModifiedViewCount>0)
1516 // both views
1517 UINT ret = IDNO;
1518 if (m_bUseTaskDialog)
1520 CTaskDialog taskdlg(CString(MAKEINTRESOURCE(IDS_SAVE_MORE)),
1521 CString(MAKEINTRESOURCE(IDS_SAVE)),
1522 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1524 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
1525 CString sTaskTemp;
1526 if (m_pwndLeftView->m_pWorkingFile->InUse() && !m_pwndLeftView->m_pWorkingFile->IsReadonly())
1527 sTaskTemp.Format(IDS_ASKFORSAVE_SAVELEFT, (LPCTSTR)m_pwndLeftView->m_pWorkingFile->GetFilename());
1528 else
1529 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS));
1530 taskdlg.AddCommandControl(201, sTaskTemp, bLeftIsModified);// left
1531 if (bLeftIsModified) {
1532 taskdlg.SetDefaultCommandControl(201);
1534 if (m_pwndRightView->m_pWorkingFile->InUse() && !m_pwndRightView->m_pWorkingFile->IsReadonly())
1535 sTaskTemp.Format(IDS_ASKFORSAVE_SAVERIGHT, (LPCTSTR)m_pwndRightView->m_pWorkingFile->GetFilename());
1536 else
1537 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS));
1538 taskdlg.AddCommandControl(202, sTaskTemp, bRightIsModified); // right
1539 if (bRightIsModified) {
1540 taskdlg.SetDefaultCommandControl(202);
1542 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEALL2)), nModifiedViewCount>1); // both
1543 if (nModifiedViewCount>1) {
1544 taskdlg.SetDefaultCommandControl(203);
1546 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1547 taskdlg.SetMainIcon(TD_WARNING_ICON);
1548 ret = (UINT)taskdlg.DoModal(m_hWnd);
1549 switch (ret)
1551 case 201: // left
1552 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1553 break;
1554 case 203: // both
1555 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1556 case 202: // right
1557 m_pwndRightView->SaveFile();
1558 break;
1563 else
1565 // only target view was modified
1566 FileSave();
1570 void CMainFrame::PatchSave()
1572 bool bDoesNotExist = !PathFileExists(m_Data.m_mergedFile.GetFilename());
1573 if (m_Data.m_bPatchRequired)
1575 m_Patch.PatchPath(m_Data.m_mergedFile.GetFilename());
1577 if (!PathIsDirectory(m_Data.m_mergedFile.GetFilename()))
1579 int saveret = SaveFile(m_Data.m_mergedFile.GetFilename());
1580 if (saveret==0)
1582 // file was saved with 0 lines, remove it.
1583 m_Patch.RemoveFile(m_Data.m_mergedFile.GetFilename());
1584 // just in case
1585 DeleteFile(m_Data.m_mergedFile.GetFilename());
1587 m_Data.m_mergedFile.StoreFileAttributes();
1588 if (m_Data.m_mergedFile.GetFilename() == m_Data.m_yourFile.GetFilename())
1589 m_Data.m_yourFile.StoreFileAttributes();
1590 if ((bDoesNotExist)&&(DWORD(CRegDWORD(_T("Software\\TortoiseGitMerge\\AutoAdd"), TRUE))))
1592 // call TortoiseProc to add the new file to version control
1593 CString cmd = _T("/command:add /noui /path:\"");
1594 cmd += m_Data.m_mergedFile.GetFilename() + _T("\"");
1595 CAppUtils::RunTortoiseGitProc(cmd);
1600 bool CMainFrame::FileSave(bool bCheckResolved /*=true*/)
1602 if (!m_Data.m_mergedFile.InUse())
1603 return FileSaveAs(bCheckResolved);
1604 // check if the file has the readonly attribute set
1605 bool bDoesNotExist = false;
1606 DWORD fAttribs = GetFileAttributes(m_Data.m_mergedFile.GetFilename());
1607 if ((fAttribs != INVALID_FILE_ATTRIBUTES)&&(fAttribs & FILE_ATTRIBUTE_READONLY))
1608 return FileSaveAs(bCheckResolved);
1609 if (fAttribs == INVALID_FILE_ATTRIBUTES)
1611 bDoesNotExist = (GetLastError() == ERROR_FILE_NOT_FOUND);
1613 if (bCheckResolved && HasConflictsWontKeep())
1614 return false;
1616 if (((DWORD)CRegDWORD(_T("Software\\TortoiseGitMerge\\Backup"))) != 0)
1618 MoveFileEx(m_Data.m_mergedFile.GetFilename(), m_Data.m_mergedFile.GetFilename() + _T(".bak"), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
1620 if (m_Data.m_bPatchRequired)
1622 m_Patch.PatchPath(m_Data.m_mergedFile.GetFilename());
1624 int saveret = SaveFile(m_Data.m_mergedFile.GetFilename());
1625 if (saveret==0)
1627 // file was saved with 0 lines!
1628 // ask the user if the file should be deleted
1629 bool bDelete = false;
1630 if (m_bUseTaskDialog)
1632 CString msg;
1633 msg.Format(IDS_DELETEWHENEMPTY, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1634 CTaskDialog taskdlg(msg,
1635 CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK2)),
1636 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1638 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
1639 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK3)));
1640 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK4)));
1641 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1642 taskdlg.SetDefaultCommandControl(1);
1643 taskdlg.SetMainIcon(TD_WARNING_ICON);
1644 bDelete = (taskdlg.DoModal(m_hWnd) == 1);
1646 else
1648 CString sTemp;
1649 sTemp.Format(IDS_DELETEWHENEMPTY, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
1650 bDelete = (CMessageBox::ShowCheck(m_hWnd, sTemp, _T("TortoiseGitMerge"), MB_YESNO, _T("DeleteFileWhenEmpty")) == IDYES);
1652 if (bDelete)
1654 m_Patch.RemoveFile(m_Data.m_mergedFile.GetFilename());
1655 DeleteFile(m_Data.m_mergedFile.GetFilename());
1658 else if (saveret < 0)
1660 // error while saving the file
1661 return false;
1664 // if we're in conflict resolve mode (three pane view), check if there are no more conflicts
1665 // and if there aren't, ask to mark the file as resolved
1666 if (IsViewGood(m_pwndBottomView) && !m_bHasConflicts && bCheckResolved)
1668 CString projectRoot;
1669 if (g_GitAdminDir.HasAdminDir(m_Data.m_mergedFile.GetFilename(), false, &projectRoot))
1671 CString subpath = m_Data.m_mergedFile.GetFilename();
1672 subpath.Replace(_T('\\'), _T('/'));
1673 if (subpath.GetLength() >= projectRoot.GetLength())
1675 if (subpath[projectRoot.GetLength()] == _T('/'))
1676 subpath = subpath.Right(subpath.GetLength() - projectRoot.GetLength() - 1);
1677 else
1678 subpath = subpath.Right(subpath.GetLength() - projectRoot.GetLength());
1681 CAutoRepository repository(projectRoot);
1682 bool hasConflictInIndex = false;
1685 if (!repository)
1686 break;
1688 CAutoIndex index;
1689 if (git_repository_index(index.GetPointer(), repository))
1690 break;
1692 CStringA path = CUnicodeUtils::GetMulti(subpath, CP_UTF8);
1693 const git_index_entry * entry = git_index_get_bypath(index, path, 1);
1694 hasConflictInIndex = entry != nullptr;
1695 } while(0);
1697 if (hasConflictInIndex)
1699 bool bResolve = false;
1700 if (m_bUseTaskDialog)
1702 CString msg;
1703 msg.Format(IDS_MARKASRESOLVED, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1704 CTaskDialog taskdlg(msg,
1705 CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK2)),
1706 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1708 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
1709 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK3)));
1710 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK4)));
1711 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1712 taskdlg.SetDefaultCommandControl(1);
1713 taskdlg.SetMainIcon(TD_WARNING_ICON);
1714 bResolve = (taskdlg.DoModal(m_hWnd) == 1);
1716 else
1718 CString sTemp;
1719 sTemp.Format(IDS_MARKASRESOLVED, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1720 bResolve = (CMessageBox::Show(m_hWnd, sTemp, _T("TortoiseGitMerge"), MB_YESNO | MB_ICONQUESTION) == IDYES);
1722 if (bResolve)
1724 MarkAsResolved();
1730 m_bSaveRequired = false;
1731 m_Data.m_mergedFile.StoreFileAttributes();
1733 if ((bDoesNotExist)&&(DWORD(CRegDWORD(_T("Software\\TortoiseGitMerge\\AutoAdd"), TRUE))))
1735 // call TortoiseProc to add the new file to version control
1736 CString cmd = _T("/command:add /noui /path:\"");
1737 cmd += m_Data.m_mergedFile.GetFilename() + _T("\"");
1738 if(!CAppUtils::RunTortoiseGitProc(cmd))
1739 return false;
1741 return true;
1744 void CMainFrame::OnFileSaveAs()
1746 if (m_bUseTaskDialog)
1748 // ask what file to save as
1749 bool bHaveConflict = (CheckResolved() >= 0);
1750 CTaskDialog taskdlg(
1751 CString(MAKEINTRESOURCE(bHaveConflict ? IDS_ASKFORSAVEAS_MORECONFLICT : IDS_ASKFORSAVEAS_MORE)),
1752 CString(MAKEINTRESOURCE(IDS_ASKFORSAVEAS)),
1753 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1755 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
1756 // default can be last view (target) as was in 1.7 or actual (where is cursor) as is in most text editor
1757 if (IsViewGood(m_pwndLeftView))
1759 taskdlg.AddCommandControl(201, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS))); // left
1760 taskdlg.SetDefaultCommandControl(201);
1762 if (IsViewGood(m_pwndRightView))
1764 taskdlg.AddCommandControl(202, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS))); // right
1765 taskdlg.SetDefaultCommandControl(202);
1767 if (IsViewGood(m_pwndBottomView))
1769 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEBOTTOMAS))); // bottom
1770 taskdlg.SetDefaultCommandControl(203);
1772 if (bHaveConflict)
1774 taskdlg.AddCommandControl(204, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_NEEDRESOLVE))); // resolve
1775 taskdlg.SetDefaultCommandControl(204);
1777 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1778 taskdlg.SetMainIcon(bHaveConflict ? TD_WARNING_ICON : TD_INFORMATION_ICON);
1779 int nCommand = (int)taskdlg.DoModal(m_hWnd);
1780 CString sFileName;
1781 switch (nCommand)
1783 case 201: // left
1784 if (TryGetFileName(sFileName))
1786 // in 2, 3 view display we want to keep removed lines
1787 m_pwndLeftView->SaveFileTo(sFileName, IsViewGood(m_pwndRightView) ? SAVE_REMOVEDLINES : 0);
1789 break;
1790 case 202: // right
1791 if (TryGetFileName(sFileName))
1793 m_pwndRightView->SaveFileTo(sFileName);
1795 break;
1796 case 203: // bottom
1797 FileSaveAs();
1798 break;
1799 case 204: // continue resolving
1800 if (m_pwndBottomView)
1802 m_pwndBottomView->GoToLine(CheckResolved());
1804 break;
1807 else
1809 int nEditableViewCount =
1810 (CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsWritable() ? 1 : 0)
1811 + (CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsWritable() ? 1 : 0)
1812 + (CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsWritable() ? 1 : 0);
1813 bool bLeftIsModified = CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsModified();
1814 bool bRightIsModified = CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsModified();
1815 bool bBottomIsModified = CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsModified();
1816 int nModifiedViewCount =
1817 (bLeftIsModified ? 1 : 0)
1818 + (bRightIsModified ? 1 : 0)
1819 + (bBottomIsModified ? 1 : 0);
1820 if (nEditableViewCount>1)
1822 if (nModifiedViewCount == 1)
1824 if (bLeftIsModified)
1826 CString sFileName;
1827 if (TryGetFileName(sFileName))
1829 m_pwndLeftView->SaveFileTo(sFileName);
1832 else
1833 FileSaveAs();
1835 else
1837 FileSaveAs();
1838 CString sFileName;
1839 if (TryGetFileName(sFileName))
1841 m_pwndLeftView->SaveFileTo(sFileName);
1848 bool CMainFrame::FileSaveAs(bool bCheckResolved /*=true*/)
1850 if (bCheckResolved && HasConflictsWontKeep())
1851 return false;
1853 CString fileName;
1854 if(!TryGetFileName(fileName))
1855 return false;
1857 SaveFile(fileName);
1858 return true;
1861 void CMainFrame::OnUpdateFileSave(CCmdUI *pCmdUI)
1863 BOOL bEnable = FALSE;
1864 if (m_Data.m_mergedFile.InUse())
1866 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1867 bEnable = TRUE;
1868 else if ( (IsViewGood(m_pwndRightView)&&(m_pwndRightView->m_pViewData)) &&
1869 (m_pwndRightView->IsModified() || (m_Data.m_yourFile.GetWindowName().Right(9).Compare(_T(": patched"))==0)) )
1870 bEnable = TRUE;
1871 else if (IsViewGood(m_pwndLeftView)
1872 && (m_pwndLeftView->m_pViewData)
1873 && (m_pwndLeftView->IsModified()))
1874 bEnable = TRUE;
1876 pCmdUI->Enable(bEnable);
1879 void CMainFrame::OnUpdateFileSaveAs(CCmdUI *pCmdUI)
1881 // any file is open we can save it as
1882 BOOL bEnable = FALSE;
1883 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1884 bEnable = TRUE;
1885 else if (IsViewGood(m_pwndRightView)&&(m_pwndRightView->m_pViewData))
1886 bEnable = TRUE;
1887 else if (IsViewGood(m_pwndLeftView)&&(m_pwndLeftView->m_pViewData))
1888 bEnable = TRUE;
1889 pCmdUI->Enable(bEnable);
1892 void CMainFrame::OnUpdateViewOnewaydiff(CCmdUI *pCmdUI)
1894 pCmdUI->SetCheck(!m_bOneWay);
1895 BOOL bEnable = TRUE;
1896 if (IsViewGood(m_pwndBottomView))
1898 bEnable = FALSE;
1900 pCmdUI->Enable(bEnable);
1903 void CMainFrame::OnViewOptions()
1905 CString sTemp;
1906 sTemp.LoadString(IDS_SETTINGSTITLE);
1907 CSettings dlg(sTemp);
1908 dlg.DoModal();
1909 if (dlg.IsReloadNeeded())
1911 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
1912 return;
1913 CDiffColors::GetInstance().LoadRegistry();
1914 LoadViews();
1915 return;
1917 CDiffColors::GetInstance().LoadRegistry();
1918 if (m_pwndBottomView)
1919 m_pwndBottomView->Invalidate();
1920 if (m_pwndLeftView)
1921 m_pwndLeftView->Invalidate();
1922 if (m_pwndRightView)
1923 m_pwndRightView->Invalidate();
1926 void CMainFrame::OnClose()
1928 if (CheckForSave(CHFSR_CLOSE)!=IDCANCEL)
1930 WINDOWPLACEMENT wp;
1932 // before it is destroyed, save the position of the window
1933 wp.length = sizeof wp;
1935 if (GetWindowPlacement(&wp))
1938 if (IsIconic())
1939 // never restore to Iconic state
1940 wp.showCmd = SW_SHOW ;
1942 if ((wp.flags & WPF_RESTORETOMAXIMIZED) != 0)
1943 // if maximized and maybe iconic restore maximized state
1944 wp.showCmd = SW_SHOWMAXIMIZED ;
1946 // and write it
1947 WriteWindowPlacement(&wp);
1949 __super::OnClose();
1953 void CMainFrame::OnActivate(UINT nValue, CWnd* /*pwnd*/, BOOL /*bActivated?*/)
1955 if (nValue != 0) // activated
1957 if (IsIconic())
1959 m_bCheckReload = TRUE;
1961 else
1963 // use a timer to give other messages time to get processed
1964 // first, like e.g. the WM_CLOSE message in case the user
1965 // clicked the close button and that brought the window
1966 // to the front - in that case checking for reload wouldn't
1967 // do any good.
1968 SetTimer(IDT_RELOADCHECKTIMER, 300, NULL);
1973 void CMainFrame::OnViewLinedown()
1975 OnViewLineUpDown(1);
1978 void CMainFrame::OnViewLineup()
1980 OnViewLineUpDown(-1);
1983 void CMainFrame::OnViewLineUpDown(int direction)
1985 if (m_pwndLeftView)
1986 m_pwndLeftView->ScrollToLine(m_pwndLeftView->m_nTopLine+direction);
1987 if (m_pwndRightView)
1988 m_pwndRightView->ScrollToLine(m_pwndRightView->m_nTopLine+direction);
1989 if (m_pwndBottomView)
1990 m_pwndBottomView->ScrollToLine(m_pwndBottomView->m_nTopLine+direction);
1991 m_wndLocatorBar.Invalidate();
1992 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1995 void CMainFrame::OnViewLineleft()
1997 OnViewLineLeftRight(-1);
2000 void CMainFrame::OnViewLineright()
2002 OnViewLineLeftRight(1);
2005 void CMainFrame::OnViewLineLeftRight(int direction)
2007 if (m_pwndLeftView)
2008 m_pwndLeftView->ScrollSide(direction);
2009 if (m_pwndRightView)
2010 m_pwndRightView->ScrollSide(direction);
2011 if (m_pwndBottomView)
2012 m_pwndBottomView->ScrollSide(direction);
2015 void CMainFrame::OnEditUseTheirs()
2017 if (m_pwndBottomView)
2018 m_pwndBottomView->UseTheirTextBlock();
2020 void CMainFrame::OnUpdateEditUsetheirblock(CCmdUI *pCmdUI)
2022 pCmdUI->Enable(m_pwndBottomView && m_pwndBottomView->HasSelection());
2025 void CMainFrame::OnEditUseMine()
2027 if (m_pwndBottomView)
2028 m_pwndBottomView->UseMyTextBlock();
2030 void CMainFrame::OnUpdateEditUsemyblock(CCmdUI *pCmdUI)
2032 OnUpdateEditUsetheirblock(pCmdUI);
2035 void CMainFrame::OnEditUseTheirsThenMine()
2037 if (m_pwndBottomView)
2038 m_pwndBottomView->UseTheirAndYourBlock();
2041 void CMainFrame::OnUpdateEditUsetheirthenmyblock(CCmdUI *pCmdUI)
2043 OnUpdateEditUsetheirblock(pCmdUI);
2046 void CMainFrame::OnEditUseMineThenTheirs()
2048 if (m_pwndBottomView)
2049 m_pwndBottomView->UseYourAndTheirBlock();
2052 void CMainFrame::OnUpdateEditUseminethentheirblock(CCmdUI *pCmdUI)
2054 OnUpdateEditUsetheirblock(pCmdUI);
2057 void CMainFrame::OnEditUseleftblock()
2059 if (m_pwndBottomView->IsWindowVisible())
2060 m_pwndBottomView->UseRightBlock();
2061 else
2062 m_pwndRightView->UseLeftBlock();
2065 void CMainFrame::OnUpdateEditUseleftblock(CCmdUI *pCmdUI)
2067 pCmdUI->Enable(IsViewGood(m_pwndRightView) && m_pwndRightView->IsTarget() && m_pwndRightView->HasSelection());
2070 void CMainFrame::OnUpdateUseBlock(CCmdUI *pCmdUI)
2072 pCmdUI->Enable(TRUE);
2075 void CMainFrame::OnEditUseleftfile()
2077 if (m_pwndBottomView->IsWindowVisible())
2078 m_pwndBottomView->UseRightFile();
2079 else
2080 m_pwndRightView->UseLeftFile();
2083 void CMainFrame::OnUpdateEditUseleftfile(CCmdUI *pCmdUI)
2085 pCmdUI->Enable(IsViewGood(m_pwndRightView) && m_pwndRightView->IsTarget());
2088 void CMainFrame::OnEditUseblockfromleftbeforeright()
2090 if (m_pwndRightView)
2091 m_pwndRightView->UseBothLeftFirst();
2094 void CMainFrame::OnUpdateEditUseblockfromleftbeforeright(CCmdUI *pCmdUI)
2096 OnUpdateEditUseleftblock(pCmdUI);
2099 void CMainFrame::OnEditUseblockfromrightbeforeleft()
2101 if (m_pwndRightView)
2102 m_pwndRightView->UseBothRightFirst();
2105 void CMainFrame::OnUpdateEditUseblockfromrightbeforeleft(CCmdUI *pCmdUI)
2107 OnUpdateEditUseleftblock(pCmdUI);
2110 void CMainFrame::OnFileReload()
2112 if (CheckForSave(CHFSR_RELOAD)==IDCANCEL)
2113 return;
2114 CDiffColors::GetInstance().LoadRegistry();
2115 LoadViews(-1);
2118 void CMainFrame::ActivateFrame(int nCmdShow)
2120 // nCmdShow is the normal show mode this frame should be in
2121 // translate default nCmdShow (-1)
2122 if (nCmdShow == -1)
2124 if (!IsWindowVisible())
2125 nCmdShow = SW_SHOWNORMAL;
2126 else if (IsIconic())
2127 nCmdShow = SW_RESTORE;
2130 // bring to top before showing
2131 BringToTop(nCmdShow);
2133 if (nCmdShow != -1)
2135 // show the window as specified
2136 WINDOWPLACEMENT wp;
2138 if ( !ReadWindowPlacement(&wp) )
2140 ShowWindow(nCmdShow);
2142 else
2144 if ( nCmdShow != SW_SHOWNORMAL )
2145 wp.showCmd = nCmdShow;
2147 SetWindowPlacement(&wp);
2150 // and finally, bring to top after showing
2151 BringToTop(nCmdShow);
2155 BOOL CMainFrame::ReadWindowPlacement(WINDOWPLACEMENT * pwp)
2157 CRegString placement = CRegString(_T("Software\\TortoiseGitMerge\\WindowPos"));
2158 CString sPlacement = placement;
2159 if (sPlacement.IsEmpty())
2160 return FALSE;
2161 int nRead = _stscanf_s(sPlacement, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
2162 &pwp->flags, &pwp->showCmd,
2163 &pwp->ptMinPosition.x, &pwp->ptMinPosition.y,
2164 &pwp->ptMaxPosition.x, &pwp->ptMaxPosition.y,
2165 &pwp->rcNormalPosition.left, &pwp->rcNormalPosition.top,
2166 &pwp->rcNormalPosition.right, &pwp->rcNormalPosition.bottom);
2167 if ( nRead != 10 )
2168 return FALSE;
2169 pwp->length = sizeof(WINDOWPLACEMENT);
2171 return TRUE;
2174 void CMainFrame::WriteWindowPlacement(WINDOWPLACEMENT * pwp)
2176 CRegString placement = CRegString(_T("Software\\TortoiseGitMerge\\WindowPos"));
2177 TCHAR szBuffer[_countof("-32767")*8 + sizeof("65535")*2];
2179 _stprintf_s(szBuffer, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
2180 pwp->flags, pwp->showCmd,
2181 pwp->ptMinPosition.x, pwp->ptMinPosition.y,
2182 pwp->ptMaxPosition.x, pwp->ptMaxPosition.y,
2183 pwp->rcNormalPosition.left, pwp->rcNormalPosition.top,
2184 pwp->rcNormalPosition.right, pwp->rcNormalPosition.bottom);
2185 placement = szBuffer;
2188 void CMainFrame::OnUpdateMergeMarkasresolved(CCmdUI *pCmdUI)
2190 if (pCmdUI == NULL)
2191 return;
2192 BOOL bEnable = FALSE;
2193 if ((!m_bReadOnly)&&(m_Data.m_mergedFile.InUse()))
2195 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
2197 bEnable = TRUE;
2200 pCmdUI->Enable(bEnable);
2203 void CMainFrame::OnMergeMarkasresolved()
2205 if(HasConflictsWontKeep())
2206 return;
2208 // now check if the file has already been saved and if not, save it.
2209 if (m_Data.m_mergedFile.InUse())
2211 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
2213 FileSave(false);
2214 m_bSaveRequired = false;
2217 MarkAsResolved();
2220 BOOL CMainFrame::MarkAsResolved()
2222 if (m_bReadOnly)
2223 return FALSE;
2224 if (!IsViewGood(m_pwndBottomView))
2225 return FALSE;
2227 CString cmd = _T("/command:resolve /path:\"");
2228 cmd += m_Data.m_mergedFile.GetFilename();
2229 cmd += _T("\" /closeonend:1 /noquestion /skipcheck /silent");
2230 if (resolveMsgWnd)
2232 CString s;
2233 s.Format(L" /resolvemsghwnd:%I64d /resolvemsgwparam:%I64d /resolvemsglparam:%I64d", (__int64)resolveMsgWnd, (__int64)resolveMsgWParam, (__int64)resolveMsgLParam);
2234 cmd += s;
2236 if(!CAppUtils::RunTortoiseGitProc(cmd))
2237 return FALSE;
2238 m_bSaveRequired = false;
2239 return TRUE;
2242 void CMainFrame::OnUpdateMergeNextconflict(CCmdUI *pCmdUI)
2244 BOOL bShow = FALSE;
2245 if (HasNextConflict(m_pwndBottomView))
2246 bShow = TRUE;
2247 else if (HasNextConflict(m_pwndRightView))
2248 bShow = TRUE;
2249 else if (HasNextConflict(m_pwndLeftView))
2250 bShow = TRUE;
2251 pCmdUI->Enable(bShow);
2254 bool CMainFrame::HasNextConflict(CBaseView* view)
2256 if (view == 0)
2257 return false;
2258 if (!view->IsTarget())
2259 return false;
2260 return view->HasNextConflict();
2263 void CMainFrame::OnUpdateMergePreviousconflict(CCmdUI *pCmdUI)
2265 BOOL bShow = FALSE;
2266 if (HasPrevConflict(m_pwndBottomView))
2267 bShow = TRUE;
2268 else if (HasPrevConflict(m_pwndRightView))
2269 bShow = TRUE;
2270 else if (HasPrevConflict(m_pwndLeftView))
2271 bShow = TRUE;
2272 pCmdUI->Enable(bShow);
2275 bool CMainFrame::HasPrevConflict(CBaseView* view)
2277 if (view == 0)
2278 return false;
2279 if (!view->IsTarget())
2280 return false;
2281 return view->HasPrevConflict();
2284 void CMainFrame::OnUpdateNavigateNextdifference(CCmdUI *pCmdUI)
2286 CBaseView* baseView = GetActiveBaseView();
2287 BOOL bShow = FALSE;
2288 if (baseView != 0)
2289 bShow = baseView->HasNextDiff();
2290 pCmdUI->Enable(bShow);
2293 void CMainFrame::OnUpdateNavigatePreviousdifference(CCmdUI *pCmdUI)
2295 CBaseView* baseView = GetActiveBaseView();
2296 BOOL bShow = FALSE;
2297 if (baseView != 0)
2298 bShow = baseView->HasPrevDiff();
2299 pCmdUI->Enable(bShow);
2302 void CMainFrame::OnUpdateNavigateNextinlinediff(CCmdUI *pCmdUI)
2304 BOOL bShow = FALSE;
2305 if (HasNextInlineDiff(m_pwndBottomView))
2306 bShow = TRUE;
2307 else if (HasNextInlineDiff(m_pwndRightView))
2308 bShow = TRUE;
2309 else if (HasNextInlineDiff(m_pwndLeftView))
2310 bShow = TRUE;
2311 pCmdUI->Enable(bShow);
2314 bool CMainFrame::HasNextInlineDiff(CBaseView* view)
2316 if (view == 0)
2317 return false;
2318 if (!view->IsTarget())
2319 return false;
2320 return view->HasNextInlineDiff();
2323 void CMainFrame::OnUpdateNavigatePrevinlinediff(CCmdUI *pCmdUI)
2325 BOOL bShow = FALSE;
2326 if (HasPrevInlineDiff(m_pwndBottomView))
2327 bShow = TRUE;
2328 else if (HasPrevInlineDiff(m_pwndRightView))
2329 bShow = TRUE;
2330 else if (HasPrevInlineDiff(m_pwndLeftView))
2331 bShow = TRUE;
2332 pCmdUI->Enable(bShow);
2335 bool CMainFrame::HasPrevInlineDiff(CBaseView* view)
2337 if (view == 0)
2338 return false;
2339 if (!view->IsTarget())
2340 return false;
2341 return view->HasPrevInlineDiff();
2344 void CMainFrame::OnMoving(UINT fwSide, LPRECT pRect)
2346 // if the pathfilelist dialog is attached to the mainframe,
2347 // move it along with the mainframe
2348 if (::IsWindow(m_dlgFilePatches.m_hWnd))
2350 RECT patchrect;
2351 m_dlgFilePatches.GetWindowRect(&patchrect);
2352 if (::IsWindow(m_hWnd))
2354 RECT thisrect;
2355 GetWindowRect(&thisrect);
2356 if (patchrect.right == thisrect.left)
2358 m_dlgFilePatches.SetWindowPos(NULL, patchrect.left - (thisrect.left - pRect->left), patchrect.top - (thisrect.top - pRect->top),
2359 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
2363 __super::OnMoving(fwSide, pRect);
2366 void CMainFrame::OnUpdateEditCopy(CCmdUI *pCmdUI)
2368 BOOL bShow = FALSE;
2369 if ((m_pwndBottomView)&&(m_pwndBottomView->HasSelection()))
2370 bShow = TRUE;
2371 else if ((m_pwndRightView)&&(m_pwndRightView->HasSelection()))
2372 bShow = TRUE;
2373 else if ((m_pwndLeftView)&&(m_pwndLeftView->HasSelection()))
2374 bShow = TRUE;
2375 pCmdUI->Enable(bShow);
2378 void CMainFrame::OnUpdateEditPaste(CCmdUI *pCmdUI)
2380 BOOL bWritable = FALSE;
2381 if ((m_pwndBottomView)&&(m_pwndBottomView->IsWritable()))
2382 bWritable = TRUE;
2383 else if ((m_pwndRightView)&&(m_pwndRightView->IsWritable()))
2384 bWritable = TRUE;
2385 else if ((m_pwndLeftView)&&(m_pwndLeftView->IsWritable()))
2386 bWritable = TRUE;
2387 pCmdUI->Enable(bWritable && ::IsClipboardFormatAvailable(CF_TEXT));
2390 void CMainFrame::OnViewSwitchleft()
2392 if (CheckForSave(CHFSR_SWITCH)!=IDCANCEL)
2394 CWorkingFile file = m_Data.m_baseFile;
2395 m_Data.m_baseFile = m_Data.m_yourFile;
2396 m_Data.m_yourFile = file;
2397 if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_yourFile.GetFilename())==0)
2399 m_Data.m_mergedFile = m_Data.m_baseFile;
2401 else if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_baseFile.GetFilename())==0)
2403 m_Data.m_mergedFile = m_Data.m_yourFile;
2405 LoadViews();
2409 void CMainFrame::OnUpdateViewSwitchleft(CCmdUI *pCmdUI)
2411 BOOL bEnable = !IsViewGood(m_pwndBottomView);
2412 pCmdUI->Enable(bEnable);
2415 void CMainFrame::OnUpdateViewShowfilelist(CCmdUI *pCmdUI)
2417 BOOL bEnable = m_dlgFilePatches.HasFiles();
2418 pCmdUI->Enable(bEnable);
2419 pCmdUI->SetCheck(m_dlgFilePatches.IsWindowVisible());
2422 void CMainFrame::OnViewShowfilelist()
2424 m_dlgFilePatches.ShowWindow(m_dlgFilePatches.IsWindowVisible() ? SW_HIDE : SW_SHOW);
2427 void CMainFrame::OnEditUndo()
2429 if (CUndo::GetInstance().CanUndo())
2431 CUndo::GetInstance().Undo(m_pwndLeftView, m_pwndRightView, m_pwndBottomView);
2435 void CMainFrame::OnUpdateEditUndo(CCmdUI *pCmdUI)
2437 pCmdUI->Enable(CUndo::GetInstance().CanUndo());
2440 void CMainFrame::OnEditEnable()
2442 CBaseView * pView = GetActiveBaseView();
2443 if (pView && pView->IsReadonlyChangable())
2445 bool isReadOnly = pView->IsReadonly();
2446 pView->SetReadonly(!isReadOnly);
2450 void CMainFrame::OnUpdateEditEnable(CCmdUI *pCmdUI)
2452 CBaseView * pView = GetActiveBaseView();
2453 if (pView)
2455 pCmdUI->Enable(pView->IsReadonlyChangable() || !pView->IsReadonly());
2456 pCmdUI->SetCheck(!pView->IsReadonly());
2458 else
2460 pCmdUI->Enable(FALSE);
2464 void CMainFrame::OnIndicatorLeftview()
2466 if (m_bUseRibbons)
2467 return;
2468 if (IsViewGood(m_pwndLeftView))
2470 m_pwndLeftView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_LEFTVIEW);
2474 void CMainFrame::OnIndicatorRightview()
2476 if (m_bUseRibbons)
2477 return;
2478 if (IsViewGood(m_pwndRightView))
2480 m_pwndRightView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_RIGHTVIEW);
2484 void CMainFrame::OnIndicatorBottomview()
2486 if (m_bUseRibbons)
2487 return;
2488 if (IsViewGood(m_pwndBottomView))
2490 m_pwndBottomView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_BOTTOMVIEW);
2494 int CMainFrame::CheckForReload()
2496 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
2497 if (bLock)
2499 return IDNO;
2501 bLock = true;
2502 bool bSourceChanged =
2503 m_Data.m_baseFile.HasSourceFileChanged()
2504 || m_Data.m_yourFile.HasSourceFileChanged()
2505 || m_Data.m_theirFile.HasSourceFileChanged()
2506 /*|| m_Data.m_mergedFile.HasSourceFileChanged()*/;
2507 if (!bSourceChanged)
2509 bLock = false;
2510 return IDNO;
2513 UINT ret = IDNO;
2514 if (m_bUseTaskDialog)
2516 CString msg = HasUnsavedEdits() ? CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDELOOSECHANGES)) : CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE));
2517 CTaskDialog taskdlg(msg,
2518 CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE_TASK2)),
2519 L"TortoiseGitMerge",
2521 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
2522 CString sTask3;
2523 if (HasUnsavedEdits())
2524 sTask3.LoadString(IDS_WARNMODIFIEDOUTSIDE_TASK3);
2525 else
2526 sTask3.LoadString(IDS_WARNMODIFIEDOUTSIDE_TASK4);
2527 taskdlg.AddCommandControl(IDYES, sTask3);
2528 taskdlg.AddCommandControl(IDNO, CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE_TASK5)));
2529 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2530 taskdlg.SetDefaultCommandControl(IDYES);
2531 taskdlg.SetMainIcon(TD_WARNING_ICON);
2532 ret = (UINT)taskdlg.DoModal(m_hWnd);
2534 else
2536 int idsMessage = HasUnsavedEdits() ? IDS_WARNMODIFIEDOUTSIDELOOSECHANGES : IDS_WARNMODIFIEDOUTSIDE;
2537 ret = CMessageBox::Show(m_hWnd, idsMessage, IDS_APPNAME, MB_YESNO | MB_ICONQUESTION);
2540 if (ret == IDYES)
2542 CDiffColors::GetInstance().LoadRegistry();
2543 LoadViews(-1);
2545 else
2547 if (IsViewGood(m_pwndBottomView)) // three pane view
2549 /*if (m_Data.m_sourceFile.HasSourceFileChanged())
2550 m_pwndBottomView->SetModified();
2551 if (m_Data.m_mergedFile.HasSourceFileChanged())
2552 m_pwndBottomView->SetModified();//*/
2553 if (m_Data.m_yourFile.HasSourceFileChanged())
2554 m_pwndRightView->SetModified();
2555 if (m_Data.m_theirFile.HasSourceFileChanged())
2556 m_pwndLeftView->SetModified();
2558 else if (IsViewGood(m_pwndRightView)) // two pane view
2560 if (m_Data.m_baseFile.HasSourceFileChanged())
2561 m_pwndLeftView->SetModified();
2562 if (m_Data.m_yourFile.HasSourceFileChanged())
2563 m_pwndRightView->SetModified();
2565 else
2567 if (m_Data.m_yourFile.HasSourceFileChanged())
2568 m_pwndLeftView->SetModified();
2571 // no reload just store updated file time
2572 m_Data.m_baseFile.StoreFileAttributes();
2573 m_Data.m_theirFile.StoreFileAttributes();
2574 m_Data.m_yourFile.StoreFileAttributes();
2575 //m_Data.m_mergedFile.StoreFileAttributes();
2577 bLock = false;
2578 return ret;
2581 int CMainFrame::CheckForSave(ECheckForSaveReason eReason)
2583 int idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2584 int idNoSave = IDS_ASKFORSAVE_TASK7;
2585 int idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2586 switch (eReason)
2588 case CHFSR_CLOSE:
2589 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2590 idNoSave = IDS_ASKFORSAVE_TASK4;
2591 idCancelAction = IDS_ASKFORSAVE_TASK5;
2592 break;
2593 case CHFSR_SWITCH:
2594 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2595 //idNoSave = IDS_ASKFORSAVE_TASK7;
2596 idCancelAction = IDS_ASKFORSAVE_TASK8;
2597 break;
2598 case CHFSR_RELOAD:
2599 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2600 //idNoSave = IDS_ASKFORSAVE_TASK7;
2601 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2602 break;
2603 case CHFSR_OPTIONS:
2604 idTitle = IDS_WARNMODIFIEDLOOSECHANGESOPTIONS;
2605 //idNoSave = IDS_ASKFORSAVE_TASK7;
2606 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPTIONS;
2607 break;
2608 case CHFSR_OPEN:
2609 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2610 idNoSave = IDS_ASKFORSAVE_NOSAVE_OPEN;
2611 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2612 break;
2615 CString sTitle(MAKEINTRESOURCE(idTitle));
2616 CString sSubTitle(MAKEINTRESOURCE(IDS_ASKFORSAVE_TASK2));
2617 CString sNoSave(MAKEINTRESOURCE(idNoSave));
2618 CString sCancelAction(MAKEINTRESOURCE(idCancelAction));
2619 CString sAppName(MAKEINTRESOURCE(IDS_APPNAME));
2621 // TODO simplify logic, reduce code duplication
2622 if (CBaseView::IsViewGood(m_pwndBottomView))
2624 // three-way diff - by design only bottom can be changed
2625 // use 1.7 way to do that
2627 else if (CBaseView::IsViewGood(m_pwndRightView))
2629 // two-way diff -
2630 // 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
2631 if (HasUnsavedEdits(m_pwndLeftView))
2633 // both views
2634 UINT ret = IDNO;
2635 if (m_bUseTaskDialog)
2637 CTaskDialog taskdlg(sTitle,
2638 sSubTitle,
2639 sAppName,
2641 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
2642 CString sTaskTemp;
2643 if (m_pwndLeftView->m_pWorkingFile->InUse() && !m_pwndLeftView->m_pWorkingFile->IsReadonly())
2644 sTaskTemp.Format(IDS_ASKFORSAVE_SAVELEFT, (LPCTSTR)m_pwndLeftView->m_pWorkingFile->GetFilename());
2645 else
2646 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS));
2647 taskdlg.AddCommandControl(201, sTaskTemp); // left
2648 taskdlg.SetDefaultCommandControl(201);
2649 if (HasUnsavedEdits(m_pwndRightView))
2651 if (m_pwndRightView->m_pWorkingFile->InUse() && !m_pwndRightView->m_pWorkingFile->IsReadonly())
2652 sTaskTemp.Format(IDS_ASKFORSAVE_SAVERIGHT, (LPCTSTR)m_pwndRightView->m_pWorkingFile->GetFilename());
2653 else
2654 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS));
2655 taskdlg.AddCommandControl(202, sTaskTemp); // right
2656 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEALL2))); // both
2657 taskdlg.SetDefaultCommandControl(203);
2659 taskdlg.AddCommandControl(IDNO, sNoSave); // none
2660 taskdlg.AddCommandControl(IDCANCEL, sCancelAction); // cancel
2661 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2662 taskdlg.SetMainIcon(TD_WARNING_ICON);
2663 ret = (UINT)taskdlg.DoModal(m_hWnd);
2664 switch (ret)
2666 case 201: // left
2667 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
2668 break;
2669 case 203: // both
2670 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
2671 case 202: // right
2672 m_pwndRightView->SaveFile();
2673 break;
2675 return ret;
2677 else
2679 // show separate questions
2680 // first show question for left view
2681 ret = MessageBox(sTitle, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
2682 if (ret == IDCANCEL)
2684 return IDCANCEL;
2686 if (ret == IDYES)
2688 if (m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES)<0)
2690 return IDCANCEL;
2693 // right file is handled old way
2696 else
2698 // only secondary (left) view
2700 // only right view - 1.7 implementation is used
2702 else if (CBaseView::IsViewGood(m_pwndLeftView))
2704 // only one view - only one to save
2705 // 1.7 FileSave don't support this mode
2706 if (HasUnsavedEdits(m_pwndLeftView))
2708 UINT ret = IDNO;
2709 if (m_bUseTaskDialog)
2711 CTaskDialog taskdlg(sTitle,
2712 sSubTitle,
2713 sAppName,
2715 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
2716 CString sTask3;
2717 if (m_Data.m_mergedFile.InUse())
2718 sTask3.Format(IDS_ASKFORSAVE_TASK3, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
2719 else
2720 sTask3.LoadString(IDS_ASKFORSAVE_TASK6);
2721 taskdlg.AddCommandControl(IDYES, sTask3);
2722 taskdlg.AddCommandControl(IDNO, sNoSave);
2723 taskdlg.AddCommandControl(IDCANCEL, sCancelAction);
2724 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2725 taskdlg.SetDefaultCommandControl(IDYES);
2726 taskdlg.SetMainIcon(TD_WARNING_ICON);
2727 ret = (UINT)taskdlg.DoModal(m_hWnd);
2729 else
2731 ret = MessageBox(sTitle, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
2734 if (ret == IDYES)
2736 if (m_pwndLeftView->SaveFile()<0)
2737 return IDCANCEL;
2740 return IDNO;
2742 else
2744 return IDNO; // nothing to save
2747 // 1.7 implementation
2748 UINT ret = IDNO;
2749 if (HasUnsavedEdits())
2751 if (m_bUseTaskDialog)
2753 CTaskDialog taskdlg(sTitle,
2754 sSubTitle,
2755 sAppName,
2757 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
2758 CString sTask3;
2759 if (m_Data.m_mergedFile.InUse())
2760 sTask3.Format(IDS_ASKFORSAVE_TASK3, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
2761 else
2762 sTask3.LoadString(IDS_ASKFORSAVE_TASK6);
2763 taskdlg.AddCommandControl(IDYES, sTask3);
2764 taskdlg.AddCommandControl(IDNO, sNoSave);
2765 taskdlg.AddCommandControl(IDCANCEL, sCancelAction);
2766 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2767 taskdlg.SetDefaultCommandControl(IDYES);
2768 taskdlg.SetMainIcon(TD_WARNING_ICON);
2769 ret = (UINT)taskdlg.DoModal(m_hWnd);
2771 else
2773 ret = MessageBox(sTitle, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
2776 if (ret == IDYES)
2778 if (!FileSave())
2779 ret = IDCANCEL;
2782 return ret;
2785 bool CMainFrame::HasUnsavedEdits() const
2787 return HasUnsavedEdits(m_pwndBottomView) || HasUnsavedEdits(m_pwndRightView) || m_bSaveRequired;
2790 bool CMainFrame::HasUnsavedEdits(const CBaseView* view)
2792 if (!CBaseView::IsViewGood(view))
2793 return false;
2794 return view->IsModified();
2797 bool CMainFrame::IsViewGood(const CBaseView* view)
2799 return CBaseView::IsViewGood(view);
2802 void CMainFrame::OnViewInlinediffword()
2804 m_bInlineWordDiff = !m_bInlineWordDiff;
2805 if (m_pwndLeftView)
2807 m_pwndLeftView->SetInlineWordDiff(m_bInlineWordDiff);
2808 m_pwndLeftView->BuildAllScreen2ViewVector();
2809 m_pwndLeftView->DocumentUpdated();
2811 if (m_pwndRightView)
2813 m_pwndRightView->SetInlineWordDiff(m_bInlineWordDiff);
2814 m_pwndRightView->BuildAllScreen2ViewVector();
2815 m_pwndRightView->DocumentUpdated();
2817 if (m_pwndBottomView)
2819 m_pwndBottomView->SetInlineWordDiff(m_bInlineWordDiff);
2820 m_pwndBottomView->BuildAllScreen2ViewVector();
2821 m_pwndBottomView->DocumentUpdated();
2823 m_wndLineDiffBar.DocumentUpdated();
2826 void CMainFrame::OnUpdateViewInlinediffword(CCmdUI *pCmdUI)
2828 pCmdUI->Enable(m_bInlineDiff && IsViewGood(m_pwndLeftView) && IsViewGood(m_pwndRightView));
2829 pCmdUI->SetCheck(m_bInlineWordDiff);
2832 void CMainFrame::OnViewInlinediff()
2834 m_bInlineDiff = !m_bInlineDiff;
2835 if (m_pwndLeftView)
2837 m_pwndLeftView->SetInlineDiff(m_bInlineDiff);
2838 m_pwndLeftView->BuildAllScreen2ViewVector();
2839 m_pwndLeftView->DocumentUpdated();
2841 if (m_pwndRightView)
2843 m_pwndRightView->SetInlineDiff(m_bInlineDiff);
2844 m_pwndRightView->BuildAllScreen2ViewVector();
2845 m_pwndRightView->DocumentUpdated();
2847 if (m_pwndBottomView)
2849 m_pwndBottomView->SetInlineDiff(m_bInlineDiff);
2850 m_pwndBottomView->BuildAllScreen2ViewVector();
2851 m_pwndBottomView->DocumentUpdated();
2853 m_wndLineDiffBar.DocumentUpdated();
2856 void CMainFrame::OnUpdateViewInlinediff(CCmdUI *pCmdUI)
2858 pCmdUI->Enable(IsViewGood(m_pwndLeftView) && IsViewGood(m_pwndRightView));
2859 pCmdUI->SetCheck(m_bInlineDiff);
2862 void CMainFrame::OnUpdateEditCreateunifieddifffile(CCmdUI *pCmdUI)
2864 // "create unified diff file" is only available if two files
2865 // are diffed, not three.
2866 bool bEnabled = true;
2867 if (!IsViewGood(m_pwndLeftView))
2868 bEnabled = false;
2869 else if (!IsViewGood(m_pwndRightView))
2870 bEnabled = false;
2871 else if (IsViewGood(m_pwndBottomView)) //no negation here
2872 bEnabled = false;
2873 pCmdUI->Enable(bEnabled);
2876 void CMainFrame::OnEditCreateunifieddifffile()
2878 CString origFile, modifiedFile;
2879 // the original file is the one on the left
2880 if (m_pwndLeftView)
2881 origFile = m_pwndLeftView->m_sFullFilePath;
2882 if (m_pwndRightView)
2883 modifiedFile = m_pwndRightView->m_sFullFilePath;
2884 if (origFile.IsEmpty() || modifiedFile.IsEmpty())
2885 return;
2887 CString outputFile;
2888 if(!TryGetFileName(outputFile))
2889 return;
2891 CAppUtils::CreateUnifiedDiff(origFile, modifiedFile, outputFile, true);
2894 void CMainFrame::OnUpdateViewLinediffbar(CCmdUI *pCmdUI)
2896 pCmdUI->SetCheck(m_bLineDiff);
2897 pCmdUI->Enable();
2900 void CMainFrame::OnViewLinediffbar()
2902 m_bLineDiff = !m_bLineDiff;
2903 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2904 m_wndLineDiffBar.DocumentUpdated();
2905 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2906 m_wndLocatorBar.DocumentUpdated();
2909 void CMainFrame::OnUpdateViewLocatorbar(CCmdUI *pCmdUI)
2911 pCmdUI->SetCheck(m_bLocatorBar);
2912 pCmdUI->Enable();
2915 void CMainFrame::OnViewLocatorbar()
2917 m_bLocatorBar = !m_bLocatorBar;
2918 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2919 m_wndLocatorBar.DocumentUpdated();
2920 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2921 m_wndLineDiffBar.DocumentUpdated();
2924 void CMainFrame::OnViewComparewhitespaces()
2926 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2927 return;
2928 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2929 regIgnoreWS = 0;
2930 LoadViews(-1);
2933 void CMainFrame::OnUpdateViewComparewhitespaces(CCmdUI *pCmdUI)
2935 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2936 DWORD dwIgnoreWS = regIgnoreWS;
2937 pCmdUI->SetCheck(dwIgnoreWS == 0);
2940 void CMainFrame::OnViewIgnorewhitespacechanges()
2942 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2943 return;
2944 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2945 regIgnoreWS = 2;
2946 LoadViews(-1);
2949 void CMainFrame::OnUpdateViewIgnorewhitespacechanges(CCmdUI *pCmdUI)
2951 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2952 DWORD dwIgnoreWS = regIgnoreWS;
2953 pCmdUI->SetCheck(dwIgnoreWS == 2);
2956 void CMainFrame::OnViewIgnoreallwhitespacechanges()
2958 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2959 return;
2960 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2961 regIgnoreWS = 1;
2962 LoadViews(-1);
2965 void CMainFrame::OnUpdateViewIgnoreallwhitespacechanges(CCmdUI *pCmdUI)
2967 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2968 DWORD dwIgnoreWS = regIgnoreWS;
2969 pCmdUI->SetCheck(dwIgnoreWS == 1);
2972 void CMainFrame::OnViewMovedBlocks()
2974 m_bViewMovedBlocks = !(DWORD)m_regViewModedBlocks;
2975 m_regViewModedBlocks = m_bViewMovedBlocks;
2976 LoadViews(-1);
2979 void CMainFrame::OnUpdateViewMovedBlocks(CCmdUI *pCmdUI)
2981 pCmdUI->SetCheck(m_bViewMovedBlocks);
2982 BOOL bEnable = TRUE;
2983 if (IsViewGood(m_pwndBottomView))
2985 bEnable = FALSE;
2987 pCmdUI->Enable(bEnable);
2990 bool CMainFrame::HasConflictsWontKeep()
2992 const int nConflictLine = CheckResolved();
2993 if (nConflictLine < 0)
2994 return false;
2996 CString sTemp;
2997 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
2998 bool bSave = false;
2999 if (m_bUseTaskDialog)
3001 CTaskDialog taskdlg(sTemp,
3002 CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK2)),
3003 L"TortoiseGitMerge",
3005 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
3006 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK3)));
3007 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK4)));
3008 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
3009 taskdlg.SetDefaultCommandControl(2);
3010 taskdlg.SetMainIcon(TD_ERROR_ICON);
3011 bSave = (taskdlg.DoModal(m_hWnd) == 1);
3013 else
3015 bSave = (MessageBox(sTemp, 0, MB_ICONERROR | MB_YESNO)==IDYES);
3018 if (bSave)
3019 return false;
3021 if (m_pwndBottomView)
3022 m_pwndBottomView->GoToLine(nConflictLine);
3023 return true;
3026 bool CMainFrame::TryGetFileName(CString& result)
3028 return CCommonAppUtils::FileOpenSave(result, NULL, IDS_SAVEASTITLE, IDS_COMMONFILEFILTER, false, m_hWnd);
3031 CBaseView* CMainFrame::GetActiveBaseView() const
3033 CView* activeView = GetActiveView();
3034 CBaseView* activeBase = dynamic_cast<CBaseView*>( activeView );
3035 return activeBase;
3038 void CMainFrame::SetWindowTitle()
3040 // try to find a suitable window title
3041 CString sYour = m_Data.m_yourFile.GetDescriptiveName();
3042 if (sYour.Find(_T(" - "))>=0)
3043 sYour = sYour.Left(sYour.Find(_T(" - ")));
3044 if (sYour.Find(_T(" : "))>=0)
3045 sYour = sYour.Left(sYour.Find(_T(" : ")));
3046 CString sTheir = m_Data.m_theirFile.GetDescriptiveName();
3047 if (sTheir.IsEmpty())
3048 sTheir = m_Data.m_baseFile.GetDescriptiveName();
3049 if (sTheir.Find(_T(" - "))>=0)
3050 sTheir = sTheir.Left(sTheir.Find(_T(" - ")));
3051 if (sTheir.Find(_T(" : "))>=0)
3052 sTheir = sTheir.Left(sTheir.Find(_T(" : ")));
3054 if (!sYour.IsEmpty() && !sTheir.IsEmpty())
3056 if (sYour.CompareNoCase(sTheir)==0)
3057 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
3058 else if ((sYour.GetLength() < 10) &&
3059 (sTheir.GetLength() < 10))
3060 SetWindowText(sYour + _T(" - ") + sTheir + _T(" - TortoiseGitMerge"));
3061 else
3063 // we have two very long descriptive texts here, which
3064 // means we have to find a way to use them as a window
3065 // title in a shorter way.
3066 // for simplicity, we just use the one from "yourfile"
3067 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
3070 else if (!sYour.IsEmpty())
3071 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
3072 else if (!sTheir.IsEmpty())
3073 SetWindowText(sTheir + _T(" - TortoiseGitMerge"));
3074 else
3075 SetWindowText(L"TortoiseGitMerge");
3078 void CMainFrame::OnTimer(UINT_PTR nIDEvent)
3080 switch (nIDEvent)
3082 case IDT_RELOADCHECKTIMER:
3083 KillTimer(nIDEvent);
3084 CheckForReload();
3085 break;
3088 __super::OnTimer(nIDEvent);
3091 void CMainFrame::LoadIgnoreCommentData()
3093 static bool bLoaded = false;
3094 if (bLoaded)
3095 return;
3096 CString sPath = CPathUtils::GetAppDataDirectory() + L"ignorecomments.txt";
3097 if (!PathFileExists(sPath))
3099 // ignore comments file does not exist (yet), so create a default one
3100 HRSRC hRes = FindResource(NULL, MAKEINTRESOURCE(IDR_IGNORECOMMENTSTXT), L"config");
3101 if (hRes)
3103 HGLOBAL hResourceLoaded = LoadResource(NULL, hRes);
3104 if (hResourceLoaded)
3106 char * lpResLock = (char *) LockResource(hResourceLoaded);
3107 DWORD dwSizeRes = SizeofResource(NULL, hRes);
3108 if (lpResLock)
3110 HANDLE hFile = CreateFile(sPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3111 if (hFile != INVALID_HANDLE_VALUE)
3113 DWORD dwWritten = 0;
3114 WriteFile(hFile, lpResLock, dwSizeRes, &dwWritten, NULL);
3115 CloseHandle(hFile);
3121 CStdioFile file;
3122 if (file.Open(sPath, CFile::modeRead))
3124 CString sLine;
3125 while (file.ReadString(sLine))
3127 int eqpos = sLine.Find('=');
3128 if (eqpos >= 0)
3130 CString sExts = sLine.Left(eqpos);
3131 CString sComments = sLine.Mid(eqpos+1);
3133 int pos = sComments.Find(',');
3134 CString sLineStart = sComments.Left(pos);
3135 pos = sComments.Find(',', pos);
3136 int pos2 = sComments.Find(',', pos+1);
3137 CString sBlockStart = sComments.Mid(pos+1, pos2-pos-1);
3138 CString sBlockEnd = sComments.Mid(pos2+1);
3140 auto commentTuple = std::make_tuple(sLineStart, sBlockStart, sBlockEnd);
3142 pos = 0;
3143 CString temp;
3144 for (;;)
3146 temp = sExts.Tokenize(_T(","),pos);
3147 if (temp.IsEmpty())
3149 break;
3151 ASSERT(m_IgnoreCommentsMap.find(temp) == m_IgnoreCommentsMap.end());
3152 m_IgnoreCommentsMap[temp] = commentTuple;
3157 bLoaded = true;
3160 void CMainFrame::OnViewIgnorecomments()
3162 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3163 return;
3164 m_regIgnoreComments = !DWORD(m_regIgnoreComments);
3165 LoadViews(-1);
3168 void CMainFrame::OnUpdateViewIgnorecomments(CCmdUI *pCmdUI)
3170 // only enable if we have comments defined for this file extension
3171 CString sExt = CPathUtils::GetFileExtFromPath(m_Data.m_baseFile.GetFilename()).MakeLower();
3172 sExt.TrimLeft(L".");
3173 auto sC = m_IgnoreCommentsMap.find(sExt);
3174 if (sC == m_IgnoreCommentsMap.end())
3176 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_yourFile.GetFilename()).MakeLower();
3177 sExt.TrimLeft(L".");
3178 sC = m_IgnoreCommentsMap.find(sExt);
3179 if (sC == m_IgnoreCommentsMap.end())
3181 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_theirFile.GetFilename()).MakeLower();
3182 sExt.TrimLeft(L".");
3183 sC = m_IgnoreCommentsMap.find(sExt);
3186 pCmdUI->Enable(sC != m_IgnoreCommentsMap.end());
3188 pCmdUI->SetCheck(DWORD(m_regIgnoreComments) != 0);
3192 void CMainFrame::OnRegexfilter(UINT cmd)
3194 if ((cmd == ID_REGEXFILTER)||(cmd == (ID_REGEXFILTER+1)))
3196 CRegexFiltersDlg dlg(this);
3197 dlg.SetIniFile(&m_regexIni);
3198 if (dlg.DoModal() == IDOK)
3200 FILE * pFile = NULL;
3201 _tfopen_s(&pFile, CPathUtils::GetAppDataDirectory() + L"regexfilters.ini", _T("wb"));
3202 m_regexIni.SaveFile(pFile);
3203 fclose(pFile);
3205 BuildRegexSubitems();
3207 else
3209 if (cmd == (UINT)m_regexIndex)
3211 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3212 return;
3213 m_Data.SetRegexTokens(std::wregex(), L"");
3214 m_regexIndex = -1;
3215 LoadViews(-1);
3217 else
3219 CSimpleIni::TNamesDepend sections;
3220 m_regexIni.GetAllSections(sections);
3221 int index = ID_REGEXFILTER + 2;
3222 m_regexIndex = -1;
3223 for (const auto& section : sections)
3225 if (cmd == (UINT)index)
3227 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3228 break;
3231 std::wregex rx(m_regexIni.GetValue(section, L"regex", L""));
3232 m_Data.SetRegexTokens(rx, m_regexIni.GetValue(section, L"replace", L""));
3234 catch (std::exception &ex)
3236 MessageBox(_T("Regex is invalid!\r\n") + CString(ex.what()));
3238 m_regexIndex = index;
3239 LoadViews(-1);
3240 break;
3242 ++index;
3248 void CMainFrame::OnUpdateViewRegexFilter( CCmdUI *pCmdUI )
3250 pCmdUI->Enable();
3251 pCmdUI->SetCheck(pCmdUI->m_nID == (UINT)m_regexIndex);
3254 void CMainFrame::BuildRegexSubitems()
3256 CArray<CMFCRibbonBaseElement*, CMFCRibbonBaseElement*> arButtons;
3257 m_wndRibbonBar.GetElementsByID(ID_REGEXFILTER, arButtons);
3258 if (arButtons.GetCount() == 1)
3260 CMFCRibbonButton * pButton = (CMFCRibbonButton*)arButtons.GetAt(0);
3261 if (pButton)
3263 pButton->RemoveAllSubItems();
3264 pButton->AddSubItem(new CMFCRibbonButton(ID_REGEXFILTER+1, CString(MAKEINTRESOURCE(IDS_CONFIGUREREGEXES)), 47));
3266 CString sIniPath = CPathUtils::GetAppDataDirectory() + L"regexfilters.ini";
3267 if (!PathFileExists(sIniPath))
3269 // ini file does not exist (yet), so create a default one
3270 HRSRC hRes = FindResource(NULL, MAKEINTRESOURCE(IDR_REGEXFILTERINI), L"config");
3271 if (hRes)
3273 HGLOBAL hResourceLoaded = LoadResource(NULL, hRes);
3274 if (hResourceLoaded)
3276 char * lpResLock = (char *) LockResource(hResourceLoaded);
3277 DWORD dwSizeRes = SizeofResource(NULL, hRes);
3278 if (lpResLock)
3280 HANDLE hFile = CreateFile(sIniPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3281 if (hFile != INVALID_HANDLE_VALUE)
3283 DWORD dwWritten = 0;
3284 WriteFile(hFile, lpResLock, dwSizeRes, &dwWritten, NULL);
3285 CloseHandle(hFile);
3292 m_regexIni.LoadFile(sIniPath);
3293 CSimpleIni::TNamesDepend sections;
3294 m_regexIni.GetAllSections(sections);
3295 if (!sections.empty())
3296 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3297 int cmdIndex = 2;
3298 for (const auto& section : sections)
3300 pButton->AddSubItem(new CMFCRibbonButton(ID_REGEXFILTER+cmdIndex, section, 46));
3301 cmdIndex++;
3307 void CMainFrame::FillEncodingButton( CMFCRibbonButton * pButton, int start )
3309 pButton->SetDefaultCommand(FALSE);
3310 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::ASCII, L"ASCII" ));
3311 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::BINARY, L"BINARY" ));
3312 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_LE, L"UTF-16LE" ));
3313 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_LEBOM, L"UTF-16LE BOM"));
3314 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_BE, L"UTF-16BE" ));
3315 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_BEBOM, L"UTF-16BE BOM"));
3316 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF32_LE, L"UTF-32LE" ));
3317 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF32_BE, L"UTF-32BE" ));
3318 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF8, L"UTF-8" ));
3319 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF8BOM, L"UTF-8 BOM" ));
3322 void CMainFrame::FillEOLButton( CMFCRibbonButton * pButton, int start )
3324 pButton->SetDefaultCommand(FALSE);
3325 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LF , L"LF" ));
3326 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_CRLF, L"CRLF"));
3327 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LFCR, L"LRCR"));
3328 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_CR , L"CR" ));
3329 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_VT , L"VT" ));
3330 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_FF , L"FF" ));
3331 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_NEL , L"NEL" ));
3332 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LS , L"LS" ));
3333 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_PS , L"PS" ));
3336 void CMainFrame::FillTabModeButton(CMFCRibbonButton * pButton, int start)
3338 pButton->SetDefaultCommand(FALSE);
3339 pButton->AddSubItem(new CMFCRibbonButton(start + TABMODE_NONE , L"Tab"));
3340 pButton->AddSubItem(new CMFCRibbonButton(start + TABMODE_USESPACES , L"Space"));
3341 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3342 pButton->AddSubItem(new CMFCRibbonButton(start + TABMODE_SMARTINDENT , L"Smart tab char"));
3343 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3344 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON1, L"1"));
3345 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON2, L"2"));
3346 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON4, L"4"));
3347 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON8, L"8"));
3348 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3349 pButton->AddSubItem(new CMFCRibbonButton(start + ENABLEEDITORCONFIG, L"EditorConfig"));
3352 void CMainFrame::OnEncodingLeft( UINT cmd )
3354 if (m_pwndLeftView)
3356 m_pwndLeftView->SetTextType(CFileTextLines::UnicodeType(cmd-ID_INDICATOR_LEFTENCODINGSTART));
3357 m_pwndLeftView->RefreshViews();
3361 void CMainFrame::OnEncodingRight( UINT cmd )
3363 if (m_pwndRightView)
3365 m_pwndRightView->SetTextType(CFileTextLines::UnicodeType(cmd-ID_INDICATOR_RIGHTENCODINGSTART));
3366 m_pwndRightView->RefreshViews();
3370 void CMainFrame::OnEncodingBottom( UINT cmd )
3372 if (m_pwndBottomView)
3374 m_pwndBottomView->SetTextType(CFileTextLines::UnicodeType(cmd-ID_INDICATOR_BOTTOMENCODINGSTART));
3375 m_pwndBottomView->RefreshViews();
3379 void CMainFrame::OnEOLLeft( UINT cmd )
3381 if (m_pwndLeftView)
3383 m_pwndLeftView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_LEFTEOLSTART));
3384 m_pwndLeftView->RefreshViews();
3388 void CMainFrame::OnEOLRight( UINT cmd )
3390 if (m_pwndRightView)
3392 m_pwndRightView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_RIGHTEOLSTART));
3393 m_pwndRightView->RefreshViews();
3397 void CMainFrame::OnEOLBottom( UINT cmd )
3399 if (m_pwndBottomView)
3401 m_pwndBottomView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_BOTTOMEOLSTART));
3402 m_pwndBottomView->RefreshViews();
3406 void CMainFrame::OnTabModeLeft( UINT cmd )
3408 OnTabMode(m_pwndLeftView, (int)cmd - ID_INDICATOR_LEFTTABMODESTART);
3411 void CMainFrame::OnTabModeRight( UINT cmd )
3413 OnTabMode(m_pwndRightView, (int)cmd - ID_INDICATOR_RIGHTTABMODESTART);
3416 void CMainFrame::OnTabModeBottom( UINT cmd )
3418 OnTabMode(m_pwndBottomView, (int)cmd - ID_INDICATOR_BOTTOMTABMODESTART);
3421 void CMainFrame::OnTabMode(CBaseView *view, int cmd)
3423 if (!view)
3424 return;
3425 int nTabMode = view->GetTabMode();
3426 if (cmd == TABMODE_NONE || cmd == TABMODE_USESPACES)
3427 view->SetTabMode((nTabMode & (~TABMODE_USESPACES)) | (cmd & TABMODE_USESPACES));
3428 else if (cmd == TABMODE_SMARTINDENT) // Toggle
3429 view->SetTabMode((nTabMode & (~TABMODE_SMARTINDENT)) | (nTabMode & TABMODE_SMARTINDENT ? 0 : TABMODE_SMARTINDENT));
3430 else if (cmd == TABSIZEBUTTON1)
3431 view->SetTabSize(1);
3432 else if (cmd == TABSIZEBUTTON2)
3433 view->SetTabSize(2);
3434 else if (cmd == TABSIZEBUTTON4)
3435 view->SetTabSize(4);
3436 else if (cmd == TABSIZEBUTTON8)
3437 view->SetTabSize(8);
3438 else if (cmd == ENABLEEDITORCONFIG)
3439 view->SetEditorConfigEnabled(!view->GetEditorConfigEnabled());
3440 view->RefreshViews();
3443 void CMainFrame::OnUpdateEncodingLeft( CCmdUI *pCmdUI )
3445 if (m_pwndLeftView)
3447 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_LEFTENCODINGSTART) == m_pwndLeftView->GetTextType());
3448 pCmdUI->Enable(m_pwndLeftView->IsWritable());
3450 else
3451 pCmdUI->Enable(FALSE);
3454 void CMainFrame::OnUpdateEncodingRight( CCmdUI *pCmdUI )
3456 if (m_pwndRightView)
3458 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_RIGHTENCODINGSTART) == m_pwndRightView->GetTextType());
3459 pCmdUI->Enable(m_pwndRightView->IsWritable());
3461 else
3462 pCmdUI->Enable(FALSE);
3465 void CMainFrame::OnUpdateEncodingBottom( CCmdUI *pCmdUI )
3467 if (m_pwndBottomView)
3469 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_BOTTOMENCODINGSTART) == m_pwndBottomView->GetTextType());
3470 pCmdUI->Enable(m_pwndBottomView->IsWritable());
3472 else
3473 pCmdUI->Enable(FALSE);
3476 void CMainFrame::OnUpdateEOLLeft( CCmdUI *pCmdUI )
3478 if (m_pwndLeftView)
3480 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_LEFTEOLSTART) == m_pwndLeftView->GetLineEndings());
3481 pCmdUI->Enable(m_pwndLeftView->IsWritable());
3483 else
3484 pCmdUI->Enable(FALSE);
3487 void CMainFrame::OnUpdateEOLRight( CCmdUI *pCmdUI )
3489 if (m_pwndRightView)
3491 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_RIGHTEOLSTART) == m_pwndRightView->GetLineEndings());
3492 pCmdUI->Enable(m_pwndRightView->IsWritable());
3494 else
3495 pCmdUI->Enable(FALSE);
3498 void CMainFrame::OnUpdateEOLBottom( CCmdUI *pCmdUI )
3500 if (m_pwndBottomView)
3502 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_BOTTOMEOLSTART) == m_pwndBottomView->GetLineEndings());
3503 pCmdUI->Enable(m_pwndBottomView->IsWritable());
3505 else
3506 pCmdUI->Enable(FALSE);
3509 void CMainFrame::OnUpdateTabModeLeft(CCmdUI *pCmdUI)
3511 OnUpdateTabMode(m_pwndLeftView, pCmdUI, ID_INDICATOR_LEFTTABMODESTART);
3514 void CMainFrame::OnUpdateTabModeRight(CCmdUI *pCmdUI)
3516 OnUpdateTabMode(m_pwndRightView, pCmdUI, ID_INDICATOR_RIGHTTABMODESTART);
3519 void CMainFrame::OnUpdateTabModeBottom(CCmdUI *pCmdUI)
3521 OnUpdateTabMode(m_pwndBottomView, pCmdUI, ID_INDICATOR_BOTTOMTABMODESTART);
3524 void CMainFrame::OnUpdateTabMode(CBaseView *view, CCmdUI *pCmdUI, int startid)
3526 if (view)
3528 int cmd = (int)pCmdUI->m_nID - startid;
3529 if (cmd == TABMODE_NONE)
3530 pCmdUI->SetCheck((view->GetTabMode() & TABMODE_USESPACES) == TABMODE_NONE);
3531 else if (cmd == TABMODE_USESPACES)
3532 pCmdUI->SetCheck(view->GetTabMode() & TABMODE_USESPACES);
3533 else if (cmd == TABMODE_SMARTINDENT)
3534 pCmdUI->SetCheck(view->GetTabMode() & TABMODE_SMARTINDENT);
3535 else if (cmd == TABSIZEBUTTON1)
3536 pCmdUI->SetCheck(view->GetTabSize() == 1);
3537 else if (cmd == TABSIZEBUTTON2)
3538 pCmdUI->SetCheck(view->GetTabSize() == 2);
3539 else if (cmd == TABSIZEBUTTON4)
3540 pCmdUI->SetCheck(view->GetTabSize() == 4);
3541 else if (cmd == TABSIZEBUTTON8)
3542 pCmdUI->SetCheck(view->GetTabSize() == 8);
3543 else if (cmd == ENABLEEDITORCONFIG)
3544 pCmdUI->SetCheck(view->GetEditorConfigEnabled());
3545 pCmdUI->Enable(view->IsWritable());
3546 if (cmd == ENABLEEDITORCONFIG)
3547 pCmdUI->Enable(view->IsWritable() && view->GetEditorConfigLoaded());
3549 else
3550 pCmdUI->Enable(FALSE);