1
// TortoiseGitMerge - a Diff/Patch program
3 // Copyright (C) 2008-2024 - TortoiseGit
4 // Copyright (C) 2004-2018, 2020 - 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.
22 #include "TortoiseMerge.h"
25 #include "SysProgressDlg.h"
27 #include "MessageBox.h"
29 #include "PathUtils.h"
32 #include "RightView.h"
33 #include "BottomView.h"
34 #include "DiffColors.h"
35 #include "SelectFileFilter.h"
36 #include "FormatMessageWrapper.h"
37 #include "TaskbarUUID.h"
38 #include "RegexFiltersDlg.h"
41 #include "StringUtils.h"
42 #include "Windows10Colors.h"
43 #include "DarkModeHelper.h"
44 #include "ThemeMFCVisualManager.h"
51 #define IDT_RELOADCHECKTIMER 123
53 IMPLEMENT_DYNCREATE(CMainFrame
, CFrameWndEx
)
55 BEGIN_MESSAGE_MAP(CMainFrame
, CFrameWndEx
)
58 // Global help commands
59 ON_COMMAND(ID_HELP_FINDER
, CFrameWndEx::OnHelpFinder
)
60 ON_COMMAND(ID_HELP
, CFrameWndEx::OnHelp
)
61 ON_COMMAND(ID_CONTEXT_HELP
, CFrameWndEx::OnContextHelp
)
62 ON_COMMAND(ID_DEFAULT_HELP
, CFrameWndEx::OnHelpFinder
)
63 ON_COMMAND(ID_FILE_OPEN
, OnFileOpen
)
64 ON_COMMAND(ID_VIEW_WHITESPACES
, OnViewWhitespaces
)
66 ON_COMMAND(ID_FILE_SAVE
, OnFileSave
)
67 ON_COMMAND(ID_FILE_SAVE_AS
, OnFileSaveAs
)
68 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE
, OnUpdateFileSave
)
69 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_AS
, OnUpdateFileSaveAs
)
70 ON_COMMAND(ID_VIEW_ONEWAYDIFF
, OnViewOnewaydiff
)
71 ON_UPDATE_COMMAND_UI(ID_VIEW_ONEWAYDIFF
, OnUpdateViewOnewaydiff
)
72 ON_UPDATE_COMMAND_UI(ID_VIEW_WHITESPACES
, OnUpdateViewWhitespaces
)
73 ON_COMMAND(ID_VIEW_OPTIONS
, OnViewOptions
)
74 ON_MESSAGE(WM_IDLEUPDATECMDUI
, OnIdleUpdateCmdUI
)
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
)
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_REDO
, &CMainFrame::OnEditRedo
)
102 ON_UPDATE_COMMAND_UI(ID_EDIT_REDO
, &CMainFrame::OnUpdateEditRedo
)
103 ON_COMMAND(ID_EDIT_ENABLE
, &CMainFrame::OnEditEnable
)
104 ON_UPDATE_COMMAND_UI(ID_EDIT_ENABLE
, &CMainFrame::OnUpdateEditEnable
)
105 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMINETHENTHEIRBLOCK
, &CMainFrame::OnUpdateEditUseminethentheirblock
)
106 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMYBLOCK
, &CMainFrame::OnUpdateEditUsemyblock
)
107 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRBLOCK
, &CMainFrame::OnUpdateEditUsetheirblock
)
108 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRTHENMYBLOCK
, &CMainFrame::OnUpdateEditUsetheirthenmyblock
)
109 ON_COMMAND(ID_VIEW_INLINEDIFFWORD
, &CMainFrame::OnViewInlinediffword
)
110 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFFWORD
, &CMainFrame::OnUpdateViewInlinediffword
)
111 ON_COMMAND(ID_VIEW_INLINEDIFF
, &CMainFrame::OnViewInlinediff
)
112 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFF
, &CMainFrame::OnUpdateViewInlinediff
)
113 ON_UPDATE_COMMAND_UI(ID_EDIT_CREATEUNIFIEDDIFFFILE
, &CMainFrame::OnUpdateEditCreateunifieddifffile
)
114 ON_COMMAND(ID_EDIT_CREATEUNIFIEDDIFFFILE
, &CMainFrame::OnEditCreateunifieddifffile
)
115 ON_UPDATE_COMMAND_UI(ID_VIEW_LINEDIFFBAR
, &CMainFrame::OnUpdateViewLinediffbar
)
116 ON_COMMAND(ID_VIEW_LINEDIFFBAR
, &CMainFrame::OnViewLinediffbar
)
117 ON_UPDATE_COMMAND_UI(ID_VIEW_BARS
, &CMainFrame::OnUpdateViewBars
)
118 ON_UPDATE_COMMAND_UI(ID_VIEW_LOCATORBAR
, &CMainFrame::OnUpdateViewLocatorbar
)
119 ON_COMMAND(ID_VIEW_LOCATORBAR
, &CMainFrame::OnViewLocatorbar
)
120 ON_COMMAND(ID_EDIT_USELEFTBLOCK
, &CMainFrame::OnEditUseleftblock
)
121 ON_UPDATE_COMMAND_UI(ID_USEBLOCKS
, &CMainFrame::OnUpdateUseBlock
)
122 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTBLOCK
, &CMainFrame::OnUpdateEditUseleftblock
)
123 ON_COMMAND(ID_EDIT_USELEFTFILE
, &CMainFrame::OnEditUseleftfile
)
124 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTFILE
, &CMainFrame::OnUpdateEditUseleftfile
)
125 ON_COMMAND(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT
, &CMainFrame::OnEditUseblockfromleftbeforeright
)
126 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT
, &CMainFrame::OnUpdateEditUseblockfromleftbeforeright
)
127 ON_COMMAND(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT
, &CMainFrame::OnEditUseblockfromrightbeforeleft
)
128 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT
, &CMainFrame::OnUpdateEditUseblockfromrightbeforeleft
)
129 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTDIFFERENCE
, &CMainFrame::OnUpdateNavigateNextdifference
)
130 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSDIFFERENCE
, &CMainFrame::OnUpdateNavigatePreviousdifference
)
131 ON_COMMAND(ID_VIEW_COLLAPSED
, &CMainFrame::OnViewCollapsed
)
132 ON_UPDATE_COMMAND_UI(ID_VIEW_COLLAPSED
, &CMainFrame::OnUpdateViewCollapsed
)
133 ON_COMMAND(ID_VIEW_COMPAREWHITESPACES
, &CMainFrame::OnViewComparewhitespaces
)
134 ON_UPDATE_COMMAND_UI(ID_VIEW_COMPAREWHITESPACES
, &CMainFrame::OnUpdateViewComparewhitespaces
)
135 ON_COMMAND(ID_VIEW_IGNOREWHITESPACECHANGES
, &CMainFrame::OnViewIgnorewhitespacechanges
)
136 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREWHITESPACECHANGES
, &CMainFrame::OnUpdateViewIgnorewhitespacechanges
)
137 ON_COMMAND(ID_VIEW_IGNOREALLWHITESPACECHANGES
, &CMainFrame::OnViewIgnoreallwhitespacechanges
)
138 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREALLWHITESPACECHANGES
, &CMainFrame::OnUpdateViewIgnoreallwhitespacechanges
)
139 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTINLINEDIFF
, &CMainFrame::OnUpdateNavigateNextinlinediff
)
140 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVINLINEDIFF
, &CMainFrame::OnUpdateNavigatePrevinlinediff
)
141 ON_COMMAND(ID_VIEW_WRAPLONGLINES
, &CMainFrame::OnViewWraplonglines
)
142 ON_UPDATE_COMMAND_UI(ID_VIEW_WRAPLONGLINES
, &CMainFrame::OnUpdateViewWraplonglines
)
143 ON_REGISTERED_MESSAGE( TaskBarButtonCreated
, CMainFrame::OnTaskbarButtonCreated
)
144 ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE
, &CMainFrame::OnUpdateEditPaste
)
145 ON_COMMAND(ID_INDICATOR_LEFTVIEW
, &CMainFrame::OnIndicatorLeftview
)
146 ON_COMMAND(ID_INDICATOR_RIGHTVIEW
, &CMainFrame::OnIndicatorRightview
)
147 ON_COMMAND(ID_INDICATOR_BOTTOMVIEW
, &CMainFrame::OnIndicatorBottomview
)
149 ON_COMMAND(ID_VIEW_IGNORECOMMENTS
, &CMainFrame::OnViewIgnorecomments
)
150 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNORECOMMENTS
, &CMainFrame::OnUpdateViewIgnorecomments
)
151 ON_COMMAND(ID_VIEW_IGNOREEOL
, &CMainFrame::OnViewIgnoreEOL
)
152 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREEOL
, &CMainFrame::OnUpdateViewIgnoreEOL
)
153 ON_COMMAND_RANGE(ID_REGEXFILTER
, ID_REGEXFILTER
+400, &CMainFrame::OnRegexfilter
)
154 ON_UPDATE_COMMAND_UI_RANGE(ID_REGEXFILTER
, ID_REGEXFILTER
+400, &CMainFrame::OnUpdateViewRegexFilter
)
155 ON_COMMAND(ID_REGEX_NO_FILTER
, &CMainFrame::OnRegexNoFilter
)
156 ON_UPDATE_COMMAND_UI(ID_REGEX_NO_FILTER
, &CMainFrame::OnUpdateRegexNoFilter
)
157 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOENCODING
, &CMainFrame::OnDummyEnabled
)
158 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOENCODING
, &CMainFrame::OnDummyEnabled
)
159 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOENCODING
, &CMainFrame::OnDummyEnabled
)
160 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOEOL
, &CMainFrame::OnDummyEnabled
)
161 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOEOL
, &CMainFrame::OnDummyEnabled
)
162 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOEOL
, &CMainFrame::OnDummyEnabled
)
163 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOTABMODE
, &CMainFrame::OnDummyEnabled
)
164 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOTABMODE
, &CMainFrame::OnDummyEnabled
)
165 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOTABMODE
, &CMainFrame::OnDummyEnabled
)
166 ON_UPDATE_COMMAND_UI(ID_EDIT_THREEWAY_ACTIONS
, &CMainFrame::OnUpdateThreeWayActions
)
167 ON_UPDATE_COMMAND_UI(ID_INDICATOR_COLUMN
, &CMainFrame::OnUpdateColumnStatusBar
)
168 ON_UPDATE_COMMAND_UI(ID_INDICATOR_MARKEDWORDS
, &CMainFrame::OnUpdateMarkedWords
)
169 ON_UPDATE_COMMAND_UI(ID_EDIT_FINDNEXTSTART
, &CMainFrame::OnUpdateEnableIfSelection
)
170 ON_UPDATE_COMMAND_UI(ID_EDIT_FINDPREVSTART
, &CMainFrame::OnUpdateEnableIfSelection
)
171 ON_COMMAND_RANGE(ID_INDICATOR_LEFTENCODINGSTART
, ID_INDICATOR_LEFTENCODINGSTART
+19, &CMainFrame::OnEncodingLeft
)
172 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTENCODINGSTART
, ID_INDICATOR_RIGHTENCODINGSTART
+19, &CMainFrame::OnEncodingRight
)
173 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMENCODINGSTART
, ID_INDICATOR_BOTTOMENCODINGSTART
+19, &CMainFrame::OnEncodingBottom
)
174 ON_COMMAND_RANGE(ID_INDICATOR_LEFTEOLSTART
, ID_INDICATOR_LEFTEOLSTART
+19, &CMainFrame::OnEOLLeft
)
175 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTEOLSTART
, ID_INDICATOR_RIGHTEOLSTART
+19, &CMainFrame::OnEOLRight
)
176 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMEOLSTART
, ID_INDICATOR_BOTTOMEOLSTART
+19, &CMainFrame::OnEOLBottom
)
177 ON_COMMAND_RANGE(ID_INDICATOR_LEFTTABMODESTART
, ID_INDICATOR_LEFTTABMODESTART
+19, &CMainFrame::OnTabModeLeft
)
178 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTTABMODESTART
, ID_INDICATOR_RIGHTTABMODESTART
+19, &CMainFrame::OnTabModeRight
)
179 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMTABMODESTART
, ID_INDICATOR_BOTTOMTABMODESTART
+19, &CMainFrame::OnTabModeBottom
)
180 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTENCODINGSTART
, ID_INDICATOR_LEFTENCODINGSTART
+19, &CMainFrame::OnUpdateEncodingLeft
)
181 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTENCODINGSTART
, ID_INDICATOR_RIGHTENCODINGSTART
+19, &CMainFrame::OnUpdateEncodingRight
)
182 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMENCODINGSTART
, ID_INDICATOR_BOTTOMENCODINGSTART
+19, &CMainFrame::OnUpdateEncodingBottom
)
183 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTEOLSTART
, ID_INDICATOR_LEFTEOLSTART
+19, &CMainFrame::OnUpdateEOLLeft
)
184 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTEOLSTART
, ID_INDICATOR_RIGHTEOLSTART
+19, &CMainFrame::OnUpdateEOLRight
)
185 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMEOLSTART
, ID_INDICATOR_BOTTOMEOLSTART
+19, &CMainFrame::OnUpdateEOLBottom
)
186 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTTABMODESTART
, ID_INDICATOR_LEFTTABMODESTART
+19, &CMainFrame::OnUpdateTabModeLeft
)
187 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTTABMODESTART
, ID_INDICATOR_RIGHTTABMODESTART
+19, &CMainFrame::OnUpdateTabModeRight
)
188 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMTABMODESTART
, ID_INDICATOR_BOTTOMTABMODESTART
+19, &CMainFrame::OnUpdateTabModeBottom
)
189 ON_WM_SETTINGCHANGE()
190 ON_WM_SYSCOLORCHANGE()
191 ON_MESSAGE(WM_DPICHANGED
, OnDPIChanged
)
194 static UINT indicators
[] =
196 ID_SEPARATOR
, // status line indicator
197 ID_INDICATOR_LEFTVIEW
,
198 ID_INDICATOR_RIGHTVIEW
,
199 ID_INDICATOR_BOTTOMVIEW
,
206 // CMainFrame construction/destruction
208 CMainFrame::CMainFrame()
209 : m_bInitSplitter(FALSE
)
210 , m_regWrapLines(L
"Software\\TortoiseGitMerge\\WrapLines", 0)
211 , m_regViewModedBlocks(L
"Software\\TortoiseGitMerge\\ViewMovedBlocks", TRUE
)
212 , m_regOneWay(L
"Software\\TortoiseGitMerge\\OnePane")
213 , m_regCollapsed(L
"Software\\TortoiseGitMerge\\Collapsed", 0)
214 , m_regInlineDiff(L
"Software\\TortoiseGitMerge\\DisplayBinDiff", TRUE
)
215 , m_regUseRibbons(L
"Software\\TortoiseGitMerge\\UseRibbons", TRUE
)
216 , m_regIgnoreComments(L
"Software\\TortoiseGitMerge\\IgnoreComments", FALSE
)
218 m_bOneWay
= (0 != (static_cast<DWORD
>(m_regOneWay
)));
219 m_bCollapsed
= !!static_cast<DWORD
>(m_regCollapsed
);
220 m_bViewMovedBlocks
= !!static_cast<DWORD
>(m_regViewModedBlocks
);
221 m_bWrapLines
= !!static_cast<DWORD
>(m_regWrapLines
);
222 m_bInlineDiff
= !!m_regInlineDiff
;
223 m_bUseRibbons
= !!m_regUseRibbons
;
226 CMainFrame::~CMainFrame()
230 LRESULT
CMainFrame::OnTaskbarButtonCreated(WPARAM
/*wParam*/, LPARAM
/*lParam*/)
232 SetUUIDOverlayIcon(m_hWnd
);
236 int CMainFrame::InitRibbon()
240 if (CTheme::Instance().IsDarkTheme())
241 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CThemeMFCVisualManager
));
243 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows
));
245 if (HRESULT hr
= m_pRibbonFramework
.CoCreateInstance(__uuidof(UIRibbonFramework
)); FAILED(hr
))
247 TRACE(L
"Failed to create ribbon framework (%08x)\n", hr
);
248 return -1; // fail to create
251 m_pRibbonApp
.reset(new CNativeRibbonApp(this, m_pRibbonFramework
));
252 m_pRibbonApp
->SetSettingsFileName(CPathUtils::GetAppDataDirectory() + L
"TortoiseGitMerge-RibbonSettings");
254 if (HRESULT hr
= m_pRibbonFramework
->Initialize(m_hWnd
, m_pRibbonApp
.get()); FAILED(hr
))
256 TRACE(L
"Failed to initialize ribbon framework (%08x)\n", hr
);
257 return -1; // fail to create
260 if (HRESULT hr
= m_pRibbonFramework
->LoadUI(AfxGetResourceHandle(), L
"TORTOISEGITMERGERIBBON_RIBBON"); FAILED(hr
))
262 TRACE(L
"Failed to load ribbon UI (%08x)\n", hr
);
263 return -1; // fail to create
266 m_themeCallbackId
= CTheme::Instance().RegisterThemeChangeCallback([this]()
268 if (CTheme::Instance().IsDarkTheme() || CTheme::Instance().IsHighContrastModeDark())
269 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CThemeMFCVisualManager
));
271 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows
));
272 SetTheme(CTheme::Instance().IsDarkTheme());});
273 SetTheme(CTheme::Instance().IsDarkTheme());
275 BuildRegexSubitems();
276 if (!m_wndRibbonStatusBar
.Create(this))
278 TRACE0("Failed to create ribbon status bar\n");
279 return -1; // fail to create
284 sColumn
.Format(IDS_INDICATOR_COLUMN
, 0);
285 auto columnPane
= new CMFCRibbonStatusBarPane(ID_INDICATOR_COLUMN
, sColumn
, FALSE
);
286 m_wndRibbonStatusBar
.AddElement(columnPane
, L
"");
287 sColumn
.Format(IDS_INDICATOR_COLUMN
, 999999);
288 columnPane
->SetAlmostLargeText(sColumn
);
289 // marked word counter
290 auto columnPaneMW
= new CMFCRibbonStatusBarPane(ID_INDICATOR_MARKEDWORDS
, L
"", FALSE
);
291 m_wndRibbonStatusBar
.AddElement(columnPaneMW
, L
"");
292 columnPaneMW
->SetAlmostLargeText(L
"Marked words: l: XXXX | r: XXXX | b: XXXX");
294 CString
sTooltip(MAKEINTRESOURCE(IDS_ENCODING_COMBO_TOOLTIP
));
295 auto apBtnGroupLeft
= std::make_unique
<CMFCRibbonButtonsGroup
>();
296 apBtnGroupLeft
->SetID(ID_INDICATOR_LEFTVIEW
);
297 apBtnGroupLeft
->AddButton(new CMFCRibbonStatusBarPane(ID_SEPARATOR
, CString(MAKEINTRESOURCE(IDS_STATUSBAR_LEFTVIEW
)), TRUE
));
298 CMFCRibbonButton
* pButton
= new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOENCODING
, L
"");
299 pButton
->SetToolTipText(sTooltip
);
300 FillEncodingButton(pButton
, ID_INDICATOR_LEFTENCODINGSTART
);
301 apBtnGroupLeft
->AddButton(pButton
);
302 pButton
= new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOEOL
, L
"");
303 FillEOLButton(pButton
, ID_INDICATOR_LEFTEOLSTART
);
304 apBtnGroupLeft
->AddButton(pButton
);
305 pButton
= new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOTABMODE
, L
"");
306 FillTabModeButton(pButton
, ID_INDICATOR_LEFTTABMODESTART
);
307 apBtnGroupLeft
->AddButton(pButton
);
308 apBtnGroupLeft
->AddButton(new CMFCRibbonStatusBarPane(ID_INDICATOR_LEFTVIEW
, L
"", TRUE
));
309 m_wndRibbonStatusBar
.AddExtendedElement(apBtnGroupLeft
.release(), L
"");
311 auto apBtnGroupRight
= std::make_unique
<CMFCRibbonButtonsGroup
>();
312 apBtnGroupRight
->SetID(ID_INDICATOR_RIGHTVIEW
);
313 apBtnGroupRight
->AddButton(new CMFCRibbonStatusBarPane(ID_SEPARATOR
, CString(MAKEINTRESOURCE(IDS_STATUSBAR_RIGHTVIEW
)), TRUE
));
314 pButton
= new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOENCODING
, L
"");
315 pButton
->SetToolTipText(sTooltip
);
316 FillEncodingButton(pButton
, ID_INDICATOR_RIGHTENCODINGSTART
);
317 apBtnGroupRight
->AddButton(pButton
);
318 pButton
= new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOEOL
, L
"");
319 FillEOLButton(pButton
, ID_INDICATOR_RIGHTEOLSTART
);
320 apBtnGroupRight
->AddButton(pButton
);
321 pButton
= new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOTABMODE
, L
"");
322 FillTabModeButton(pButton
, ID_INDICATOR_RIGHTTABMODESTART
);
323 apBtnGroupRight
->AddButton(pButton
);
324 apBtnGroupRight
->AddButton(new CMFCRibbonStatusBarPane(ID_INDICATOR_RIGHTVIEW
, L
"", TRUE
));
325 m_wndRibbonStatusBar
.AddExtendedElement(apBtnGroupRight
.release(), L
"");
330 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct
)
332 if (CFrameWndEx::OnCreate(lpCreateStruct
) == -1)
337 if (!m_wndMenuBar
.Create(this))
339 TRACE0("Failed to create menubar\n");
340 return -1; // fail to create
342 m_wndMenuBar
.SetPaneStyle(m_wndMenuBar
.GetPaneStyle() | CBRS_SIZE_DYNAMIC
| CBRS_TOOLTIPS
| CBRS_FLYBY
);
344 // prevent the menu bar from taking the focus on activation
345 CMFCPopupMenu::SetForceMenuFocus(FALSE
);
346 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
))
348 TRACE0("Failed to create toolbar\n");
349 return -1; // fail to create
351 m_wndToolBar
.SetWindowText(L
"Main");
352 if (!m_wndStatusBar
.Create(this) ||
353 !m_wndStatusBar
.SetIndicators(indicators
,
354 _countof(indicators
)))
356 TRACE0("Failed to create status bar\n");
357 return -1; // fail to create
359 m_wndStatusBar
.EnablePaneDoubleClick();
361 m_themeCallbackId
= CTheme::Instance().RegisterThemeChangeCallback([this]()
363 if (CTheme::Instance().IsDarkTheme() || CTheme::Instance().IsHighContrastModeDark())
364 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CThemeMFCVisualManager
));
366 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows
));
367 SetTheme(CTheme::Instance().IsDarkTheme());
369 SetTheme(CTheme::Instance().IsDarkTheme());
372 if (!m_wndLocatorBar
.Create(this, IDD_DIFFLOCATOR
,
373 CBRS_ALIGN_LEFT
| CBRS_SIZE_FIXED
, ID_VIEW_LOCATORBAR
))
375 TRACE0("Failed to create dialogbar\n");
376 return -1; // fail to create
378 if (!m_wndLineDiffBar
.Create(this, IDD_LINEDIFF
,
379 CBRS_ALIGN_BOTTOM
| CBRS_SIZE_FIXED
, ID_VIEW_LINEDIFFBAR
))
381 TRACE0("Failed to create dialogbar\n");
382 return -1; // fail to create
384 m_wndLocatorBar
.m_pMainFrm
= this;
385 m_wndLineDiffBar
.m_pMainFrm
= this;
387 EnableDocking(CBRS_ALIGN_ANY
);
390 m_wndMenuBar
.EnableDocking(CBRS_ALIGN_TOP
);
391 m_wndToolBar
.EnableDocking(CBRS_ALIGN_TOP
);
392 DockPane(&m_wndMenuBar
);
393 DockPane(&m_wndToolBar
);
395 DockPane(&m_wndLocatorBar
);
396 DockPane(&m_wndLineDiffBar
);
397 ShowPane(&m_wndLocatorBar
, true, false, true);
398 ShowPane(&m_wndLineDiffBar
, true, false, true);
400 m_wndLocatorBar
.EnableGripper(FALSE
);
401 m_wndLineDiffBar
.EnableGripper(FALSE
);
406 void CMainFrame::OnDestroy()
408 CTheme::Instance().RemoveRegisteredCallback(m_themeCallbackId
);
409 if (m_pRibbonFramework
)
410 m_pRibbonFramework
->Destroy();
412 CFrameWndEx::OnDestroy();
415 BOOL
CMainFrame::PreCreateWindow(CREATESTRUCT
& cs
)
417 cs
.style
&= ~WS_VISIBLE
;
418 // extra styles needed to avoid refresh problems with the ribbon
419 cs
.style
|= WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
;
420 if (!CFrameWndEx::PreCreateWindow(cs
))
422 if (CTheme::Instance().IsDarkTheme())
424 WNDCLASSEX wndClass
{};
425 wndClass
.cbSize
= sizeof(WNDCLASSEX
);
426 GetClassInfoEx(AfxGetInstanceHandle(), cs
.lpszClass
, &wndClass
);
427 UnregisterClass(cs
.lpszClass
, AfxGetInstanceHandle());
428 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOWTEXT
+ 1);
429 RegisterClassEx(&wndClass
);
434 // CMainFrame diagnostics
437 void CMainFrame::AssertValid() const
439 CFrameWndEx::AssertValid();
442 void CMainFrame::Dump(CDumpContext
& dc
) const
444 CFrameWndEx::Dump(dc
);
450 // CMainFrame message handlers
453 BOOL
CMainFrame::OnCreateClient(LPCREATESTRUCT
/*lpcs*/, CCreateContext
* pContext
)
459 // split into three panes:
468 // create a splitter with 2 rows, 1 column
469 if (!m_wndSplitter
.CreateStatic(this, 2, 1))
471 TRACE0("Failed to CreateStaticSplitter\n");
475 // add the second splitter pane - which is a nested splitter with 2 columns
476 if (!m_wndSplitter2
.CreateStatic(
477 &m_wndSplitter
, // our parent window is the first splitter
478 1, 2, // the new splitter is 1 row, 2 columns
479 WS_CHILD
| WS_VISIBLE
| WS_BORDER
, // style, WS_BORDER is needed
480 m_wndSplitter
.IdFromRowCol(0, 0)
481 // new splitter is in the first row, 1st column of first splitter
484 TRACE0("Failed to create nested splitter\n");
487 // add the first splitter pane - the default view in row 0
488 if (!m_wndSplitter
.CreateView(1, 0,
489 RUNTIME_CLASS(CBottomView
), CSize(cr
.Width(), cr
.Height()), pContext
))
491 TRACE0("Failed to create first pane\n");
494 m_pwndBottomView
= static_cast<CBottomView
*>(m_wndSplitter
.GetPane(1, 0));
495 m_pwndBottomView
->m_pwndLocator
= &m_wndLocatorBar
;
496 m_pwndBottomView
->m_pwndLineDiffBar
= &m_wndLineDiffBar
;
498 m_pwndBottomView
->m_pwndRibbonStatusBar
= &m_wndRibbonStatusBar
;
500 m_pwndBottomView
->m_pwndStatusBar
= &m_wndStatusBar
;
501 m_pwndBottomView
->m_pMainFrame
= this;
503 // now create the two views inside the nested splitter
505 if (!m_wndSplitter2
.CreateView(0, 0,
506 RUNTIME_CLASS(CLeftView
), CSize(cr
.Width()/2, cr
.Height()/2), pContext
))
508 TRACE0("Failed to create second pane\n");
511 m_pwndLeftView
= static_cast<CLeftView
*>(m_wndSplitter2
.GetPane(0, 0));
512 m_pwndLeftView
->m_pwndLocator
= &m_wndLocatorBar
;
513 m_pwndLeftView
->m_pwndLineDiffBar
= &m_wndLineDiffBar
;
515 m_pwndLeftView
->m_pwndRibbonStatusBar
= &m_wndRibbonStatusBar
;
517 m_pwndLeftView
->m_pwndStatusBar
= &m_wndStatusBar
;
518 m_pwndLeftView
->m_pMainFrame
= this;
520 if (!m_wndSplitter2
.CreateView(0, 1,
521 RUNTIME_CLASS(CRightView
), CSize(cr
.Width()/2, cr
.Height()/2), pContext
))
523 TRACE0("Failed to create third pane\n");
526 m_pwndRightView
= static_cast<CRightView
*>(m_wndSplitter2
.GetPane(0, 1));
527 m_pwndRightView
->m_pwndLocator
= &m_wndLocatorBar
;
528 m_pwndRightView
->m_pwndLineDiffBar
= &m_wndLineDiffBar
;
530 m_pwndRightView
->m_pwndRibbonStatusBar
= &m_wndRibbonStatusBar
;
532 m_pwndRightView
->m_pwndStatusBar
= &m_wndStatusBar
;
533 m_pwndRightView
->m_pMainFrame
= this;
534 m_bInitSplitter
= TRUE
;
536 m_dlgFilePatches
.Create(IDD_FILEPATCHES
, this);
542 BOOL
CMainFrame::PatchFile(CString sFilePath
, bool /*bContentMods*/, bool bPropMods
, CString sVersion
, BOOL bAutoPatch
)
544 //"dry run" was successful, so save the patched file somewhere...
545 CString sTempFile
= CTempFiles::Instance().GetTempFilePathString();
546 CString sRejectedFile
, sBasePath
;
547 if (m_Patch
.GetPatchResult(sFilePath
, sTempFile
, sRejectedFile
, sBasePath
) < 0)
549 MessageBox(m_Patch
.GetErrorMessage(), nullptr, MB_ICONERROR
);
552 sFilePath
= m_Patch
.GetTargetPath() + L
'\\' + sFilePath
;
553 sFilePath
.Replace('/', '\\');
554 if (sBasePath
.IsEmpty())
555 sBasePath
= sFilePath
;
556 if (m_bReversedPatch
)
558 m_Data
.m_baseFile
.SetFileName(sTempFile
);
560 temp
.Format(L
"%s %s", static_cast<LPCWSTR
>(CPathUtils::GetFileNameFromPath(sFilePath
)), static_cast<LPCWSTR
>(m_Data
.m_sPatchPatched
));
561 m_Data
.m_baseFile
.SetDescriptiveName(temp
);
562 m_Data
.m_yourFile
.SetFileName(sFilePath
);
563 temp
.Format(L
"%s %s", static_cast<LPCWSTR
>(CPathUtils::GetFileNameFromPath(sFilePath
)), static_cast<LPCWSTR
>(m_Data
.m_sPatchOriginal
));
564 m_Data
.m_yourFile
.SetDescriptiveName(temp
);
565 m_Data
.m_theirFile
.SetOutOfUse();
566 m_Data
.m_mergedFile
.SetOutOfUse();
570 if ((!PathFileExists(sBasePath
))||(PathIsDirectory(sBasePath
)))
572 m_Data
.m_baseFile
.SetFileName(CTempFiles::Instance().GetTempFilePathString());
573 m_Data
.m_baseFile
.CreateEmptyFile();
577 m_Data
.m_baseFile
.SetFileName(sBasePath
);
579 CString sDescription
;
580 sDescription
.Format(L
"%s %s", static_cast<LPCWSTR
>(CPathUtils::GetFileNameFromPath(sBasePath
)), static_cast<LPCWSTR
>(m_Data
.m_sPatchOriginal
));
581 m_Data
.m_baseFile
.SetDescriptiveName(sDescription
);
582 if (sBasePath
== sFilePath
)
584 m_Data
.m_yourFile
.SetFileName(sTempFile
);
586 temp
.Format(L
"%s %s", static_cast<LPCWSTR
>(CPathUtils::GetFileNameFromPath(sBasePath
)), static_cast<LPCWSTR
>(m_Data
.m_sPatchPatched
));
587 m_Data
.m_yourFile
.SetDescriptiveName(temp
);
588 m_Data
.m_theirFile
.SetOutOfUse();
592 if (!PathFileExists(sFilePath
) || PathIsDirectory(sFilePath
))
594 m_Data
.m_yourFile
.SetFileName(CTempFiles::Instance().GetTempFilePathString());
595 m_Data
.m_yourFile
.CreateEmptyFile();
597 temp
.Format(L
"%s %s", static_cast<LPCWSTR
>(CPathUtils::GetFileNameFromPath(sFilePath
)), static_cast<LPCWSTR
>(CString(MAKEINTRESOURCE(IDS_NOTFOUNDVIEWTITLEINDICATOR
))));
598 m_Data
.m_yourFile
.SetDescriptiveName(temp
);
601 m_Data
.m_yourFile
.SetFileName(sFilePath
);
602 m_Data
.m_theirFile
.SetFileName(sTempFile
);
604 temp
.Format(L
"%s %s", static_cast<LPCWSTR
>(CPathUtils::GetFileNameFromPath(sFilePath
)), static_cast<LPCWSTR
>(m_Data
.m_sPatchPatched
));
605 m_Data
.m_theirFile
.SetDescriptiveName(temp
);
607 m_Data
.m_mergedFile
.SetFileName(sFilePath
);
608 m_Data
.m_bPatchRequired
= bPropMods
;
610 TRACE(L
"comparing %s\nwith the patched result %s\n", static_cast<LPCWSTR
>(sFilePath
), static_cast<LPCWSTR
>(sTempFile
));
613 if (!sRejectedFile
.IsEmpty())
616 // start TortoiseUDiff with the rejected hunks
618 sTitle
.Format(IDS_TITLE_REJECTEDHUNKS
, static_cast<LPCWSTR
>(CPathUtils::GetFileNameFromPath(sFilePath
)));
619 CAppUtils::StartUnifiedDiffViewer(sRejectedFile
, sTitle
);
624 if (sBasePath
!= sFilePath
&& HasConflictsWontKeep())
633 BOOL
CMainFrame::DiffFiles(CString sURL1
, CString sRev1
, CString sURL2
, CString sRev2
)
635 CString tempfile1
= CTempFiles::Instance().GetTempFilePathString();
636 CString tempfile2
= CTempFiles::Instance().GetTempFilePathString();
638 ASSERT(tempfile1
.Compare(tempfile2
));
641 CSysProgressDlg progDlg
;
642 sTemp
.Format(IDS_GETVERSIONOFFILE
, static_cast<LPCWSTR
>(sRev1
));
643 progDlg
.SetLine(1, sTemp
, true);
644 progDlg
.SetLine(2, sURL1
, true);
645 sTemp
.LoadString(IDS_GETVERSIONOFFILETITLE
);
646 progDlg
.SetTitle(sTemp
);
647 progDlg
.SetShowProgressBar(true);
648 progDlg
.SetTime(FALSE
);
649 progDlg
.SetProgress(1,100);
650 progDlg
.ShowModeless(this);
651 if (!CAppUtils::GetVersionedFile(sURL1
, sRev1
, tempfile1
, &progDlg
, m_hWnd
))
655 sErrMsg
.FormatMessage(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND
, static_cast<LPCWSTR
>(sRev1
), static_cast<LPCWSTR
>(sURL1
));
656 MessageBox(sErrMsg
, nullptr, MB_ICONERROR
);
659 sTemp
.Format(IDS_GETVERSIONOFFILE
, static_cast<LPCWSTR
>(sRev2
));
660 progDlg
.SetLine(1, sTemp
, true);
661 progDlg
.SetLine(2, sURL2
, true);
662 progDlg
.SetProgress(50, 100);
663 if (!CAppUtils::GetVersionedFile(sURL2
, sRev2
, tempfile2
, &progDlg
, m_hWnd
))
667 sErrMsg
.FormatMessage(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND
, static_cast<LPCWSTR
>(sRev2
), static_cast<LPCWSTR
>(sURL2
));
668 MessageBox(sErrMsg
, nullptr, MB_ICONERROR
);
671 progDlg
.SetProgress(100,100);
674 temp
.Format(L
"%s Revision %s", static_cast<LPCWSTR
>(CPathUtils::GetFileNameFromPath(sURL1
)), static_cast<LPCWSTR
>(sRev1
));
675 m_Data
.m_baseFile
.SetFileName(tempfile1
);
676 m_Data
.m_baseFile
.SetDescriptiveName(temp
);
677 temp
.Format(L
"%s Revision %s", static_cast<LPCWSTR
>(CPathUtils::GetFileNameFromPath(sURL2
)), static_cast<LPCWSTR
>(sRev2
));
678 m_Data
.m_yourFile
.SetFileName(tempfile2
);
679 m_Data
.m_yourFile
.SetDescriptiveName(temp
);
686 void CMainFrame::OnFileOpen()
688 if (CheckForSave(ECheckForSaveReason::Open
)==IDCANCEL
)
690 return OnFileOpen(false);
693 void CMainFrame::OnFileOpen(bool fillyours
)
697 dlg
.m_sBaseFile
= m_Data
.m_yourFile
.GetFilename();
698 if (dlg
.DoModal() != IDOK
)
702 m_bMarkedAsResolvedWasDone
= false;
703 m_dlgFilePatches
.ShowWindow(SW_HIDE
);
704 m_dlgFilePatches
.Init(nullptr, nullptr, CString(), nullptr);
705 TRACE(L
"got the files:\n %s\n %s\n %s\n %s\n %s\n", static_cast<LPCWSTR
>(dlg
.m_sBaseFile
), static_cast<LPCWSTR
>(dlg
.m_sTheirFile
), static_cast<LPCWSTR
>(dlg
.m_sYourFile
),
706 static_cast<LPCWSTR
>(dlg
.m_sUnifiedDiffFile
), static_cast<LPCWSTR
>(dlg
.m_sPatchDirectory
));
707 m_Data
.m_baseFile
.SetFileName(dlg
.m_sBaseFile
);
708 m_Data
.m_theirFile
.SetFileName(dlg
.m_sTheirFile
);
709 m_Data
.m_yourFile
.SetFileName(dlg
.m_sYourFile
);
710 m_Data
.m_sDiffFile
= dlg
.m_sUnifiedDiffFile
;
711 m_Data
.m_sPatchPath
= dlg
.m_sPatchDirectory
;
712 m_Data
.m_mergedFile
.SetOutOfUse();
713 CCrashReport::Instance().AddFile2(dlg
.m_sBaseFile
, nullptr, L
"Basefile", CR_AF_MAKE_FILE_COPY
);
714 CCrashReport::Instance().AddFile2(dlg
.m_sTheirFile
, nullptr, L
"Theirfile", CR_AF_MAKE_FILE_COPY
);
715 CCrashReport::Instance().AddFile2(dlg
.m_sYourFile
, nullptr, L
"Yourfile", CR_AF_MAKE_FILE_COPY
);
716 CCrashReport::Instance().AddFile2(dlg
.m_sUnifiedDiffFile
, nullptr, L
"Difffile", CR_AF_MAKE_FILE_COPY
);
718 if (!m_Data
.IsBaseFileInUse() && m_Data
.IsTheirFileInUse() && m_Data
.IsYourFileInUse())
720 // a diff between two files means "Yours" against "Base", not "Theirs" against "Yours"
721 m_Data
.m_baseFile
.TransferDetailsFrom(m_Data
.m_theirFile
);
723 if (m_Data
.IsBaseFileInUse() && m_Data
.IsTheirFileInUse() && !m_Data
.IsYourFileInUse())
725 // a diff between two files means "Yours" against "Base", not "Theirs" against "Base"
726 m_Data
.m_yourFile
.TransferDetailsFrom(m_Data
.m_theirFile
);
728 m_bSaveRequired
= false;
733 void CMainFrame::ClearViewNamesAndPaths()
735 m_pwndLeftView
->m_sWindowName
.Empty();
736 m_pwndLeftView
->m_sFullFilePath
.Empty();
737 m_pwndLeftView
->m_sReflectedName
.Empty();
738 m_pwndRightView
->m_sWindowName
.Empty();
739 m_pwndRightView
->m_sFullFilePath
.Empty();
740 m_pwndRightView
->m_sReflectedName
.Empty();
741 m_pwndBottomView
->m_sWindowName
.Empty();
742 m_pwndBottomView
->m_sFullFilePath
.Empty();
743 m_pwndBottomView
->m_sReflectedName
.Empty();
746 bool CMainFrame::LoadViews(int line
)
748 LoadIgnoreCommentData();
749 m_Data
.SetBlame(m_bBlame
);
750 m_Data
.SetMovedBlocks(m_bViewMovedBlocks
);
751 m_bHasConflicts
= false;
752 CBaseView
* pwndActiveView
= m_pwndLeftView
;
753 int nOldLine
= m_pwndRightView
? m_pwndRightView
->m_nTopLine
: -1;
755 m_pwndRightView
&& m_pwndRightView
->m_pViewData
?
756 m_pwndRightView
->m_pViewData
->GetLineNumber(m_pwndRightView
->m_nTopLine
) : -1;
757 POINT ptOldCaretPos
= {-1, -1};
758 if (m_pwndRightView
&& m_pwndRightView
->IsTarget())
759 ptOldCaretPos
= m_pwndRightView
->GetCaretPosition();
760 if (m_pwndBottomView
&& m_pwndBottomView
->IsTarget())
761 ptOldCaretPos
= m_pwndBottomView
->GetCaretPosition();
762 CString sExt
= CPathUtils::GetFileExtFromPath(m_Data
.m_baseFile
.GetFilename()).MakeLower();
764 auto sC
= m_IgnoreCommentsMap
.find(sExt
);
765 if (sC
== m_IgnoreCommentsMap
.end())
767 sExt
= CPathUtils::GetFileExtFromPath(m_Data
.m_yourFile
.GetFilename()).MakeLower();
768 sC
= m_IgnoreCommentsMap
.find(sExt
);
769 if (sC
== m_IgnoreCommentsMap
.end())
771 sExt
= CPathUtils::GetFileExtFromPath(m_Data
.m_theirFile
.GetFilename()).MakeLower();
772 sC
= m_IgnoreCommentsMap
.find(sExt
);
775 if (sC
!= m_IgnoreCommentsMap
.end())
776 m_Data
.SetCommentTokens(std::get
<0>(sC
->second
), std::get
<1>(sC
->second
), std::get
<2>(sC
->second
));
778 m_Data
.SetCommentTokens(L
"", L
"", L
"");
781 m_pwndLeftView
->BuildAllScreen2ViewVector();
782 m_pwndLeftView
->DocumentUpdated();
783 m_pwndRightView
->DocumentUpdated();
784 m_pwndBottomView
->DocumentUpdated();
785 m_wndLocatorBar
.DocumentUpdated();
786 m_wndLineDiffBar
.DocumentUpdated();
787 ::MessageBox(m_hWnd
, m_Data
.GetError(), L
"TortoiseGitMerge", MB_ICONERROR
);
788 m_Data
.m_mergedFile
.SetOutOfUse();
789 m_bSaveRequired
= false;
793 m_pwndLeftView
->BuildAllScreen2ViewVector();
794 m_pwndLeftView
->DocumentUpdated();
795 m_pwndRightView
->DocumentUpdated();
796 m_pwndBottomView
->DocumentUpdated();
797 m_wndLocatorBar
.DocumentUpdated();
798 m_wndLineDiffBar
.DocumentUpdated();
800 m_pwndLeftView
->SetWritable(false);
801 m_pwndLeftView
->SetWritableIsChangable(false);
802 m_pwndLeftView
->SetTarget(false);
803 m_pwndRightView
->SetWritable(false);
804 m_pwndRightView
->SetWritableIsChangable(false);
805 m_pwndRightView
->SetTarget(false);
806 m_pwndBottomView
->SetWritable(false);
807 m_pwndBottomView
->SetWritableIsChangable(false);
808 m_pwndBottomView
->SetTarget(false);
810 if (!m_Data
.IsBaseFileInUse())
812 CSysProgressDlg progDlg
;
813 if (m_Data
.IsYourFileInUse() && m_Data
.IsTheirFileInUse())
815 m_Data
.m_baseFile
.TransferDetailsFrom(m_Data
.m_theirFile
);
817 else if ((!m_Data
.m_sDiffFile
.IsEmpty())&&(!m_Patch
.Init(m_Data
.m_sDiffFile
, m_Data
.m_sPatchPath
, &progDlg
)))
820 ClearViewNamesAndPaths();
821 MessageBox(m_Patch
.GetErrorMessage(), nullptr, MB_ICONERROR
);
822 m_bSaveRequired
= false;
826 if (m_Patch
.GetNumberOfFiles() > 0)
828 CString betterpatchpath
= m_Patch
.CheckPatchPath(m_Data
.m_sPatchPath
);
829 if (betterpatchpath
.CompareNoCase(m_Data
.m_sPatchPath
)!=0)
832 msg
.FormatMessage(IDS_WARNBETTERPATCHPATHFOUND
, static_cast<LPCWSTR
>(m_Data
.m_sPatchPath
), static_cast<LPCWSTR
>(betterpatchpath
));
833 CTaskDialog
taskdlg(msg
,
834 CString(MAKEINTRESOURCE(IDS_WARNBETTERPATCHPATHFOUND_TASK2
)),
837 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
839 WCHAR t3
[MAX_PATH
] = { 0 };
840 CString cp
= betterpatchpath
.Left(MAX_PATH
- 1);
841 PathCompactPathEx(t3
, cp
, 50, 0);
842 task3
.Format(IDS_WARNBETTERPATCHPATHFOUND_TASK3
, t3
);
843 taskdlg
.AddCommandControl(1, task3
);
845 WCHAR t4
[MAX_PATH
] = { 0 };
846 cp
= m_Data
.m_sPatchPath
.Left(MAX_PATH
- 1);
847 PathCompactPathEx(t4
, cp
, 50, 0);
848 task4
.Format(IDS_WARNBETTERPATCHPATHFOUND_TASK4
, t4
);
849 taskdlg
.AddCommandControl(2, task4
);
850 taskdlg
.SetDefaultCommandControl(1);
851 taskdlg
.SetMainIcon(TD_INFORMATION_ICON
);
852 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
853 if (taskdlg
.DoModal(m_hWnd
) == 1)
855 m_Data
.m_sPatchPath
= betterpatchpath
;
856 m_Patch
.Init(m_Data
.m_sDiffFile
, m_Data
.m_sPatchPath
, &progDlg
);
859 m_dlgFilePatches
.Init(&m_Patch
, this, m_Data
.m_sPatchPath
, this);
860 m_dlgFilePatches
.ShowWindow(SW_SHOW
);
861 ClearViewNamesAndPaths();
862 if (!m_wndSplitter
.IsRowHidden(1))
863 m_wndSplitter
.HideRow(1);
864 m_pwndLeftView
->SetHidden(FALSE
);
865 m_pwndRightView
->SetHidden(FALSE
);
866 m_pwndBottomView
->SetHidden(TRUE
);
869 if (m_Data
.IsBaseFileInUse() && !m_Data
.IsYourFileInUse() && m_Data
.IsTheirFileInUse())
871 m_Data
.m_yourFile
.TransferDetailsFrom(m_Data
.m_theirFile
);
873 if (m_Data
.IsBaseFileInUse() && m_Data
.IsYourFileInUse() && !m_Data
.IsTheirFileInUse())
875 //diff between YOUR and BASE
878 pwndActiveView
= m_pwndLeftView
;
879 if (!m_wndSplitter2
.IsColumnHidden(1))
880 m_wndSplitter2
.HideColumn(1);
882 m_pwndLeftView
->m_pViewData
= &m_Data
.m_YourBaseBoth
;
883 m_pwndLeftView
->SetTextType(m_Data
.m_arYourFile
.GetUnicodeType());
884 m_pwndLeftView
->SetLineEndingStyle(m_Data
.m_arYourFile
.GetLineEndings());
885 m_pwndLeftView
->m_sWindowName
= m_Data
.m_baseFile
.GetWindowName() + L
" - " + m_Data
.m_yourFile
.GetWindowName();
886 m_pwndLeftView
->m_sFullFilePath
= m_Data
.m_baseFile
.GetFilename() + L
" - " + m_Data
.m_yourFile
.GetFilename();
887 m_pwndLeftView
->m_sReflectedName
= m_Data
.m_yourFile
.GetReflectedName();
888 m_pwndLeftView
->m_pWorkingFile
= &m_Data
.m_yourFile
;
889 m_pwndLeftView
->SetTarget();
890 m_pwndLeftView
->SetWritableIsChangable(true);
892 m_pwndRightView
->m_pViewData
= nullptr;
893 m_pwndRightView
->m_pWorkingFile
= nullptr;
894 m_pwndBottomView
->m_pViewData
= nullptr;
895 m_pwndBottomView
->m_pWorkingFile
= nullptr;
897 if (!m_wndSplitter
.IsRowHidden(1))
898 m_wndSplitter
.HideRow(1);
899 m_pwndLeftView
->SetHidden(FALSE
);
900 m_pwndRightView
->SetHidden(TRUE
);
901 m_pwndBottomView
->SetHidden(TRUE
);
902 ::SetWindowPos(m_pwndLeftView
->m_hWnd
, nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
);
906 pwndActiveView
= m_pwndRightView
;
907 if (m_wndSplitter2
.IsColumnHidden(1))
908 m_wndSplitter2
.ShowColumn();
910 m_pwndLeftView
->m_pViewData
= &m_Data
.m_YourBaseLeft
;
911 m_pwndLeftView
->SetTextType(m_Data
.m_arBaseFile
.GetUnicodeType());
912 m_pwndLeftView
->SetLineEndingStyle(m_Data
.m_arBaseFile
.GetLineEndings());
913 m_pwndLeftView
->m_sWindowName
= m_Data
.m_baseFile
.GetWindowName();
914 m_pwndLeftView
->m_sFullFilePath
= m_Data
.m_baseFile
.GetFilename();
915 m_pwndLeftView
->m_sConvertedFilePath
= m_Data
.m_baseFile
.GetConvertedFileName();
916 m_pwndLeftView
->m_sReflectedName
= m_Data
.m_baseFile
.GetReflectedName();
917 m_pwndLeftView
->m_pWorkingFile
= &m_Data
.m_baseFile
;
918 m_pwndLeftView
->SetWritableIsChangable(true);
920 m_pwndRightView
->m_pViewData
= &m_Data
.m_YourBaseRight
;
921 m_pwndRightView
->SetTextType(m_Data
.m_arYourFile
.GetUnicodeType());
922 m_pwndRightView
->SetLineEndingStyle(m_Data
.m_arYourFile
.GetLineEndings());
923 m_pwndRightView
->m_sWindowName
= m_Data
.m_yourFile
.GetWindowName();
924 m_pwndRightView
->m_sFullFilePath
= m_Data
.m_yourFile
.GetFilename();
925 m_pwndRightView
->m_sConvertedFilePath
= m_Data
.m_yourFile
.GetConvertedFileName();
926 m_pwndRightView
->m_sReflectedName
= m_Data
.m_yourFile
.GetReflectedName();
927 m_pwndRightView
->m_pWorkingFile
= &m_Data
.m_yourFile
;
928 m_pwndRightView
->SetWritable();
929 m_pwndRightView
->SetTarget();
931 m_pwndBottomView
->m_pViewData
= nullptr;
932 m_pwndBottomView
->m_pWorkingFile
= nullptr;
934 if (!m_wndSplitter
.IsRowHidden(1))
935 m_wndSplitter
.HideRow(1);
936 m_pwndLeftView
->SetHidden(FALSE
);
937 m_pwndRightView
->SetHidden(FALSE
);
938 m_pwndBottomView
->SetHidden(TRUE
);
940 bool hasMods
, hasConflicts
, hasWhitespaceMods
, hasFilteredMods
;
941 pwndActiveView
->CheckModifications(hasMods
, hasConflicts
, hasWhitespaceMods
, hasFilteredMods
);
942 if (!hasMods
&& !hasConflicts
)
944 // files appear identical, show a dialog informing the user that there are or might
945 // be other differences
946 bool hasEncodingDiff
= m_Data
.m_arBaseFile
.GetUnicodeType() != m_Data
.m_arYourFile
.GetUnicodeType();
947 bool hasEOLDiff
= m_Data
.m_arBaseFile
.GetLineEndings() != m_Data
.m_arYourFile
.GetLineEndings();
948 if (hasWhitespaceMods
|| hasEncodingDiff
|| hasEOLDiff
)
950 // text is identical, but the files do not match
951 CString
sWarning(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_MAIN
));
952 CString
sWhitespace(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_WHITESPACE
));
953 CString
sEncoding(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_ENCODING
));
954 CString
sEOL(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_EOL
));
955 if (hasWhitespaceMods
)
958 sWarning
+= sWhitespace
;
963 sWarning
+= sEncoding
;
965 sWarning
+= m_Data
.m_arBaseFile
.GetEncodingName(m_Data
.m_arBaseFile
.GetUnicodeType());
967 sWarning
+= m_Data
.m_arYourFile
.GetEncodingName(m_Data
.m_arYourFile
.GetUnicodeType());
975 AfxMessageBox(sWarning
, MB_ICONINFORMATION
);
979 else if (m_Data
.IsBaseFileInUse() && m_Data
.IsYourFileInUse() && m_Data
.IsTheirFileInUse())
981 //diff between THEIR, YOUR and BASE
982 m_pwndBottomView
->SetWritable();
983 m_pwndBottomView
->SetTarget();
984 pwndActiveView
= m_pwndBottomView
;
986 m_pwndLeftView
->m_pViewData
= &m_Data
.m_TheirBaseBoth
;
987 m_pwndLeftView
->SetTextType(m_Data
.m_arTheirFile
.GetUnicodeType());
988 m_pwndLeftView
->SetLineEndingStyle(m_Data
.m_arTheirFile
.GetLineEndings());
989 m_pwndLeftView
->m_sWindowName
= m_Data
.m_theirFile
.GetWindowName(IDS_VIEWTITLE_THEIRS
);
990 m_pwndLeftView
->m_sFullFilePath
= m_Data
.m_theirFile
.GetFilename();
991 m_pwndLeftView
->m_sConvertedFilePath
= m_Data
.m_theirFile
.GetConvertedFileName();
992 m_pwndLeftView
->m_sReflectedName
= m_Data
.m_theirFile
.GetReflectedName();
993 m_pwndLeftView
->m_pWorkingFile
= &m_Data
.m_theirFile
;
995 m_pwndRightView
->m_pViewData
= &m_Data
.m_YourBaseBoth
;
996 m_pwndRightView
->SetTextType(m_Data
.m_arYourFile
.GetUnicodeType());
997 m_pwndRightView
->SetLineEndingStyle(m_Data
.m_arYourFile
.GetLineEndings());
998 m_pwndRightView
->m_sWindowName
= m_Data
.m_yourFile
.GetWindowName(IDS_VIEWTITLE_MINE
);
999 m_pwndRightView
->m_sFullFilePath
= m_Data
.m_yourFile
.GetFilename();
1000 m_pwndRightView
->m_sConvertedFilePath
= m_Data
.m_yourFile
.GetConvertedFileName();
1001 m_pwndRightView
->m_sReflectedName
= m_Data
.m_yourFile
.GetReflectedName();
1002 m_pwndRightView
->m_pWorkingFile
= &m_Data
.m_yourFile
;
1004 m_pwndBottomView
->m_pViewData
= &m_Data
.m_Diff3
;
1005 m_pwndBottomView
->SetTextType(m_Data
.m_arTheirFile
.GetUnicodeType());
1006 m_pwndBottomView
->SetLineEndingStyle(m_Data
.m_arTheirFile
.GetLineEndings());
1007 m_pwndBottomView
->m_sWindowName
.LoadString(IDS_VIEWTITLE_MERGED
);
1008 m_pwndBottomView
->m_sWindowName
+= L
" - " + m_Data
.m_mergedFile
.GetWindowName();
1009 m_pwndBottomView
->m_sFullFilePath
= m_Data
.m_mergedFile
.GetFilename();
1010 m_pwndBottomView
->m_sConvertedFilePath
= m_Data
.m_mergedFile
.GetConvertedFileName();
1011 m_pwndBottomView
->m_sReflectedName
= m_Data
.m_mergedFile
.GetReflectedName();
1012 m_pwndBottomView
->m_pWorkingFile
= &m_Data
.m_mergedFile
;
1014 if (m_wndSplitter2
.IsColumnHidden(1))
1015 m_wndSplitter2
.ShowColumn();
1016 if (m_wndSplitter
.IsRowHidden(1))
1017 m_wndSplitter
.ShowRow();
1018 m_pwndLeftView
->SetHidden(FALSE
);
1019 m_pwndRightView
->SetHidden(FALSE
);
1020 m_pwndBottomView
->SetHidden(FALSE
);
1021 // in three pane view, hide the line diff bar
1022 m_wndLineDiffBar
.ShowPane(false, false, true);
1023 m_wndLineDiffBar
.DocumentUpdated();
1025 if (!m_Data
.m_mergedFile
.InUse())
1027 m_Data
.m_mergedFile
.SetFileName(m_Data
.m_yourFile
.GetFilename());
1029 m_pwndLeftView
->BuildAllScreen2ViewVector();
1030 m_pwndLeftView
->DocumentUpdated();
1031 m_pwndRightView
->DocumentUpdated();
1032 m_pwndBottomView
->DocumentUpdated();
1033 m_wndLocatorBar
.DocumentUpdated();
1034 m_wndLineDiffBar
.DocumentUpdated();
1036 SetActiveView(pwndActiveView
);
1038 if ((line
>= -1) && m_pwndRightView
->m_pViewData
)
1040 int n
= line
== -1 ? min( nOldLineNumber
, nOldLine
) : line
;
1043 n
= m_pwndRightView
->m_pViewData
->FindLineNumber(n
);
1044 if (m_bCollapsed
&& line
>= 0)
1046 // adjust the goto-line position if we're collapsed
1047 int step
= m_pwndRightView
->m_nTopLine
> n
? -1 : 1;
1049 for (int i
= m_pwndRightView
->m_nTopLine
; i
!= n
; i
+= step
)
1051 if (m_pwndRightView
->m_pViewData
->GetHideState(i
) == HideState::Hidden
)
1054 if (m_pwndRightView
->m_pViewData
->GetHideState(n
) == HideState::Hidden
)
1055 OnViewTextFoldUnfold();
1057 n
= n
+ (skip
* step
* -1);
1063 m_pwndRightView
->ScrollAllToLine(n
);
1067 if ((ptOldCaretPos
.x
>= 0) || (ptOldCaretPos
.y
>= 0))
1069 m_pwndLeftView
->SetCaretPosition(p
);
1070 m_pwndRightView
->SetCaretPosition(p
);
1071 m_pwndBottomView
->SetCaretPosition(p
);
1072 m_pwndBottomView
->ScrollToChar(0);
1073 m_pwndLeftView
->ScrollToChar(0);
1074 m_pwndRightView
->ScrollToChar(0);
1078 CRegDWORD regFirstDiff
= CRegDWORD(L
"Software\\TortoiseGitMerge\\FirstDiffOnLoad", TRUE
);
1079 CRegDWORD regFirstConflict
= CRegDWORD(L
"Software\\TortoiseGitMerge\\FirstConflictOnLoad", TRUE
);
1080 bool bGoFirstDiff
= (0 != static_cast<DWORD
>(regFirstDiff
));
1081 bool bGoFirstConflict
= (0 != static_cast<DWORD
>(regFirstConflict
));
1082 if (bGoFirstConflict
&& (CheckResolved()>=0))
1084 pwndActiveView
->GoToFirstConflict();
1085 // Ignore the first few Mouse Move messages, so that the line diff stays on
1086 // the first diff line until the user actually moves the mouse
1087 m_nMoveMovesToIgnore
= MOVESTOIGNORE
;
1089 else if (bGoFirstDiff
)
1091 pwndActiveView
->GoToFirstDifference();
1092 // Ignore the first few Mouse Move messages, so that the line diff stays on
1093 // the first diff line until the user actually moves the mouse
1094 m_nMoveMovesToIgnore
= MOVESTOIGNORE
;
1098 // Avoid incorrect rendering of active pane.
1099 m_pwndBottomView
->ScrollToChar(0);
1100 m_pwndLeftView
->ScrollToChar(0);
1101 m_pwndRightView
->ScrollToChar(0);
1105 if (m_bHasConflicts
&& !m_bSaveRequiredOnConflicts
)
1106 m_bSaveRequired
= false;
1107 CUndo::GetInstance().Clear();
1111 void CMainFrame::UpdateLayout()
1113 if (m_bInitSplitter
)
1115 m_wndSplitter
.CenterSplitter();
1116 m_wndSplitter2
.CenterSplitter();
1120 void CMainFrame::RecalcLayout(BOOL bNotify
)
1122 GetClientRect(&m_dockManager
.m_rectInPlace
);
1124 m_dockManager
.m_rectInPlace
.top
+= m_pRibbonApp
->GetRibbonHeight();
1125 CFrameWndEx::RecalcLayout(bNotify
);
1128 void CMainFrame::OnSize(UINT nType
, int cx
, int cy
)
1130 CFrameWndEx::OnSize(nType
, cx
, cy
);
1131 if (m_bInitSplitter
&& nType
!= SIZE_MINIMIZED
)
1133 if (m_wndSplitter
.GetSafeHwnd())
1135 if (m_wndSplitter
.HasOldRowSize() && (m_wndSplitter
.GetOldRowCount() == 2))
1137 int oldTotal
= m_wndSplitter
.GetOldRowSize(0) + m_wndSplitter
.GetOldRowSize(1);
1140 int cxCur0
, cxCur1
, cxMin0
, cxMin1
;
1141 m_wndSplitter
.GetRowInfo(0, cxCur0
, cxMin0
);
1142 m_wndSplitter
.GetRowInfo(1, cxCur1
, cxMin1
);
1143 cxCur0
= m_wndSplitter
.GetOldRowSize(0) * (cxCur0
+ cxCur1
) / oldTotal
;
1144 cxCur1
= m_wndSplitter
.GetOldRowSize(1) * (cxCur0
+ cxCur1
) / oldTotal
;
1145 m_wndSplitter
.SetRowInfo(0, cxCur0
, 0);
1146 m_wndSplitter
.SetRowInfo(1, cxCur1
, 0);
1147 m_wndSplitter
.RecalcLayout();
1151 if (m_wndSplitter2
.HasOldColSize() && (m_wndSplitter2
.GetOldColCount() == 2))
1153 int oldTotal
= m_wndSplitter2
.GetOldColSize(0) + m_wndSplitter2
.GetOldColSize(1);
1156 int cyCur0
, cyCur1
, cyMin0
, cyMin1
;
1157 m_wndSplitter2
.GetColumnInfo(0, cyCur0
, cyMin0
);
1158 m_wndSplitter2
.GetColumnInfo(1, cyCur1
, cyMin1
);
1159 cyCur0
= m_wndSplitter2
.GetOldColSize(0) * (cyCur0
+ cyCur1
) / oldTotal
;
1160 cyCur1
= m_wndSplitter2
.GetOldColSize(1) * (cyCur0
+ cyCur1
) / oldTotal
;
1161 m_wndSplitter2
.SetColumnInfo(0, cyCur0
, 0);
1162 m_wndSplitter2
.SetColumnInfo(1, cyCur1
, 0);
1163 m_wndSplitter2
.RecalcLayout();
1168 if ((nType
== SIZE_RESTORED
)&&m_bCheckReload
)
1170 m_bCheckReload
= false;
1175 void CMainFrame::OnViewWhitespaces()
1177 CRegDWORD regViewWhitespaces
= CRegDWORD(L
"Software\\TortoiseGitMerge\\ViewWhitespaces", 1);
1178 BOOL bViewWhitespaces
= regViewWhitespaces
;
1180 bViewWhitespaces
= m_pwndLeftView
->m_bViewWhitespace
;
1182 bViewWhitespaces
= !bViewWhitespaces
;
1183 regViewWhitespaces
= bViewWhitespaces
;
1186 m_pwndLeftView
->m_bViewWhitespace
= bViewWhitespaces
;
1187 m_pwndLeftView
->Invalidate();
1189 if (m_pwndRightView
)
1191 m_pwndRightView
->m_bViewWhitespace
= bViewWhitespaces
;
1192 m_pwndRightView
->Invalidate();
1194 if (m_pwndBottomView
)
1196 m_pwndBottomView
->m_bViewWhitespace
= bViewWhitespaces
;
1197 m_pwndBottomView
->Invalidate();
1201 void CMainFrame::OnUpdateViewWhitespaces(CCmdUI
*pCmdUI
)
1204 pCmdUI
->SetCheck(m_pwndLeftView
->m_bViewWhitespace
);
1207 void CMainFrame::OnViewCollapsed()
1209 m_regCollapsed
= !static_cast<DWORD
>(m_regCollapsed
);
1210 m_bCollapsed
= !!static_cast<DWORD
>(m_regCollapsed
);
1212 OnViewTextFoldUnfold();
1213 m_wndLocatorBar
.Invalidate();
1216 void CMainFrame::OnUpdateViewCollapsed(CCmdUI
*pCmdUI
)
1218 pCmdUI
->SetCheck(m_bCollapsed
);
1221 void CMainFrame::OnViewWraplonglines()
1223 m_bWrapLines
= !static_cast<DWORD
>(m_regWrapLines
);
1224 m_regWrapLines
= m_bWrapLines
;
1226 if (m_pwndLeftView
) m_pwndLeftView
->WrapChanged();
1227 if (m_pwndRightView
) m_pwndRightView
->WrapChanged();
1228 if (m_pwndBottomView
) m_pwndBottomView
->WrapChanged();
1229 OnViewTextFoldUnfold();
1230 m_wndLocatorBar
.DocumentUpdated();
1233 void CMainFrame::OnViewTextFoldUnfold()
1235 OnViewTextFoldUnfold(m_pwndLeftView
);
1236 OnViewTextFoldUnfold(m_pwndRightView
);
1237 OnViewTextFoldUnfold(m_pwndBottomView
);
1240 void CMainFrame::OnViewTextFoldUnfold(CBaseView
* view
)
1244 view
->BuildAllScreen2ViewVector();
1245 view
->UpdateCaret();
1247 view
->EnsureCaretVisible();
1250 void CMainFrame::OnUpdateViewWraplonglines(CCmdUI
*pCmdUI
)
1252 pCmdUI
->SetCheck(m_bWrapLines
);
1255 void CMainFrame::OnViewOnewaydiff()
1257 if (CheckForSave(ECheckForSaveReason::Reload
)==IDCANCEL
)
1259 m_bOneWay
= !m_bOneWay
;
1260 m_regOneWay
= m_bOneWay
;
1261 ShowDiffBar(!m_bOneWay
);
1265 void CMainFrame::DiffLeftToBase()
1267 DiffTwo(m_Data
.m_baseFile
, m_Data
.m_theirFile
);
1270 void CMainFrame::DiffRightToBase()
1272 DiffTwo(m_Data
.m_baseFile
, m_Data
.m_yourFile
);
1275 void CMainFrame::DiffTwo(const CWorkingFile
& file1
, const CWorkingFile
& file2
)
1277 wchar_t ownpath
[MAX_PATH
] = { 0 };
1278 GetModuleFileName(nullptr, ownpath
, MAX_PATH
);
1280 sCmd
.Format(L
"\"%s\"", ownpath
);
1281 sCmd
+= L
" /base:\"";
1282 sCmd
+= file1
.GetFilename();
1283 sCmd
+= L
"\" /mine:\"";
1284 sCmd
+= file2
.GetFilename();
1286 if (!file1
.GetWindowName().IsEmpty())
1287 sCmd
+= L
" /basename:\"" + file1
.GetWindowName() + L
"\"";
1288 if (!file2
.GetWindowName().IsEmpty())
1289 sCmd
+= L
" /yourname:\"" + file2
.GetWindowName() + L
"\"";
1291 CAppUtils::LaunchApplication(sCmd
, CAppUtils::LaunchApplicationFlags());
1294 void CMainFrame::ShowDiffBar(bool bShow
)
1298 // restore the line diff bar
1299 m_wndLineDiffBar
.ShowPane(m_bLineDiff
, false, true);
1300 m_wndLineDiffBar
.DocumentUpdated();
1301 m_wndLocatorBar
.ShowPane(m_bLocatorBar
, false, true);
1302 m_wndLocatorBar
.DocumentUpdated();
1306 // in one way view, hide the line diff bar
1307 m_wndLineDiffBar
.ShowPane(false, false, true);
1308 m_wndLineDiffBar
.DocumentUpdated();
1312 // Implementation helper only,
1313 // use CTheme::Instance::SetDarkTheme to actually set the theme.
1314 #ifndef UI_PKEY_DarkModeRibbon
1315 DEFINE_UIPROPERTYKEY(UI_PKEY_DarkModeRibbon
, VT_BOOL
, 2004);
1316 DEFINE_UIPROPERTYKEY(UI_PKEY_ApplicationButtonColor
, VT_UI4
, 2003);
1318 void CMainFrame::SetTheme(bool bDark
)
1325 CComPtr
<IPropertyStore
> spPropertyStore
;
1326 if (m_bUseRibbons
&& SUCCEEDED(m_pRibbonFramework
->QueryInterface(&spPropertyStore
)))
1328 DarkModeHelper::Instance().AllowDarkModeForApp(TRUE
);
1329 DarkModeHelper::Instance().AllowDarkModeForWindow(GetSafeHwnd(), TRUE
);
1330 PROPVARIANT propvarDarkMode
;
1331 InitPropVariantFromBoolean(1, &propvarDarkMode
);
1332 spPropertyStore
->SetValue(UI_PKEY_DarkModeRibbon
, propvarDarkMode
);
1333 spPropertyStore
->Commit();
1335 SetClassLongPtr(GetSafeHwnd(), GCLP_HBRBACKGROUND
, reinterpret_cast<LONG_PTR
>(GetStockObject(BLACK_BRUSH
)));
1336 BOOL darkFlag
= TRUE
;
1337 DarkModeHelper::WINDOWCOMPOSITIONATTRIBDATA data
= { DarkModeHelper::WINDOWCOMPOSITIONATTRIB::WCA_USEDARKMODECOLORS
, &darkFlag
, sizeof(darkFlag
) };
1338 DarkModeHelper::Instance().SetWindowCompositionAttribute(*this, &data
);
1339 DarkModeHelper::Instance().FlushMenuThemes();
1340 DarkModeHelper::Instance().RefreshImmersiveColorPolicyState();
1344 DarkModeHelper::Instance().AllowDarkModeForApp(FALSE
);
1345 DarkModeHelper::Instance().AllowDarkModeForWindow(GetSafeHwnd(), FALSE
);
1346 CComPtr
<IPropertyStore
> spPropertyStore
;
1347 if (m_bUseRibbons
&& SUCCEEDED(m_pRibbonFramework
->QueryInterface(&spPropertyStore
)))
1349 PROPVARIANT propvarDarkMode
;
1350 InitPropVariantFromBoolean(false, &propvarDarkMode
);
1351 spPropertyStore
->SetValue(UI_PKEY_DarkModeRibbon
, propvarDarkMode
);
1352 spPropertyStore
->Commit();
1354 SetClassLongPtr(GetSafeHwnd(), GCLP_HBRBACKGROUND
, reinterpret_cast<LONG_PTR
>(GetSysColorBrush(COLOR_3DFACE
)));
1355 BOOL darkFlag
= FALSE
;
1356 DarkModeHelper::WINDOWCOMPOSITIONATTRIBDATA data
= { DarkModeHelper::WINDOWCOMPOSITIONATTRIB::WCA_USEDARKMODECOLORS
, &darkFlag
, sizeof(darkFlag
) };
1357 DarkModeHelper::Instance().SetWindowCompositionAttribute(*this, &data
);
1358 DarkModeHelper::Instance().FlushMenuThemes();
1359 DarkModeHelper::Instance().RefreshImmersiveColorPolicyState();
1361 ::RedrawWindow(GetSafeHwnd(), nullptr, nullptr, RDW_FRAME
| RDW_INVALIDATE
| RDW_ERASE
| RDW_INTERNALPAINT
| RDW_ALLCHILDREN
| RDW_UPDATENOW
);
1364 void CMainFrame::SetAccentColor()
1369 // set the accent color for the main button
1370 if (m_pRibbonFramework
)
1372 Win10Colors::AccentColor accentColor
;
1373 if (SUCCEEDED(Win10Colors::GetAccentColor(accentColor
)))
1376 CTheme::RGBToHSB(accentColor
.accent
, h
, s
, b
);
1377 UI_HSBCOLOR aColor
= UI_HSB(h
, s
, b
);
1379 CComPtr
<IPropertyStore
> spPropertyStore
;
1380 HRESULT hr
= m_pRibbonFramework
->QueryInterface(&spPropertyStore
);
1383 PROPVARIANT propvarAccentColor
;
1384 InitPropVariantFromUInt32(aColor
, &propvarAccentColor
);
1385 spPropertyStore
->SetValue(UI_PKEY_ApplicationButtonColor
, propvarAccentColor
);
1386 spPropertyStore
->Commit();
1392 int CMainFrame::CheckResolved()
1394 //only in three way diffs can be conflicts!
1395 m_bHasConflicts
= true;
1396 if (IsViewGood(m_pwndBottomView
))
1398 CViewData
* viewdata
= m_pwndBottomView
->m_pViewData
;
1401 for (int i
=0; i
<viewdata
->GetCount(); i
++)
1403 const DiffState state
= viewdata
->GetState(i
);
1404 if ((DiffState::Conflicted
== state
)||(DiffState::Conflicted_Ignored
== state
))
1409 m_bHasConflicts
= false;
1413 int CMainFrame::SaveFile(const CString
& sFilePath
)
1415 CBaseView
* pView
= nullptr;
1416 CViewData
* pViewData
= nullptr;
1417 CFileTextLines
* pOriginFile
= &m_Data
.m_arBaseFile
;
1418 if (IsViewGood(m_pwndBottomView
))
1420 pView
= m_pwndBottomView
;
1421 pViewData
= m_pwndBottomView
->m_pViewData
;
1423 else if (IsViewGood(m_pwndRightView
))
1425 pView
= m_pwndRightView
;
1426 pViewData
= m_pwndRightView
->m_pViewData
;
1427 if (m_Data
.IsYourFileInUse())
1428 pOriginFile
= &m_Data
.m_arYourFile
;
1429 else if (m_Data
.IsTheirFileInUse())
1430 pOriginFile
= &m_Data
.m_arTheirFile
;
1438 if ((pViewData
)&&(pOriginFile
))
1440 CFileTextLines file
;
1441 pOriginFile
->CopySettings(&file
);
1442 CFileTextLines::SaveParams saveParams
;
1443 saveParams
.m_LineEndings
= pView
->GetLineEndings();
1444 saveParams
.m_UnicodeType
= pView
->GetTextType();
1445 file
.SetSaveParams(saveParams
);
1446 for (int i
=0; i
<pViewData
->GetCount(); i
++)
1448 //only copy non-removed lines
1449 DiffState state
= pViewData
->GetState(i
);
1452 case DiffState::Conflicted
:
1453 case DiffState::Conflicted_Ignored
:
1460 } while((last
<pViewData
->GetCount()) && ((pViewData
->GetState(last
)==DiffState::Conflicted
)||(pViewData
->GetState(last
)==DiffState::Conflicted_Ignored
)));
1461 // TortoiseGitMerge changes here
1462 file
.Add(L
"<<<<<<< .mine", m_pwndRightView
->GetLineEndings());
1463 for (int j
=first
; j
<last
; j
++)
1465 EOL lineending
= m_pwndRightView
->m_pViewData
->GetLineEnding(j
);
1466 if (lineending
== EOL::NoEnding
)
1467 lineending
= m_pwndRightView
->GetLineEndings();
1468 file
.Add(m_pwndRightView
->m_pViewData
->GetLine(j
), lineending
);
1470 file
.Add(L
"=======", m_pwndRightView
->GetLineEndings());
1471 for (int j
=first
; j
<last
; j
++)
1473 EOL lineending
= m_pwndLeftView
->m_pViewData
->GetLineEnding(j
);
1474 if (lineending
== EOL::NoEnding
)
1475 lineending
= m_pwndLeftView
->GetLineEndings();
1476 file
.Add(m_pwndLeftView
->m_pViewData
->GetLine(j
), lineending
);
1478 file
.Add(L
">>>>>>> .theirs", m_pwndRightView
->GetLineEndings());
1482 case DiffState::Empty
:
1483 case DiffState::ConflictEmpty
:
1484 case DiffState::IdenticalRemoved
:
1485 case DiffState::Removed
:
1486 case DiffState::TheirsRemoved
:
1487 case DiffState::YoursRemoved
:
1488 case DiffState::ConflictResolvedEmpty
:
1489 // do not save removed lines
1492 file
.Add(pViewData
->GetLine(i
), pViewData
->GetLineEnding(i
));
1496 if (!file
.Save(sFilePath
, false, false))
1498 CMessageBox::Show(m_hWnd
, file
.GetErrorString(), L
"TortoiseGitMerge", MB_ICONERROR
);
1501 if (sFilePath
== m_Data
.m_baseFile
.GetFilename())
1503 m_Data
.m_baseFile
.StoreFileAttributes();
1505 if (sFilePath
== m_Data
.m_theirFile
.GetFilename())
1507 m_Data
.m_theirFile
.StoreFileAttributes();
1509 if (sFilePath
== m_Data
.m_yourFile
.GetFilename())
1511 m_Data
.m_yourFile
.StoreFileAttributes();
1513 /*if (sFilePath == m_Data.m_mergedFile.GetFilename())
1515 m_Data.m_mergedFile.StoreFileAttributes();
1517 m_dlgFilePatches
.SetFileStatusAsPatched(sFilePath
);
1518 if (IsViewGood(m_pwndBottomView
))
1519 m_pwndBottomView
->SetModified(FALSE
);
1520 else if (IsViewGood(m_pwndRightView
))
1521 m_pwndRightView
->SetModified(FALSE
);
1522 CUndo::GetInstance().MarkAsOriginalState(
1524 IsViewGood(m_pwndRightView
) && (pViewData
== m_pwndRightView
->m_pViewData
),
1525 IsViewGood(m_pwndBottomView
) && (pViewData
== m_pwndBottomView
->m_pViewData
));
1526 if (file
.GetCount() == 1 && file
.GetAt(0).IsEmpty() && file
.GetLineEnding(0) == EOL::NoEnding
)
1528 return file
.GetCount();
1533 void CMainFrame::OnFileSave()
1535 // when multiple files are set as writable we have to ask what file to save
1536 int nEditableViewCount
=
1537 (CBaseView::IsViewGood(m_pwndLeftView
) && m_pwndLeftView
->IsWritable() ? 1 : 0)
1538 + (CBaseView::IsViewGood(m_pwndRightView
) && m_pwndRightView
->IsWritable() ? 1 : 0)
1539 + (CBaseView::IsViewGood(m_pwndBottomView
) && m_pwndBottomView
->IsWritable() ? 1 : 0);
1540 bool bLeftIsModified
= CBaseView::IsViewGood(m_pwndLeftView
) && m_pwndLeftView
->IsModified();
1541 bool bRightIsModified
= CBaseView::IsViewGood(m_pwndRightView
) && m_pwndRightView
->IsModified();
1542 bool bBottomIsModified
= CBaseView::IsViewGood(m_pwndBottomView
) && m_pwndBottomView
->IsModified();
1543 int nModifiedViewCount
=
1544 (bLeftIsModified
? 1 : 0)
1545 + (bRightIsModified
? 1 : 0)
1546 + (bBottomIsModified
? 1 : 0);
1547 if (nEditableViewCount
>1)
1549 if (nModifiedViewCount
== 1)
1551 if (bLeftIsModified
)
1552 m_pwndLeftView
->SaveFile(SAVE_REMOVEDLINES
);
1556 else if (nModifiedViewCount
>0)
1559 CTaskDialog
taskdlg(CString(MAKEINTRESOURCE(IDS_SAVE_MORE
)),
1560 CString(MAKEINTRESOURCE(IDS_SAVE
)),
1561 CString(MAKEINTRESOURCE(IDS_APPNAME
)),
1563 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
1565 if (m_pwndLeftView
->m_pWorkingFile
->InUse() && !m_pwndLeftView
->m_pWorkingFile
->IsReadonly())
1566 sTaskTemp
.Format(IDS_ASKFORSAVE_SAVELEFT
, static_cast<LPCWSTR
>(m_pwndLeftView
->m_pWorkingFile
->GetFilename()));
1568 sTaskTemp
= CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS
));
1569 taskdlg
.AddCommandControl(201, sTaskTemp
, bLeftIsModified
);// left
1570 if (bLeftIsModified
)
1571 taskdlg
.SetDefaultCommandControl(201);
1572 if (m_pwndRightView
->m_pWorkingFile
->InUse() && !m_pwndRightView
->m_pWorkingFile
->IsReadonly())
1573 sTaskTemp
.Format(IDS_ASKFORSAVE_SAVERIGHT
, static_cast<LPCWSTR
>(m_pwndRightView
->m_pWorkingFile
->GetFilename()));
1575 sTaskTemp
= CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS
));
1576 taskdlg
.AddCommandControl(202, sTaskTemp
, bRightIsModified
); // right
1577 if (bRightIsModified
)
1578 taskdlg
.SetDefaultCommandControl(202);
1579 taskdlg
.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEALL2
)), nModifiedViewCount
>1); // both
1580 if (nModifiedViewCount
> 1)
1581 taskdlg
.SetDefaultCommandControl(203);
1582 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
1583 taskdlg
.SetMainIcon(TD_WARNING_ICON
);
1584 UINT ret
= static_cast<UINT
>(taskdlg
.DoModal(m_hWnd
));
1588 m_pwndLeftView
->SaveFile(SAVE_REMOVEDLINES
);
1591 m_pwndLeftView
->SaveFile(SAVE_REMOVEDLINES
);
1594 m_pwndRightView
->SaveFile();
1601 // only target view was modified
1606 void CMainFrame::PatchSave()
1608 bool bDoesNotExist
= !PathFileExists(m_Data
.m_mergedFile
.GetFilename());
1609 if (m_Data
.m_bPatchRequired
)
1611 m_Patch
.PatchPath(m_Data
.m_mergedFile
.GetFilename());
1613 if (!PathIsDirectory(m_Data
.m_mergedFile
.GetFilename()))
1615 int saveret
= SaveFile(m_Data
.m_mergedFile
.GetFilename());
1618 // file was saved with 0 lines, remove it.
1619 m_Patch
.RemoveFile(m_Data
.m_mergedFile
.GetFilename());
1621 DeleteFile(m_Data
.m_mergedFile
.GetFilename());
1623 m_Data
.m_mergedFile
.StoreFileAttributes();
1624 if (m_Data
.m_mergedFile
.GetFilename() == m_Data
.m_yourFile
.GetFilename())
1625 m_Data
.m_yourFile
.StoreFileAttributes();
1626 if (bDoesNotExist
&& (DWORD(CRegDWORD(L
"Software\\TortoiseGitMerge\\AutoAdd", TRUE
))))
1628 // call TortoiseProc to add the new file to version control
1629 CString cmd
= L
"/command:add /noui /path:\"";
1630 cmd
+= m_Data
.m_mergedFile
.GetFilename() + L
'"';
1631 CAppUtils::RunTortoiseGitProc(cmd
);
1636 bool CMainFrame::FileSave(bool bCheckResolved
/*=true*/)
1638 if (HasMarkedBlocks())
1640 CString
sTitle(MAKEINTRESOURCE(IDS_WARNMARKEDBLOCKS
));
1641 CString
sSubTitle(MAKEINTRESOURCE(IDS_ASKFORSAVE_MARKEDBLOCKS
));
1642 CString
sAppName(MAKEINTRESOURCE(IDS_APPNAME
));
1643 CTaskDialog
taskdlg(sTitle
,
1647 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
1648 taskdlg
.AddCommandControl(10, CString(MAKEINTRESOURCE(IDS_MARKEDBLOCKSSAVEINCLUDE
)));
1649 taskdlg
.AddCommandControl(11, CString(MAKEINTRESOURCE(IDS_MARKEDBLOCKSSAVEEXCLUDE
)));
1650 taskdlg
.AddCommandControl(12, CString(MAKEINTRESOURCE(IDS_MARKEDBLCOKSSAVEIGNORE
)));
1651 taskdlg
.AddCommandControl(IDCANCEL
, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_CANCEL_OPEN
)));
1652 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
1653 taskdlg
.SetDefaultCommandControl(10);
1654 taskdlg
.SetMainIcon(TD_WARNING_ICON
);
1655 UINT ret
= static_cast<UINT
>(taskdlg
.DoModal(m_hWnd
));
1657 m_pwndRightView
->LeaveOnlyMarkedBlocks();
1659 m_pwndRightView
->UseViewFileOfMarked();
1661 m_pwndRightView
->UseViewFileExceptEdited();
1666 if (!m_Data
.m_mergedFile
.InUse())
1667 return FileSaveAs(bCheckResolved
);
1668 // check if the file has the readonly attribute set
1669 bool bDoesNotExist
= false;
1670 DWORD fAttribs
= GetFileAttributes(m_Data
.m_mergedFile
.GetFilename());
1671 if ((fAttribs
!= INVALID_FILE_ATTRIBUTES
)&&(fAttribs
& FILE_ATTRIBUTE_READONLY
))
1672 return FileSaveAs(bCheckResolved
);
1673 if (fAttribs
== INVALID_FILE_ATTRIBUTES
)
1675 bDoesNotExist
= (GetLastError() == ERROR_FILE_NOT_FOUND
);
1677 if (bCheckResolved
&& HasConflictsWontKeep())
1680 if ((static_cast<DWORD
>(CRegDWORD(L
"Software\\TortoiseGitMerge\\Backup"))) != 0)
1682 MoveFileEx(m_Data
.m_mergedFile
.GetFilename(), m_Data
.m_mergedFile
.GetFilename() + L
".bak", MOVEFILE_COPY_ALLOWED
| MOVEFILE_REPLACE_EXISTING
| MOVEFILE_WRITE_THROUGH
);
1684 if (m_Data
.m_bPatchRequired
)
1686 m_Patch
.PatchPath(m_Data
.m_mergedFile
.GetFilename());
1688 int saveret
= SaveFile(m_Data
.m_mergedFile
.GetFilename());
1691 // file was saved with 0 lines!
1692 // ask the user if the file should be deleted
1694 msg
.Format(IDS_DELETEWHENEMPTY
, static_cast<LPCWSTR
>(CPathUtils::GetFileNameFromPath(m_Data
.m_mergedFile
.GetFilename())));
1695 CTaskDialog
taskdlg(msg
,
1696 CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK2
)),
1697 CString(MAKEINTRESOURCE(IDS_APPNAME
)),
1699 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
1700 taskdlg
.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK3
)));
1701 taskdlg
.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK4
)));
1702 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
1703 taskdlg
.SetDefaultCommandControl(1);
1704 taskdlg
.SetMainIcon(TD_WARNING_ICON
);
1705 if (taskdlg
.DoModal(m_hWnd
) == 1)
1707 m_Patch
.RemoveFile(m_Data
.m_mergedFile
.GetFilename());
1708 DeleteFile(m_Data
.m_mergedFile
.GetFilename());
1711 else if (saveret
< 0)
1713 // error while saving the file
1717 // if we're in conflict resolve mode (three pane view), check if there are no more conflicts
1718 // and if there aren't, ask to mark the file as resolved
1719 if (IsViewGood(m_pwndBottomView
) && !m_bHasConflicts
&& bCheckResolved
)
1721 CString projectRoot
;
1722 if (GitAdminDir::HasAdminDir(m_Data
.m_mergedFile
.GetFilename(), false, &projectRoot
))
1724 CString subpath
= m_Data
.m_mergedFile
.GetFilename();
1725 subpath
.Replace(L
'\\', L
'/');
1726 if (subpath
.GetLength() >= projectRoot
.GetLength())
1728 if (subpath
[projectRoot
.GetLength()] == L
'/')
1729 subpath
= subpath
.Right(subpath
.GetLength() - projectRoot
.GetLength() - 1);
1731 subpath
= subpath
.Right(subpath
.GetLength() - projectRoot
.GetLength());
1734 CAutoRepository
repository(projectRoot
);
1735 bool hasConflictInIndex
= false;
1742 if (git_repository_index(index
.GetPointer(), repository
))
1745 CStringA path
= CUnicodeUtils::GetUTF8(subpath
);
1746 hasConflictInIndex
= git_index_get_bypath(index
, path
, 1) || git_index_get_bypath(index
, path
, 2);
1749 if (hasConflictInIndex
)
1752 msg
.Format(IDS_MARKASRESOLVED
, static_cast<LPCWSTR
>(CPathUtils::GetFileNameFromPath(m_Data
.m_mergedFile
.GetFilename())));
1753 CTaskDialog
taskdlg(msg
,
1754 CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK2
)),
1755 CString(MAKEINTRESOURCE(IDS_APPNAME
)),
1757 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
1758 taskdlg
.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK3
)));
1759 taskdlg
.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK4
)));
1760 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
1761 taskdlg
.SetDefaultCommandControl(1);
1762 taskdlg
.SetMainIcon(TD_WARNING_ICON
);
1763 if (taskdlg
.DoModal(m_hWnd
) == 1)
1769 m_bSaveRequired
= false;
1770 m_Data
.m_mergedFile
.StoreFileAttributes();
1772 if (bDoesNotExist
&& (DWORD(CRegDWORD(L
"Software\\TortoiseGitMerge\\AutoAdd", TRUE
))))
1774 // call TortoiseProc to add the new file to version control
1775 CString cmd
= L
"/command:add /noui /path:\"";
1776 cmd
+= m_Data
.m_mergedFile
.GetFilename() + L
'"';
1777 if(!CAppUtils::RunTortoiseGitProc(cmd
))
1783 void CMainFrame::OnFileSaveAs()
1785 // ask what file to save as
1786 bool bHaveConflict
= (CheckResolved() >= 0);
1787 CTaskDialog
taskdlg(
1788 CString(MAKEINTRESOURCE(bHaveConflict
? IDS_ASKFORSAVEAS_MORECONFLICT
: IDS_ASKFORSAVEAS_MORE
)),
1789 CString(MAKEINTRESOURCE(IDS_ASKFORSAVEAS
)),
1790 CString(MAKEINTRESOURCE(IDS_APPNAME
)),
1792 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
1793 // default can be last view (target) as was in 1.7 or actual (where is cursor) as is in most text editor
1794 if (IsViewGood(m_pwndLeftView
))
1796 taskdlg
.AddCommandControl(201, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS
))); // left
1797 taskdlg
.SetDefaultCommandControl(201);
1799 if (IsViewGood(m_pwndRightView
))
1801 taskdlg
.AddCommandControl(202, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS
))); // right
1802 taskdlg
.SetDefaultCommandControl(202);
1804 if (IsViewGood(m_pwndBottomView
))
1806 taskdlg
.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEBOTTOMAS
))); // bottom
1807 taskdlg
.SetDefaultCommandControl(203);
1811 taskdlg
.AddCommandControl(204, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_NEEDRESOLVE
))); // resolve
1812 taskdlg
.SetDefaultCommandControl(204);
1814 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
1815 taskdlg
.SetMainIcon(bHaveConflict
? TD_WARNING_ICON
: TD_INFORMATION_ICON
);
1816 int nCommand
= static_cast<int>(taskdlg
.DoModal(m_hWnd
));
1821 if (TryGetFileName(sFileName
))
1823 // in 2, 3 view display we want to keep removed lines
1824 m_pwndLeftView
->SaveFileTo(sFileName
, IsViewGood(m_pwndRightView
) ? SAVE_REMOVEDLINES
: 0);
1828 if (TryGetFileName(sFileName
))
1830 m_pwndRightView
->SaveFileTo(sFileName
);
1836 case 204: // continue resolving
1837 if (IsViewGood(m_pwndBottomView
))
1839 m_pwndBottomView
->GoToLine(CheckResolved());
1845 bool CMainFrame::FileSaveAs(bool bCheckResolved
/*=true*/)
1847 if (bCheckResolved
&& HasConflictsWontKeep())
1851 if(!TryGetFileName(fileName
))
1858 void CMainFrame::OnUpdateFileSave(CCmdUI
*pCmdUI
)
1860 BOOL bEnable
= FALSE
;
1861 if (m_Data
.m_mergedFile
.InUse())
1863 if (IsViewGood(m_pwndBottomView
)&&(m_pwndBottomView
->m_pViewData
))
1865 else if ( (IsViewGood(m_pwndRightView
)&&(m_pwndRightView
->m_pViewData
)) &&
1866 (m_pwndRightView
->IsModified() || (m_Data
.m_yourFile
.GetWindowName().Right(static_cast<int>(wcslen(L
": patched"))).Compare(L
": patched") == 0)))
1868 else if (IsViewGood(m_pwndLeftView
)
1869 && (m_pwndLeftView
->m_pViewData
)
1870 && (m_pwndLeftView
->IsModified()))
1873 pCmdUI
->Enable(bEnable
);
1876 void CMainFrame::OnUpdateFileSaveAs(CCmdUI
*pCmdUI
)
1878 // any file is open we can save it as
1879 BOOL bEnable
= FALSE
;
1880 if (IsViewGood(m_pwndBottomView
)&&(m_pwndBottomView
->m_pViewData
))
1882 else if (IsViewGood(m_pwndRightView
)&&(m_pwndRightView
->m_pViewData
))
1884 else if (IsViewGood(m_pwndLeftView
)&&(m_pwndLeftView
->m_pViewData
))
1886 pCmdUI
->Enable(bEnable
);
1889 void CMainFrame::OnUpdateViewOnewaydiff(CCmdUI
*pCmdUI
)
1891 pCmdUI
->SetCheck(!m_bOneWay
);
1892 BOOL bEnable
= TRUE
;
1893 if (IsViewGood(m_pwndBottomView
))
1897 pCmdUI
->Enable(bEnable
);
1900 void CMainFrame::OnViewOptions()
1903 sTemp
.LoadString(IDS_SETTINGSTITLE
);
1904 using SetThreadDpiAwarenessContextProc
= DPI_AWARENESS_CONTEXT(WINAPI
*)(DPI_AWARENESS_CONTEXT
);
1905 SetThreadDpiAwarenessContextProc SetThreadDpiAwarenessContext
= reinterpret_cast<SetThreadDpiAwarenessContextProc
>(GetProcAddress(GetModuleHandle(L
"user32"), "SetThreadDpiAwarenessContext"));
1906 DPI_AWARENESS_CONTEXT oldDpiAwareness
= DPI_AWARENESS_CONTEXT_UNAWARE
;
1907 // dialog does not work well with different dpi settings, disable awareness
1908 if (SetThreadDpiAwarenessContext
)
1909 oldDpiAwareness
= SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE
);
1910 CSettings
dlg(sTemp
);
1912 if (SetThreadDpiAwarenessContext
)
1913 SetThreadDpiAwarenessContext(oldDpiAwareness
);
1914 CTheme::Instance().SetDarkTheme(dlg
.IsDarkMode());
1915 if (dlg
.IsReloadNeeded())
1917 if (CheckForSave(ECheckForSaveReason::Options
)==IDCANCEL
)
1919 CDiffColors::GetInstance().LoadRegistry();
1923 CDiffColors::GetInstance().LoadRegistry();
1924 if (m_pwndBottomView
)
1925 m_pwndBottomView
->DocumentUpdated();
1927 m_pwndLeftView
->DocumentUpdated();
1928 if (m_pwndRightView
)
1929 m_pwndRightView
->DocumentUpdated();
1932 void CMainFrame::OnClose()
1934 if (!IsWindowEnabled())
1935 return; // just in case someone sends a WM_CLOSE to the main window while another window (dialog,...) is open
1936 if (CheckForSave(ECheckForSaveReason::Close
)!=IDCANCEL
)
1940 // before it is destroyed, save the position of the window
1941 wp
.length
= sizeof wp
;
1943 if (GetWindowPlacement(&wp
))
1947 // never restore to Iconic state
1948 wp
.showCmd
= SW_SHOW
;
1950 if ((wp
.flags
& WPF_RESTORETOMAXIMIZED
) != 0)
1951 // if maximized and maybe iconic restore maximized state
1952 wp
.showCmd
= SW_SHOWMAXIMIZED
;
1955 WriteWindowPlacement(&wp
);
1961 void CMainFrame::OnActivate(UINT nValue
, CWnd
* /*pwnd*/, BOOL
/*bActivated?*/)
1963 if (nValue
!= 0) // activated
1967 m_bCheckReload
= TRUE
;
1971 // use a timer to give other messages time to get processed
1972 // first, like e.g. the WM_CLOSE message in case the user
1973 // clicked the close button and that brought the window
1974 // to the front - in that case checking for reload wouldn't
1976 SetTimer(IDT_RELOADCHECKTIMER
, 300, nullptr);
1981 void CMainFrame::OnViewLinedown()
1983 OnViewLineUpDown(1);
1986 void CMainFrame::OnViewLineup()
1988 OnViewLineUpDown(-1);
1991 void CMainFrame::OnViewLineUpDown(int direction
)
1994 m_pwndLeftView
->ScrollToLine(m_pwndLeftView
->m_nTopLine
+direction
);
1995 if (m_pwndRightView
)
1996 m_pwndRightView
->ScrollToLine(m_pwndRightView
->m_nTopLine
+direction
);
1997 if (m_pwndBottomView
)
1998 m_pwndBottomView
->ScrollToLine(m_pwndBottomView
->m_nTopLine
+direction
);
1999 m_wndLocatorBar
.Invalidate();
2000 m_nMoveMovesToIgnore
= MOVESTOIGNORE
;
2003 void CMainFrame::OnViewLineleft()
2005 OnViewLineLeftRight(-1);
2008 void CMainFrame::OnViewLineright()
2010 OnViewLineLeftRight(1);
2013 void CMainFrame::OnViewLineLeftRight(int direction
)
2016 m_pwndLeftView
->ScrollSide(direction
);
2017 if (m_pwndRightView
)
2018 m_pwndRightView
->ScrollSide(direction
);
2019 if (m_pwndBottomView
)
2020 m_pwndBottomView
->ScrollSide(direction
);
2023 void CMainFrame::OnEditUseTheirs()
2025 if (m_pwndBottomView
)
2026 m_pwndBottomView
->UseTheirTextBlock();
2028 void CMainFrame::OnUpdateEditUsetheirblock(CCmdUI
*pCmdUI
)
2030 pCmdUI
->Enable(m_pwndBottomView
&& m_pwndBottomView
->HasSelection());
2033 void CMainFrame::OnEditUseMine()
2035 if (m_pwndBottomView
)
2036 m_pwndBottomView
->UseMyTextBlock();
2038 void CMainFrame::OnUpdateEditUsemyblock(CCmdUI
*pCmdUI
)
2040 OnUpdateEditUsetheirblock(pCmdUI
);
2043 void CMainFrame::OnEditUseTheirsThenMine()
2045 if (m_pwndBottomView
)
2046 m_pwndBottomView
->UseTheirAndYourBlock();
2049 void CMainFrame::OnUpdateEditUsetheirthenmyblock(CCmdUI
*pCmdUI
)
2051 OnUpdateEditUsetheirblock(pCmdUI
);
2054 void CMainFrame::OnEditUseMineThenTheirs()
2056 if (m_pwndBottomView
)
2057 m_pwndBottomView
->UseYourAndTheirBlock();
2060 void CMainFrame::OnUpdateEditUseminethentheirblock(CCmdUI
*pCmdUI
)
2062 OnUpdateEditUsetheirblock(pCmdUI
);
2065 void CMainFrame::OnEditUseleftblock()
2067 if (m_pwndBottomView
->IsWindowVisible())
2068 m_pwndBottomView
->UseRightBlock();
2070 m_pwndRightView
->UseLeftBlock();
2073 void CMainFrame::OnUpdateEditUseleftblock(CCmdUI
*pCmdUI
)
2075 pCmdUI
->Enable(IsViewGood(m_pwndRightView
) && m_pwndRightView
->IsTarget() && m_pwndRightView
->HasSelection());
2078 void CMainFrame::OnUpdateUseBlock(CCmdUI
*pCmdUI
)
2080 pCmdUI
->Enable(TRUE
);
2083 void CMainFrame::OnEditUseleftfile()
2085 if (m_pwndBottomView
->IsWindowVisible())
2086 m_pwndBottomView
->UseRightFile();
2088 m_pwndRightView
->UseLeftFile();
2091 void CMainFrame::OnUpdateEditUseleftfile(CCmdUI
*pCmdUI
)
2093 pCmdUI
->Enable(IsViewGood(m_pwndRightView
) && m_pwndRightView
->IsTarget());
2096 void CMainFrame::OnEditUseblockfromleftbeforeright()
2098 if (m_pwndRightView
)
2099 m_pwndRightView
->UseBothLeftFirst();
2102 void CMainFrame::OnUpdateEditUseblockfromleftbeforeright(CCmdUI
*pCmdUI
)
2104 OnUpdateEditUseleftblock(pCmdUI
);
2107 void CMainFrame::OnEditUseblockfromrightbeforeleft()
2109 if (m_pwndRightView
)
2110 m_pwndRightView
->UseBothRightFirst();
2113 void CMainFrame::OnUpdateEditUseblockfromrightbeforeleft(CCmdUI
*pCmdUI
)
2115 OnUpdateEditUseleftblock(pCmdUI
);
2118 void CMainFrame::OnFileReload()
2120 if (CheckForSave(ECheckForSaveReason::Reload
)==IDCANCEL
)
2122 CDiffColors::GetInstance().LoadRegistry();
2126 void CMainFrame::ActivateFrame(int nCmdShow
)
2128 // nCmdShow is the normal show mode this frame should be in
2129 // translate default nCmdShow (-1)
2132 if (!IsWindowVisible())
2133 nCmdShow
= SW_SHOWNORMAL
;
2134 else if (IsIconic())
2135 nCmdShow
= SW_RESTORE
;
2138 // bring to top before showing
2139 BringToTop(nCmdShow
);
2143 // show the window as specified
2146 if ( !ReadWindowPlacement(&wp
) )
2148 ShowWindow(nCmdShow
);
2152 if ( nCmdShow
!= SW_SHOWNORMAL
)
2153 wp
.showCmd
= nCmdShow
;
2155 SetWindowPlacement(&wp
);
2158 // and finally, bring to top after showing
2159 BringToTop(nCmdShow
);
2161 CTheme::Instance().SetDarkTheme(CTheme::Instance().IsDarkTheme());
2164 BOOL
CMainFrame::ReadWindowPlacement(WINDOWPLACEMENT
* pwp
)
2166 CRegString placement
= CRegString(CString(L
"Software\\TortoiseGitMerge\\WindowPos_") + GetMonitorSetupHash().c_str());
2167 CString sPlacement
= placement
;
2168 if (sPlacement
.IsEmpty())
2170 int nRead
= swscanf_s(sPlacement
, L
"%u,%u,%d,%d,%d,%d,%d,%d,%d,%d",
2171 &pwp
->flags
, &pwp
->showCmd
,
2172 &pwp
->ptMinPosition
.x
, &pwp
->ptMinPosition
.y
,
2173 &pwp
->ptMaxPosition
.x
, &pwp
->ptMaxPosition
.y
,
2174 &pwp
->rcNormalPosition
.left
, &pwp
->rcNormalPosition
.top
,
2175 &pwp
->rcNormalPosition
.right
, &pwp
->rcNormalPosition
.bottom
);
2178 pwp
->length
= sizeof(WINDOWPLACEMENT
);
2180 CDPIAware::Instance().ScaleWindowPlacement(GetSafeHwnd(), pwp
);
2185 void CMainFrame::WriteWindowPlacement(WINDOWPLACEMENT
* pwp
)
2187 CRegString
placement(CString(L
"Software\\TortoiseGitMerge\\WindowPos_") + GetMonitorSetupHash().c_str());
2188 wchar_t szBuffer
[_countof("-32767") * 8 + sizeof("65535") * 2];
2190 CDPIAware::Instance().UnscaleWindowPlacement(GetSafeHwnd(), pwp
);
2192 swprintf_s(szBuffer
, L
"%u,%u,%d,%d,%d,%d,%d,%d,%d,%d",
2193 pwp
->flags
, pwp
->showCmd
,
2194 pwp
->ptMinPosition
.x
, pwp
->ptMinPosition
.y
,
2195 pwp
->ptMaxPosition
.x
, pwp
->ptMaxPosition
.y
,
2196 pwp
->rcNormalPosition
.left
, pwp
->rcNormalPosition
.top
,
2197 pwp
->rcNormalPosition
.right
, pwp
->rcNormalPosition
.bottom
);
2198 placement
= szBuffer
;
2201 void CMainFrame::OnUpdateMergeMarkasresolved(CCmdUI
*pCmdUI
)
2205 BOOL bEnable
= FALSE
;
2206 if ((!m_bReadOnly
)&&(m_Data
.m_mergedFile
.InUse()))
2208 if (IsViewGood(m_pwndBottomView
)&&(m_pwndBottomView
->m_pViewData
))
2210 bEnable
= !m_bMarkedAsResolvedWasDone
;
2213 pCmdUI
->Enable(bEnable
);
2216 void CMainFrame::OnMergeMarkasresolved()
2218 if(HasConflictsWontKeep())
2221 // now check if the file has already been saved and if not, save it.
2222 if (m_Data
.m_mergedFile
.InUse())
2224 if (IsViewGood(m_pwndBottomView
)&&(m_pwndBottomView
->m_pViewData
))
2226 if (!FileSave(false))
2228 m_bSaveRequired
= false;
2234 BOOL
CMainFrame::MarkAsResolved()
2238 if (!IsViewGood(m_pwndBottomView
))
2240 if (m_bMarkedAsResolvedWasDone
)
2243 CString cmd
= L
"/command:resolve /path:\"";
2244 cmd
+= m_Data
.m_mergedFile
.GetFilename();
2245 cmd
+= L
"\" /closeonend:1 /noquestion /skipcheck /silent";
2249 s
.Format(L
" /resolvemsghwnd:%I64d /resolvemsgwparam:%I64d /resolvemsglparam:%I64d", reinterpret_cast<__int64
>(resolveMsgWnd
), static_cast<__int64
>(resolveMsgWParam
), static_cast<__int64
>(resolveMsgLParam
));
2252 if(!CAppUtils::RunTortoiseGitProc(cmd
))
2254 m_bSaveRequired
= false;
2255 m_bMarkedAsResolvedWasDone
= true;
2259 void CMainFrame::OnUpdateMergeNextconflict(CCmdUI
*pCmdUI
)
2262 if (HasNextConflict(m_pwndBottomView
))
2264 else if (HasNextConflict(m_pwndRightView
))
2266 else if (HasNextConflict(m_pwndLeftView
))
2268 pCmdUI
->Enable(bShow
);
2271 bool CMainFrame::HasNextConflict(CBaseView
* view
)
2275 if (!view
->IsTarget())
2277 return view
->HasNextConflict();
2280 void CMainFrame::OnUpdateMergePreviousconflict(CCmdUI
*pCmdUI
)
2283 if (HasPrevConflict(m_pwndBottomView
))
2285 else if (HasPrevConflict(m_pwndRightView
))
2287 else if (HasPrevConflict(m_pwndLeftView
))
2289 pCmdUI
->Enable(bShow
);
2292 bool CMainFrame::HasPrevConflict(CBaseView
* view
)
2296 if (!view
->IsTarget())
2298 return view
->HasPrevConflict();
2301 void CMainFrame::OnUpdateNavigateNextdifference(CCmdUI
*pCmdUI
)
2303 CBaseView
* baseView
= GetActiveBaseView();
2306 bShow
= baseView
->HasNextDiff();
2307 pCmdUI
->Enable(bShow
);
2310 void CMainFrame::OnUpdateNavigatePreviousdifference(CCmdUI
*pCmdUI
)
2312 CBaseView
* baseView
= GetActiveBaseView();
2315 bShow
= baseView
->HasPrevDiff();
2316 pCmdUI
->Enable(bShow
);
2319 void CMainFrame::OnUpdateNavigateNextinlinediff(CCmdUI
*pCmdUI
)
2322 if (HasNextInlineDiff(m_pwndBottomView
))
2324 else if (HasNextInlineDiff(m_pwndRightView
))
2326 else if (HasNextInlineDiff(m_pwndLeftView
))
2328 pCmdUI
->Enable(bShow
);
2331 bool CMainFrame::HasNextInlineDiff(CBaseView
* view
)
2335 if (!view
->IsTarget())
2337 return view
->HasNextInlineDiff();
2340 void CMainFrame::OnUpdateNavigatePrevinlinediff(CCmdUI
*pCmdUI
)
2343 if (HasPrevInlineDiff(m_pwndBottomView
))
2345 else if (HasPrevInlineDiff(m_pwndRightView
))
2347 else if (HasPrevInlineDiff(m_pwndLeftView
))
2349 pCmdUI
->Enable(bShow
);
2352 bool CMainFrame::HasPrevInlineDiff(CBaseView
* view
)
2356 if (!view
->IsTarget())
2358 return view
->HasPrevInlineDiff();
2361 void CMainFrame::OnMoving(UINT fwSide
, LPRECT pRect
)
2363 m_dlgFilePatches
.ParentOnMoving(m_hWnd
, pRect
);
2364 __super::OnMoving(fwSide
, pRect
);
2367 void CMainFrame::OnUpdateEditCopy(CCmdUI
*pCmdUI
)
2370 if ((m_pwndBottomView
)&&(m_pwndBottomView
->HasSelection()))
2372 else if ((m_pwndRightView
)&&(m_pwndRightView
->HasSelection()))
2374 else if ((m_pwndLeftView
)&&(m_pwndLeftView
->HasSelection()))
2376 pCmdUI
->Enable(bShow
);
2379 void CMainFrame::OnUpdateEditPaste(CCmdUI
*pCmdUI
)
2381 BOOL bWritable
= FALSE
;
2382 if ((m_pwndBottomView
)&&(m_pwndBottomView
->IsWritable()))
2384 else if ((m_pwndRightView
)&&(m_pwndRightView
->IsWritable()))
2386 else if ((m_pwndLeftView
)&&(m_pwndLeftView
->IsWritable()))
2388 pCmdUI
->Enable(bWritable
&& (::IsClipboardFormatAvailable(CF_TEXT
) || ::IsClipboardFormatAvailable(CF_UNICODETEXT
)));
2391 void CMainFrame::OnViewSwitchleft()
2393 if (CheckForSave(ECheckForSaveReason::Switch
)!=IDCANCEL
)
2395 CWorkingFile file
= m_Data
.m_baseFile
;
2396 m_Data
.m_baseFile
= m_Data
.m_yourFile
;
2397 m_Data
.m_yourFile
= file
;
2398 if (m_Data
.m_mergedFile
.GetFilename().CompareNoCase(m_Data
.m_yourFile
.GetFilename())==0)
2400 m_Data
.m_mergedFile
= m_Data
.m_baseFile
;
2402 else if (m_Data
.m_mergedFile
.GetFilename().CompareNoCase(m_Data
.m_baseFile
.GetFilename())==0)
2404 m_Data
.m_mergedFile
= m_Data
.m_yourFile
;
2410 void CMainFrame::OnUpdateViewSwitchleft(CCmdUI
*pCmdUI
)
2412 BOOL bEnable
= !IsViewGood(m_pwndBottomView
);
2413 pCmdUI
->Enable(bEnable
);
2416 void CMainFrame::OnUpdateViewShowfilelist(CCmdUI
*pCmdUI
)
2418 BOOL bEnable
= m_dlgFilePatches
.HasFiles();
2419 pCmdUI
->Enable(bEnable
);
2420 pCmdUI
->SetCheck(m_dlgFilePatches
.IsWindowVisible());
2423 void CMainFrame::OnViewShowfilelist()
2425 m_dlgFilePatches
.ShowWindow(m_dlgFilePatches
.IsWindowVisible() ? SW_HIDE
: SW_SHOW
);
2428 void CMainFrame::OnEditUndo()
2430 if (CUndo::GetInstance().CanUndo())
2432 CUndo::GetInstance().Undo(m_pwndLeftView
, m_pwndRightView
, m_pwndBottomView
);
2436 void CMainFrame::OnUpdateEditUndo(CCmdUI
*pCmdUI
)
2438 pCmdUI
->Enable(CUndo::GetInstance().CanUndo());
2441 void CMainFrame::OnEditRedo()
2443 if (CUndo::GetInstance().CanRedo())
2445 CUndo::GetInstance().Redo(m_pwndLeftView
, m_pwndRightView
, m_pwndBottomView
);
2449 void CMainFrame::OnUpdateEditRedo(CCmdUI
*pCmdUI
)
2451 pCmdUI
->Enable(CUndo::GetInstance().CanRedo());
2454 void CMainFrame::OnEditEnable()
2456 CBaseView
* pView
= GetActiveBaseView();
2457 if (pView
&& pView
->IsReadonlyChangable())
2459 bool isReadOnly
= pView
->IsReadonly();
2460 pView
->SetReadonly(!isReadOnly
);
2464 void CMainFrame::OnUpdateEditEnable(CCmdUI
*pCmdUI
)
2466 CBaseView
* pView
= GetActiveBaseView();
2469 pCmdUI
->Enable(pView
->IsReadonlyChangable() || !pView
->IsReadonly());
2470 pCmdUI
->SetCheck(!pView
->IsReadonly());
2474 pCmdUI
->Enable(FALSE
);
2478 void CMainFrame::OnIndicatorLeftview()
2482 if (IsViewGood(m_pwndLeftView
))
2484 m_pwndLeftView
->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_LEFTVIEW
);
2488 void CMainFrame::OnIndicatorRightview()
2492 if (IsViewGood(m_pwndRightView
))
2494 m_pwndRightView
->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_RIGHTVIEW
);
2498 void CMainFrame::OnIndicatorBottomview()
2502 if (IsViewGood(m_pwndBottomView
))
2504 m_pwndBottomView
->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_BOTTOMVIEW
);
2508 int CMainFrame::CheckForReload()
2510 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
2516 bool bSourceChanged
=
2517 m_Data
.m_baseFile
.HasSourceFileChanged()
2518 || m_Data
.m_yourFile
.HasSourceFileChanged()
2519 || m_Data
.m_theirFile
.HasSourceFileChanged()
2520 /*|| m_Data.m_mergedFile.HasSourceFileChanged()*/;
2521 if (!bSourceChanged
)
2527 CString msg
= HasUnsavedEdits() ? CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDELOOSECHANGES
)) : CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE
));
2528 CTaskDialog
taskdlg(msg
,
2529 CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE_TASK2
)),
2530 L
"TortoiseGitMerge",
2532 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
2534 if (HasUnsavedEdits())
2535 sTask3
.LoadString(IDS_WARNMODIFIEDOUTSIDE_TASK3
);
2537 sTask3
.LoadString(IDS_WARNMODIFIEDOUTSIDE_TASK4
);
2538 taskdlg
.AddCommandControl(IDYES
, sTask3
);
2539 taskdlg
.AddCommandControl(IDNO
, CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE_TASK5
)));
2540 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
2541 taskdlg
.SetDefaultCommandControl(IDYES
);
2542 taskdlg
.SetMainIcon(TD_WARNING_ICON
);
2543 UINT ret
= static_cast<UINT
>(taskdlg
.DoModal(m_hWnd
));
2546 CDiffColors::GetInstance().LoadRegistry();
2551 if (IsViewGood(m_pwndBottomView
)) // three pane view
2553 /*if (m_Data.m_sourceFile.HasSourceFileChanged())
2554 m_pwndBottomView->SetModified();
2555 if (m_Data.m_mergedFile.HasSourceFileChanged())
2556 m_pwndBottomView->SetModified();//*/
2557 if (m_Data
.m_yourFile
.HasSourceFileChanged())
2558 m_pwndRightView
->SetModified();
2559 if (m_Data
.m_theirFile
.HasSourceFileChanged())
2560 m_pwndLeftView
->SetModified();
2562 else if (IsViewGood(m_pwndRightView
)) // two pane view
2564 if (m_Data
.m_baseFile
.HasSourceFileChanged())
2565 m_pwndLeftView
->SetModified();
2566 if (m_Data
.m_yourFile
.HasSourceFileChanged())
2567 m_pwndRightView
->SetModified();
2571 if (m_Data
.m_yourFile
.HasSourceFileChanged())
2572 m_pwndLeftView
->SetModified();
2575 // no reload just store updated file time
2576 m_Data
.m_baseFile
.StoreFileAttributes();
2577 m_Data
.m_theirFile
.StoreFileAttributes();
2578 m_Data
.m_yourFile
.StoreFileAttributes();
2579 //m_Data.m_mergedFile.StoreFileAttributes();
2585 int CMainFrame::CheckForSave(ECheckForSaveReason eReason
)
2587 int idTitle
= IDS_WARNMODIFIEDLOOSECHANGES
;
2588 int idNoSave
= IDS_ASKFORSAVE_TASK7
;
2589 int idCancelAction
= IDS_ASKFORSAVE_CANCEL_OPEN
;
2592 case ECheckForSaveReason::Close
:
2593 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2594 idNoSave
= IDS_ASKFORSAVE_TASK4
;
2595 idCancelAction
= IDS_ASKFORSAVE_TASK5
;
2597 case ECheckForSaveReason::Switch
:
2598 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2599 //idNoSave = IDS_ASKFORSAVE_TASK7;
2600 idCancelAction
= IDS_ASKFORSAVE_TASK8
;
2602 case ECheckForSaveReason::Reload
:
2603 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2604 //idNoSave = IDS_ASKFORSAVE_TASK7;
2605 idCancelAction
= IDS_ASKFORSAVE_CANCEL_OPEN
;
2607 case ECheckForSaveReason::Options
:
2608 idTitle
= IDS_WARNMODIFIEDLOOSECHANGESOPTIONS
;
2609 //idNoSave = IDS_ASKFORSAVE_TASK7;
2610 idCancelAction
= IDS_ASKFORSAVE_CANCEL_OPTIONS
;
2612 case ECheckForSaveReason::Open
:
2613 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2614 idNoSave
= IDS_ASKFORSAVE_NOSAVE_OPEN
;
2615 idCancelAction
= IDS_ASKFORSAVE_CANCEL_OPEN
;
2619 CString
sTitle(MAKEINTRESOURCE(idTitle
));
2620 CString
sSubTitle(MAKEINTRESOURCE(IDS_ASKFORSAVE_TASK2
));
2621 CString
sNoSave(MAKEINTRESOURCE(idNoSave
));
2622 CString
sCancelAction(MAKEINTRESOURCE(idCancelAction
));
2623 CString
sAppName(MAKEINTRESOURCE(IDS_APPNAME
));
2625 // TODO simplify logic, reduce code duplication
2626 if (CBaseView::IsViewGood(m_pwndBottomView
))
2628 // three-way diff - by design only bottom can be changed
2629 // use 1.7 way to do that
2631 else if (CBaseView::IsViewGood(m_pwndRightView
))
2634 // 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
2635 if (HasUnsavedEdits(m_pwndLeftView
))
2638 CTaskDialog
taskdlg(sTitle
,
2642 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
2644 if (m_pwndLeftView
->m_pWorkingFile
->InUse() && !m_pwndLeftView
->m_pWorkingFile
->IsReadonly())
2645 sTaskTemp
.Format(IDS_ASKFORSAVE_SAVELEFT
, static_cast<LPCWSTR
>(m_pwndLeftView
->m_pWorkingFile
->GetFilename()));
2647 sTaskTemp
= CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS
));
2648 taskdlg
.AddCommandControl(201, sTaskTemp
); // left
2649 taskdlg
.SetDefaultCommandControl(201);
2650 if (HasUnsavedEdits(m_pwndRightView
))
2652 if (m_pwndRightView
->m_pWorkingFile
->InUse() && !m_pwndRightView
->m_pWorkingFile
->IsReadonly())
2653 sTaskTemp
.Format(IDS_ASKFORSAVE_SAVERIGHT
, static_cast<LPCWSTR
>(m_pwndRightView
->m_pWorkingFile
->GetFilename()));
2655 sTaskTemp
= CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS
));
2656 taskdlg
.AddCommandControl(202, sTaskTemp
); // right
2657 taskdlg
.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEALL2
))); // both
2658 taskdlg
.SetDefaultCommandControl(203);
2660 taskdlg
.AddCommandControl(IDNO
, sNoSave
); // none
2661 taskdlg
.AddCommandControl(IDCANCEL
, sCancelAction
); // cancel
2662 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
2663 taskdlg
.SetMainIcon(TD_WARNING_ICON
);
2664 UINT ret
= static_cast<UINT
>(taskdlg
.DoModal(m_hWnd
));
2668 m_pwndLeftView
->SaveFile(SAVE_REMOVEDLINES
);
2671 m_pwndLeftView
->SaveFile(SAVE_REMOVEDLINES
);
2674 m_pwndRightView
->SaveFile();
2677 if (ret
!= IDCANCEL
&& (eReason
== ECheckForSaveReason::Close
|| eReason
== ECheckForSaveReason::Open
))
2678 DeleteBaseTheirsMineOnClose();
2683 // only secondary (left) view
2685 // only right view - 1.7 implementation is used
2687 else if (CBaseView::IsViewGood(m_pwndLeftView
))
2689 // only one view - only one to save
2690 // 1.7 FileSave don't support this mode
2691 if (HasUnsavedEdits(m_pwndLeftView
))
2693 CTaskDialog
taskdlg(sTitle
,
2697 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
2699 if (m_Data
.m_mergedFile
.InUse())
2700 sTask3
.Format(IDS_ASKFORSAVE_TASK3
, static_cast<LPCWSTR
>(m_Data
.m_mergedFile
.GetFilename()));
2702 sTask3
.LoadString(IDS_ASKFORSAVE_TASK6
);
2703 taskdlg
.AddCommandControl(IDYES
, sTask3
);
2704 taskdlg
.AddCommandControl(IDNO
, sNoSave
);
2705 taskdlg
.AddCommandControl(IDCANCEL
, sCancelAction
);
2706 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
2707 taskdlg
.SetDefaultCommandControl(IDYES
);
2708 taskdlg
.SetMainIcon(TD_WARNING_ICON
);
2709 if (static_cast<UINT
>(taskdlg
.DoModal(m_hWnd
)) == IDYES
)
2711 if (m_pwndLeftView
->SaveFile()<0)
2715 if (eReason
== ECheckForSaveReason::Close
|| eReason
== ECheckForSaveReason::Open
)
2716 DeleteBaseTheirsMineOnClose();
2721 if (eReason
== ECheckForSaveReason::Close
|| eReason
== ECheckForSaveReason::Open
)
2722 DeleteBaseTheirsMineOnClose();
2723 return IDNO
; // nothing to save
2726 // 1.7 implementation
2728 if (HasUnsavedEdits())
2730 CTaskDialog
taskdlg(sTitle
,
2734 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
2736 if (m_Data
.m_mergedFile
.InUse())
2737 sTask3
.Format(IDS_ASKFORSAVE_TASK3
, static_cast<LPCWSTR
>(m_Data
.m_mergedFile
.GetFilename()));
2739 sTask3
.LoadString(IDS_ASKFORSAVE_TASK6
);
2740 taskdlg
.AddCommandControl(IDYES
, sTask3
);
2741 taskdlg
.AddCommandControl(IDNO
, sNoSave
);
2742 taskdlg
.AddCommandControl(IDCANCEL
, sCancelAction
);
2743 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
2744 taskdlg
.SetDefaultCommandControl(IDYES
);
2745 taskdlg
.SetMainIcon(TD_WARNING_ICON
);
2746 ret
= static_cast<UINT
>(taskdlg
.DoModal(m_hWnd
));
2755 if (ret
!= IDCANCEL
&& (eReason
== ECheckForSaveReason::Close
|| eReason
== ECheckForSaveReason::Open
))
2756 DeleteBaseTheirsMineOnClose();
2761 void CMainFrame::DeleteBaseTheirsMineOnClose()
2763 if (!m_bDeleteBaseTheirsMineOnClose
)
2766 m_bDeleteBaseTheirsMineOnClose
= false;
2768 DeleteFile(m_Data
.m_baseFile
.GetFilename());
2769 DeleteFile(m_Data
.m_theirFile
.GetFilename());
2770 DeleteFile(m_Data
.m_yourFile
.GetFilename());
2773 bool CMainFrame::HasUnsavedEdits() const
2775 return HasUnsavedEdits(m_pwndBottomView
) || HasUnsavedEdits(m_pwndRightView
) || m_bSaveRequired
;
2778 bool CMainFrame::HasUnsavedEdits(const CBaseView
* view
)
2780 if (!CBaseView::IsViewGood(view
))
2782 return view
->IsModified();
2785 bool CMainFrame::HasMarkedBlocks() const
2787 return CBaseView::IsViewGood(m_pwndRightView
) && m_pwndRightView
->HasMarkedBlocks();
2790 bool CMainFrame::IsViewGood(const CBaseView
* view
)
2792 return CBaseView::IsViewGood(view
);
2795 void CMainFrame::OnViewInlinediffword()
2797 m_bInlineWordDiff
= !m_bInlineWordDiff
;
2800 m_pwndLeftView
->SetInlineWordDiff(m_bInlineWordDiff
);
2801 m_pwndLeftView
->BuildAllScreen2ViewVector();
2802 m_pwndLeftView
->DocumentUpdated();
2804 if (m_pwndRightView
)
2806 m_pwndRightView
->SetInlineWordDiff(m_bInlineWordDiff
);
2807 m_pwndRightView
->BuildAllScreen2ViewVector();
2808 m_pwndRightView
->DocumentUpdated();
2810 if (m_pwndBottomView
)
2812 m_pwndBottomView
->SetInlineWordDiff(m_bInlineWordDiff
);
2813 m_pwndBottomView
->BuildAllScreen2ViewVector();
2814 m_pwndBottomView
->DocumentUpdated();
2816 m_wndLineDiffBar
.DocumentUpdated();
2819 void CMainFrame::OnUpdateViewInlinediffword(CCmdUI
*pCmdUI
)
2821 pCmdUI
->Enable(m_bInlineDiff
&& IsViewGood(m_pwndLeftView
) && IsViewGood(m_pwndRightView
));
2822 pCmdUI
->SetCheck(m_bInlineWordDiff
);
2825 void CMainFrame::OnViewInlinediff()
2827 m_bInlineDiff
= !m_bInlineDiff
;
2830 m_pwndLeftView
->SetInlineDiff(m_bInlineDiff
);
2831 m_pwndLeftView
->BuildAllScreen2ViewVector();
2832 m_pwndLeftView
->DocumentUpdated();
2834 if (m_pwndRightView
)
2836 m_pwndRightView
->SetInlineDiff(m_bInlineDiff
);
2837 m_pwndRightView
->BuildAllScreen2ViewVector();
2838 m_pwndRightView
->DocumentUpdated();
2840 if (m_pwndBottomView
)
2842 m_pwndBottomView
->SetInlineDiff(m_bInlineDiff
);
2843 m_pwndBottomView
->BuildAllScreen2ViewVector();
2844 m_pwndBottomView
->DocumentUpdated();
2846 m_wndLineDiffBar
.DocumentUpdated();
2849 void CMainFrame::OnUpdateViewInlinediff(CCmdUI
*pCmdUI
)
2851 pCmdUI
->Enable(IsViewGood(m_pwndLeftView
) && IsViewGood(m_pwndRightView
));
2852 pCmdUI
->SetCheck(m_bInlineDiff
);
2855 void CMainFrame::OnUpdateEditCreateunifieddifffile(CCmdUI
*pCmdUI
)
2857 // "create unified diff file" is only available if two files
2858 // are diffed, not three.
2859 bool bEnabled
= true;
2860 if (!IsViewGood(m_pwndLeftView
))
2862 else if (!IsViewGood(m_pwndRightView
))
2864 else if (IsViewGood(m_pwndBottomView
)) //no negation here
2866 pCmdUI
->Enable(bEnabled
);
2869 void CMainFrame::OnEditCreateunifieddifffile()
2871 CString origFile
, modifiedFile
;
2872 CString origReflected
, modifiedReflected
;
2873 // the original file is the one on the left
2876 origFile
= m_pwndLeftView
->m_sFullFilePath
;
2877 origReflected
= m_pwndLeftView
->m_sReflectedName
;
2879 if (m_pwndRightView
)
2881 modifiedFile
= m_pwndRightView
->m_sFullFilePath
;
2882 modifiedReflected
= m_pwndRightView
->m_sReflectedName
;
2884 if (origFile
.IsEmpty() || modifiedFile
.IsEmpty())
2888 if(!TryGetFileName(outputFile
))
2891 CRegStdDWORD
regContextLines(L
"Software\\TortoiseGitMerge\\ContextLines", static_cast<DWORD
>(-1));
2892 CAppUtils::CreateUnifiedDiff(origFile
, modifiedFile
, outputFile
, regContextLines
, true);
2893 // from here a hacky solution exchanges the paths included in the patch, see issue #2541
2894 if (origReflected
.IsEmpty() || modifiedReflected
.IsEmpty())
2896 CString projectDir1
, projectDir2
;
2897 if (!GitAdminDir::HasAdminDir(origReflected
, &projectDir1
) || !GitAdminDir::HasAdminDir(modifiedReflected
, &projectDir2
) || projectDir1
!= projectDir2
)
2899 CStringA origReflectedA
= CUnicodeUtils::GetUTF8(origReflected
.Mid(projectDir1
.GetLength() + 1));
2900 CStringA modifiedReflectedA
= CUnicodeUtils::GetUTF8(modifiedReflected
.Mid(projectDir1
.GetLength() + 1));
2901 origReflectedA
.Replace('\\', '/');
2902 modifiedReflectedA
.Replace('\\', '/');
2905 CStdioFile
file(outputFile
, CFile::typeBinary
| CFile::modeReadWrite
| CFile::shareExclusive
); // w/o typeBinary \r gets dropped for some files
2906 if (file
.GetLength() >= INT_MAX
)
2908 CMessageBox::Show(GetSafeHwnd(), IDS_ERR_FILE_TOOBIG
, IDS_APPNAME
, MB_ICONERROR
);
2912 CStringA filecontent
;
2913 int filelength
= static_cast<int>(file
.GetLength());
2914 int bytesread
= static_cast<int>(file
.Read(filecontent
.GetBuffer(filelength
), filelength
));
2915 filecontent
.ReleaseBuffer(bytesread
);
2917 if (!CStringUtils::StartsWith(filecontent
, "diff --git "))
2919 int lineend
= filecontent
.Find("\n");
2920 if (lineend
<= static_cast<int>(strlen("diff --git ")))
2922 CStringA newStart
= "diff --git \"a/" + origReflectedA
+ "\" \"b/" + modifiedReflectedA
+ "\"\n";
2923 if (!CStringUtils::StartsWith(static_cast<LPCSTR
>(filecontent
) + lineend
, "\nindex "))
2925 int nextlineend
= filecontent
.Find("\n", lineend
+ 1);
2926 if (nextlineend
<= lineend
)
2928 newStart
+= filecontent
.Mid(lineend
+ 1, nextlineend
- lineend
);
2929 lineend
= filecontent
.Find("\n--- ", nextlineend
);
2930 nextlineend
= filecontent
.Find("\n@@ ", lineend
);
2931 if (nextlineend
<= lineend
)
2933 newStart
+= "--- \"a/" + origReflectedA
+ "\"\n+++ \"b/" + modifiedReflectedA
+ "\"";
2934 filecontent
= newStart
+ filecontent
.Mid(nextlineend
);
2936 file
.Write(filecontent
, static_cast<UINT
>(filecontent
.GetLength()));
2937 file
.SetLength(file
.GetPosition());
2940 catch (CFileException
* e
)
2942 CString sErrorString
;
2943 e
->GetErrorMessage(CStrBuf(sErrorString
, 4096), 4096);
2945 MessageBox(sErrorString
, L
"TortoiseGitMerge", MB_ICONERROR
);
2949 void CMainFrame::OnUpdateViewLinediffbar(CCmdUI
*pCmdUI
)
2951 pCmdUI
->SetCheck(m_bLineDiff
);
2955 void CMainFrame::OnViewLinediffbar()
2957 m_bLineDiff
= !m_bLineDiff
;
2958 m_wndLineDiffBar
.ShowPane(m_bLineDiff
, false, true);
2959 m_wndLineDiffBar
.DocumentUpdated();
2960 m_wndLocatorBar
.ShowPane(m_bLocatorBar
, false, true);
2961 m_wndLocatorBar
.DocumentUpdated();
2964 void CMainFrame::OnUpdateViewLocatorbar(CCmdUI
*pCmdUI
)
2966 pCmdUI
->SetCheck(m_bLocatorBar
);
2970 void CMainFrame::OnUpdateViewBars(CCmdUI
* pCmdUI
)
2975 void CMainFrame::OnViewLocatorbar()
2977 m_bLocatorBar
= !m_bLocatorBar
;
2978 m_wndLocatorBar
.ShowPane(m_bLocatorBar
, false, true);
2979 m_wndLocatorBar
.DocumentUpdated();
2980 m_wndLineDiffBar
.ShowPane(m_bLineDiff
, false, true);
2981 m_wndLineDiffBar
.DocumentUpdated();
2984 void CMainFrame::OnViewComparewhitespaces()
2986 if (CheckForSave(ECheckForSaveReason::Options
)==IDCANCEL
)
2988 CRegDWORD
regIgnoreWS(L
"Software\\TortoiseGitMerge\\IgnoreWS");
2989 regIgnoreWS
= static_cast<int>(IgnoreWS::None
);
2993 void CMainFrame::OnUpdateViewComparewhitespaces(CCmdUI
*pCmdUI
)
2995 CRegDWORD
regIgnoreWS(L
"Software\\TortoiseGitMerge\\IgnoreWS");
2996 IgnoreWS ignoreWs
= static_cast<IgnoreWS
>(static_cast<DWORD
>(regIgnoreWS
));
2997 pCmdUI
->SetCheck(ignoreWs
== IgnoreWS::None
);
3000 void CMainFrame::OnViewIgnorewhitespacechanges()
3002 if (CheckForSave(ECheckForSaveReason::Options
)==IDCANCEL
)
3004 CRegDWORD
regIgnoreWS(L
"Software\\TortoiseGitMerge\\IgnoreWS");
3005 regIgnoreWS
= static_cast<int>(IgnoreWS::WhiteSpaces
);
3009 void CMainFrame::OnUpdateViewIgnorewhitespacechanges(CCmdUI
*pCmdUI
)
3011 CRegDWORD
regIgnoreWS(L
"Software\\TortoiseGitMerge\\IgnoreWS");
3012 IgnoreWS ignoreWs
= static_cast<IgnoreWS
>(static_cast<DWORD
>(regIgnoreWS
));
3013 pCmdUI
->SetCheck(ignoreWs
== IgnoreWS::WhiteSpaces
);
3016 void CMainFrame::OnViewIgnoreallwhitespacechanges()
3018 if (CheckForSave(ECheckForSaveReason::Options
)==IDCANCEL
)
3020 CRegDWORD
regIgnoreWS(L
"Software\\TortoiseGitMerge\\IgnoreWS");
3021 regIgnoreWS
= static_cast<int>(IgnoreWS::AllWhiteSpaces
);
3025 void CMainFrame::OnUpdateViewIgnoreallwhitespacechanges(CCmdUI
*pCmdUI
)
3027 CRegDWORD
regIgnoreWS(L
"Software\\TortoiseGitMerge\\IgnoreWS");
3028 IgnoreWS ignoreWs
= static_cast<IgnoreWS
>(static_cast<DWORD
>(regIgnoreWS
));
3029 pCmdUI
->SetCheck(ignoreWs
== IgnoreWS::AllWhiteSpaces
);
3032 void CMainFrame::OnViewMovedBlocks()
3034 m_bViewMovedBlocks
= !static_cast<DWORD
>(m_regViewModedBlocks
);
3035 m_regViewModedBlocks
= m_bViewMovedBlocks
;
3039 void CMainFrame::OnUpdateViewMovedBlocks(CCmdUI
*pCmdUI
)
3041 pCmdUI
->SetCheck(m_bViewMovedBlocks
);
3042 BOOL bEnable
= TRUE
;
3043 if (IsViewGood(m_pwndBottomView
))
3047 pCmdUI
->Enable(bEnable
);
3050 bool CMainFrame::HasConflictsWontKeep()
3052 const int nConflictLine
= CheckResolved();
3053 if (nConflictLine
< 0)
3055 if (!m_pwndBottomView
)
3059 sTemp
.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS
, m_pwndBottomView
->m_pViewData
->GetLineNumber(nConflictLine
)+1);
3060 CTaskDialog
taskdlg(sTemp
,
3061 CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK2
)),
3062 L
"TortoiseGitMerge",
3064 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
3065 taskdlg
.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK3
)));
3066 taskdlg
.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK4
)));
3067 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
3068 taskdlg
.SetDefaultCommandControl(2);
3069 taskdlg
.SetMainIcon(TD_ERROR_ICON
);
3070 if (taskdlg
.DoModal(m_hWnd
) == 1)
3073 m_pwndBottomView
->GoToLine(nConflictLine
);
3077 bool CMainFrame::TryGetFileName(CString
& result
)
3079 return CCommonAppUtils::FileOpenSave(result
, nullptr, IDS_SAVEASTITLE
, IDS_COMMONFILEFILTER
, false, m_hWnd
);
3082 CBaseView
* CMainFrame::GetActiveBaseView() const
3084 CView
* activeView
= GetActiveView();
3085 CBaseView
* activeBase
= dynamic_cast<CBaseView
*>( activeView
);
3089 void CMainFrame::SetWindowTitle()
3091 // try to find a suitable window title
3092 CString sYour
= m_Data
.m_yourFile
.GetDescriptiveName();
3093 if (sYour
.Find(L
" - ") >= 0)
3094 sYour
= sYour
.Left(sYour
.Find(L
" - "));
3095 if (sYour
.Find(L
" : ") >= 0)
3096 sYour
= sYour
.Left(sYour
.Find(L
" : "));
3097 CString sTheir
= m_Data
.m_theirFile
.GetDescriptiveName();
3098 if (sTheir
.IsEmpty())
3099 sTheir
= m_Data
.m_baseFile
.GetDescriptiveName();
3100 if (sTheir
.Find(L
" - ") >= 0)
3101 sTheir
= sTheir
.Left(sTheir
.Find(L
" - "));
3102 if (sTheir
.Find(L
" : ") >= 0)
3103 sTheir
= sTheir
.Left(sTheir
.Find(L
" : "));
3105 if (!sYour
.IsEmpty() && !sTheir
.IsEmpty())
3107 if (sYour
.CompareNoCase(sTheir
)==0)
3108 SetWindowText(sYour
+ L
" - TortoiseGitMerge");
3109 else if ((sYour
.GetLength() < 10) &&
3110 (sTheir
.GetLength() < 10))
3111 SetWindowText(sYour
+ L
" - " + sTheir
+ L
" - TortoiseGitMerge");
3114 // we have two very long descriptive texts here, which
3115 // means we have to find a way to use them as a window
3116 // title in a shorter way.
3117 // for simplicity, we just use the one from "yourfile"
3118 SetWindowText(sYour
+ L
" - TortoiseGitMerge");
3121 else if (!sYour
.IsEmpty())
3122 SetWindowText(sYour
+ L
" - TortoiseGitMerge");
3123 else if (!sTheir
.IsEmpty())
3124 SetWindowText(sTheir
+ L
" - TortoiseGitMerge");
3126 SetWindowText(L
"TortoiseGitMerge");
3129 void CMainFrame::OnTimer(UINT_PTR nIDEvent
)
3133 case IDT_RELOADCHECKTIMER
:
3134 KillTimer(nIDEvent
);
3139 __super::OnTimer(nIDEvent
);
3142 void CMainFrame::LoadIgnoreCommentData()
3144 static bool bLoaded
= false;
3147 CString sPath
= CPathUtils::GetAppDataDirectory() + L
"ignorecomments.txt";
3148 if (!PathFileExists(sPath
))
3150 // ignore comments file does not exist (yet), so create a default one
3151 HRSRC hRes
= FindResource(nullptr, MAKEINTRESOURCE(IDR_IGNORECOMMENTSTXT
), L
"config");
3154 HGLOBAL hResourceLoaded
= LoadResource(nullptr, hRes
);
3155 if (hResourceLoaded
)
3157 auto lpResLock
= static_cast<char*>(LockResource(hResourceLoaded
));
3158 DWORD dwSizeRes
= SizeofResource(nullptr, hRes
);
3161 HANDLE hFile
= CreateFile(sPath
, GENERIC_WRITE
, 0, nullptr, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, nullptr);
3162 if (hFile
!= INVALID_HANDLE_VALUE
)
3164 DWORD dwWritten
= 0;
3165 WriteFile(hFile
, lpResLock
, dwSizeRes
, &dwWritten
, nullptr);
3176 if (file
.Open(sPath
, CFile::modeRead
))
3179 while (file
.ReadString(sLine
))
3181 int eqpos
= sLine
.Find('=');
3184 CString sExts
= sLine
.Left(eqpos
);
3185 CString sComments
= sLine
.Mid(eqpos
+1);
3187 int pos
= sComments
.Find(',');
3188 CString sLineStart
= sComments
.Left(pos
);
3189 pos
= sComments
.Find(',', pos
);
3190 int pos2
= sComments
.Find(',', pos
+1);
3191 CString sBlockStart
= sComments
.Mid(pos
+1, pos2
-pos
-1);
3192 CString sBlockEnd
= sComments
.Mid(pos2
+1);
3194 auto commentTuple
= std::make_tuple(sLineStart
, sBlockStart
, sBlockEnd
);
3200 temp
= sExts
.Tokenize(L
",", pos
);
3205 ASSERT(m_IgnoreCommentsMap
.find(temp
) == m_IgnoreCommentsMap
.end());
3206 m_IgnoreCommentsMap
[temp
] = commentTuple
;
3212 catch (CFileException
* e
)
3219 void CMainFrame::OnViewIgnorecomments()
3221 if (CheckForSave(ECheckForSaveReason::Options
)==IDCANCEL
)
3223 m_regIgnoreComments
= !DWORD(m_regIgnoreComments
);
3227 void CMainFrame::OnUpdateViewIgnorecomments(CCmdUI
*pCmdUI
)
3229 // only enable if we have comments defined for this file extension
3230 CString sExt
= CPathUtils::GetFileExtFromPath(m_Data
.m_baseFile
.GetFilename()).MakeLower();
3231 sExt
.TrimLeft(L
".");
3232 auto sC
= m_IgnoreCommentsMap
.find(sExt
);
3233 if (sC
== m_IgnoreCommentsMap
.end())
3235 sExt
= CPathUtils::GetFileExtFromPath(m_Data
.m_yourFile
.GetFilename()).MakeLower();
3236 sExt
.TrimLeft(L
".");
3237 sC
= m_IgnoreCommentsMap
.find(sExt
);
3238 if (sC
== m_IgnoreCommentsMap
.end())
3240 sExt
= CPathUtils::GetFileExtFromPath(m_Data
.m_theirFile
.GetFilename()).MakeLower();
3241 sExt
.TrimLeft(L
".");
3242 sC
= m_IgnoreCommentsMap
.find(sExt
);
3245 pCmdUI
->Enable(sC
!= m_IgnoreCommentsMap
.end());
3247 pCmdUI
->SetCheck(DWORD(m_regIgnoreComments
) != 0);
3250 void CMainFrame::OnViewIgnoreEOL()
3252 if (CheckForSave(ECheckForSaveReason::Options
) == IDCANCEL
)
3254 CRegDWORD
regIgnoreEOL(L
"Software\\TortoiseGitMerge\\IgnoreEOL", TRUE
);
3255 bool bIgnoreEOL
= static_cast<DWORD
>(regIgnoreEOL
) != 0;
3256 bIgnoreEOL
= !bIgnoreEOL
;
3257 regIgnoreEOL
= bIgnoreEOL
;
3261 void CMainFrame::OnUpdateViewIgnoreEOL(CCmdUI
* pCmdUI
)
3263 CRegDWORD
regIgnoreEOL(L
"Software\\TortoiseGitMerge\\IgnoreEOL", TRUE
);
3264 bool bIgnoreEOL
= static_cast<DWORD
>(regIgnoreEOL
) != 0;
3265 pCmdUI
->SetCheck(bIgnoreEOL
);
3268 void CMainFrame::OnUpdateMarkedWords(CCmdUI
* pCmdUI
)
3272 if (IsViewGood(m_pwndLeftView
) && m_pwndLeftView
->GetMarkedWordCount())
3274 sTmp
.Format(L
"L: %d", m_pwndLeftView
->GetMarkedWordCount());
3275 if (!sText
.IsEmpty())
3279 if (IsViewGood(m_pwndRightView
) && m_pwndRightView
->GetMarkedWordCount())
3281 sTmp
.Format(L
"R: %d", m_pwndRightView
->GetMarkedWordCount());
3282 if (!sText
.IsEmpty())
3286 if (IsViewGood(m_pwndBottomView
) && m_pwndBottomView
->GetMarkedWordCount())
3288 sTmp
.Format(L
"B: %d", m_pwndBottomView
->GetMarkedWordCount());
3289 if (!sText
.IsEmpty())
3293 if (!sText
.IsEmpty())
3295 CString sStatusBarText
;
3296 sStatusBarText
.Format(IDS_INDICATOR_MARKEDWORDCOUNT
, LPCWSTR(sText
));
3297 pCmdUI
->SetText(sStatusBarText
);
3298 pCmdUI
->Enable(true);
3302 void CMainFrame::OnUpdateEnableIfSelection(CCmdUI
* pCmdUI
)
3304 bool bEnabled
= false;
3305 auto pWndWithFocus
= GetFocus();
3308 if (pWndWithFocus
== m_pwndBottomView
)
3309 bEnabled
= !m_pwndBottomView
->GetSelectedText().IsEmpty();
3310 if (pWndWithFocus
== m_pwndLeftView
)
3311 bEnabled
= !m_pwndLeftView
->GetSelectedText().IsEmpty();
3312 if (pWndWithFocus
== m_pwndRightView
)
3313 bEnabled
= !m_pwndRightView
->GetSelectedText().IsEmpty();
3315 pCmdUI
->Enable(bEnabled
);
3318 void CMainFrame::OnRegexfilter(UINT cmd
)
3320 if ((cmd
== ID_REGEXFILTER
)||(cmd
== (ID_REGEXFILTER
+1)))
3322 CRegexFiltersDlg
dlg(this);
3323 dlg
.SetIniFile(&m_regexIni
);
3324 if (dlg
.DoModal() == IDOK
)
3326 FILE* pFile
= nullptr;
3327 _wfopen_s(&pFile
, CPathUtils::GetAppDataDirectory() + L
"regexfilters.ini", L
"wb");
3328 m_regexIni
.SaveFile(pFile
);
3331 BuildRegexSubitems();
3335 if (cmd
== static_cast<UINT
>(m_regexIndex
) && !m_bUseRibbons
)
3337 if (CheckForSave(ECheckForSaveReason::Options
)==IDCANCEL
)
3339 m_Data
.SetRegexTokens(std::wregex(), L
"");
3343 else if (cmd
!= static_cast<UINT
>(m_regexIndex
))
3345 CSimpleIni::TNamesDepend sections
;
3346 m_regexIni
.GetAllSections(sections
);
3347 int index
= ID_REGEXFILTER
+ 2;
3349 for (const auto& section
: sections
)
3351 if (cmd
== static_cast<UINT
>(index
))
3353 if (CheckForSave(ECheckForSaveReason::Options
)==IDCANCEL
)
3357 std::wregex
rx(m_regexIni
.GetValue(section
.pItem
, L
"regex", L
""));
3358 m_Data
.SetRegexTokens(rx
, m_regexIni
.GetValue(section
.pItem
, L
"replace", L
""));
3360 catch (std::exception
&ex
)
3362 MessageBox(L
"Regex is invalid!\r\n" + CString(ex
.what()));
3364 m_regexIndex
= index
;
3369 catch (const std::regex_error
& ex
)
3371 MessageBox(L
"Regexp error caught:\r\n" + CString(ex
.what()) + L
"\r\nTrying to recover by unsetting it again.");
3372 m_Data
.SetRegexTokens(std::wregex(), L
"");
3384 void CMainFrame::OnUpdateViewRegexFilter( CCmdUI
*pCmdUI
)
3387 pCmdUI
->SetCheck(pCmdUI
->m_nID
== static_cast<UINT
>(m_regexIndex
));
3390 void CMainFrame::BuildRegexSubitems(CMFCPopupMenu
* pMenuPopup
)
3392 CString sIniPath
= CPathUtils::GetAppDataDirectory() + L
"regexfilters.ini";
3393 if (!PathFileExists(sIniPath
))
3395 // ini file does not exist (yet), so create a default one
3396 HRSRC hRes
= FindResource(nullptr, MAKEINTRESOURCE(IDR_REGEXFILTERINI
), L
"config");
3399 HGLOBAL hResourceLoaded
= LoadResource(nullptr, hRes
);
3400 if (hResourceLoaded
)
3402 auto lpResLock
= static_cast<char*>(LockResource(hResourceLoaded
));
3403 DWORD dwSizeRes
= SizeofResource(nullptr, hRes
);
3406 HANDLE hFile
= CreateFile(sIniPath
, GENERIC_WRITE
, 0, nullptr, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, nullptr);
3407 if (hFile
!= INVALID_HANDLE_VALUE
)
3409 DWORD dwWritten
= 0;
3410 WriteFile(hFile
, lpResLock
, dwSizeRes
, &dwWritten
, nullptr);
3418 m_regexIni
.LoadFile(sIniPath
);
3419 CSimpleIni::TNamesDepend sections
;
3420 m_regexIni
.GetAllSections(sections
);
3424 std::list
<CNativeRibbonDynamicItemInfo
> items
;
3426 items
.push_back(CNativeRibbonDynamicItemInfo(ID_REGEX_NO_FILTER
, CString(MAKEINTRESOURCE(ID_REGEX_NO_FILTER
)), IDB_REGEX_FILTER
));
3427 for (const auto& section
: sections
)
3429 items
.emplace_back(ID_REGEXFILTER
+ cmdIndex
, section
.pItem
, IDB_REGEX_FILTER
);
3433 m_pRibbonApp
->SetItems(ID_REGEXFILTER
, items
);
3435 else if (pMenuPopup
)
3438 if (!CMFCToolBar::IsCustomizeMode() &&
3439 (iIndex
= pMenuPopup
->GetMenuBar()->CommandToIndex(ID_REGEXFILTER
)) >= 0)
3441 if (!sections
.empty())
3442 pMenuPopup
->InsertSeparator(iIndex
+ 1); // insert the separator at the end
3444 for (const auto& section
: sections
)
3446 pMenuPopup
->InsertItem(CMFCToolBarMenuButton(ID_REGEXFILTER
+ cmdIndex
, nullptr, -1, section
.pItem
), iIndex
+ cmdIndex
);
3453 void CMainFrame::FillEncodingButton( CMFCRibbonButton
* pButton
, int start
)
3455 pButton
->SetDefaultCommand(FALSE
);
3456 pButton
->AddSubItem(new CMFCRibbonButton(start
+ static_cast<int>(CFileTextLines::UnicodeType::ASCII
), L
"ASCII" ));
3457 pButton
->AddSubItem(new CMFCRibbonButton(start
+ static_cast<int>(CFileTextLines::UnicodeType::BINARY
), L
"BINARY" ));
3458 pButton
->AddSubItem(new CMFCRibbonButton(start
+ static_cast<int>(CFileTextLines::UnicodeType::UTF16_LE
), L
"UTF-16LE" ));
3459 pButton
->AddSubItem(new CMFCRibbonButton(start
+ static_cast<int>(CFileTextLines::UnicodeType::UTF16_LEBOM
), L
"UTF-16LE BOM"));
3460 pButton
->AddSubItem(new CMFCRibbonButton(start
+ static_cast<int>(CFileTextLines::UnicodeType::UTF16_BE
), L
"UTF-16BE" ));
3461 pButton
->AddSubItem(new CMFCRibbonButton(start
+ static_cast<int>(CFileTextLines::UnicodeType::UTF16_BEBOM
), L
"UTF-16BE BOM"));
3462 pButton
->AddSubItem(new CMFCRibbonButton(start
+ static_cast<int>(CFileTextLines::UnicodeType::UTF32_LE
), L
"UTF-32LE" ));
3463 pButton
->AddSubItem(new CMFCRibbonButton(start
+ static_cast<int>(CFileTextLines::UnicodeType::UTF32_BE
), L
"UTF-32BE" ));
3464 pButton
->AddSubItem(new CMFCRibbonButton(start
+ static_cast<int>(CFileTextLines::UnicodeType::UTF8
), L
"UTF-8" ));
3465 pButton
->AddSubItem(new CMFCRibbonButton(start
+ static_cast<int>(CFileTextLines::UnicodeType::UTF8BOM
), L
"UTF-8 BOM" ));
3468 void CMainFrame::FillEOLButton( CMFCRibbonButton
* pButton
, int start
)
3470 pButton
->SetDefaultCommand(FALSE
);
3471 pButton
->AddSubItem(new CMFCRibbonButton(start
+ static_cast<int>(EOL::LF
) , L
"LF" ));
3472 pButton
->AddSubItem(new CMFCRibbonButton(start
+ static_cast<int>(EOL::CRLF
), L
"CRLF"));
3473 pButton
->AddSubItem(new CMFCRibbonButton(start
+ static_cast<int>(EOL::LFCR
), L
"LRCR"));
3474 pButton
->AddSubItem(new CMFCRibbonButton(start
+ static_cast<int>(EOL::CR
) , L
"CR" ));
3475 pButton
->AddSubItem(new CMFCRibbonButton(start
+ static_cast<int>(EOL::VT
) , L
"VT" ));
3476 pButton
->AddSubItem(new CMFCRibbonButton(start
+ static_cast<int>(EOL::FF
) , L
"FF" ));
3477 pButton
->AddSubItem(new CMFCRibbonButton(start
+ static_cast<int>(EOL::NEL
) , L
"NEL" ));
3478 pButton
->AddSubItem(new CMFCRibbonButton(start
+ static_cast<int>(EOL::LS
) , L
"LS" ));
3479 pButton
->AddSubItem(new CMFCRibbonButton(start
+ static_cast<int>(EOL::PS
) , L
"PS" ));
3482 void CMainFrame::FillTabModeButton(CMFCRibbonButton
* pButton
, int start
)
3484 pButton
->SetDefaultCommand(FALSE
);
3485 pButton
->AddSubItem(new CMFCRibbonButton(start
+ TABMODE_NONE
, L
"Tab"));
3486 pButton
->AddSubItem(new CMFCRibbonButton(start
+ TABMODE_USESPACES
, L
"Space"));
3487 pButton
->AddSubItem(new CMFCRibbonSeparator(TRUE
));
3488 pButton
->AddSubItem(new CMFCRibbonButton(start
+ TABMODE_SMARTINDENT
, L
"Smart tab char"));
3489 pButton
->AddSubItem(new CMFCRibbonSeparator(TRUE
));
3490 pButton
->AddSubItem(new CMFCRibbonButton(start
+ TABSIZEBUTTON1
, L
"1"));
3491 pButton
->AddSubItem(new CMFCRibbonButton(start
+ TABSIZEBUTTON2
, L
"2"));
3492 pButton
->AddSubItem(new CMFCRibbonButton(start
+ TABSIZEBUTTON4
, L
"4"));
3493 pButton
->AddSubItem(new CMFCRibbonButton(start
+ TABSIZEBUTTON8
, L
"8"));
3494 pButton
->AddSubItem(new CMFCRibbonSeparator(TRUE
));
3495 pButton
->AddSubItem(new CMFCRibbonButton(start
+ ENABLEEDITORCONFIG
, L
"EditorConfig"));
3498 bool CMainFrame::AdjustUnicodeTypeForLoad(CFileTextLines::UnicodeType
& type
)
3502 case CFileTextLines::UnicodeType::AUTOTYPE
:
3503 case CFileTextLines::UnicodeType::BINARY
:
3506 case CFileTextLines::UnicodeType::ASCII
:
3507 case CFileTextLines::UnicodeType::UTF16_LE
:
3508 case CFileTextLines::UnicodeType::UTF16_BE
:
3509 case CFileTextLines::UnicodeType::UTF32_LE
:
3510 case CFileTextLines::UnicodeType::UTF32_BE
:
3511 case CFileTextLines::UnicodeType::UTF8
:
3514 case CFileTextLines::UnicodeType::UTF16_LEBOM
:
3515 type
= CFileTextLines::UnicodeType::UTF16_LE
;
3518 case CFileTextLines::UnicodeType::UTF16_BEBOM
:
3519 type
= CFileTextLines::UnicodeType::UTF16_BE
;
3522 case CFileTextLines::UnicodeType::UTF8BOM
:
3523 type
= CFileTextLines::UnicodeType::UTF8
;
3529 void CMainFrame::OnEncodingLeft( UINT cmd
)
3533 if (GetKeyState(VK_CONTROL
) & 0x8000)
3535 // reload with selected encoding
3536 auto saveparams
= m_Data
.m_arBaseFile
.GetSaveParams();
3537 saveparams
.m_UnicodeType
= CFileTextLines::UnicodeType(cmd
- ID_INDICATOR_LEFTENCODINGSTART
);
3538 if (AdjustUnicodeTypeForLoad(saveparams
.m_UnicodeType
))
3540 m_Data
.m_arBaseFile
.SetSaveParams(saveparams
);
3541 m_Data
.m_arBaseFile
.KeepEncoding();
3547 m_pwndLeftView
->SetTextType(CFileTextLines::UnicodeType(cmd
- ID_INDICATOR_LEFTENCODINGSTART
));
3548 m_pwndLeftView
->RefreshViews();
3553 void CMainFrame::OnEncodingRight( UINT cmd
)
3555 if (m_pwndRightView
)
3557 if (GetKeyState(VK_CONTROL
) & 0x8000)
3559 // reload with selected encoding
3560 auto saveparams
= m_Data
.m_arYourFile
.GetSaveParams();
3561 saveparams
.m_UnicodeType
= CFileTextLines::UnicodeType(cmd
- ID_INDICATOR_RIGHTENCODINGSTART
);
3562 if (AdjustUnicodeTypeForLoad(saveparams
.m_UnicodeType
))
3564 m_Data
.m_arYourFile
.SetSaveParams(saveparams
);
3565 m_Data
.m_arYourFile
.KeepEncoding();
3571 m_pwndRightView
->SetTextType(CFileTextLines::UnicodeType(cmd
- ID_INDICATOR_RIGHTENCODINGSTART
));
3572 m_pwndRightView
->RefreshViews();
3577 void CMainFrame::OnEncodingBottom( UINT cmd
)
3579 if (m_pwndBottomView
)
3581 if (GetKeyState(VK_CONTROL
) & 0x8000)
3583 // reload with selected encoding
3584 auto saveparams
= m_Data
.m_arTheirFile
.GetSaveParams();
3585 saveparams
.m_UnicodeType
= CFileTextLines::UnicodeType(cmd
- ID_INDICATOR_BOTTOMENCODINGSTART
);
3586 if (AdjustUnicodeTypeForLoad(saveparams
.m_UnicodeType
))
3588 m_Data
.m_arTheirFile
.SetSaveParams(saveparams
);
3589 m_Data
.m_arTheirFile
.KeepEncoding();
3595 m_pwndBottomView
->SetTextType(CFileTextLines::UnicodeType(cmd
- ID_INDICATOR_BOTTOMENCODINGSTART
));
3596 m_pwndBottomView
->RefreshViews();
3601 void CMainFrame::OnEOLLeft( UINT cmd
)
3605 m_pwndLeftView
->ReplaceLineEndings(EOL(cmd
-ID_INDICATOR_LEFTEOLSTART
));
3606 m_pwndLeftView
->RefreshViews();
3610 void CMainFrame::OnEOLRight( UINT cmd
)
3612 if (m_pwndRightView
)
3614 m_pwndRightView
->ReplaceLineEndings(EOL(cmd
-ID_INDICATOR_RIGHTEOLSTART
));
3615 m_pwndRightView
->RefreshViews();
3619 void CMainFrame::OnEOLBottom( UINT cmd
)
3621 if (m_pwndBottomView
)
3623 m_pwndBottomView
->ReplaceLineEndings(EOL(cmd
-ID_INDICATOR_BOTTOMEOLSTART
));
3624 m_pwndBottomView
->RefreshViews();
3628 void CMainFrame::OnTabModeLeft( UINT cmd
)
3630 OnTabMode(m_pwndLeftView
, static_cast<int>(cmd
) - ID_INDICATOR_LEFTTABMODESTART
);
3633 void CMainFrame::OnTabModeRight( UINT cmd
)
3635 OnTabMode(m_pwndRightView
, static_cast<int>(cmd
) - ID_INDICATOR_RIGHTTABMODESTART
);
3638 void CMainFrame::OnTabModeBottom( UINT cmd
)
3640 OnTabMode(m_pwndBottomView
, static_cast<int>(cmd
) - ID_INDICATOR_BOTTOMTABMODESTART
);
3643 void CMainFrame::OnTabMode(CBaseView
*view
, int cmd
)
3647 int nTabMode
= view
->GetTabMode();
3648 if (cmd
== TABMODE_NONE
|| cmd
== TABMODE_USESPACES
)
3649 view
->SetTabMode((nTabMode
& (~TABMODE_USESPACES
)) | (cmd
& TABMODE_USESPACES
));
3650 else if (cmd
== TABMODE_SMARTINDENT
) // Toggle
3651 view
->SetTabMode((nTabMode
& (~TABMODE_SMARTINDENT
)) | ((nTabMode
& TABMODE_SMARTINDENT
) ? 0 : TABMODE_SMARTINDENT
));
3652 else if (cmd
== TABSIZEBUTTON1
)
3653 view
->SetTabSize(1);
3654 else if (cmd
== TABSIZEBUTTON2
)
3655 view
->SetTabSize(2);
3656 else if (cmd
== TABSIZEBUTTON4
)
3657 view
->SetTabSize(4);
3658 else if (cmd
== TABSIZEBUTTON8
)
3659 view
->SetTabSize(8);
3660 else if (cmd
== ENABLEEDITORCONFIG
)
3661 view
->SetEditorConfigEnabled(!view
->GetEditorConfigEnabled());
3662 view
->RefreshViews();
3665 void CMainFrame::OnUpdateEncodingLeft( CCmdUI
*pCmdUI
)
3669 pCmdUI
->SetCheck(CFileTextLines::UnicodeType(pCmdUI
->m_nID
- ID_INDICATOR_LEFTENCODINGSTART
) == m_pwndLeftView
->GetTextType());
3670 pCmdUI
->Enable(m_pwndLeftView
->IsWritable() || (GetKeyState(VK_CONTROL
)&0x8000));
3673 pCmdUI
->Enable(FALSE
);
3676 void CMainFrame::OnUpdateEncodingRight( CCmdUI
*pCmdUI
)
3678 if (m_pwndRightView
)
3680 pCmdUI
->SetCheck(CFileTextLines::UnicodeType(pCmdUI
->m_nID
- ID_INDICATOR_RIGHTENCODINGSTART
) == m_pwndRightView
->GetTextType());
3681 pCmdUI
->Enable(m_pwndRightView
->IsWritable() || (GetKeyState(VK_CONTROL
) & 0x8000));
3684 pCmdUI
->Enable(FALSE
);
3687 void CMainFrame::OnUpdateEncodingBottom( CCmdUI
*pCmdUI
)
3689 if (m_pwndBottomView
)
3691 pCmdUI
->SetCheck(CFileTextLines::UnicodeType(pCmdUI
->m_nID
- ID_INDICATOR_BOTTOMENCODINGSTART
) == m_pwndBottomView
->GetTextType());
3692 pCmdUI
->Enable(m_pwndBottomView
->IsWritable() || (GetKeyState(VK_CONTROL
) & 0x8000));
3695 pCmdUI
->Enable(FALSE
);
3698 void CMainFrame::OnUpdateEOLLeft( CCmdUI
*pCmdUI
)
3702 pCmdUI
->SetCheck(EOL(pCmdUI
->m_nID
- ID_INDICATOR_LEFTEOLSTART
) == m_pwndLeftView
->GetLineEndings());
3703 pCmdUI
->Enable(m_pwndLeftView
->IsWritable());
3706 pCmdUI
->Enable(FALSE
);
3709 void CMainFrame::OnUpdateEOLRight( CCmdUI
*pCmdUI
)
3711 if (m_pwndRightView
)
3713 pCmdUI
->SetCheck(EOL(pCmdUI
->m_nID
- ID_INDICATOR_RIGHTEOLSTART
) == m_pwndRightView
->GetLineEndings());
3714 pCmdUI
->Enable(m_pwndRightView
->IsWritable());
3717 pCmdUI
->Enable(FALSE
);
3720 void CMainFrame::OnUpdateEOLBottom( CCmdUI
*pCmdUI
)
3722 if (m_pwndBottomView
)
3724 pCmdUI
->SetCheck(EOL(pCmdUI
->m_nID
- ID_INDICATOR_BOTTOMEOLSTART
) == m_pwndBottomView
->GetLineEndings());
3725 pCmdUI
->Enable(m_pwndBottomView
->IsWritable());
3728 pCmdUI
->Enable(FALSE
);
3731 void CMainFrame::OnUpdateTabModeLeft(CCmdUI
*pCmdUI
)
3733 OnUpdateTabMode(m_pwndLeftView
, pCmdUI
, ID_INDICATOR_LEFTTABMODESTART
);
3736 void CMainFrame::OnUpdateTabModeRight(CCmdUI
*pCmdUI
)
3738 OnUpdateTabMode(m_pwndRightView
, pCmdUI
, ID_INDICATOR_RIGHTTABMODESTART
);
3741 void CMainFrame::OnUpdateTabModeBottom(CCmdUI
*pCmdUI
)
3743 OnUpdateTabMode(m_pwndBottomView
, pCmdUI
, ID_INDICATOR_BOTTOMTABMODESTART
);
3746 void CMainFrame::OnUpdateTabMode(CBaseView
*view
, CCmdUI
*pCmdUI
, int startid
)
3750 int cmd
= static_cast<int>(pCmdUI
->m_nID
) - startid
;
3751 if (cmd
== TABMODE_NONE
)
3752 pCmdUI
->SetCheck((view
->GetTabMode() & TABMODE_USESPACES
) == TABMODE_NONE
);
3753 else if (cmd
== TABMODE_USESPACES
)
3754 pCmdUI
->SetCheck(view
->GetTabMode() & TABMODE_USESPACES
);
3755 else if (cmd
== TABMODE_SMARTINDENT
)
3756 pCmdUI
->SetCheck(view
->GetTabMode() & TABMODE_SMARTINDENT
);
3757 else if (cmd
== TABSIZEBUTTON1
)
3758 pCmdUI
->SetCheck(view
->GetTabSize() == 1);
3759 else if (cmd
== TABSIZEBUTTON2
)
3760 pCmdUI
->SetCheck(view
->GetTabSize() == 2);
3761 else if (cmd
== TABSIZEBUTTON4
)
3762 pCmdUI
->SetCheck(view
->GetTabSize() == 4);
3763 else if (cmd
== TABSIZEBUTTON8
)
3764 pCmdUI
->SetCheck(view
->GetTabSize() == 8);
3765 else if (cmd
== ENABLEEDITORCONFIG
)
3766 pCmdUI
->SetCheck(view
->GetEditorConfigEnabled());
3767 pCmdUI
->Enable(view
->IsWritable());
3768 if (cmd
== ENABLEEDITORCONFIG
)
3769 pCmdUI
->Enable(view
->IsWritable() && view
->GetEditorConfigLoaded());
3772 pCmdUI
->Enable(FALSE
);
3775 BOOL
CMainFrame::OnShowPopupMenu(CMFCPopupMenu
* pMenuPopup
)
3777 __super::OnShowPopupMenu(pMenuPopup
);
3782 if (!CMFCToolBar::IsCustomizeMode() &&
3783 pMenuPopup
->GetMenuBar()->CommandToIndex(ID_REGEXFILTER
) >= 0)
3785 BuildRegexSubitems(pMenuPopup
);
3791 LRESULT
CMainFrame::OnIdleUpdateCmdUI(WPARAM wParam
, LPARAM lParam
)
3793 __super::OnIdleUpdateCmdUI(wParam
, lParam
);
3797 auto bDisableIfNoHandler
= static_cast<BOOL
>(wParam
);
3798 m_pRibbonApp
->UpdateCmdUI(bDisableIfNoHandler
);
3803 LRESULT
CMainFrame::OnDPIChanged(WPARAM
, LPARAM lParam
)
3805 CDPIAware::Instance().Invalidate();
3807 m_pwndLeftView
->DPIChanged();
3808 if (m_pwndRightView
)
3809 m_pwndRightView
->DPIChanged();
3810 if (m_pwndBottomView
)
3811 m_pwndBottomView
->DPIChanged();
3812 const RECT
* rect
= reinterpret_cast<RECT
*>(lParam
);
3813 SetWindowPos(nullptr, rect
->left
, rect
->top
, rect
->right
- rect
->left
, rect
->bottom
- rect
->top
, SWP_NOZORDER
| SWP_NOACTIVATE
);
3814 ::RedrawWindow(GetSafeHwnd(), nullptr, nullptr, RDW_FRAME
| RDW_INVALIDATE
| RDW_ERASE
| RDW_INTERNALPAINT
| RDW_ALLCHILDREN
| RDW_UPDATENOW
);
3815 return 1; // let MFC handle this message as well
3818 void CMainFrame::OnUpdateThreeWayActions(CCmdUI
* pCmdUI
)
3823 void CMainFrame::OnUpdateColumnStatusBar(CCmdUI
* pCmdUI
)
3826 auto pWndWithFocus
= GetFocus();
3829 if (pWndWithFocus
== m_pwndBottomView
)
3830 column
= m_pwndBottomView
->GetCaretViewPosition().x
;
3831 if (pWndWithFocus
== m_pwndLeftView
)
3832 column
= m_pwndLeftView
->GetCaretViewPosition().x
;
3833 if (pWndWithFocus
== m_pwndRightView
)
3834 column
= m_pwndRightView
->GetCaretViewPosition().x
;
3837 sColumn
.Format(IDS_INDICATOR_COLUMN
, column
+ 1);
3838 pCmdUI
->SetText(sColumn
);
3839 pCmdUI
->Enable(true);
3842 void CMainFrame::OnRegexNoFilter()
3844 if (CheckForSave(ECheckForSaveReason::Options
) == IDCANCEL
)
3846 m_Data
.SetRegexTokens(std::wregex(), L
"");
3851 void CMainFrame::OnUpdateRegexNoFilter(CCmdUI
* pCmdUI
)
3853 pCmdUI
->SetCheck(m_regexIndex
< 0);
3856 void CMainFrame::OnSettingChange(UINT uFlags
, LPCWSTR lpszSection
)
3858 __super::OnSettingChange(uFlags
, lpszSection
);
3863 void CMainFrame::OnSysColorChange()
3865 __super::OnSysColorChange();
3867 CTheme::Instance().OnSysColorChanged();
3868 CTheme::Instance().SetDarkTheme(CTheme::Instance().IsDarkTheme(), true);