Add ad-hoc tab mode combobox in ribbon status bar
[TortoiseGit.git] / src / TortoiseMerge / MainFrm.cpp
blob4fa23197662477a223b82eedad8b0fe7bc447cff
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_EDIT_TABSPACE, &CMainFrame::OnUpdateEditTabspace)
114 ON_COMMAND(ID_EDIT_TABSPACE, &CMainFrame::OnEditTabspace)
115 ON_UPDATE_COMMAND_UI(ID_EDIT_SMARTTAB, &CMainFrame::OnUpdateEditSmartTab)
116 ON_COMMAND(ID_EDIT_SMARTTAB, &CMainFrame::OnEditSmartTab)
117 ON_UPDATE_COMMAND_UI(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnUpdateViewLinediffbar)
118 ON_COMMAND(ID_VIEW_LINEDIFFBAR, &CMainFrame::OnViewLinediffbar)
119 ON_UPDATE_COMMAND_UI(ID_VIEW_LOCATORBAR, &CMainFrame::OnUpdateViewLocatorbar)
120 ON_COMMAND(ID_VIEW_LOCATORBAR, &CMainFrame::OnViewLocatorbar)
121 ON_COMMAND(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnEditUseleftblock)
122 ON_UPDATE_COMMAND_UI(ID_USEBLOCKS, &CMainFrame::OnUpdateUseBlock)
123 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTBLOCK, &CMainFrame::OnUpdateEditUseleftblock)
124 ON_COMMAND(ID_EDIT_USELEFTFILE, &CMainFrame::OnEditUseleftfile)
125 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTFILE, &CMainFrame::OnUpdateEditUseleftfile)
126 ON_COMMAND(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnEditUseblockfromleftbeforeright)
127 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT, &CMainFrame::OnUpdateEditUseblockfromleftbeforeright)
128 ON_COMMAND(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnEditUseblockfromrightbeforeleft)
129 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT, &CMainFrame::OnUpdateEditUseblockfromrightbeforeleft)
130 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTDIFFERENCE, &CMainFrame::OnUpdateNavigateNextdifference)
131 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSDIFFERENCE, &CMainFrame::OnUpdateNavigatePreviousdifference)
132 ON_COMMAND(ID_VIEW_COLLAPSED, &CMainFrame::OnViewCollapsed)
133 ON_UPDATE_COMMAND_UI(ID_VIEW_COLLAPSED, &CMainFrame::OnUpdateViewCollapsed)
134 ON_COMMAND(ID_VIEW_COMPAREWHITESPACES, &CMainFrame::OnViewComparewhitespaces)
135 ON_UPDATE_COMMAND_UI(ID_VIEW_COMPAREWHITESPACES, &CMainFrame::OnUpdateViewComparewhitespaces)
136 ON_COMMAND(ID_VIEW_IGNOREWHITESPACECHANGES, &CMainFrame::OnViewIgnorewhitespacechanges)
137 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREWHITESPACECHANGES, &CMainFrame::OnUpdateViewIgnorewhitespacechanges)
138 ON_COMMAND(ID_VIEW_IGNOREALLWHITESPACECHANGES, &CMainFrame::OnViewIgnoreallwhitespacechanges)
139 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREALLWHITESPACECHANGES, &CMainFrame::OnUpdateViewIgnoreallwhitespacechanges)
140 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTINLINEDIFF, &CMainFrame::OnUpdateNavigateNextinlinediff)
141 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVINLINEDIFF, &CMainFrame::OnUpdateNavigatePrevinlinediff)
142 ON_COMMAND(ID_VIEW_WRAPLONGLINES, &CMainFrame::OnViewWraplonglines)
143 ON_UPDATE_COMMAND_UI(ID_VIEW_WRAPLONGLINES, &CMainFrame::OnUpdateViewWraplonglines)
144 ON_REGISTERED_MESSAGE( TaskBarButtonCreated, CMainFrame::OnTaskbarButtonCreated )
145 ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, &CMainFrame::OnUpdateEditPaste)
146 ON_COMMAND(ID_INDICATOR_LEFTVIEW, &CMainFrame::OnIndicatorLeftview)
147 ON_COMMAND(ID_INDICATOR_RIGHTVIEW, &CMainFrame::OnIndicatorRightview)
148 ON_COMMAND(ID_INDICATOR_BOTTOMVIEW, &CMainFrame::OnIndicatorBottomview)
149 ON_WM_TIMER()
150 ON_COMMAND(ID_VIEW_IGNORECOMMENTS, &CMainFrame::OnViewIgnorecomments)
151 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNORECOMMENTS, &CMainFrame::OnUpdateViewIgnorecomments)
152 ON_COMMAND_RANGE(ID_REGEXFILTER, ID_REGEXFILTER+400, &CMainFrame::OnRegexfilter)
153 ON_UPDATE_COMMAND_UI_RANGE(ID_REGEXFILTER, ID_REGEXFILTER+400, &CMainFrame::OnUpdateViewRegexFilter)
154 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOENCODING, &CMainFrame::OnDummyEnabled)
155 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOENCODING, &CMainFrame::OnDummyEnabled)
156 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOENCODING, &CMainFrame::OnDummyEnabled)
157 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOEOL, &CMainFrame::OnDummyEnabled)
158 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOEOL, &CMainFrame::OnDummyEnabled)
159 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOEOL, &CMainFrame::OnDummyEnabled)
160 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOTABMODE, &CMainFrame::OnDummyEnabled)
161 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOTABMODE, &CMainFrame::OnDummyEnabled)
162 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOTABMODE, &CMainFrame::OnDummyEnabled)
163 ON_COMMAND_RANGE(ID_INDICATOR_LEFTENCODINGSTART, ID_INDICATOR_LEFTENCODINGSTART+19, &CMainFrame::OnEncodingLeft)
164 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTENCODINGSTART, ID_INDICATOR_RIGHTENCODINGSTART+19, &CMainFrame::OnEncodingRight)
165 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMENCODINGSTART, ID_INDICATOR_BOTTOMENCODINGSTART+19, &CMainFrame::OnEncodingBottom)
166 ON_COMMAND_RANGE(ID_INDICATOR_LEFTEOLSTART, ID_INDICATOR_LEFTEOLSTART+19, &CMainFrame::OnEOLLeft)
167 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTEOLSTART, ID_INDICATOR_RIGHTEOLSTART+19, &CMainFrame::OnEOLRight)
168 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMEOLSTART, ID_INDICATOR_BOTTOMEOLSTART+19, &CMainFrame::OnEOLBottom)
169 ON_COMMAND_RANGE(ID_INDICATOR_LEFTTABMODESTART, ID_INDICATOR_LEFTTABMODESTART+19, &CMainFrame::OnTabModeLeft)
170 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTTABMODESTART, ID_INDICATOR_RIGHTTABMODESTART+19, &CMainFrame::OnTabModeRight)
171 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMTABMODESTART, ID_INDICATOR_BOTTOMTABMODESTART+19, &CMainFrame::OnTabModeBottom)
172 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTENCODINGSTART, ID_INDICATOR_LEFTENCODINGSTART+19, &CMainFrame::OnUpdateEncodingLeft)
173 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTENCODINGSTART, ID_INDICATOR_RIGHTENCODINGSTART+19, &CMainFrame::OnUpdateEncodingRight)
174 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMENCODINGSTART, ID_INDICATOR_BOTTOMENCODINGSTART+19, &CMainFrame::OnUpdateEncodingBottom)
175 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTEOLSTART, ID_INDICATOR_LEFTEOLSTART+19, &CMainFrame::OnUpdateEOLLeft)
176 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTEOLSTART, ID_INDICATOR_RIGHTEOLSTART+19, &CMainFrame::OnUpdateEOLRight)
177 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMEOLSTART, ID_INDICATOR_BOTTOMEOLSTART+19, &CMainFrame::OnUpdateEOLBottom)
178 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTTABMODESTART, ID_INDICATOR_LEFTTABMODESTART+19, &CMainFrame::OnUpdateTabModeLeft)
179 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTTABMODESTART, ID_INDICATOR_RIGHTTABMODESTART+19, &CMainFrame::OnUpdateTabModeRight)
180 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMTABMODESTART, ID_INDICATOR_BOTTOMTABMODESTART+19, &CMainFrame::OnUpdateTabModeBottom)
181 END_MESSAGE_MAP()
183 static UINT indicators[] =
185 ID_SEPARATOR, // status line indicator
186 ID_INDICATOR_LEFTVIEW,
187 ID_INDICATOR_RIGHTVIEW,
188 ID_INDICATOR_BOTTOMVIEW,
189 ID_INDICATOR_CAPS,
190 ID_INDICATOR_NUM,
194 // CMainFrame construction/destruction
196 CMainFrame::CMainFrame()
197 : m_bInitSplitter(FALSE)
198 , m_bReversedPatch(FALSE)
199 , m_bHasConflicts(false)
200 , m_bInlineWordDiff(true)
201 , m_bLineDiff(true)
202 , m_bLocatorBar(true)
203 , m_nMoveMovesToIgnore(0)
204 , m_pwndLeftView(NULL)
205 , m_pwndRightView(NULL)
206 , m_pwndBottomView(NULL)
207 , m_bReadOnly(false)
208 , m_bBlame(false)
209 , m_bCheckReload(false)
210 , m_bSaveRequired(false)
211 , m_bSaveRequiredOnConflicts(false)
212 , resolveMsgWnd(0)
213 , resolveMsgWParam(0)
214 , resolveMsgLParam(0)
215 , m_regWrapLines(L"Software\\TortoiseGitMerge\\WrapLines", 0)
216 , m_regViewModedBlocks(L"Software\\TortoiseGitMerge\\ViewMovedBlocks", TRUE)
217 , m_regOneWay(L"Software\\TortoiseGitMerge\\OnePane")
218 , m_regCollapsed(L"Software\\TortoiseGitMerge\\Collapsed", 0)
219 , m_regInlineDiff(L"Software\\TortoiseGitMerge\\DisplayBinDiff", TRUE)
220 , m_regUseRibbons(L"Software\\TortoiseGitMerge\\UseRibbons", TRUE)
221 , m_regUseTaskDialog(L"Software\\TortoiseGitMerge\\UseTaskDialog", TRUE)
222 , m_regIgnoreComments(_T("Software\\TortoiseGitMerge\\IgnoreComments"), FALSE)
223 , m_regexIndex(-1)
224 , m_regTabMode(L"Software\\TortoiseGitMerge\\TabMode", TABMODE_NONE)
226 m_bOneWay = (0 != ((DWORD)m_regOneWay));
227 theApp.m_nAppLook = theApp.GetInt(_T("ApplicationLook"), ID_VIEW_APPLOOK_VS_2005);
228 m_bCollapsed = !!(DWORD)m_regCollapsed;
229 m_bViewMovedBlocks = !!(DWORD)m_regViewModedBlocks;
230 m_bWrapLines = !!(DWORD)m_regWrapLines;
231 m_bInlineDiff = !!m_regInlineDiff;
232 m_bUseRibbons = !!m_regUseRibbons;
233 #if _WIN64
234 if (SysInfo::Instance().IsXP())
235 m_bUseRibbons = FALSE;
236 #endif
237 m_bUseTaskDialog = CTaskDialog::IsSupported() && (DWORD)m_regUseTaskDialog;
238 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
241 CMainFrame::~CMainFrame()
245 LRESULT CMainFrame::OnTaskbarButtonCreated(WPARAM /*wParam*/, LPARAM /*lParam*/)
247 SetUUIDOverlayIcon(m_hWnd);
248 return 0;
252 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
254 if (CFrameWndEx::OnCreate(lpCreateStruct) == -1)
255 return -1;
257 OnApplicationLook(theApp.m_nAppLook);
259 if (m_bUseRibbons)
261 m_wndRibbonBar.Create(this);
262 m_wndRibbonBar.LoadFromResource(IDR_RIBBON);
264 // enable the dialog launch button on the view panel
265 CMFCRibbonCategory * pMainCat = m_wndRibbonBar.GetCategory(1);
266 if (pMainCat)
268 CMFCRibbonPanel * pPanel = pMainCat->GetPanel(3);
269 if (pPanel)
270 pPanel->EnableLaunchButton(ID_VIEW_OPTIONS);
272 // now replace all buttons with our custom button class
273 for (int i = 0; i < m_wndRibbonBar.GetCategoryCount(); ++i)
275 CMFCRibbonCategory * pCat = m_wndRibbonBar.GetCategory(i);
276 for (int j = 0; j < pCat->GetPanelCount(); ++j)
278 CMFCRibbonPanel * pPanel = pCat->GetPanel(j);
279 CList<UINT, UINT> lstItems;
280 pPanel->GetItemIDsList(lstItems);
281 while (!lstItems.IsEmpty())
283 UINT id = lstItems.GetHead();
284 lstItems.RemoveHead();
285 CMFCRibbonButton * pButton = dynamic_cast<CMFCRibbonButton*>(pPanel->FindByID(id));
286 if (pButton)
288 CCustomMFCRibbonButton * c = new CCustomMFCRibbonButton(id, pButton->GetText());
289 pPanel->ReplaceByID(id, c);
294 BuildRegexSubitems();
295 if (!m_wndRibbonStatusBar.Create(this))
297 TRACE0("Failed to create ribbon status bar\n");
298 return -1; // fail to create
300 m_wndRibbonStatusBar.AddElement(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(AFX_IDS_IDLEMESSAGE)), TRUE), L"");
302 std::unique_ptr<CMFCRibbonButtonsGroup> apBtnGroupLeft(new CMFCRibbonButtonsGroup);
303 apBtnGroupLeft->SetID(ID_INDICATOR_LEFTVIEW);
304 apBtnGroupLeft->AddButton(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(IDS_STATUSBAR_LEFTVIEW)), TRUE));
305 CMFCRibbonButton * pButton = new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOENCODING, L"");
306 FillEncodingButton(pButton, ID_INDICATOR_LEFTENCODINGSTART);
307 apBtnGroupLeft->AddButton(pButton);
308 pButton = new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOEOL, L"");
309 FillEOLButton(pButton, ID_INDICATOR_LEFTEOLSTART);
310 apBtnGroupLeft->AddButton(pButton);
311 pButton = new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOTABMODE, L"");
312 FillTabModeButton(pButton, ID_INDICATOR_LEFTTABMODESTART);
313 apBtnGroupLeft->AddButton(pButton);
314 apBtnGroupLeft->AddButton(new CMFCRibbonStatusBarPane(ID_INDICATOR_LEFTVIEW, L"", TRUE));
315 m_wndRibbonStatusBar.AddExtendedElement(apBtnGroupLeft.release(), L"");
317 std::unique_ptr<CMFCRibbonButtonsGroup> apBtnGroupRight(new CMFCRibbonButtonsGroup);
318 apBtnGroupRight->SetID(ID_INDICATOR_RIGHTVIEW);
319 apBtnGroupRight->AddButton(new CMFCRibbonStatusBarPane(ID_SEPARATOR, CString(MAKEINTRESOURCE(IDS_STATUSBAR_RIGHTVIEW)), TRUE));
320 pButton = new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOENCODING, L"");
321 FillEncodingButton(pButton, ID_INDICATOR_RIGHTENCODINGSTART);
322 apBtnGroupRight->AddButton(pButton);
323 pButton = new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOEOL, L"");
324 FillEOLButton(pButton, ID_INDICATOR_RIGHTEOLSTART);
325 apBtnGroupRight->AddButton(pButton);
326 pButton = new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOTABMODE, L"");
327 FillTabModeButton(pButton, ID_INDICATOR_RIGHTTABMODESTART);
328 apBtnGroupRight->AddButton(pButton);
329 apBtnGroupRight->AddButton(new CMFCRibbonStatusBarPane(ID_INDICATOR_RIGHTVIEW, L"", TRUE));
330 m_wndRibbonStatusBar.AddExtendedElement(apBtnGroupRight.release(), L"");
332 else
334 if (!m_wndMenuBar.Create(this))
336 TRACE0("Failed to create menubar\n");
337 return -1; // fail to create
339 m_wndMenuBar.SetPaneStyle(m_wndMenuBar.GetPaneStyle() | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY);
341 // prevent the menu bar from taking the focus on activation
342 CMFCPopupMenu::SetForceMenuFocus(FALSE);
343 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))
345 TRACE0("Failed to create toolbar\n");
346 return -1; // fail to create
348 m_wndToolBar.SetWindowText(_T("Main"));
349 if (!m_wndStatusBar.Create(this) ||
350 !m_wndStatusBar.SetIndicators(indicators,
351 _countof(indicators)))
353 TRACE0("Failed to create status bar\n");
354 return -1; // fail to create
356 m_wndStatusBar.EnablePaneDoubleClick();
359 if (!m_wndLocatorBar.Create(this, IDD_DIFFLOCATOR,
360 CBRS_ALIGN_LEFT | CBRS_SIZE_FIXED, ID_VIEW_LOCATORBAR))
362 TRACE0("Failed to create dialogbar\n");
363 return -1; // fail to create
365 if (!m_wndLineDiffBar.Create(this, IDD_LINEDIFF,
366 CBRS_ALIGN_BOTTOM | CBRS_SIZE_FIXED, ID_VIEW_LINEDIFFBAR))
368 TRACE0("Failed to create dialogbar\n");
369 return -1; // fail to create
371 m_wndLocatorBar.m_pMainFrm = this;
372 m_wndLineDiffBar.m_pMainFrm = this;
374 EnableDocking(CBRS_ALIGN_ANY);
375 if (!m_bUseRibbons)
377 m_wndMenuBar.EnableDocking(CBRS_ALIGN_TOP);
378 m_wndToolBar.EnableDocking(CBRS_ALIGN_TOP);
379 DockPane(&m_wndMenuBar);
380 DockPane(&m_wndToolBar);
382 DockPane(&m_wndLocatorBar);
383 DockPane(&m_wndLineDiffBar);
384 ShowPane(&m_wndLocatorBar, true, false, true);
385 ShowPane(&m_wndLineDiffBar, true, false, true);
387 m_wndLocatorBar.EnableGripper(FALSE);
388 m_wndLineDiffBar.EnableGripper(FALSE);
390 return 0;
393 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
395 if( !CFrameWndEx::PreCreateWindow(cs) )
396 return FALSE;
397 return TRUE;
400 void CMainFrame::OnApplicationLook(UINT id)
402 CWaitCursor wait;
404 theApp.m_nAppLook = id;
406 switch (theApp.m_nAppLook)
408 case ID_VIEW_APPLOOK_WIN_2000:
409 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManager));
410 m_wndRibbonBar.SetWindows7Look(FALSE);
411 break;
413 case ID_VIEW_APPLOOK_OFF_XP:
414 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOfficeXP));
415 m_wndRibbonBar.SetWindows7Look(FALSE);
416 break;
418 case ID_VIEW_APPLOOK_WIN_XP:
419 CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
420 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
421 m_wndRibbonBar.SetWindows7Look(FALSE);
422 break;
424 case ID_VIEW_APPLOOK_OFF_2003:
425 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2003));
426 CDockingManager::SetDockingMode(DT_SMART);
427 m_wndRibbonBar.SetWindows7Look(FALSE);
428 break;
430 case ID_VIEW_APPLOOK_VS_2005:
431 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2005));
432 CDockingManager::SetDockingMode(DT_SMART);
433 m_wndRibbonBar.SetWindows7Look(FALSE);
434 break;
436 case ID_VIEW_APPLOOK_VS_2008:
437 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2008));
438 CDockingManager::SetDockingMode(DT_SMART);
439 m_wndRibbonBar.SetWindows7Look(FALSE);
440 break;
442 case ID_VIEW_APPLOOK_WIN7:
443 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows7));
444 CDockingManager::SetDockingMode(DT_SMART);
445 m_wndRibbonBar.SetWindows7Look(TRUE);
446 break;
448 default:
449 switch (theApp.m_nAppLook)
451 case ID_VIEW_APPLOOK_OFF_2007_BLUE:
452 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_LunaBlue);
453 break;
455 case ID_VIEW_APPLOOK_OFF_2007_BLACK:
456 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_ObsidianBlack);
457 break;
459 case ID_VIEW_APPLOOK_OFF_2007_SILVER:
460 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Silver);
461 break;
463 case ID_VIEW_APPLOOK_OFF_2007_AQUA:
464 CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Aqua);
465 break;
468 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));
469 CDockingManager::SetDockingMode(DT_SMART);
470 m_wndRibbonBar.SetWindows7Look(FALSE);
473 RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_FRAME | RDW_ERASE);
475 theApp.WriteInt(_T("ApplicationLook"), theApp.m_nAppLook);
478 void CMainFrame::OnUpdateApplicationLook(CCmdUI* pCmdUI)
480 pCmdUI->Enable();
481 pCmdUI->SetRadio(theApp.m_nAppLook == pCmdUI->m_nID);
485 // CMainFrame diagnostics
487 #ifdef _DEBUG
488 void CMainFrame::AssertValid() const
490 CFrameWndEx::AssertValid();
493 void CMainFrame::Dump(CDumpContext& dc) const
495 CFrameWndEx::Dump(dc);
498 #endif //_DEBUG
501 // CMainFrame message handlers
504 BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, CCreateContext* pContext)
506 CRect cr;
507 GetClientRect( &cr);
510 // split into three panes:
511 // -------------
512 // | | |
513 // | | |
514 // |------------
515 // | |
516 // | |
517 // |------------
519 // create a splitter with 2 rows, 1 column
520 if (!m_wndSplitter.CreateStatic(this, 2, 1))
522 TRACE0("Failed to CreateStaticSplitter\n");
523 return FALSE;
526 // add the second splitter pane - which is a nested splitter with 2 columns
527 if (!m_wndSplitter2.CreateStatic(
528 &m_wndSplitter, // our parent window is the first splitter
529 1, 2, // the new splitter is 1 row, 2 columns
530 WS_CHILD | WS_VISIBLE | WS_BORDER, // style, WS_BORDER is needed
531 m_wndSplitter.IdFromRowCol(0, 0)
532 // new splitter is in the first row, 1st column of first splitter
535 TRACE0("Failed to create nested splitter\n");
536 return FALSE;
538 // add the first splitter pane - the default view in row 0
539 if (!m_wndSplitter.CreateView(1, 0,
540 RUNTIME_CLASS(CBottomView), CSize(cr.Width(), cr.Height()), pContext))
542 TRACE0("Failed to create first pane\n");
543 return FALSE;
545 m_pwndBottomView = (CBottomView *)m_wndSplitter.GetPane(1,0);
546 m_pwndBottomView->m_pwndLocator = &m_wndLocatorBar;
547 m_pwndBottomView->m_pwndLineDiffBar = &m_wndLineDiffBar;
548 if (m_bUseRibbons)
549 m_pwndBottomView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
550 else
551 m_pwndBottomView->m_pwndStatusBar = &m_wndStatusBar;
552 m_pwndBottomView->m_pMainFrame = this;
554 // now create the two views inside the nested splitter
556 if (!m_wndSplitter2.CreateView(0, 0,
557 RUNTIME_CLASS(CLeftView), CSize(cr.Width()/2, cr.Height()/2), pContext))
559 TRACE0("Failed to create second pane\n");
560 return FALSE;
562 m_pwndLeftView = (CLeftView *)m_wndSplitter2.GetPane(0,0);
563 m_pwndLeftView->m_pwndLocator = &m_wndLocatorBar;
564 m_pwndLeftView->m_pwndLineDiffBar = &m_wndLineDiffBar;
565 if (m_bUseRibbons)
566 m_pwndLeftView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
567 else
568 m_pwndLeftView->m_pwndStatusBar = &m_wndStatusBar;
569 m_pwndLeftView->m_pMainFrame = this;
571 if (!m_wndSplitter2.CreateView(0, 1,
572 RUNTIME_CLASS(CRightView), CSize(cr.Width()/2, cr.Height()/2), pContext))
574 TRACE0("Failed to create third pane\n");
575 return FALSE;
577 m_pwndRightView = (CRightView *)m_wndSplitter2.GetPane(0,1);
578 m_pwndRightView->m_pwndLocator = &m_wndLocatorBar;
579 m_pwndRightView->m_pwndLineDiffBar = &m_wndLineDiffBar;
580 if (m_bUseRibbons)
581 m_pwndRightView->m_pwndRibbonStatusBar = &m_wndRibbonStatusBar;
582 else
583 m_pwndRightView->m_pwndStatusBar = &m_wndStatusBar;
584 m_pwndRightView->m_pMainFrame = this;
585 m_bInitSplitter = TRUE;
587 m_dlgFilePatches.Create(IDD_FILEPATCHES, this);
588 UpdateLayout();
589 return TRUE;
592 // Callback function
593 BOOL CMainFrame::PatchFile(CString sFilePath, bool /*bContentMods*/, bool bPropMods, CString sVersion, BOOL bAutoPatch)
595 CString sDummy;
596 //"dry run" was successful, so save the patched file somewhere...
597 CString sTempFile = CTempFiles::Instance().GetTempFilePathString();
598 CString sRejectedFile, sBasePath;
599 if (m_Patch.GetPatchResult(sFilePath, sTempFile, sRejectedFile, sBasePath) < 0)
601 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
602 return FALSE;
604 sFilePath = m_Patch.GetTargetPath() + _T("\\") + sFilePath;
605 sFilePath.Replace('/', '\\');
606 if (sBasePath.IsEmpty())
607 sBasePath = sFilePath;
608 if (m_bReversedPatch)
610 m_Data.m_baseFile.SetFileName(sTempFile);
611 CString temp;
612 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
613 m_Data.m_baseFile.SetDescriptiveName(temp);
614 m_Data.m_yourFile.SetFileName(sFilePath);
615 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchOriginal);
616 m_Data.m_yourFile.SetDescriptiveName(temp);
617 m_Data.m_theirFile.SetOutOfUse();
618 m_Data.m_mergedFile.SetOutOfUse();
620 else
622 if ((!PathFileExists(sBasePath))||(PathIsDirectory(sBasePath)))
624 m_Data.m_baseFile.SetFileName(CTempFiles::Instance().GetTempFilePathString());
625 m_Data.m_baseFile.CreateEmptyFile();
627 else
629 m_Data.m_baseFile.SetFileName(sBasePath);
631 CString sDescription;
632 sDescription.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sBasePath), (LPCTSTR)m_Data.m_sPatchOriginal);
633 m_Data.m_baseFile.SetDescriptiveName(sDescription);
634 if (sBasePath == sFilePath)
636 m_Data.m_yourFile.SetFileName(sTempFile);
637 CString temp;
638 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sBasePath), (LPCTSTR)m_Data.m_sPatchPatched);
639 m_Data.m_yourFile.SetDescriptiveName(temp);
640 m_Data.m_theirFile.SetOutOfUse();
642 else
644 if (!PathFileExists(sFilePath) || PathIsDirectory(sFilePath))
646 m_Data.m_yourFile.SetFileName(CTempFiles::Instance().GetTempFilePathString());
647 m_Data.m_yourFile.CreateEmptyFile();
648 CString temp;
649 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), CString(MAKEINTRESOURCE(IDS_NOTFOUNDVIEWTITLEINDICATOR)));
650 m_Data.m_yourFile.SetDescriptiveName(temp);
652 else
653 m_Data.m_yourFile.SetFileName(sFilePath);
654 m_Data.m_theirFile.SetFileName(sTempFile);
655 CString temp;
656 temp.Format(_T("%s %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath), (LPCTSTR)m_Data.m_sPatchPatched);
657 m_Data.m_theirFile.SetDescriptiveName(temp);
659 m_Data.m_mergedFile.SetFileName(sFilePath);
660 m_Data.m_bPatchRequired = bPropMods;
662 TRACE(_T("comparing %s\nwith the patched result %s\n"), (LPCTSTR)sFilePath, (LPCTSTR)sTempFile);
664 LoadViews();
665 if (!sRejectedFile.IsEmpty())
667 #if 0 // TGIT TODO
668 // start TortoiseUDiff with the rejected hunks
669 CString sTitle;
670 sTitle.Format(IDS_TITLE_REJECTEDHUNKS, (LPCTSTR)CPathUtils::GetFileNameFromPath(sFilePath));
671 CAppUtils::StartUnifiedDiffViewer(sRejectedFile, sTitle);
672 #endif
674 if (bAutoPatch)
676 if (sBasePath != sFilePath && HasConflictsWontKeep())
677 return FALSE;
679 PatchSave();
681 return TRUE;
684 // Callback function
685 BOOL CMainFrame::DiffFiles(CString sURL1, CString sRev1, CString sURL2, CString sRev2)
687 CString tempfile1 = CTempFiles::Instance().GetTempFilePathString();
688 CString tempfile2 = CTempFiles::Instance().GetTempFilePathString();
690 ASSERT(tempfile1.Compare(tempfile2));
692 CString sTemp;
693 CSysProgressDlg progDlg;
694 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev1);
695 progDlg.SetLine(1, sTemp, true);
696 progDlg.SetLine(2, sURL1, true);
697 sTemp.LoadString(IDS_GETVERSIONOFFILETITLE);
698 progDlg.SetTitle(sTemp);
699 progDlg.SetShowProgressBar(true);
700 progDlg.SetAnimation(IDR_DOWNLOAD);
701 progDlg.SetTime(FALSE);
702 progDlg.SetProgress(1,100);
703 progDlg.ShowModeless(this);
704 if (!CAppUtils::GetVersionedFile(sURL1, sRev1, tempfile1, &progDlg, m_hWnd))
706 progDlg.Stop();
707 CString sErrMsg;
708 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev1, (LPCTSTR)sURL1);
709 MessageBox(sErrMsg, NULL, MB_ICONERROR);
710 return FALSE;
712 sTemp.Format(IDS_GETVERSIONOFFILE, (LPCTSTR)sRev2);
713 progDlg.SetLine(1, sTemp, true);
714 progDlg.SetLine(2, sURL2, true);
715 progDlg.SetProgress(50, 100);
716 if (!CAppUtils::GetVersionedFile(sURL2, sRev2, tempfile2, &progDlg, m_hWnd))
718 progDlg.Stop();
719 CString sErrMsg;
720 sErrMsg.Format(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND, (LPCTSTR)sRev2, (LPCTSTR)sURL2);
721 MessageBox(sErrMsg, NULL, MB_ICONERROR);
722 return FALSE;
724 progDlg.SetProgress(100,100);
725 progDlg.Stop();
726 CString temp;
727 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL1), (LPCTSTR)sRev1);
728 m_Data.m_baseFile.SetFileName(tempfile1);
729 m_Data.m_baseFile.SetDescriptiveName(temp);
730 temp.Format(_T("%s Revision %s"), (LPCTSTR)CPathUtils::GetFileNameFromPath(sURL2), (LPCTSTR)sRev2);
731 m_Data.m_yourFile.SetFileName(tempfile2);
732 m_Data.m_yourFile.SetDescriptiveName(temp);
734 LoadViews();
736 return TRUE;
739 void CMainFrame::OnFileOpen()
741 if (CheckForSave(CHFSR_OPEN)==IDCANCEL)
742 return;
743 COpenDlg dlg;
744 if (dlg.DoModal()!=IDOK)
746 return;
748 m_dlgFilePatches.ShowWindow(SW_HIDE);
749 m_dlgFilePatches.Init(NULL, NULL, CString(), NULL);
750 TRACE(_T("got the files:\n %s\n %s\n %s\n %s\n %s\n"), (LPCTSTR)dlg.m_sBaseFile, (LPCTSTR)dlg.m_sTheirFile, (LPCTSTR)dlg.m_sYourFile,
751 (LPCTSTR)dlg.m_sUnifiedDiffFile, (LPCTSTR)dlg.m_sPatchDirectory);
752 m_Data.m_baseFile.SetFileName(dlg.m_sBaseFile);
753 m_Data.m_theirFile.SetFileName(dlg.m_sTheirFile);
754 m_Data.m_yourFile.SetFileName(dlg.m_sYourFile);
755 m_Data.m_sDiffFile = dlg.m_sUnifiedDiffFile;
756 m_Data.m_sPatchPath = dlg.m_sPatchDirectory;
757 m_Data.m_mergedFile.SetOutOfUse();
758 CCrashReport::Instance().AddFile2(dlg.m_sBaseFile, NULL, _T("Basefile"), CR_AF_MAKE_FILE_COPY);
759 CCrashReport::Instance().AddFile2(dlg.m_sTheirFile, NULL, _T("Theirfile"), CR_AF_MAKE_FILE_COPY);
760 CCrashReport::Instance().AddFile2(dlg.m_sYourFile, NULL, _T("Yourfile"), CR_AF_MAKE_FILE_COPY);
761 CCrashReport::Instance().AddFile2(dlg.m_sUnifiedDiffFile, NULL, _T("Difffile"), CR_AF_MAKE_FILE_COPY);
763 if (!m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && m_Data.IsYourFileInUse())
765 // a diff between two files means "Yours" against "Base", not "Theirs" against "Yours"
766 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
768 if (m_Data.IsBaseFileInUse() && m_Data.IsTheirFileInUse() && !m_Data.IsYourFileInUse())
770 // a diff between two files means "Yours" against "Base", not "Theirs" against "Base"
771 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
773 m_bSaveRequired = false;
775 LoadViews();
778 void CMainFrame::ClearViewNamesAndPaths()
780 m_pwndLeftView->m_sWindowName.Empty();
781 m_pwndLeftView->m_sFullFilePath.Empty();
782 m_pwndRightView->m_sWindowName.Empty();
783 m_pwndRightView->m_sFullFilePath.Empty();
784 m_pwndBottomView->m_sWindowName.Empty();
785 m_pwndBottomView->m_sFullFilePath.Empty();
788 bool CMainFrame::LoadViews(int line)
790 LoadIgnoreCommentData();
791 m_Data.SetBlame(m_bBlame);
792 m_Data.SetMovedBlocks(m_bViewMovedBlocks);
793 m_bHasConflicts = false;
794 CBaseView* pwndActiveView = m_pwndLeftView;
795 int nOldLine = m_pwndRightView ? m_pwndRightView->m_nTopLine : -1;
796 int nOldLineNumber =
797 m_pwndRightView && m_pwndRightView->m_pViewData ?
798 m_pwndRightView->m_pViewData->GetLineNumber(m_pwndRightView->m_nTopLine) : -1;
799 POINT ptOldCaretPos = {-1, -1};
800 if (m_pwndRightView && m_pwndRightView->IsTarget())
801 ptOldCaretPos = m_pwndRightView->GetCaretPosition();
802 if (m_pwndBottomView && m_pwndBottomView->IsTarget())
803 ptOldCaretPos = m_pwndBottomView->GetCaretPosition();
804 CString sExt = CPathUtils::GetFileExtFromPath(m_Data.m_baseFile.GetFilename()).MakeLower();
805 sExt.TrimLeft(L".");
806 auto sC = m_IgnoreCommentsMap.find(sExt);
807 if (sC == m_IgnoreCommentsMap.end())
809 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_yourFile.GetFilename()).MakeLower();
810 sC = m_IgnoreCommentsMap.find(sExt);
811 if (sC == m_IgnoreCommentsMap.end())
813 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_theirFile.GetFilename()).MakeLower();
814 sC = m_IgnoreCommentsMap.find(sExt);
817 if (sC != m_IgnoreCommentsMap.end())
818 m_Data.SetCommentTokens(std::get<0>(sC->second), std::get<1>(sC->second), std::get<2>(sC->second));
819 else
820 m_Data.SetCommentTokens(L"", L"", L"");
821 if (!m_Data.Load())
823 m_pwndLeftView->BuildAllScreen2ViewVector();
824 m_pwndLeftView->DocumentUpdated();
825 m_pwndRightView->DocumentUpdated();
826 m_pwndBottomView->DocumentUpdated();
827 m_wndLocatorBar.DocumentUpdated();
828 m_wndLineDiffBar.DocumentUpdated();
829 ::MessageBox(m_hWnd, m_Data.GetError(), _T("TortoiseGitMerge"), MB_ICONERROR);
830 m_Data.m_mergedFile.SetOutOfUse();
831 m_bSaveRequired = false;
832 return false;
834 SetWindowTitle();
835 m_pwndLeftView->BuildAllScreen2ViewVector();
836 m_pwndLeftView->DocumentUpdated();
837 m_pwndRightView->DocumentUpdated();
838 m_pwndBottomView->DocumentUpdated();
839 m_wndLocatorBar.DocumentUpdated();
840 m_wndLineDiffBar.DocumentUpdated();
842 m_pwndLeftView->SetWritable(false);
843 m_pwndLeftView->SetWritableIsChangable(false);
844 m_pwndLeftView->SetTarget(false);
845 m_pwndRightView->SetWritable(false);
846 m_pwndRightView->SetWritableIsChangable(false);
847 m_pwndRightView->SetTarget(false);
848 m_pwndBottomView->SetWritable(false);
849 m_pwndBottomView->SetWritableIsChangable(false);
850 m_pwndBottomView->SetTarget(false);
852 if (!m_Data.IsBaseFileInUse())
854 CSysProgressDlg progDlg;
855 if (m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
857 m_Data.m_baseFile.TransferDetailsFrom(m_Data.m_theirFile);
859 else if ((!m_Data.m_sDiffFile.IsEmpty())&&(!m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg)))
861 progDlg.Stop();
862 ClearViewNamesAndPaths();
863 MessageBox(m_Patch.GetErrorMessage(), NULL, MB_ICONERROR);
864 m_bSaveRequired = false;
865 return false;
867 progDlg.Stop();
868 if (m_Patch.GetNumberOfFiles() > 0)
870 CString betterpatchpath = m_Patch.CheckPatchPath(m_Data.m_sPatchPath);
871 if (betterpatchpath.CompareNoCase(m_Data.m_sPatchPath)!=0)
873 CString msg;
874 msg.Format(IDS_WARNBETTERPATCHPATHFOUND, (LPCTSTR)m_Data.m_sPatchPath, (LPCTSTR)betterpatchpath);
875 if (m_bUseTaskDialog)
877 CTaskDialog taskdlg(msg,
878 CString(MAKEINTRESOURCE(IDS_WARNBETTERPATCHPATHFOUND_TASK2)),
879 L"TortoiseGitMerge",
881 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
882 CString task3;
883 WCHAR t3[MAX_PATH] = {0};
884 CString cp = betterpatchpath.Left(MAX_PATH-1);
885 PathCompactPathEx(t3, cp, 50, 0);
886 task3.Format(IDS_WARNBETTERPATCHPATHFOUND_TASK3, t3);
887 taskdlg.AddCommandControl(1, task3);
888 CString task4;
889 WCHAR t4[MAX_PATH] = {0};
890 cp = m_Data.m_sPatchPath.Left(MAX_PATH-1);
891 PathCompactPathEx(t4, cp, 50, 0);
892 task4.Format(IDS_WARNBETTERPATCHPATHFOUND_TASK4, t4);
893 taskdlg.AddCommandControl(2, task4);
894 taskdlg.SetDefaultCommandControl(1);
895 taskdlg.SetMainIcon(TD_INFORMATION_ICON);
896 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
897 if (taskdlg.DoModal(m_hWnd) == 1)
899 m_Data.m_sPatchPath = betterpatchpath;
900 m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg);
903 else if (::MessageBox(m_hWnd, msg, _T("TortoiseGitMerge"), MB_ICONQUESTION | MB_YESNO)==IDYES)
905 m_Data.m_sPatchPath = betterpatchpath;
906 m_Patch.Init(m_Data.m_sDiffFile, m_Data.m_sPatchPath, &progDlg);
909 m_dlgFilePatches.Init(&m_Patch, this, m_Data.m_sPatchPath, this);
910 m_dlgFilePatches.ShowWindow(SW_SHOW);
911 ClearViewNamesAndPaths();
912 if (!m_wndSplitter.IsRowHidden(1))
913 m_wndSplitter.HideRow(1);
914 m_pwndLeftView->SetHidden(FALSE);
915 m_pwndRightView->SetHidden(FALSE);
916 m_pwndBottomView->SetHidden(TRUE);
919 if (m_Data.IsBaseFileInUse() && !m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
921 m_Data.m_yourFile.TransferDetailsFrom(m_Data.m_theirFile);
923 if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && !m_Data.IsTheirFileInUse())
925 //diff between YOUR and BASE
926 if (m_bOneWay)
928 pwndActiveView = m_pwndLeftView;
929 if (!m_wndSplitter2.IsColumnHidden(1))
930 m_wndSplitter2.HideColumn(1);
932 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseBoth;
933 m_pwndLeftView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
934 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
935 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName() + _T(" - ") + m_Data.m_yourFile.GetWindowName();
936 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename() + _T(" - ") + m_Data.m_yourFile.GetFilename();
937 m_pwndLeftView->m_pWorkingFile = &m_Data.m_yourFile;
938 m_pwndLeftView->SetTarget();
939 m_pwndLeftView->SetWritableIsChangable(true);
941 m_pwndRightView->m_pViewData = NULL;
942 m_pwndRightView->m_pWorkingFile = NULL;
943 m_pwndBottomView->m_pViewData = NULL;
944 m_pwndBottomView->m_pWorkingFile = NULL;
946 if (!m_wndSplitter.IsRowHidden(1))
947 m_wndSplitter.HideRow(1);
948 m_pwndLeftView->SetHidden(FALSE);
949 m_pwndRightView->SetHidden(TRUE);
950 m_pwndBottomView->SetHidden(TRUE);
951 ::SetWindowPos(m_pwndLeftView->m_hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
953 else
955 pwndActiveView = m_pwndRightView;
956 if (m_wndSplitter2.IsColumnHidden(1))
957 m_wndSplitter2.ShowColumn();
959 m_pwndLeftView->m_pViewData = &m_Data.m_YourBaseLeft;
960 m_pwndLeftView->SetTextType(m_Data.m_arBaseFile.GetUnicodeType());
961 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arBaseFile.GetLineEndings());
962 m_pwndLeftView->m_sWindowName = m_Data.m_baseFile.GetWindowName();
963 m_pwndLeftView->m_sFullFilePath = m_Data.m_baseFile.GetFilename();
964 m_pwndLeftView->m_sConvertedFilePath = m_Data.m_baseFile.GetConvertedFileName();
965 m_pwndLeftView->m_pWorkingFile = &m_Data.m_baseFile;
966 m_pwndLeftView->SetWritableIsChangable(true);
968 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseRight;
969 m_pwndRightView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
970 m_pwndRightView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
971 m_pwndRightView->m_sWindowName = m_Data.m_yourFile.GetWindowName();
972 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
973 m_pwndRightView->m_sConvertedFilePath = m_Data.m_yourFile.GetConvertedFileName();
974 m_pwndRightView->m_pWorkingFile = &m_Data.m_yourFile;
975 m_pwndRightView->SetWritable();
976 m_pwndRightView->SetTarget();
978 m_pwndBottomView->m_pViewData = NULL;
979 m_pwndBottomView->m_pWorkingFile = NULL;
981 if (!m_wndSplitter.IsRowHidden(1))
982 m_wndSplitter.HideRow(1);
983 m_pwndLeftView->SetHidden(FALSE);
984 m_pwndRightView->SetHidden(FALSE);
985 m_pwndBottomView->SetHidden(TRUE);
987 bool hasMods, hasConflicts, hasWhitespaceMods;
988 pwndActiveView->CheckModifications(hasMods, hasConflicts, hasWhitespaceMods);
989 if (!hasMods && !hasConflicts)
991 // files appear identical, show a dialog informing the user that there are or might
992 // be other differences
993 bool hasEncodingDiff = m_Data.m_arBaseFile.GetUnicodeType() != m_Data.m_arYourFile.GetUnicodeType();
994 bool hasEOLDiff = m_Data.m_arBaseFile.GetLineEndings() != m_Data.m_arYourFile.GetLineEndings();
995 if (hasWhitespaceMods || hasEncodingDiff || hasEOLDiff)
997 // text is identical, but the files do not match
998 CString sWarning(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_MAIN));
999 CString sWhitespace(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_WHITESPACE));
1000 CString sEncoding(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_ENCODING));
1001 CString sEOL(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_EOL));
1002 if (hasWhitespaceMods)
1004 sWarning += L"\r\n";
1005 sWarning += sWhitespace;
1007 if (hasEncodingDiff)
1009 sWarning += L"\r\n";
1010 sWarning += sEncoding;
1011 sWarning += L" (";
1012 sWarning += m_Data.m_arBaseFile.GetEncodingName(m_Data.m_arBaseFile.GetUnicodeType());
1013 sWarning += L", ";
1014 sWarning += m_Data.m_arYourFile.GetEncodingName(m_Data.m_arYourFile.GetUnicodeType());
1015 sWarning += L")";
1017 if (hasEOLDiff)
1019 sWarning += L"\r\n";
1020 sWarning += sEOL;
1022 AfxMessageBox(sWarning, MB_ICONINFORMATION);
1026 else if (m_Data.IsBaseFileInUse() && m_Data.IsYourFileInUse() && m_Data.IsTheirFileInUse())
1028 //diff between THEIR, YOUR and BASE
1029 m_pwndBottomView->SetWritable();
1030 m_pwndBottomView->SetTarget();
1031 pwndActiveView = m_pwndBottomView;
1033 m_pwndLeftView->m_pViewData = &m_Data.m_TheirBaseBoth;
1034 m_pwndLeftView->SetTextType(m_Data.m_arTheirFile.GetUnicodeType());
1035 m_pwndLeftView->SetLineEndingStyle(m_Data.m_arTheirFile.GetLineEndings());
1036 m_pwndLeftView->m_sWindowName.LoadString(IDS_VIEWTITLE_THEIRS);
1037 m_pwndLeftView->m_sWindowName += _T(" - ") + m_Data.m_theirFile.GetWindowName();
1038 m_pwndLeftView->m_sFullFilePath = m_Data.m_theirFile.GetFilename();
1039 m_pwndLeftView->m_sConvertedFilePath = m_Data.m_theirFile.GetConvertedFileName();
1040 m_pwndLeftView->m_pWorkingFile = &m_Data.m_theirFile;
1042 m_pwndRightView->m_pViewData = &m_Data.m_YourBaseBoth;
1043 m_pwndRightView->SetTextType(m_Data.m_arYourFile.GetUnicodeType());
1044 m_pwndRightView->SetLineEndingStyle(m_Data.m_arYourFile.GetLineEndings());
1045 m_pwndRightView->m_sWindowName.LoadString(IDS_VIEWTITLE_MINE);
1046 m_pwndRightView->m_sWindowName += _T(" - ") + m_Data.m_yourFile.GetWindowName();
1047 m_pwndRightView->m_sFullFilePath = m_Data.m_yourFile.GetFilename();
1048 m_pwndRightView->m_sConvertedFilePath = m_Data.m_yourFile.GetConvertedFileName();
1049 m_pwndRightView->m_pWorkingFile = &m_Data.m_yourFile;
1051 m_pwndBottomView->m_pViewData = &m_Data.m_Diff3;
1052 m_pwndBottomView->SetTextType(m_Data.m_arTheirFile.GetUnicodeType());
1053 m_pwndBottomView->SetLineEndingStyle(m_Data.m_arTheirFile.GetLineEndings());
1054 m_pwndBottomView->m_sWindowName.LoadString(IDS_VIEWTITLE_MERGED);
1055 m_pwndBottomView->m_sWindowName += _T(" - ") + m_Data.m_mergedFile.GetWindowName();
1056 m_pwndBottomView->m_sFullFilePath = m_Data.m_mergedFile.GetFilename();
1057 m_pwndBottomView->m_sConvertedFilePath = m_Data.m_mergedFile.GetConvertedFileName();
1058 m_pwndBottomView->m_pWorkingFile = &m_Data.m_mergedFile;
1060 if (m_wndSplitter2.IsColumnHidden(1))
1061 m_wndSplitter2.ShowColumn();
1062 if (m_wndSplitter.IsRowHidden(1))
1063 m_wndSplitter.ShowRow();
1064 m_pwndLeftView->SetHidden(FALSE);
1065 m_pwndRightView->SetHidden(FALSE);
1066 m_pwndBottomView->SetHidden(FALSE);
1067 // in three pane view, hide the line diff bar
1068 m_wndLineDiffBar.ShowPane(false, false, true);
1069 m_wndLineDiffBar.DocumentUpdated();
1071 if (!m_Data.m_mergedFile.InUse())
1073 m_Data.m_mergedFile.SetFileName(m_Data.m_yourFile.GetFilename());
1075 m_pwndLeftView->BuildAllScreen2ViewVector();
1076 m_pwndLeftView->DocumentUpdated();
1077 m_pwndRightView->DocumentUpdated();
1078 m_pwndBottomView->DocumentUpdated();
1079 m_wndLocatorBar.DocumentUpdated();
1080 m_wndLineDiffBar.DocumentUpdated();
1081 UpdateLayout();
1082 SetActiveView(pwndActiveView);
1084 if ((line >= -1) && m_pwndRightView->m_pViewData)
1086 int n = line == -1 ? min( nOldLineNumber, nOldLine ) : line;
1087 if (n >= 0)
1088 n = m_pwndRightView->m_pViewData->FindLineNumber(n);
1089 if (n < 0)
1090 n = nOldLine;
1092 m_pwndRightView->ScrollAllToLine(n);
1093 POINT p;
1094 p.x = 0;
1095 p.y = n;
1096 if ((ptOldCaretPos.x >= 0) || (ptOldCaretPos.y >= 0))
1097 p = ptOldCaretPos;
1098 m_pwndLeftView->SetCaretPosition(p);
1099 m_pwndRightView->SetCaretPosition(p);
1100 m_pwndBottomView->SetCaretPosition(p);
1101 m_pwndBottomView->ScrollToChar(0);
1102 m_pwndLeftView->ScrollToChar(0);
1103 m_pwndRightView->ScrollToChar(0);
1105 else
1107 CRegDWORD regFirstDiff = CRegDWORD(_T("Software\\TortoiseGitMerge\\FirstDiffOnLoad"), TRUE);
1108 CRegDWORD regFirstConflict = CRegDWORD(_T("Software\\TortoiseGitMerge\\FirstConflictOnLoad"), TRUE);
1109 bool bGoFirstDiff = (0 != (DWORD)regFirstDiff);
1110 bool bGoFirstConflict = (0 != (DWORD)regFirstConflict);
1111 if (bGoFirstConflict && (CheckResolved()>=0))
1113 pwndActiveView->GoToFirstConflict();
1114 // Ignore the first few Mouse Move messages, so that the line diff stays on
1115 // the first diff line until the user actually moves the mouse
1116 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1118 else if (bGoFirstDiff)
1120 pwndActiveView->GoToFirstDifference();
1121 // Ignore the first few Mouse Move messages, so that the line diff stays on
1122 // the first diff line until the user actually moves the mouse
1123 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1125 else
1127 // Avoid incorrect rendering of active pane.
1128 m_pwndBottomView->ScrollToChar(0);
1129 m_pwndLeftView->ScrollToChar(0);
1130 m_pwndRightView->ScrollToChar(0);
1133 CheckResolved();
1134 if (m_bHasConflicts && !m_bSaveRequiredOnConflicts)
1135 m_bSaveRequired = false;
1136 CUndo::GetInstance().Clear();
1137 return true;
1140 void CMainFrame::UpdateLayout()
1142 if (m_bInitSplitter)
1144 m_wndSplitter.CenterSplitter();
1145 m_wndSplitter2.CenterSplitter();
1149 void CMainFrame::OnSize(UINT nType, int cx, int cy)
1151 CFrameWndEx::OnSize(nType, cx, cy);
1152 if (m_bInitSplitter && nType != SIZE_MINIMIZED)
1154 if (m_wndSplitter.GetSafeHwnd())
1156 if (m_wndSplitter.HasOldRowSize() && (m_wndSplitter.GetOldRowCount() == 2))
1158 int oldTotal = m_wndSplitter.GetOldRowSize(0) + m_wndSplitter.GetOldRowSize(1);
1159 if (oldTotal)
1161 int cxCur0, cxCur1, cxMin0, cxMin1;
1162 m_wndSplitter.GetRowInfo(0, cxCur0, cxMin0);
1163 m_wndSplitter.GetRowInfo(1, cxCur1, cxMin1);
1164 cxCur0 = m_wndSplitter.GetOldRowSize(0) * (cxCur0 + cxCur1) / oldTotal;
1165 cxCur1 = m_wndSplitter.GetOldRowSize(1) * (cxCur0 + cxCur1) / oldTotal;
1166 m_wndSplitter.SetRowInfo(0, cxCur0, 0);
1167 m_wndSplitter.SetRowInfo(1, cxCur1, 0);
1168 m_wndSplitter.RecalcLayout();
1172 if (m_wndSplitter2.HasOldColSize() && (m_wndSplitter2.GetOldColCount() == 2))
1174 int oldTotal = m_wndSplitter2.GetOldColSize(0) + m_wndSplitter2.GetOldColSize(1);
1175 if (oldTotal)
1177 int cyCur0, cyCur1, cyMin0, cyMin1;
1178 m_wndSplitter2.GetColumnInfo(0, cyCur0, cyMin0);
1179 m_wndSplitter2.GetColumnInfo(1, cyCur1, cyMin1);
1180 cyCur0 = m_wndSplitter2.GetOldColSize(0) * (cyCur0 + cyCur1) / oldTotal;
1181 cyCur1 = m_wndSplitter2.GetOldColSize(1) * (cyCur0 + cyCur1) / oldTotal;
1182 m_wndSplitter2.SetColumnInfo(0, cyCur0, 0);
1183 m_wndSplitter2.SetColumnInfo(1, cyCur1, 0);
1184 m_wndSplitter2.RecalcLayout();
1189 if ((nType == SIZE_RESTORED)&&m_bCheckReload)
1191 m_bCheckReload = false;
1192 CheckForReload();
1194 #if _MSC_VER < 1800
1195 // workaround for ribbon interface when the task bar is on the left or top
1196 // The bug has been fixed in VS2013
1197 // http://connect.microsoft.com/VisualStudio/feedback/details/791229/cmfcribbonbar-app-does-not-maximize-correctly-if-windows-7-taskbar-is-docked-on-left
1198 if (nType == SIZE_MAXIMIZED)
1200 HMONITOR hMon = MonitorFromWindow(this->m_hWnd, MONITOR_DEFAULTTONEAREST);
1201 MONITORINFOEX mix;
1202 mix.cbSize = sizeof(MONITORINFOEX);
1203 bool primary = true; // assume primary monitor
1204 CRect rect(0, 0, 0, 0);
1205 if (GetMonitorInfo(hMon, &mix))
1207 primary = (mix.dwFlags == MONITORINFOF_PRIMARY);
1208 rect = mix.rcWork;
1210 else
1212 ::SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
1214 if (primary)
1216 WINDOWPLACEMENT wp;
1217 GetWindowPlacement(&wp);
1218 if (wp.ptMaxPosition.x || wp.ptMaxPosition.y)
1220 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
1221 SetWindowPlacement(&wp);
1224 else
1226 MoveWindow(rect);
1229 #endif
1232 void CMainFrame::OnViewWhitespaces()
1234 CRegDWORD regViewWhitespaces = CRegDWORD(_T("Software\\TortoiseGitMerge\\ViewWhitespaces"), 1);
1235 BOOL bViewWhitespaces = regViewWhitespaces;
1236 if (m_pwndLeftView)
1237 bViewWhitespaces = m_pwndLeftView->m_bViewWhitespace;
1239 bViewWhitespaces = !bViewWhitespaces;
1240 regViewWhitespaces = bViewWhitespaces;
1241 if (m_pwndLeftView)
1243 m_pwndLeftView->m_bViewWhitespace = bViewWhitespaces;
1244 m_pwndLeftView->Invalidate();
1246 if (m_pwndRightView)
1248 m_pwndRightView->m_bViewWhitespace = bViewWhitespaces;
1249 m_pwndRightView->Invalidate();
1251 if (m_pwndBottomView)
1253 m_pwndBottomView->m_bViewWhitespace = bViewWhitespaces;
1254 m_pwndBottomView->Invalidate();
1258 void CMainFrame::OnUpdateViewWhitespaces(CCmdUI *pCmdUI)
1260 if (m_pwndLeftView)
1261 pCmdUI->SetCheck(m_pwndLeftView->m_bViewWhitespace);
1264 void CMainFrame::OnViewCollapsed()
1266 m_regCollapsed = !(DWORD)m_regCollapsed;
1267 m_bCollapsed = !!(DWORD)m_regCollapsed;
1269 OnViewTextFoldUnfold();
1270 m_wndLocatorBar.Invalidate();
1273 void CMainFrame::OnUpdateViewCollapsed(CCmdUI *pCmdUI)
1275 pCmdUI->SetCheck(m_bCollapsed);
1278 void CMainFrame::OnViewWraplonglines()
1280 m_bWrapLines = !(DWORD)m_regWrapLines;
1281 m_regWrapLines = m_bWrapLines;
1283 if (m_pwndLeftView) m_pwndLeftView ->WrapChanged();
1284 if (m_pwndRightView) m_pwndRightView ->WrapChanged();
1285 if (m_pwndBottomView) m_pwndBottomView->WrapChanged();
1286 OnViewTextFoldUnfold();
1287 m_wndLocatorBar.DocumentUpdated();
1290 void CMainFrame::OnViewTextFoldUnfold()
1292 OnViewTextFoldUnfold(m_pwndLeftView);
1293 OnViewTextFoldUnfold(m_pwndRightView);
1294 OnViewTextFoldUnfold(m_pwndBottomView);
1297 void CMainFrame::OnViewTextFoldUnfold(CBaseView* view)
1299 if (view == 0)
1300 return;
1301 view->BuildAllScreen2ViewVector();
1302 view->UpdateCaret();
1303 view->Invalidate();
1304 view->EnsureCaretVisible();
1307 void CMainFrame::OnUpdateViewWraplonglines(CCmdUI *pCmdUI)
1309 pCmdUI->SetCheck(m_bWrapLines);
1312 void CMainFrame::OnViewOnewaydiff()
1314 if (CheckForSave(CHFSR_RELOAD)==IDCANCEL)
1315 return;
1316 m_bOneWay = !m_bOneWay;
1317 ShowDiffBar(!m_bOneWay);
1318 LoadViews(-1);
1321 void CMainFrame::ShowDiffBar(bool bShow)
1323 if (bShow)
1325 // restore the line diff bar
1326 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
1327 m_wndLineDiffBar.DocumentUpdated();
1328 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
1329 m_wndLocatorBar.DocumentUpdated();
1331 else
1333 // in one way view, hide the line diff bar
1334 m_wndLineDiffBar.ShowPane(false, false, true);
1335 m_wndLineDiffBar.DocumentUpdated();
1339 int CMainFrame::CheckResolved()
1341 //only in three way diffs can be conflicts!
1342 m_bHasConflicts = true;
1343 if (IsViewGood(m_pwndBottomView))
1345 CViewData* viewdata = m_pwndBottomView->m_pViewData;
1346 if (viewdata)
1348 for (int i=0; i<viewdata->GetCount(); i++)
1350 const DiffStates state = viewdata->GetState(i);
1351 if ((DIFFSTATE_CONFLICTED == state)||(DIFFSTATE_CONFLICTED_IGNORED == state))
1352 return i;
1356 m_bHasConflicts = false;
1357 return -1;
1360 int CMainFrame::SaveFile(const CString& sFilePath)
1362 CBaseView * pView = NULL;
1363 CViewData * pViewData = NULL;
1364 CFileTextLines * pOriginFile = &m_Data.m_arBaseFile;
1365 if (IsViewGood(m_pwndBottomView))
1367 pView = m_pwndBottomView;
1368 pViewData = m_pwndBottomView->m_pViewData;
1370 else if (IsViewGood(m_pwndRightView))
1372 pView = m_pwndRightView;
1373 pViewData = m_pwndRightView->m_pViewData;
1374 if (m_Data.IsYourFileInUse())
1375 pOriginFile = &m_Data.m_arYourFile;
1376 else if (m_Data.IsTheirFileInUse())
1377 pOriginFile = &m_Data.m_arTheirFile;
1379 else
1381 // nothing to save!
1382 return 1;
1384 Invalidate();
1385 if ((pViewData)&&(pOriginFile))
1387 CFileTextLines file;
1388 pOriginFile->CopySettings(&file);
1389 CFileTextLines::SaveParams saveParams;
1390 saveParams.m_LineEndings = pView->GetLineEndings();
1391 saveParams.m_UnicodeType = pView->GetTextType();
1392 file.SetSaveParams(saveParams);
1393 for (int i=0; i<pViewData->GetCount(); i++)
1395 //only copy non-removed lines
1396 DiffStates state = pViewData->GetState(i);
1397 switch (state)
1399 case DIFFSTATE_CONFLICTED:
1400 case DIFFSTATE_CONFLICTED_IGNORED:
1402 int first = i;
1403 int last = i;
1406 last++;
1407 } while((last<pViewData->GetCount()) && ((pViewData->GetState(last)==DIFFSTATE_CONFLICTED)||(pViewData->GetState(last)==DIFFSTATE_CONFLICTED_IGNORED)));
1408 // TortoiseGitMerge changes here
1409 file.Add(_T("<<<<<<< .mine"), m_pwndRightView->GetLineEndings());
1410 for (int j=first; j<last; j++)
1412 EOL lineending = m_pwndRightView->m_pViewData->GetLineEnding(j);
1413 if (lineending == EOL_NOENDING)
1414 lineending = m_pwndRightView->GetLineEndings();
1415 file.Add(m_pwndRightView->m_pViewData->GetLine(j), lineending);
1417 file.Add(_T("======="), m_pwndRightView->GetLineEndings());
1418 for (int j=first; j<last; j++)
1420 EOL lineending = m_pwndLeftView->m_pViewData->GetLineEnding(j);
1421 if (lineending == EOL_NOENDING)
1422 lineending = m_pwndLeftView->GetLineEndings();
1423 file.Add(m_pwndLeftView->m_pViewData->GetLine(j), lineending);
1425 file.Add(_T(">>>>>>> .theirs"), m_pwndRightView->GetLineEndings());
1426 i = last-1;
1428 break;
1429 case DIFFSTATE_EMPTY:
1430 case DIFFSTATE_CONFLICTEMPTY:
1431 case DIFFSTATE_IDENTICALREMOVED:
1432 case DIFFSTATE_REMOVED:
1433 case DIFFSTATE_THEIRSREMOVED:
1434 case DIFFSTATE_YOURSREMOVED:
1435 case DIFFSTATE_CONFLICTRESOLVEDEMPTY:
1436 // do not save removed lines
1437 break;
1438 default:
1439 file.Add(pViewData->GetLine(i), pViewData->GetLineEnding(i));
1440 break;
1443 if (!file.Save(sFilePath, false, false))
1445 CMessageBox::Show(m_hWnd, file.GetErrorString(), _T("TortoiseGitMerge"), MB_ICONERROR);
1446 return -1;
1448 if (sFilePath == m_Data.m_baseFile.GetFilename())
1450 m_Data.m_baseFile.StoreFileAttributes();
1452 if (sFilePath == m_Data.m_theirFile.GetFilename())
1454 m_Data.m_theirFile.StoreFileAttributes();
1456 if (sFilePath == m_Data.m_yourFile.GetFilename())
1458 m_Data.m_yourFile.StoreFileAttributes();
1460 /*if (sFilePath == m_Data.m_mergedFile.GetFilename())
1462 m_Data.m_mergedFile.StoreFileAttributes();
1463 }//*/
1464 m_dlgFilePatches.SetFileStatusAsPatched(sFilePath);
1465 if (IsViewGood(m_pwndBottomView))
1466 m_pwndBottomView->SetModified(FALSE);
1467 else if (IsViewGood(m_pwndRightView))
1468 m_pwndRightView->SetModified(FALSE);
1469 CUndo::GetInstance().MarkAsOriginalState(
1470 false,
1471 IsViewGood(m_pwndRightView) && (pViewData == m_pwndRightView->m_pViewData),
1472 IsViewGood(m_pwndBottomView) && (pViewData == m_pwndBottomView->m_pViewData));
1473 if (file.GetCount() == 1 && file.GetAt(0).IsEmpty() && file.GetLineEnding(0) == EOL_NOENDING)
1474 return 0;
1475 return file.GetCount();
1477 return 1;
1480 void CMainFrame::OnFileSave()
1482 // when multiple files are set as writable we have to ask what file to save
1483 int nEditableViewCount =
1484 (CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsWritable() ? 1 : 0)
1485 + (CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsWritable() ? 1 : 0)
1486 + (CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsWritable() ? 1 : 0);
1487 bool bLeftIsModified = CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsModified();
1488 bool bRightIsModified = CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsModified();
1489 bool bBottomIsModified = CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsModified();
1490 int nModifiedViewCount =
1491 (bLeftIsModified ? 1 : 0)
1492 + (bRightIsModified ? 1 : 0)
1493 + (bBottomIsModified ? 1 : 0);
1494 if (nEditableViewCount>1)
1496 if (nModifiedViewCount == 1)
1498 if (bLeftIsModified)
1499 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1500 else
1501 FileSave();
1503 else if (nModifiedViewCount>0)
1505 // both views
1506 UINT ret = IDNO;
1507 if (m_bUseTaskDialog)
1509 CTaskDialog taskdlg(CString(MAKEINTRESOURCE(IDS_SAVE_MORE)),
1510 CString(MAKEINTRESOURCE(IDS_SAVE)),
1511 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1513 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
1514 CString sTaskTemp;
1515 if (m_pwndLeftView->m_pWorkingFile->InUse() && !m_pwndLeftView->m_pWorkingFile->IsReadonly())
1516 sTaskTemp.Format(IDS_ASKFORSAVE_SAVELEFT, (LPCTSTR)m_pwndLeftView->m_pWorkingFile->GetFilename());
1517 else
1518 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS));
1519 taskdlg.AddCommandControl(201, sTaskTemp, bLeftIsModified);// left
1520 if (bLeftIsModified) {
1521 taskdlg.SetDefaultCommandControl(201);
1523 if (m_pwndRightView->m_pWorkingFile->InUse() && !m_pwndRightView->m_pWorkingFile->IsReadonly())
1524 sTaskTemp.Format(IDS_ASKFORSAVE_SAVERIGHT, (LPCTSTR)m_pwndRightView->m_pWorkingFile->GetFilename());
1525 else
1526 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS));
1527 taskdlg.AddCommandControl(202, sTaskTemp, bRightIsModified); // right
1528 if (bRightIsModified) {
1529 taskdlg.SetDefaultCommandControl(202);
1531 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEALL2)), nModifiedViewCount>1); // both
1532 if (nModifiedViewCount>1) {
1533 taskdlg.SetDefaultCommandControl(203);
1535 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1536 taskdlg.SetMainIcon(TD_WARNING_ICON);
1537 ret = (UINT)taskdlg.DoModal(m_hWnd);
1538 switch (ret)
1540 case 201: // left
1541 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1542 break;
1543 case 203: // both
1544 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
1545 case 202: // right
1546 m_pwndRightView->SaveFile();
1547 break;
1552 else
1554 // only target view was modified
1555 FileSave();
1559 void CMainFrame::PatchSave()
1561 bool bDoesNotExist = !PathFileExists(m_Data.m_mergedFile.GetFilename());
1562 if (m_Data.m_bPatchRequired)
1564 m_Patch.PatchPath(m_Data.m_mergedFile.GetFilename());
1566 if (!PathIsDirectory(m_Data.m_mergedFile.GetFilename()))
1568 int saveret = SaveFile(m_Data.m_mergedFile.GetFilename());
1569 if (saveret==0)
1571 // file was saved with 0 lines, remove it.
1572 m_Patch.RemoveFile(m_Data.m_mergedFile.GetFilename());
1573 // just in case
1574 DeleteFile(m_Data.m_mergedFile.GetFilename());
1576 m_Data.m_mergedFile.StoreFileAttributes();
1577 if (m_Data.m_mergedFile.GetFilename() == m_Data.m_yourFile.GetFilename())
1578 m_Data.m_yourFile.StoreFileAttributes();
1579 if ((bDoesNotExist)&&(DWORD(CRegDWORD(_T("Software\\TortoiseGitMerge\\AutoAdd"), TRUE))))
1581 // call TortoiseProc to add the new file to version control
1582 CString cmd = _T("/command:add /noui /path:\"");
1583 cmd += m_Data.m_mergedFile.GetFilename() + _T("\"");
1584 CAppUtils::RunTortoiseGitProc(cmd);
1589 bool CMainFrame::FileSave(bool bCheckResolved /*=true*/)
1591 if (!m_Data.m_mergedFile.InUse())
1592 return FileSaveAs(bCheckResolved);
1593 // check if the file has the readonly attribute set
1594 bool bDoesNotExist = false;
1595 DWORD fAttribs = GetFileAttributes(m_Data.m_mergedFile.GetFilename());
1596 if ((fAttribs != INVALID_FILE_ATTRIBUTES)&&(fAttribs & FILE_ATTRIBUTE_READONLY))
1597 return FileSaveAs(bCheckResolved);
1598 if (fAttribs == INVALID_FILE_ATTRIBUTES)
1600 bDoesNotExist = (GetLastError() == ERROR_FILE_NOT_FOUND);
1602 if (bCheckResolved && HasConflictsWontKeep())
1603 return false;
1605 if (((DWORD)CRegDWORD(_T("Software\\TortoiseGitMerge\\Backup"))) != 0)
1607 MoveFileEx(m_Data.m_mergedFile.GetFilename(), m_Data.m_mergedFile.GetFilename() + _T(".bak"), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
1609 if (m_Data.m_bPatchRequired)
1611 m_Patch.PatchPath(m_Data.m_mergedFile.GetFilename());
1613 int saveret = SaveFile(m_Data.m_mergedFile.GetFilename());
1614 if (saveret==0)
1616 // file was saved with 0 lines!
1617 // ask the user if the file should be deleted
1618 bool bDelete = false;
1619 if (m_bUseTaskDialog)
1621 CString msg;
1622 msg.Format(IDS_DELETEWHENEMPTY, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1623 CTaskDialog taskdlg(msg,
1624 CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK2)),
1625 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1627 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
1628 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK3)));
1629 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK4)));
1630 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1631 taskdlg.SetDefaultCommandControl(1);
1632 taskdlg.SetMainIcon(TD_WARNING_ICON);
1633 bDelete = (taskdlg.DoModal(m_hWnd) == 1);
1635 else
1637 CString sTemp;
1638 sTemp.Format(IDS_DELETEWHENEMPTY, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
1639 bDelete = (CMessageBox::ShowCheck(m_hWnd, sTemp, _T("TortoiseGitMerge"), MB_YESNO, _T("DeleteFileWhenEmpty")) == IDYES);
1641 if (bDelete)
1643 m_Patch.RemoveFile(m_Data.m_mergedFile.GetFilename());
1644 DeleteFile(m_Data.m_mergedFile.GetFilename());
1647 else if (saveret < 0)
1649 // error while saving the file
1650 return false;
1653 // if we're in conflict resolve mode (three pane view), check if there are no more conflicts
1654 // and if there aren't, ask to mark the file as resolved
1655 if (IsViewGood(m_pwndBottomView) && !m_bHasConflicts && bCheckResolved)
1657 CString projectRoot;
1658 if (g_GitAdminDir.HasAdminDir(m_Data.m_mergedFile.GetFilename(), false, &projectRoot))
1660 CString subpath = m_Data.m_mergedFile.GetFilename();
1661 subpath.Replace(_T('\\'), _T('/'));
1662 if (subpath.GetLength() >= projectRoot.GetLength())
1664 if (subpath[projectRoot.GetLength()] == _T('/'))
1665 subpath = subpath.Right(subpath.GetLength() - projectRoot.GetLength() - 1);
1666 else
1667 subpath = subpath.Right(subpath.GetLength() - projectRoot.GetLength());
1670 CAutoRepository repository(projectRoot);
1671 bool hasConflictInIndex = false;
1674 if (!repository)
1675 break;
1677 CAutoIndex index;
1678 if (git_repository_index(index.GetPointer(), repository))
1679 break;
1681 CStringA path = CUnicodeUtils::GetMulti(subpath, CP_UTF8);
1682 const git_index_entry * entry = git_index_get_bypath(index, path, 1);
1683 hasConflictInIndex = entry != nullptr;
1684 } while(0);
1686 if (hasConflictInIndex)
1688 bool bResolve = false;
1689 if (m_bUseTaskDialog)
1691 CString msg;
1692 msg.Format(IDS_MARKASRESOLVED, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1693 CTaskDialog taskdlg(msg,
1694 CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK2)),
1695 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1697 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
1698 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK3)));
1699 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK4)));
1700 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1701 taskdlg.SetDefaultCommandControl(1);
1702 taskdlg.SetMainIcon(TD_WARNING_ICON);
1703 bResolve = (taskdlg.DoModal(m_hWnd) == 1);
1705 else
1707 CString sTemp;
1708 sTemp.Format(IDS_MARKASRESOLVED, (LPCTSTR)CPathUtils::GetFileNameFromPath(m_Data.m_mergedFile.GetFilename()));
1709 bResolve = (CMessageBox::Show(m_hWnd, sTemp, _T("TortoiseGitMerge"), MB_YESNO | MB_ICONQUESTION) == IDYES);
1711 if (bResolve)
1713 MarkAsResolved();
1719 m_bSaveRequired = false;
1720 m_Data.m_mergedFile.StoreFileAttributes();
1722 if ((bDoesNotExist)&&(DWORD(CRegDWORD(_T("Software\\TortoiseGitMerge\\AutoAdd"), TRUE))))
1724 // call TortoiseProc to add the new file to version control
1725 CString cmd = _T("/command:add /noui /path:\"");
1726 cmd += m_Data.m_mergedFile.GetFilename() + _T("\"");
1727 if(!CAppUtils::RunTortoiseGitProc(cmd))
1728 return false;
1730 return true;
1733 void CMainFrame::OnFileSaveAs()
1735 if (m_bUseTaskDialog)
1737 // ask what file to save as
1738 bool bHaveConflict = (CheckResolved() >= 0);
1739 CTaskDialog taskdlg(
1740 CString(MAKEINTRESOURCE(bHaveConflict ? IDS_ASKFORSAVEAS_MORECONFLICT : IDS_ASKFORSAVEAS_MORE)),
1741 CString(MAKEINTRESOURCE(IDS_ASKFORSAVEAS)),
1742 CString(MAKEINTRESOURCE(IDS_APPNAME)),
1744 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
1745 // default can be last view (target) as was in 1.7 or actual (where is cursor) as is in most text editor
1746 if (IsViewGood(m_pwndLeftView))
1748 taskdlg.AddCommandControl(201, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS))); // left
1749 taskdlg.SetDefaultCommandControl(201);
1751 if (IsViewGood(m_pwndRightView))
1753 taskdlg.AddCommandControl(202, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS))); // right
1754 taskdlg.SetDefaultCommandControl(202);
1756 if (IsViewGood(m_pwndBottomView))
1758 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEBOTTOMAS))); // bottom
1759 taskdlg.SetDefaultCommandControl(203);
1761 if (bHaveConflict)
1763 taskdlg.AddCommandControl(204, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_NEEDRESOLVE))); // resolve
1764 taskdlg.SetDefaultCommandControl(204);
1766 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
1767 taskdlg.SetMainIcon(bHaveConflict ? TD_WARNING_ICON : TD_INFORMATION_ICON);
1768 int nCommand = (int)taskdlg.DoModal(m_hWnd);
1769 CString sFileName;
1770 switch (nCommand)
1772 case 201: // left
1773 if (TryGetFileName(sFileName))
1775 // in 2, 3 view display we want to keep removed lines
1776 m_pwndLeftView->SaveFileTo(sFileName, IsViewGood(m_pwndRightView) ? SAVE_REMOVEDLINES : 0);
1778 break;
1779 case 202: // right
1780 if (TryGetFileName(sFileName))
1782 m_pwndRightView->SaveFileTo(sFileName);
1784 break;
1785 case 203: // bottom
1786 FileSaveAs();
1787 break;
1788 case 204: // continue resolving
1789 if (m_pwndBottomView)
1791 m_pwndBottomView->GoToLine(CheckResolved());
1793 break;
1796 else
1798 int nEditableViewCount =
1799 (CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsWritable() ? 1 : 0)
1800 + (CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsWritable() ? 1 : 0)
1801 + (CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsWritable() ? 1 : 0);
1802 bool bLeftIsModified = CBaseView::IsViewGood(m_pwndLeftView) && m_pwndLeftView->IsModified();
1803 bool bRightIsModified = CBaseView::IsViewGood(m_pwndRightView) && m_pwndRightView->IsModified();
1804 bool bBottomIsModified = CBaseView::IsViewGood(m_pwndBottomView) && m_pwndBottomView->IsModified();
1805 int nModifiedViewCount =
1806 (bLeftIsModified ? 1 : 0)
1807 + (bRightIsModified ? 1 : 0)
1808 + (bBottomIsModified ? 1 : 0);
1809 if (nEditableViewCount>1)
1811 if (nModifiedViewCount == 1)
1813 if (bLeftIsModified)
1815 CString sFileName;
1816 if (TryGetFileName(sFileName))
1818 m_pwndLeftView->SaveFileTo(sFileName);
1821 else
1822 FileSaveAs();
1824 else
1826 FileSaveAs();
1827 CString sFileName;
1828 if (TryGetFileName(sFileName))
1830 m_pwndLeftView->SaveFileTo(sFileName);
1837 bool CMainFrame::FileSaveAs(bool bCheckResolved /*=true*/)
1839 if (bCheckResolved && HasConflictsWontKeep())
1840 return false;
1842 CString fileName;
1843 if(!TryGetFileName(fileName))
1844 return false;
1846 SaveFile(fileName);
1847 return true;
1850 void CMainFrame::OnUpdateFileSave(CCmdUI *pCmdUI)
1852 BOOL bEnable = FALSE;
1853 if (m_Data.m_mergedFile.InUse())
1855 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1856 bEnable = TRUE;
1857 else if ( (IsViewGood(m_pwndRightView)&&(m_pwndRightView->m_pViewData)) &&
1858 (m_pwndRightView->IsModified() || (m_Data.m_yourFile.GetWindowName().Right(9).Compare(_T(": patched"))==0)) )
1859 bEnable = TRUE;
1860 else if (IsViewGood(m_pwndLeftView)
1861 && (m_pwndLeftView->m_pViewData)
1862 && (m_pwndLeftView->IsModified()))
1863 bEnable = TRUE;
1865 pCmdUI->Enable(bEnable);
1868 void CMainFrame::OnUpdateFileSaveAs(CCmdUI *pCmdUI)
1870 // any file is open we can save it as
1871 BOOL bEnable = FALSE;
1872 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
1873 bEnable = TRUE;
1874 else if (IsViewGood(m_pwndRightView)&&(m_pwndRightView->m_pViewData))
1875 bEnable = TRUE;
1876 else if (IsViewGood(m_pwndLeftView)&&(m_pwndLeftView->m_pViewData))
1877 bEnable = TRUE;
1878 pCmdUI->Enable(bEnable);
1881 void CMainFrame::OnUpdateViewOnewaydiff(CCmdUI *pCmdUI)
1883 pCmdUI->SetCheck(!m_bOneWay);
1884 BOOL bEnable = TRUE;
1885 if (IsViewGood(m_pwndBottomView))
1887 bEnable = FALSE;
1889 pCmdUI->Enable(bEnable);
1892 void CMainFrame::OnViewOptions()
1894 CString sTemp;
1895 sTemp.LoadString(IDS_SETTINGSTITLE);
1896 CSettings dlg(sTemp);
1897 dlg.DoModal();
1898 if (dlg.IsReloadNeeded())
1900 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
1901 return;
1902 CDiffColors::GetInstance().LoadRegistry();
1903 LoadViews();
1904 return;
1906 CDiffColors::GetInstance().LoadRegistry();
1907 if (m_pwndBottomView)
1908 m_pwndBottomView->Invalidate();
1909 if (m_pwndLeftView)
1910 m_pwndLeftView->Invalidate();
1911 if (m_pwndRightView)
1912 m_pwndRightView->Invalidate();
1915 void CMainFrame::OnClose()
1917 if (CheckForSave(CHFSR_CLOSE)!=IDCANCEL)
1919 WINDOWPLACEMENT wp;
1921 // before it is destroyed, save the position of the window
1922 wp.length = sizeof wp;
1924 if (GetWindowPlacement(&wp))
1927 if (IsIconic())
1928 // never restore to Iconic state
1929 wp.showCmd = SW_SHOW ;
1931 if ((wp.flags & WPF_RESTORETOMAXIMIZED) != 0)
1932 // if maximized and maybe iconic restore maximized state
1933 wp.showCmd = SW_SHOWMAXIMIZED ;
1935 // and write it
1936 WriteWindowPlacement(&wp);
1938 __super::OnClose();
1942 void CMainFrame::OnActivate(UINT nValue, CWnd* /*pwnd*/, BOOL /*bActivated?*/)
1944 if (nValue != 0) // activated
1946 if (IsIconic())
1948 m_bCheckReload = TRUE;
1950 else
1952 // use a timer to give other messages time to get processed
1953 // first, like e.g. the WM_CLOSE message in case the user
1954 // clicked the close button and that brought the window
1955 // to the front - in that case checking for reload wouldn't
1956 // do any good.
1957 SetTimer(IDT_RELOADCHECKTIMER, 300, NULL);
1962 void CMainFrame::OnViewLinedown()
1964 OnViewLineUpDown(1);
1967 void CMainFrame::OnViewLineup()
1969 OnViewLineUpDown(-1);
1972 void CMainFrame::OnViewLineUpDown(int direction)
1974 if (m_pwndLeftView)
1975 m_pwndLeftView->ScrollToLine(m_pwndLeftView->m_nTopLine+direction);
1976 if (m_pwndRightView)
1977 m_pwndRightView->ScrollToLine(m_pwndRightView->m_nTopLine+direction);
1978 if (m_pwndBottomView)
1979 m_pwndBottomView->ScrollToLine(m_pwndBottomView->m_nTopLine+direction);
1980 m_wndLocatorBar.Invalidate();
1981 m_nMoveMovesToIgnore = MOVESTOIGNORE;
1984 void CMainFrame::OnViewLineleft()
1986 OnViewLineLeftRight(-1);
1989 void CMainFrame::OnViewLineright()
1991 OnViewLineLeftRight(1);
1994 void CMainFrame::OnViewLineLeftRight(int direction)
1996 if (m_pwndLeftView)
1997 m_pwndLeftView->ScrollSide(direction);
1998 if (m_pwndRightView)
1999 m_pwndRightView->ScrollSide(direction);
2000 if (m_pwndBottomView)
2001 m_pwndBottomView->ScrollSide(direction);
2004 void CMainFrame::OnEditUseTheirs()
2006 if (m_pwndBottomView)
2007 m_pwndBottomView->UseTheirTextBlock();
2009 void CMainFrame::OnUpdateEditUsetheirblock(CCmdUI *pCmdUI)
2011 pCmdUI->Enable(m_pwndBottomView && m_pwndBottomView->HasSelection());
2014 void CMainFrame::OnEditUseMine()
2016 if (m_pwndBottomView)
2017 m_pwndBottomView->UseMyTextBlock();
2019 void CMainFrame::OnUpdateEditUsemyblock(CCmdUI *pCmdUI)
2021 OnUpdateEditUsetheirblock(pCmdUI);
2024 void CMainFrame::OnEditUseTheirsThenMine()
2026 if (m_pwndBottomView)
2027 m_pwndBottomView->UseTheirAndYourBlock();
2030 void CMainFrame::OnUpdateEditUsetheirthenmyblock(CCmdUI *pCmdUI)
2032 OnUpdateEditUsetheirblock(pCmdUI);
2035 void CMainFrame::OnEditUseMineThenTheirs()
2037 if (m_pwndBottomView)
2038 m_pwndBottomView->UseYourAndTheirBlock();
2041 void CMainFrame::OnUpdateEditUseminethentheirblock(CCmdUI *pCmdUI)
2043 OnUpdateEditUsetheirblock(pCmdUI);
2046 void CMainFrame::OnEditUseleftblock()
2048 if (m_pwndBottomView->IsWindowVisible())
2049 m_pwndBottomView->UseRightBlock();
2050 else
2051 m_pwndRightView->UseLeftBlock();
2054 void CMainFrame::OnUpdateEditUseleftblock(CCmdUI *pCmdUI)
2056 pCmdUI->Enable(IsViewGood(m_pwndRightView) && m_pwndRightView->IsTarget() && m_pwndRightView->HasSelection());
2059 void CMainFrame::OnUpdateUseBlock(CCmdUI *pCmdUI)
2061 pCmdUI->Enable(TRUE);
2064 void CMainFrame::OnEditUseleftfile()
2066 if (m_pwndBottomView->IsWindowVisible())
2067 m_pwndBottomView->UseRightFile();
2068 else
2069 m_pwndRightView->UseLeftFile();
2072 void CMainFrame::OnUpdateEditUseleftfile(CCmdUI *pCmdUI)
2074 pCmdUI->Enable(IsViewGood(m_pwndRightView) && m_pwndRightView->IsTarget());
2077 void CMainFrame::OnEditUseblockfromleftbeforeright()
2079 if (m_pwndRightView)
2080 m_pwndRightView->UseBothLeftFirst();
2083 void CMainFrame::OnUpdateEditUseblockfromleftbeforeright(CCmdUI *pCmdUI)
2085 OnUpdateEditUseleftblock(pCmdUI);
2088 void CMainFrame::OnEditUseblockfromrightbeforeleft()
2090 if (m_pwndRightView)
2091 m_pwndRightView->UseBothRightFirst();
2094 void CMainFrame::OnUpdateEditUseblockfromrightbeforeleft(CCmdUI *pCmdUI)
2096 OnUpdateEditUseleftblock(pCmdUI);
2099 void CMainFrame::OnFileReload()
2101 if (CheckForSave(CHFSR_RELOAD)==IDCANCEL)
2102 return;
2103 CDiffColors::GetInstance().LoadRegistry();
2104 LoadViews(-1);
2107 void CMainFrame::ActivateFrame(int nCmdShow)
2109 // nCmdShow is the normal show mode this frame should be in
2110 // translate default nCmdShow (-1)
2111 if (nCmdShow == -1)
2113 if (!IsWindowVisible())
2114 nCmdShow = SW_SHOWNORMAL;
2115 else if (IsIconic())
2116 nCmdShow = SW_RESTORE;
2119 // bring to top before showing
2120 BringToTop(nCmdShow);
2122 if (nCmdShow != -1)
2124 // show the window as specified
2125 WINDOWPLACEMENT wp;
2127 if ( !ReadWindowPlacement(&wp) )
2129 ShowWindow(nCmdShow);
2131 else
2133 if ( nCmdShow != SW_SHOWNORMAL )
2134 wp.showCmd = nCmdShow;
2136 SetWindowPlacement(&wp);
2139 // and finally, bring to top after showing
2140 BringToTop(nCmdShow);
2144 BOOL CMainFrame::ReadWindowPlacement(WINDOWPLACEMENT * pwp)
2146 CRegString placement = CRegString(_T("Software\\TortoiseGitMerge\\WindowPos"));
2147 CString sPlacement = placement;
2148 if (sPlacement.IsEmpty())
2149 return FALSE;
2150 int nRead = _stscanf_s(sPlacement, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
2151 &pwp->flags, &pwp->showCmd,
2152 &pwp->ptMinPosition.x, &pwp->ptMinPosition.y,
2153 &pwp->ptMaxPosition.x, &pwp->ptMaxPosition.y,
2154 &pwp->rcNormalPosition.left, &pwp->rcNormalPosition.top,
2155 &pwp->rcNormalPosition.right, &pwp->rcNormalPosition.bottom);
2156 if ( nRead != 10 )
2157 return FALSE;
2158 pwp->length = sizeof(WINDOWPLACEMENT);
2160 return TRUE;
2163 void CMainFrame::WriteWindowPlacement(WINDOWPLACEMENT * pwp)
2165 CRegString placement = CRegString(_T("Software\\TortoiseGitMerge\\WindowPos"));
2166 TCHAR szBuffer[_countof("-32767")*8 + sizeof("65535")*2];
2168 _stprintf_s(szBuffer, _T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d"),
2169 pwp->flags, pwp->showCmd,
2170 pwp->ptMinPosition.x, pwp->ptMinPosition.y,
2171 pwp->ptMaxPosition.x, pwp->ptMaxPosition.y,
2172 pwp->rcNormalPosition.left, pwp->rcNormalPosition.top,
2173 pwp->rcNormalPosition.right, pwp->rcNormalPosition.bottom);
2174 placement = szBuffer;
2177 void CMainFrame::OnUpdateMergeMarkasresolved(CCmdUI *pCmdUI)
2179 if (pCmdUI == NULL)
2180 return;
2181 BOOL bEnable = FALSE;
2182 if ((!m_bReadOnly)&&(m_Data.m_mergedFile.InUse()))
2184 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
2186 bEnable = TRUE;
2189 pCmdUI->Enable(bEnable);
2192 void CMainFrame::OnMergeMarkasresolved()
2194 if(HasConflictsWontKeep())
2195 return;
2197 // now check if the file has already been saved and if not, save it.
2198 if (m_Data.m_mergedFile.InUse())
2200 if (IsViewGood(m_pwndBottomView)&&(m_pwndBottomView->m_pViewData))
2202 FileSave(false);
2203 m_bSaveRequired = false;
2206 MarkAsResolved();
2209 BOOL CMainFrame::MarkAsResolved()
2211 if (m_bReadOnly)
2212 return FALSE;
2213 if (!IsViewGood(m_pwndBottomView))
2214 return FALSE;
2216 CString cmd = _T("/command:resolve /path:\"");
2217 cmd += m_Data.m_mergedFile.GetFilename();
2218 cmd += _T("\" /closeonend:1 /noquestion /skipcheck /silent");
2219 if (resolveMsgWnd)
2221 CString s;
2222 s.Format(L" /resolvemsghwnd:%I64d /resolvemsgwparam:%I64d /resolvemsglparam:%I64d", (__int64)resolveMsgWnd, (__int64)resolveMsgWParam, (__int64)resolveMsgLParam);
2223 cmd += s;
2225 if(!CAppUtils::RunTortoiseGitProc(cmd))
2226 return FALSE;
2227 m_bSaveRequired = false;
2228 return TRUE;
2231 void CMainFrame::OnUpdateMergeNextconflict(CCmdUI *pCmdUI)
2233 BOOL bShow = FALSE;
2234 if (HasNextConflict(m_pwndBottomView))
2235 bShow = TRUE;
2236 else if (HasNextConflict(m_pwndRightView))
2237 bShow = TRUE;
2238 else if (HasNextConflict(m_pwndLeftView))
2239 bShow = TRUE;
2240 pCmdUI->Enable(bShow);
2243 bool CMainFrame::HasNextConflict(CBaseView* view)
2245 if (view == 0)
2246 return false;
2247 if (!view->IsTarget())
2248 return false;
2249 return view->HasNextConflict();
2252 void CMainFrame::OnUpdateMergePreviousconflict(CCmdUI *pCmdUI)
2254 BOOL bShow = FALSE;
2255 if (HasPrevConflict(m_pwndBottomView))
2256 bShow = TRUE;
2257 else if (HasPrevConflict(m_pwndRightView))
2258 bShow = TRUE;
2259 else if (HasPrevConflict(m_pwndLeftView))
2260 bShow = TRUE;
2261 pCmdUI->Enable(bShow);
2264 bool CMainFrame::HasPrevConflict(CBaseView* view)
2266 if (view == 0)
2267 return false;
2268 if (!view->IsTarget())
2269 return false;
2270 return view->HasPrevConflict();
2273 void CMainFrame::OnUpdateNavigateNextdifference(CCmdUI *pCmdUI)
2275 CBaseView* baseView = GetActiveBaseView();
2276 BOOL bShow = FALSE;
2277 if (baseView != 0)
2278 bShow = baseView->HasNextDiff();
2279 pCmdUI->Enable(bShow);
2282 void CMainFrame::OnUpdateNavigatePreviousdifference(CCmdUI *pCmdUI)
2284 CBaseView* baseView = GetActiveBaseView();
2285 BOOL bShow = FALSE;
2286 if (baseView != 0)
2287 bShow = baseView->HasPrevDiff();
2288 pCmdUI->Enable(bShow);
2291 void CMainFrame::OnUpdateNavigateNextinlinediff(CCmdUI *pCmdUI)
2293 BOOL bShow = FALSE;
2294 if (HasNextInlineDiff(m_pwndBottomView))
2295 bShow = TRUE;
2296 else if (HasNextInlineDiff(m_pwndRightView))
2297 bShow = TRUE;
2298 else if (HasNextInlineDiff(m_pwndLeftView))
2299 bShow = TRUE;
2300 pCmdUI->Enable(bShow);
2303 bool CMainFrame::HasNextInlineDiff(CBaseView* view)
2305 if (view == 0)
2306 return false;
2307 if (!view->IsTarget())
2308 return false;
2309 return view->HasNextInlineDiff();
2312 void CMainFrame::OnUpdateNavigatePrevinlinediff(CCmdUI *pCmdUI)
2314 BOOL bShow = FALSE;
2315 if (HasPrevInlineDiff(m_pwndBottomView))
2316 bShow = TRUE;
2317 else if (HasPrevInlineDiff(m_pwndRightView))
2318 bShow = TRUE;
2319 else if (HasPrevInlineDiff(m_pwndLeftView))
2320 bShow = TRUE;
2321 pCmdUI->Enable(bShow);
2324 bool CMainFrame::HasPrevInlineDiff(CBaseView* view)
2326 if (view == 0)
2327 return false;
2328 if (!view->IsTarget())
2329 return false;
2330 return view->HasPrevInlineDiff();
2333 void CMainFrame::OnMoving(UINT fwSide, LPRECT pRect)
2335 // if the pathfilelist dialog is attached to the mainframe,
2336 // move it along with the mainframe
2337 if (::IsWindow(m_dlgFilePatches.m_hWnd))
2339 RECT patchrect;
2340 m_dlgFilePatches.GetWindowRect(&patchrect);
2341 if (::IsWindow(m_hWnd))
2343 RECT thisrect;
2344 GetWindowRect(&thisrect);
2345 if (patchrect.right == thisrect.left)
2347 m_dlgFilePatches.SetWindowPos(NULL, patchrect.left - (thisrect.left - pRect->left), patchrect.top - (thisrect.top - pRect->top),
2348 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
2352 __super::OnMoving(fwSide, pRect);
2355 void CMainFrame::OnUpdateEditCopy(CCmdUI *pCmdUI)
2357 BOOL bShow = FALSE;
2358 if ((m_pwndBottomView)&&(m_pwndBottomView->HasSelection()))
2359 bShow = TRUE;
2360 else if ((m_pwndRightView)&&(m_pwndRightView->HasSelection()))
2361 bShow = TRUE;
2362 else if ((m_pwndLeftView)&&(m_pwndLeftView->HasSelection()))
2363 bShow = TRUE;
2364 pCmdUI->Enable(bShow);
2367 void CMainFrame::OnUpdateEditPaste(CCmdUI *pCmdUI)
2369 BOOL bWritable = FALSE;
2370 if ((m_pwndBottomView)&&(m_pwndBottomView->IsWritable()))
2371 bWritable = TRUE;
2372 else if ((m_pwndRightView)&&(m_pwndRightView->IsWritable()))
2373 bWritable = TRUE;
2374 else if ((m_pwndLeftView)&&(m_pwndLeftView->IsWritable()))
2375 bWritable = TRUE;
2376 pCmdUI->Enable(bWritable && ::IsClipboardFormatAvailable(CF_TEXT));
2379 void CMainFrame::OnViewSwitchleft()
2381 if (CheckForSave(CHFSR_SWITCH)!=IDCANCEL)
2383 CWorkingFile file = m_Data.m_baseFile;
2384 m_Data.m_baseFile = m_Data.m_yourFile;
2385 m_Data.m_yourFile = file;
2386 if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_yourFile.GetFilename())==0)
2388 m_Data.m_mergedFile = m_Data.m_baseFile;
2390 else if (m_Data.m_mergedFile.GetFilename().CompareNoCase(m_Data.m_baseFile.GetFilename())==0)
2392 m_Data.m_mergedFile = m_Data.m_yourFile;
2394 LoadViews();
2398 void CMainFrame::OnUpdateViewSwitchleft(CCmdUI *pCmdUI)
2400 BOOL bEnable = !IsViewGood(m_pwndBottomView);
2401 pCmdUI->Enable(bEnable);
2404 void CMainFrame::OnUpdateViewShowfilelist(CCmdUI *pCmdUI)
2406 BOOL bEnable = m_dlgFilePatches.HasFiles();
2407 pCmdUI->Enable(bEnable);
2408 pCmdUI->SetCheck(m_dlgFilePatches.IsWindowVisible());
2411 void CMainFrame::OnViewShowfilelist()
2413 m_dlgFilePatches.ShowWindow(m_dlgFilePatches.IsWindowVisible() ? SW_HIDE : SW_SHOW);
2416 void CMainFrame::OnEditUndo()
2418 if (CUndo::GetInstance().CanUndo())
2420 CUndo::GetInstance().Undo(m_pwndLeftView, m_pwndRightView, m_pwndBottomView);
2424 void CMainFrame::OnUpdateEditUndo(CCmdUI *pCmdUI)
2426 pCmdUI->Enable(CUndo::GetInstance().CanUndo());
2429 void CMainFrame::OnEditEnable()
2431 CBaseView * pView = GetActiveBaseView();
2432 if (pView && pView->IsReadonlyChangable())
2434 bool isReadOnly = pView->IsReadonly();
2435 pView->SetReadonly(!isReadOnly);
2439 void CMainFrame::OnUpdateEditEnable(CCmdUI *pCmdUI)
2441 CBaseView * pView = GetActiveBaseView();
2442 if (pView)
2444 pCmdUI->Enable(pView->IsReadonlyChangable() || !pView->IsReadonly());
2445 pCmdUI->SetCheck(!pView->IsReadonly());
2447 else
2449 pCmdUI->Enable(FALSE);
2453 void CMainFrame::OnIndicatorLeftview()
2455 if (m_bUseRibbons)
2456 return;
2457 if (IsViewGood(m_pwndLeftView))
2459 m_pwndLeftView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_LEFTVIEW);
2463 void CMainFrame::OnIndicatorRightview()
2465 if (m_bUseRibbons)
2466 return;
2467 if (IsViewGood(m_pwndRightView))
2469 m_pwndRightView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_RIGHTVIEW);
2473 void CMainFrame::OnIndicatorBottomview()
2475 if (m_bUseRibbons)
2476 return;
2477 if (IsViewGood(m_pwndBottomView))
2479 m_pwndBottomView->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_BOTTOMVIEW);
2483 int CMainFrame::CheckForReload()
2485 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
2486 if (bLock)
2488 return IDNO;
2490 bLock = true;
2491 bool bSourceChanged =
2492 m_Data.m_baseFile.HasSourceFileChanged()
2493 || m_Data.m_yourFile.HasSourceFileChanged()
2494 || m_Data.m_theirFile.HasSourceFileChanged()
2495 /*|| m_Data.m_mergedFile.HasSourceFileChanged()*/;
2496 if (!bSourceChanged)
2498 bLock = false;
2499 return IDNO;
2502 UINT ret = IDNO;
2503 if (m_bUseTaskDialog)
2505 CString msg = HasUnsavedEdits() ? CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDELOOSECHANGES)) : CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE));
2506 CTaskDialog taskdlg(msg,
2507 CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE_TASK2)),
2508 L"TortoiseGitMerge",
2510 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
2511 CString sTask3;
2512 if (HasUnsavedEdits())
2513 sTask3.LoadString(IDS_WARNMODIFIEDOUTSIDE_TASK3);
2514 else
2515 sTask3.LoadString(IDS_WARNMODIFIEDOUTSIDE_TASK4);
2516 taskdlg.AddCommandControl(IDYES, sTask3);
2517 taskdlg.AddCommandControl(IDNO, CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE_TASK5)));
2518 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2519 taskdlg.SetDefaultCommandControl(IDYES);
2520 taskdlg.SetMainIcon(TD_WARNING_ICON);
2521 ret = (UINT)taskdlg.DoModal(m_hWnd);
2523 else
2525 int idsMessage = HasUnsavedEdits() ? IDS_WARNMODIFIEDOUTSIDELOOSECHANGES : IDS_WARNMODIFIEDOUTSIDE;
2526 ret = CMessageBox::Show(m_hWnd, idsMessage, IDS_APPNAME, MB_YESNO | MB_ICONQUESTION);
2529 if (ret == IDYES)
2531 CDiffColors::GetInstance().LoadRegistry();
2532 LoadViews(-1);
2534 else
2536 if (IsViewGood(m_pwndBottomView)) // three pane view
2538 /*if (m_Data.m_sourceFile.HasSourceFileChanged())
2539 m_pwndBottomView->SetModified();
2540 if (m_Data.m_mergedFile.HasSourceFileChanged())
2541 m_pwndBottomView->SetModified();//*/
2542 if (m_Data.m_yourFile.HasSourceFileChanged())
2543 m_pwndRightView->SetModified();
2544 if (m_Data.m_theirFile.HasSourceFileChanged())
2545 m_pwndLeftView->SetModified();
2547 else if (IsViewGood(m_pwndRightView)) // two pane view
2549 if (m_Data.m_baseFile.HasSourceFileChanged())
2550 m_pwndLeftView->SetModified();
2551 if (m_Data.m_yourFile.HasSourceFileChanged())
2552 m_pwndRightView->SetModified();
2554 else
2556 if (m_Data.m_yourFile.HasSourceFileChanged())
2557 m_pwndLeftView->SetModified();
2560 // no reload just store updated file time
2561 m_Data.m_baseFile.StoreFileAttributes();
2562 m_Data.m_theirFile.StoreFileAttributes();
2563 m_Data.m_yourFile.StoreFileAttributes();
2564 //m_Data.m_mergedFile.StoreFileAttributes();
2566 bLock = false;
2567 return ret;
2570 int CMainFrame::CheckForSave(ECheckForSaveReason eReason)
2572 int idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2573 int idNoSave = IDS_ASKFORSAVE_TASK7;
2574 int idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2575 switch (eReason)
2577 case CHFSR_CLOSE:
2578 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2579 idNoSave = IDS_ASKFORSAVE_TASK4;
2580 idCancelAction = IDS_ASKFORSAVE_TASK5;
2581 break;
2582 case CHFSR_SWITCH:
2583 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2584 //idNoSave = IDS_ASKFORSAVE_TASK7;
2585 idCancelAction = IDS_ASKFORSAVE_TASK8;
2586 break;
2587 case CHFSR_RELOAD:
2588 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2589 //idNoSave = IDS_ASKFORSAVE_TASK7;
2590 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2591 break;
2592 case CHFSR_OPTIONS:
2593 idTitle = IDS_WARNMODIFIEDLOOSECHANGESOPTIONS;
2594 //idNoSave = IDS_ASKFORSAVE_TASK7;
2595 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPTIONS;
2596 break;
2597 case CHFSR_OPEN:
2598 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2599 idNoSave = IDS_ASKFORSAVE_NOSAVE_OPEN;
2600 idCancelAction = IDS_ASKFORSAVE_CANCEL_OPEN;
2601 break;
2604 CString sTitle(MAKEINTRESOURCE(idTitle));
2605 CString sSubTitle(MAKEINTRESOURCE(IDS_ASKFORSAVE_TASK2));
2606 CString sNoSave(MAKEINTRESOURCE(idNoSave));
2607 CString sCancelAction(MAKEINTRESOURCE(idCancelAction));
2608 CString sAppName(MAKEINTRESOURCE(IDS_APPNAME));
2610 // TODO simplify logic, reduce code duplication
2611 if (CBaseView::IsViewGood(m_pwndBottomView))
2613 // three-way diff - by design only bottom can be changed
2614 // use 1.7 way to do that
2616 else if (CBaseView::IsViewGood(m_pwndRightView))
2618 // two-way diff -
2619 // 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
2620 if (HasUnsavedEdits(m_pwndLeftView))
2622 // both views
2623 UINT ret = IDNO;
2624 if (m_bUseTaskDialog)
2626 CTaskDialog taskdlg(sTitle,
2627 sSubTitle,
2628 sAppName,
2630 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
2631 CString sTaskTemp;
2632 if (m_pwndLeftView->m_pWorkingFile->InUse() && !m_pwndLeftView->m_pWorkingFile->IsReadonly())
2633 sTaskTemp.Format(IDS_ASKFORSAVE_SAVELEFT, (LPCTSTR)m_pwndLeftView->m_pWorkingFile->GetFilename());
2634 else
2635 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS));
2636 taskdlg.AddCommandControl(201, sTaskTemp); // left
2637 taskdlg.SetDefaultCommandControl(201);
2638 if (HasUnsavedEdits(m_pwndRightView))
2640 if (m_pwndRightView->m_pWorkingFile->InUse() && !m_pwndRightView->m_pWorkingFile->IsReadonly())
2641 sTaskTemp.Format(IDS_ASKFORSAVE_SAVERIGHT, (LPCTSTR)m_pwndRightView->m_pWorkingFile->GetFilename());
2642 else
2643 sTaskTemp = CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS));
2644 taskdlg.AddCommandControl(202, sTaskTemp); // right
2645 taskdlg.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEALL2))); // both
2646 taskdlg.SetDefaultCommandControl(203);
2648 taskdlg.AddCommandControl(IDNO, sNoSave); // none
2649 taskdlg.AddCommandControl(IDCANCEL, sCancelAction); // cancel
2650 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2651 taskdlg.SetMainIcon(TD_WARNING_ICON);
2652 ret = (UINT)taskdlg.DoModal(m_hWnd);
2653 switch (ret)
2655 case 201: // left
2656 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
2657 break;
2658 case 203: // both
2659 m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES);
2660 case 202: // right
2661 m_pwndRightView->SaveFile();
2662 break;
2664 return ret;
2666 else
2668 // show separate questions
2669 // first show question for left view
2670 ret = MessageBox(sTitle, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
2671 if (ret == IDCANCEL)
2673 return IDCANCEL;
2675 if (ret == IDYES)
2677 if (m_pwndLeftView->SaveFile(SAVE_REMOVEDLINES)<0)
2679 return IDCANCEL;
2682 // right file is handled old way
2685 else
2687 // only secondary (left) view
2689 // only right view - 1.7 implementation is used
2691 else if (CBaseView::IsViewGood(m_pwndLeftView))
2693 // only one view - only one to save
2694 // 1.7 FileSave don't support this mode
2695 if (HasUnsavedEdits(m_pwndLeftView))
2697 UINT ret = IDNO;
2698 if (m_bUseTaskDialog)
2700 CTaskDialog taskdlg(sTitle,
2701 sSubTitle,
2702 sAppName,
2704 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
2705 CString sTask3;
2706 if (m_Data.m_mergedFile.InUse())
2707 sTask3.Format(IDS_ASKFORSAVE_TASK3, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
2708 else
2709 sTask3.LoadString(IDS_ASKFORSAVE_TASK6);
2710 taskdlg.AddCommandControl(IDYES, sTask3);
2711 taskdlg.AddCommandControl(IDNO, sNoSave);
2712 taskdlg.AddCommandControl(IDCANCEL, sCancelAction);
2713 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2714 taskdlg.SetDefaultCommandControl(IDYES);
2715 taskdlg.SetMainIcon(TD_WARNING_ICON);
2716 ret = (UINT)taskdlg.DoModal(m_hWnd);
2718 else
2720 ret = MessageBox(sTitle, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
2723 if (ret == IDYES)
2725 if (m_pwndLeftView->SaveFile()<0)
2726 return IDCANCEL;
2729 return IDNO;
2731 else
2733 return IDNO; // nothing to save
2736 // 1.7 implementation
2737 UINT ret = IDNO;
2738 if (HasUnsavedEdits())
2740 if (m_bUseTaskDialog)
2742 CTaskDialog taskdlg(sTitle,
2743 sSubTitle,
2744 sAppName,
2746 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
2747 CString sTask3;
2748 if (m_Data.m_mergedFile.InUse())
2749 sTask3.Format(IDS_ASKFORSAVE_TASK3, (LPCTSTR)m_Data.m_mergedFile.GetFilename());
2750 else
2751 sTask3.LoadString(IDS_ASKFORSAVE_TASK6);
2752 taskdlg.AddCommandControl(IDYES, sTask3);
2753 taskdlg.AddCommandControl(IDNO, sNoSave);
2754 taskdlg.AddCommandControl(IDCANCEL, sCancelAction);
2755 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
2756 taskdlg.SetDefaultCommandControl(IDYES);
2757 taskdlg.SetMainIcon(TD_WARNING_ICON);
2758 ret = (UINT)taskdlg.DoModal(m_hWnd);
2760 else
2762 ret = MessageBox(sTitle, 0, MB_YESNOCANCEL | MB_ICONQUESTION);
2765 if (ret == IDYES)
2767 if (!FileSave())
2768 ret = IDCANCEL;
2771 return ret;
2774 bool CMainFrame::HasUnsavedEdits() const
2776 return HasUnsavedEdits(m_pwndBottomView) || HasUnsavedEdits(m_pwndRightView) || m_bSaveRequired;
2779 bool CMainFrame::HasUnsavedEdits(const CBaseView* view)
2781 if (!CBaseView::IsViewGood(view))
2782 return false;
2783 return view->IsModified();
2786 bool CMainFrame::IsViewGood(const CBaseView* view)
2788 return CBaseView::IsViewGood(view);
2791 void CMainFrame::OnViewInlinediffword()
2793 m_bInlineWordDiff = !m_bInlineWordDiff;
2794 if (m_pwndLeftView)
2796 m_pwndLeftView->SetInlineWordDiff(m_bInlineWordDiff);
2797 m_pwndLeftView->BuildAllScreen2ViewVector();
2798 m_pwndLeftView->DocumentUpdated();
2800 if (m_pwndRightView)
2802 m_pwndRightView->SetInlineWordDiff(m_bInlineWordDiff);
2803 m_pwndRightView->BuildAllScreen2ViewVector();
2804 m_pwndRightView->DocumentUpdated();
2806 if (m_pwndBottomView)
2808 m_pwndBottomView->SetInlineWordDiff(m_bInlineWordDiff);
2809 m_pwndBottomView->BuildAllScreen2ViewVector();
2810 m_pwndBottomView->DocumentUpdated();
2812 m_wndLineDiffBar.DocumentUpdated();
2815 void CMainFrame::OnUpdateViewInlinediffword(CCmdUI *pCmdUI)
2817 pCmdUI->Enable(m_bInlineDiff && IsViewGood(m_pwndLeftView) && IsViewGood(m_pwndRightView));
2818 pCmdUI->SetCheck(m_bInlineWordDiff);
2821 void CMainFrame::OnViewInlinediff()
2823 m_bInlineDiff = !m_bInlineDiff;
2824 if (m_pwndLeftView)
2826 m_pwndLeftView->SetInlineDiff(m_bInlineDiff);
2827 m_pwndLeftView->BuildAllScreen2ViewVector();
2828 m_pwndLeftView->DocumentUpdated();
2830 if (m_pwndRightView)
2832 m_pwndRightView->SetInlineDiff(m_bInlineDiff);
2833 m_pwndRightView->BuildAllScreen2ViewVector();
2834 m_pwndRightView->DocumentUpdated();
2836 if (m_pwndBottomView)
2838 m_pwndBottomView->SetInlineDiff(m_bInlineDiff);
2839 m_pwndBottomView->BuildAllScreen2ViewVector();
2840 m_pwndBottomView->DocumentUpdated();
2842 m_wndLineDiffBar.DocumentUpdated();
2845 void CMainFrame::OnUpdateViewInlinediff(CCmdUI *pCmdUI)
2847 pCmdUI->Enable(IsViewGood(m_pwndLeftView) && IsViewGood(m_pwndRightView));
2848 pCmdUI->SetCheck(m_bInlineDiff);
2851 void CMainFrame::OnUpdateEditCreateunifieddifffile(CCmdUI *pCmdUI)
2853 // "create unified diff file" is only available if two files
2854 // are diffed, not three.
2855 bool bEnabled = true;
2856 if (!IsViewGood(m_pwndLeftView))
2857 bEnabled = false;
2858 else if (!IsViewGood(m_pwndRightView))
2859 bEnabled = false;
2860 else if (IsViewGood(m_pwndBottomView)) //no negation here
2861 bEnabled = false;
2862 pCmdUI->Enable(bEnabled);
2865 void CMainFrame::OnEditCreateunifieddifffile()
2867 CString origFile, modifiedFile;
2868 // the original file is the one on the left
2869 if (m_pwndLeftView)
2870 origFile = m_pwndLeftView->m_sFullFilePath;
2871 if (m_pwndRightView)
2872 modifiedFile = m_pwndRightView->m_sFullFilePath;
2873 if (origFile.IsEmpty() || modifiedFile.IsEmpty())
2874 return;
2876 CString outputFile;
2877 if(!TryGetFileName(outputFile))
2878 return;
2880 CAppUtils::CreateUnifiedDiff(origFile, modifiedFile, outputFile, true);
2883 void CMainFrame::OnUpdateEditTabspace(CCmdUI *pCmdUI)
2885 pCmdUI->Enable(true);
2886 int nTabMode = m_regTabMode;
2887 pCmdUI->SetCheck(nTabMode & TABMODE_USESPACES);
2890 void CMainFrame::OnEditTabspace()
2892 int nTabMode = m_regTabMode;
2893 nTabMode ^= TABMODE_USESPACES;
2894 m_regTabMode = nTabMode;
2895 if (IsViewGood(m_pwndLeftView))
2896 m_pwndLeftView->m_nTabMode = nTabMode;
2897 if (IsViewGood(m_pwndRightView))
2898 m_pwndRightView->m_nTabMode = nTabMode;
2899 if (IsViewGood(m_pwndBottomView))
2900 m_pwndBottomView->m_nTabMode = nTabMode;
2903 void CMainFrame::OnUpdateEditSmartTab(CCmdUI *pCmdUI)
2905 pCmdUI->Enable(true);
2906 int nTabMode = m_regTabMode;
2907 pCmdUI->SetCheck(nTabMode & TABMODE_SMARTINDENT);
2910 void CMainFrame::OnEditSmartTab()
2912 int nTabMode = m_regTabMode;
2913 nTabMode ^= TABMODE_SMARTINDENT;
2914 m_regTabMode = nTabMode;
2915 if (IsViewGood(m_pwndLeftView))
2916 m_pwndLeftView->m_nTabMode = nTabMode;
2917 if (IsViewGood(m_pwndRightView))
2918 m_pwndRightView->m_nTabMode = nTabMode;
2919 if (IsViewGood(m_pwndBottomView))
2920 m_pwndBottomView->m_nTabMode = nTabMode;
2923 void CMainFrame::OnUpdateViewLinediffbar(CCmdUI *pCmdUI)
2925 pCmdUI->SetCheck(m_bLineDiff);
2926 pCmdUI->Enable();
2929 void CMainFrame::OnViewLinediffbar()
2931 m_bLineDiff = !m_bLineDiff;
2932 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2933 m_wndLineDiffBar.DocumentUpdated();
2934 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2935 m_wndLocatorBar.DocumentUpdated();
2938 void CMainFrame::OnUpdateViewLocatorbar(CCmdUI *pCmdUI)
2940 pCmdUI->SetCheck(m_bLocatorBar);
2941 pCmdUI->Enable();
2944 void CMainFrame::OnViewLocatorbar()
2946 m_bLocatorBar = !m_bLocatorBar;
2947 m_wndLocatorBar.ShowPane(m_bLocatorBar, false, true);
2948 m_wndLocatorBar.DocumentUpdated();
2949 m_wndLineDiffBar.ShowPane(m_bLineDiff, false, true);
2950 m_wndLineDiffBar.DocumentUpdated();
2953 void CMainFrame::OnViewComparewhitespaces()
2955 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2956 return;
2957 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2958 regIgnoreWS = 0;
2959 LoadViews(-1);
2962 void CMainFrame::OnUpdateViewComparewhitespaces(CCmdUI *pCmdUI)
2964 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2965 DWORD dwIgnoreWS = regIgnoreWS;
2966 pCmdUI->SetCheck(dwIgnoreWS == 0);
2969 void CMainFrame::OnViewIgnorewhitespacechanges()
2971 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2972 return;
2973 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2974 regIgnoreWS = 2;
2975 LoadViews(-1);
2978 void CMainFrame::OnUpdateViewIgnorewhitespacechanges(CCmdUI *pCmdUI)
2980 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2981 DWORD dwIgnoreWS = regIgnoreWS;
2982 pCmdUI->SetCheck(dwIgnoreWS == 2);
2985 void CMainFrame::OnViewIgnoreallwhitespacechanges()
2987 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
2988 return;
2989 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2990 regIgnoreWS = 1;
2991 LoadViews(-1);
2994 void CMainFrame::OnUpdateViewIgnoreallwhitespacechanges(CCmdUI *pCmdUI)
2996 CRegDWORD regIgnoreWS = CRegDWORD(_T("Software\\TortoiseGitMerge\\IgnoreWS"));
2997 DWORD dwIgnoreWS = regIgnoreWS;
2998 pCmdUI->SetCheck(dwIgnoreWS == 1);
3001 void CMainFrame::OnViewMovedBlocks()
3003 m_bViewMovedBlocks = !(DWORD)m_regViewModedBlocks;
3004 m_regViewModedBlocks = m_bViewMovedBlocks;
3005 LoadViews(-1);
3008 void CMainFrame::OnUpdateViewMovedBlocks(CCmdUI *pCmdUI)
3010 pCmdUI->SetCheck(m_bViewMovedBlocks);
3011 BOOL bEnable = TRUE;
3012 if (IsViewGood(m_pwndBottomView))
3014 bEnable = FALSE;
3016 pCmdUI->Enable(bEnable);
3019 bool CMainFrame::HasConflictsWontKeep()
3021 const int nConflictLine = CheckResolved();
3022 if (nConflictLine < 0)
3023 return false;
3025 CString sTemp;
3026 sTemp.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS, m_pwndBottomView->m_pViewData->GetLineNumber(nConflictLine)+1);
3027 bool bSave = false;
3028 if (m_bUseTaskDialog)
3030 CTaskDialog taskdlg(sTemp,
3031 CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK2)),
3032 L"TortoiseGitMerge",
3034 TDF_ENABLE_HYPERLINKS|TDF_USE_COMMAND_LINKS|TDF_ALLOW_DIALOG_CANCELLATION|TDF_POSITION_RELATIVE_TO_WINDOW);
3035 taskdlg.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK3)));
3036 taskdlg.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK4)));
3037 taskdlg.SetCommonButtons(TDCBF_CANCEL_BUTTON);
3038 taskdlg.SetDefaultCommandControl(2);
3039 taskdlg.SetMainIcon(TD_ERROR_ICON);
3040 bSave = (taskdlg.DoModal(m_hWnd) == 1);
3042 else
3044 bSave = (MessageBox(sTemp, 0, MB_ICONERROR | MB_YESNO)==IDYES);
3047 if (bSave)
3048 return false;
3050 if (m_pwndBottomView)
3051 m_pwndBottomView->GoToLine(nConflictLine);
3052 return true;
3055 bool CMainFrame::TryGetFileName(CString& result)
3057 return CCommonAppUtils::FileOpenSave(result, NULL, IDS_SAVEASTITLE, IDS_COMMONFILEFILTER, false, m_hWnd);
3060 CBaseView* CMainFrame::GetActiveBaseView() const
3062 CView* activeView = GetActiveView();
3063 CBaseView* activeBase = dynamic_cast<CBaseView*>( activeView );
3064 return activeBase;
3067 void CMainFrame::SetWindowTitle()
3069 // try to find a suitable window title
3070 CString sYour = m_Data.m_yourFile.GetDescriptiveName();
3071 if (sYour.Find(_T(" - "))>=0)
3072 sYour = sYour.Left(sYour.Find(_T(" - ")));
3073 if (sYour.Find(_T(" : "))>=0)
3074 sYour = sYour.Left(sYour.Find(_T(" : ")));
3075 CString sTheir = m_Data.m_theirFile.GetDescriptiveName();
3076 if (sTheir.IsEmpty())
3077 sTheir = m_Data.m_baseFile.GetDescriptiveName();
3078 if (sTheir.Find(_T(" - "))>=0)
3079 sTheir = sTheir.Left(sTheir.Find(_T(" - ")));
3080 if (sTheir.Find(_T(" : "))>=0)
3081 sTheir = sTheir.Left(sTheir.Find(_T(" : ")));
3083 if (!sYour.IsEmpty() && !sTheir.IsEmpty())
3085 if (sYour.CompareNoCase(sTheir)==0)
3086 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
3087 else if ((sYour.GetLength() < 10) &&
3088 (sTheir.GetLength() < 10))
3089 SetWindowText(sYour + _T(" - ") + sTheir + _T(" - TortoiseGitMerge"));
3090 else
3092 // we have two very long descriptive texts here, which
3093 // means we have to find a way to use them as a window
3094 // title in a shorter way.
3095 // for simplicity, we just use the one from "yourfile"
3096 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
3099 else if (!sYour.IsEmpty())
3100 SetWindowText(sYour + _T(" - TortoiseGitMerge"));
3101 else if (!sTheir.IsEmpty())
3102 SetWindowText(sTheir + _T(" - TortoiseGitMerge"));
3103 else
3104 SetWindowText(L"TortoiseGitMerge");
3107 void CMainFrame::OnTimer(UINT_PTR nIDEvent)
3109 switch (nIDEvent)
3111 case IDT_RELOADCHECKTIMER:
3112 KillTimer(nIDEvent);
3113 CheckForReload();
3114 break;
3117 __super::OnTimer(nIDEvent);
3120 void CMainFrame::LoadIgnoreCommentData()
3122 static bool bLoaded = false;
3123 if (bLoaded)
3124 return;
3125 CString sPath = CPathUtils::GetAppDataDirectory() + L"ignorecomments.txt";
3126 if (!PathFileExists(sPath))
3128 // ignore comments file does not exist (yet), so create a default one
3129 HRSRC hRes = FindResource(NULL, MAKEINTRESOURCE(IDR_IGNORECOMMENTSTXT), L"config");
3130 if (hRes)
3132 HGLOBAL hResourceLoaded = LoadResource(NULL, hRes);
3133 if (hResourceLoaded)
3135 char * lpResLock = (char *) LockResource(hResourceLoaded);
3136 DWORD dwSizeRes = SizeofResource(NULL, hRes);
3137 if (lpResLock)
3139 HANDLE hFile = CreateFile(sPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3140 if (hFile != INVALID_HANDLE_VALUE)
3142 DWORD dwWritten = 0;
3143 WriteFile(hFile, lpResLock, dwSizeRes, &dwWritten, NULL);
3144 CloseHandle(hFile);
3150 CStdioFile file;
3151 if (file.Open(sPath, CFile::modeRead))
3153 CString sLine;
3154 while (file.ReadString(sLine))
3156 int eqpos = sLine.Find('=');
3157 if (eqpos >= 0)
3159 CString sExts = sLine.Left(eqpos);
3160 CString sComments = sLine.Mid(eqpos+1);
3162 int pos = sComments.Find(',');
3163 CString sLineStart = sComments.Left(pos);
3164 pos = sComments.Find(',', pos);
3165 int pos2 = sComments.Find(',', pos+1);
3166 CString sBlockStart = sComments.Mid(pos+1, pos2-pos-1);
3167 CString sBlockEnd = sComments.Mid(pos2+1);
3169 auto commentTuple = std::make_tuple(sLineStart, sBlockStart, sBlockEnd);
3171 pos = 0;
3172 CString temp;
3173 for (;;)
3175 temp = sExts.Tokenize(_T(","),pos);
3176 if (temp.IsEmpty())
3178 break;
3180 ASSERT(m_IgnoreCommentsMap.find(temp) == m_IgnoreCommentsMap.end());
3181 m_IgnoreCommentsMap[temp] = commentTuple;
3186 bLoaded = true;
3189 void CMainFrame::OnViewIgnorecomments()
3191 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3192 return;
3193 m_regIgnoreComments = !DWORD(m_regIgnoreComments);
3194 LoadViews(-1);
3197 void CMainFrame::OnUpdateViewIgnorecomments(CCmdUI *pCmdUI)
3199 // only enable if we have comments defined for this file extension
3200 CString sExt = CPathUtils::GetFileExtFromPath(m_Data.m_baseFile.GetFilename()).MakeLower();
3201 sExt.TrimLeft(L".");
3202 auto sC = m_IgnoreCommentsMap.find(sExt);
3203 if (sC == m_IgnoreCommentsMap.end())
3205 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_yourFile.GetFilename()).MakeLower();
3206 sExt.TrimLeft(L".");
3207 sC = m_IgnoreCommentsMap.find(sExt);
3208 if (sC == m_IgnoreCommentsMap.end())
3210 sExt = CPathUtils::GetFileExtFromPath(m_Data.m_theirFile.GetFilename()).MakeLower();
3211 sExt.TrimLeft(L".");
3212 sC = m_IgnoreCommentsMap.find(sExt);
3215 pCmdUI->Enable(sC != m_IgnoreCommentsMap.end());
3217 pCmdUI->SetCheck(DWORD(m_regIgnoreComments) != 0);
3221 void CMainFrame::OnRegexfilter(UINT cmd)
3223 if ((cmd == ID_REGEXFILTER)||(cmd == (ID_REGEXFILTER+1)))
3225 CRegexFiltersDlg dlg(this);
3226 dlg.SetIniFile(&m_regexIni);
3227 if (dlg.DoModal() == IDOK)
3229 FILE * pFile = NULL;
3230 _tfopen_s(&pFile, CPathUtils::GetAppDataDirectory() + L"regexfilters.ini", _T("wb"));
3231 m_regexIni.SaveFile(pFile);
3232 fclose(pFile);
3234 BuildRegexSubitems();
3236 else
3238 if (cmd == (UINT)m_regexIndex)
3240 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3241 return;
3242 m_Data.SetRegexTokens(std::wregex(), L"");
3243 m_regexIndex = -1;
3244 LoadViews(-1);
3246 else
3248 CSimpleIni::TNamesDepend sections;
3249 m_regexIni.GetAllSections(sections);
3250 int index = ID_REGEXFILTER + 2;
3251 m_regexIndex = -1;
3252 for (const auto& section : sections)
3254 if (cmd == (UINT)index)
3256 if (CheckForSave(CHFSR_OPTIONS)==IDCANCEL)
3257 break;
3260 std::wregex rx(m_regexIni.GetValue(section, L"regex", L""));
3261 m_Data.SetRegexTokens(rx, m_regexIni.GetValue(section, L"replace", L""));
3263 catch (std::exception &ex)
3265 MessageBox(_T("Regex is invalid!\r\n") + CString(ex.what()));
3267 m_regexIndex = index;
3268 LoadViews(-1);
3269 break;
3271 ++index;
3277 void CMainFrame::OnUpdateViewRegexFilter( CCmdUI *pCmdUI )
3279 pCmdUI->Enable();
3280 pCmdUI->SetCheck(pCmdUI->m_nID == (UINT)m_regexIndex);
3283 void CMainFrame::BuildRegexSubitems()
3285 CArray<CMFCRibbonBaseElement*, CMFCRibbonBaseElement*> arButtons;
3286 m_wndRibbonBar.GetElementsByID(ID_REGEXFILTER, arButtons);
3287 if (arButtons.GetCount() == 1)
3289 CMFCRibbonButton * pButton = (CMFCRibbonButton*)arButtons.GetAt(0);
3290 if (pButton)
3292 pButton->RemoveAllSubItems();
3293 pButton->AddSubItem(new CMFCRibbonButton(ID_REGEXFILTER+1, CString(MAKEINTRESOURCE(IDS_CONFIGUREREGEXES)), 47));
3295 CString sIniPath = CPathUtils::GetAppDataDirectory() + L"regexfilters.ini";
3296 if (!PathFileExists(sIniPath))
3298 // ini file does not exist (yet), so create a default one
3299 HRSRC hRes = FindResource(NULL, MAKEINTRESOURCE(IDR_REGEXFILTERINI), L"config");
3300 if (hRes)
3302 HGLOBAL hResourceLoaded = LoadResource(NULL, hRes);
3303 if (hResourceLoaded)
3305 char * lpResLock = (char *) LockResource(hResourceLoaded);
3306 DWORD dwSizeRes = SizeofResource(NULL, hRes);
3307 if (lpResLock)
3309 HANDLE hFile = CreateFile(sIniPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3310 if (hFile != INVALID_HANDLE_VALUE)
3312 DWORD dwWritten = 0;
3313 WriteFile(hFile, lpResLock, dwSizeRes, &dwWritten, NULL);
3314 CloseHandle(hFile);
3321 m_regexIni.LoadFile(sIniPath);
3322 CSimpleIni::TNamesDepend sections;
3323 m_regexIni.GetAllSections(sections);
3324 if (!sections.empty())
3325 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3326 int cmdIndex = 2;
3327 for (const auto& section : sections)
3329 pButton->AddSubItem(new CMFCRibbonButton(ID_REGEXFILTER+cmdIndex, section, 46));
3330 cmdIndex++;
3336 void CMainFrame::FillEncodingButton( CMFCRibbonButton * pButton, int start )
3338 pButton->SetDefaultCommand(FALSE);
3339 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::ASCII, L"ASCII" ));
3340 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::BINARY, L"BINARY" ));
3341 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_LE, L"UTF-16LE" ));
3342 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_LEBOM, L"UTF-16LE BOM"));
3343 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_BE, L"UTF-16BE" ));
3344 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF16_BEBOM, L"UTF-16BE BOM"));
3345 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF32_LE, L"UTF-32LE" ));
3346 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF32_BE, L"UTF-32BE" ));
3347 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF8, L"UTF-8" ));
3348 pButton->AddSubItem(new CMFCRibbonButton(start + CFileTextLines::UnicodeType::UTF8BOM, L"UTF-8 BOM" ));
3351 void CMainFrame::FillEOLButton( CMFCRibbonButton * pButton, int start )
3353 pButton->SetDefaultCommand(FALSE);
3354 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LF , L"LF" ));
3355 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_CRLF, L"CRLF"));
3356 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LFCR, L"LRCR"));
3357 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_CR , L"CR" ));
3358 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_VT , L"VT" ));
3359 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_FF , L"FF" ));
3360 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_NEL , L"NEL" ));
3361 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_LS , L"LS" ));
3362 pButton->AddSubItem(new CMFCRibbonButton(start + EOL::EOL_PS , L"PS" ));
3365 void CMainFrame::FillTabModeButton(CMFCRibbonButton * pButton, int start)
3367 pButton->SetDefaultCommand(FALSE);
3368 pButton->AddSubItem(new CMFCRibbonButton(start + TABMODE_NONE , L"Tab"));
3369 pButton->AddSubItem(new CMFCRibbonButton(start + TABMODE_USESPACES , L"Space"));
3370 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3371 pButton->AddSubItem(new CMFCRibbonButton(start + TABMODE_SMARTINDENT , L"Smart tab char"));
3372 pButton->AddSubItem(new CMFCRibbonSeparator(TRUE));
3373 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON1, L"1"));
3374 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON2, L"2"));
3375 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON4, L"4"));
3376 pButton->AddSubItem(new CMFCRibbonButton(start + TABSIZEBUTTON8, L"8"));
3379 void CMainFrame::OnEncodingLeft( UINT cmd )
3381 if (m_pwndLeftView)
3383 m_pwndLeftView->SetTextType(CFileTextLines::UnicodeType(cmd-ID_INDICATOR_LEFTENCODINGSTART));
3384 m_pwndLeftView->RefreshViews();
3388 void CMainFrame::OnEncodingRight( UINT cmd )
3390 if (m_pwndRightView)
3392 m_pwndRightView->SetTextType(CFileTextLines::UnicodeType(cmd-ID_INDICATOR_RIGHTENCODINGSTART));
3393 m_pwndRightView->RefreshViews();
3397 void CMainFrame::OnEncodingBottom( UINT cmd )
3399 if (m_pwndBottomView)
3401 m_pwndBottomView->SetTextType(CFileTextLines::UnicodeType(cmd-ID_INDICATOR_BOTTOMENCODINGSTART));
3402 m_pwndBottomView->RefreshViews();
3406 void CMainFrame::OnEOLLeft( UINT cmd )
3408 if (m_pwndLeftView)
3410 m_pwndLeftView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_LEFTEOLSTART));
3411 m_pwndLeftView->RefreshViews();
3415 void CMainFrame::OnEOLRight( UINT cmd )
3417 if (m_pwndRightView)
3419 m_pwndRightView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_RIGHTEOLSTART));
3420 m_pwndRightView->RefreshViews();
3424 void CMainFrame::OnEOLBottom( UINT cmd )
3426 if (m_pwndBottomView)
3428 m_pwndBottomView->ReplaceLineEndings(EOL(cmd-ID_INDICATOR_BOTTOMEOLSTART));
3429 m_pwndBottomView->RefreshViews();
3433 void CMainFrame::OnTabModeLeft( UINT cmd )
3435 OnTabMode(m_pwndLeftView, (int)cmd - ID_INDICATOR_LEFTTABMODESTART);
3438 void CMainFrame::OnTabModeRight( UINT cmd )
3440 OnTabMode(m_pwndRightView, (int)cmd - ID_INDICATOR_RIGHTTABMODESTART);
3443 void CMainFrame::OnTabModeBottom( UINT cmd )
3445 OnTabMode(m_pwndBottomView, (int)cmd - ID_INDICATOR_BOTTOMTABMODESTART);
3448 void CMainFrame::OnTabMode(CBaseView *view, int cmd)
3450 if (!view)
3451 return;
3452 int nTabMode = view->GetTabMode();
3453 if (cmd == TABMODE_NONE || cmd == TABMODE_USESPACES)
3454 view->SetTabMode((nTabMode & (~TABMODE_USESPACES)) | (cmd & TABMODE_USESPACES));
3455 else if (cmd == TABMODE_SMARTINDENT) // Toggle
3456 view->SetTabMode((nTabMode & (~TABMODE_SMARTINDENT)) | (nTabMode & TABMODE_SMARTINDENT ? 0 : TABMODE_SMARTINDENT));
3457 else if (cmd == TABSIZEBUTTON1)
3458 view->SetTabSize(1);
3459 else if (cmd == TABSIZEBUTTON2)
3460 view->SetTabSize(2);
3461 else if (cmd == TABSIZEBUTTON4)
3462 view->SetTabSize(4);
3463 else if (cmd == TABSIZEBUTTON8)
3464 view->SetTabSize(8);
3465 view->RefreshViews();
3468 void CMainFrame::OnUpdateEncodingLeft( CCmdUI *pCmdUI )
3470 if (m_pwndLeftView)
3472 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_LEFTENCODINGSTART) == m_pwndLeftView->GetTextType());
3473 pCmdUI->Enable(m_pwndLeftView->IsWritable());
3475 else
3476 pCmdUI->Enable(FALSE);
3479 void CMainFrame::OnUpdateEncodingRight( CCmdUI *pCmdUI )
3481 if (m_pwndRightView)
3483 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_RIGHTENCODINGSTART) == m_pwndRightView->GetTextType());
3484 pCmdUI->Enable(m_pwndRightView->IsWritable());
3486 else
3487 pCmdUI->Enable(FALSE);
3490 void CMainFrame::OnUpdateEncodingBottom( CCmdUI *pCmdUI )
3492 if (m_pwndBottomView)
3494 pCmdUI->SetCheck(CFileTextLines::UnicodeType(pCmdUI->m_nID - ID_INDICATOR_BOTTOMENCODINGSTART) == m_pwndBottomView->GetTextType());
3495 pCmdUI->Enable(m_pwndBottomView->IsWritable());
3497 else
3498 pCmdUI->Enable(FALSE);
3501 void CMainFrame::OnUpdateEOLLeft( CCmdUI *pCmdUI )
3503 if (m_pwndLeftView)
3505 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_LEFTEOLSTART) == m_pwndLeftView->GetLineEndings());
3506 pCmdUI->Enable(m_pwndLeftView->IsWritable());
3508 else
3509 pCmdUI->Enable(FALSE);
3512 void CMainFrame::OnUpdateEOLRight( CCmdUI *pCmdUI )
3514 if (m_pwndRightView)
3516 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_RIGHTEOLSTART) == m_pwndRightView->GetLineEndings());
3517 pCmdUI->Enable(m_pwndRightView->IsWritable());
3519 else
3520 pCmdUI->Enable(FALSE);
3523 void CMainFrame::OnUpdateEOLBottom( CCmdUI *pCmdUI )
3525 if (m_pwndBottomView)
3527 pCmdUI->SetCheck(EOL(pCmdUI->m_nID - ID_INDICATOR_BOTTOMEOLSTART) == m_pwndBottomView->GetLineEndings());
3528 pCmdUI->Enable(m_pwndBottomView->IsWritable());
3530 else
3531 pCmdUI->Enable(FALSE);
3534 void CMainFrame::OnUpdateTabModeLeft(CCmdUI *pCmdUI)
3536 OnUpdateTabMode(m_pwndLeftView, pCmdUI, ID_INDICATOR_LEFTTABMODESTART);
3539 void CMainFrame::OnUpdateTabModeRight(CCmdUI *pCmdUI)
3541 OnUpdateTabMode(m_pwndRightView, pCmdUI, ID_INDICATOR_RIGHTTABMODESTART);
3544 void CMainFrame::OnUpdateTabModeBottom(CCmdUI *pCmdUI)
3546 OnUpdateTabMode(m_pwndBottomView, pCmdUI, ID_INDICATOR_BOTTOMTABMODESTART);
3549 void CMainFrame::OnUpdateTabMode(CBaseView *view, CCmdUI *pCmdUI, int startid)
3551 if (view)
3553 int cmd = (int)pCmdUI->m_nID - startid;
3554 if (cmd == TABMODE_NONE)
3555 pCmdUI->SetCheck((view->GetTabMode() & TABMODE_USESPACES) == TABMODE_NONE);
3556 else if (cmd == TABMODE_USESPACES)
3557 pCmdUI->SetCheck(view->GetTabMode() & TABMODE_USESPACES);
3558 else if (cmd == TABMODE_SMARTINDENT)
3559 pCmdUI->SetCheck(view->GetTabMode() & TABMODE_SMARTINDENT);
3560 else if (cmd == TABSIZEBUTTON1)
3561 pCmdUI->SetCheck(view->GetTabSize() == 1);
3562 else if (cmd == TABSIZEBUTTON2)
3563 pCmdUI->SetCheck(view->GetTabSize() == 2);
3564 else if (cmd == TABSIZEBUTTON4)
3565 pCmdUI->SetCheck(view->GetTabSize() == 4);
3566 else if (cmd == TABSIZEBUTTON8)
3567 pCmdUI->SetCheck(view->GetTabSize() == 8);
3568 pCmdUI->Enable(view->IsWritable());
3570 else
3571 pCmdUI->Enable(FALSE);