1
// TortoiseGitMerge - a Diff/Patch program
3 // Copyright (C) 2008-2018 - TortoiseGit
4 // Copyright (C) 2004-2018 - 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"
24 #include "SysProgressDlg.h"
26 #include "MessageBox.h"
28 #include "PathUtils.h"
31 #include "RightView.h"
32 #include "BottomView.h"
33 #include "DiffColors.h"
34 #include "SelectFileFilter.h"
35 #include "FormatMessageWrapper.h"
36 #include "TaskbarUUID.h"
37 #include "RegexFiltersDlg.h"
44 #define IDT_RELOADCHECKTIMER 123
46 IMPLEMENT_DYNCREATE(CMainFrame
, CFrameWndEx
)
48 BEGIN_MESSAGE_MAP(CMainFrame
, CFrameWndEx
)
51 // Global help commands
52 ON_COMMAND(ID_HELP_FINDER
, CFrameWndEx::OnHelpFinder
)
53 ON_COMMAND(ID_HELP
, CFrameWndEx::OnHelp
)
54 ON_COMMAND(ID_CONTEXT_HELP
, CFrameWndEx::OnContextHelp
)
55 ON_COMMAND(ID_DEFAULT_HELP
, CFrameWndEx::OnHelpFinder
)
56 ON_COMMAND(ID_FILE_OPEN
, OnFileOpen
)
57 ON_COMMAND(ID_VIEW_WHITESPACES
, OnViewWhitespaces
)
59 ON_COMMAND(ID_FILE_SAVE
, OnFileSave
)
60 ON_COMMAND(ID_FILE_SAVE_AS
, OnFileSaveAs
)
61 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE
, OnUpdateFileSave
)
62 ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_AS
, OnUpdateFileSaveAs
)
63 ON_COMMAND(ID_VIEW_ONEWAYDIFF
, OnViewOnewaydiff
)
64 ON_UPDATE_COMMAND_UI(ID_VIEW_ONEWAYDIFF
, OnUpdateViewOnewaydiff
)
65 ON_UPDATE_COMMAND_UI(ID_VIEW_WHITESPACES
, OnUpdateViewWhitespaces
)
66 ON_COMMAND(ID_VIEW_OPTIONS
, OnViewOptions
)
67 ON_MESSAGE(WM_IDLEUPDATECMDUI
, OnIdleUpdateCmdUI
)
70 ON_COMMAND(ID_FILE_RELOAD
, OnFileReload
)
71 ON_COMMAND(ID_VIEW_LINEDOWN
, OnViewLinedown
)
72 ON_COMMAND(ID_VIEW_LINEUP
, OnViewLineup
)
73 ON_COMMAND(ID_VIEW_MOVEDBLOCKS
, OnViewMovedBlocks
)
74 ON_UPDATE_COMMAND_UI(ID_VIEW_MOVEDBLOCKS
, OnUpdateViewMovedBlocks
)
75 ON_UPDATE_COMMAND_UI(ID_EDIT_MARKASRESOLVED
, OnUpdateMergeMarkasresolved
)
76 ON_COMMAND(ID_EDIT_MARKASRESOLVED
, OnMergeMarkasresolved
)
77 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTCONFLICT
, OnUpdateMergeNextconflict
)
78 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSCONFLICT
, OnUpdateMergePreviousconflict
)
81 ON_UPDATE_COMMAND_UI(ID_EDIT_COPY
, OnUpdateEditCopy
)
82 ON_COMMAND(ID_VIEW_SWITCHLEFT
, OnViewSwitchleft
)
83 ON_UPDATE_COMMAND_UI(ID_VIEW_SWITCHLEFT
, OnUpdateViewSwitchleft
)
84 ON_COMMAND(ID_VIEW_LINELEFT
, &CMainFrame::OnViewLineleft
)
85 ON_COMMAND(ID_VIEW_LINERIGHT
, &CMainFrame::OnViewLineright
)
86 ON_UPDATE_COMMAND_UI(ID_VIEW_SHOWFILELIST
, &CMainFrame::OnUpdateViewShowfilelist
)
87 ON_COMMAND(ID_VIEW_SHOWFILELIST
, &CMainFrame::OnViewShowfilelist
)
88 ON_COMMAND(ID_EDIT_USETHEIRBLOCK
, &CMainFrame::OnEditUseTheirs
)
89 ON_COMMAND(ID_EDIT_USEMYBLOCK
, &CMainFrame::OnEditUseMine
)
90 ON_COMMAND(ID_EDIT_USETHEIRTHENMYBLOCK
, &CMainFrame::OnEditUseTheirsThenMine
)
91 ON_COMMAND(ID_EDIT_USEMINETHENTHEIRBLOCK
, &CMainFrame::OnEditUseMineThenTheirs
)
92 ON_COMMAND(ID_EDIT_UNDO
, &CMainFrame::OnEditUndo
)
93 ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO
, &CMainFrame::OnUpdateEditUndo
)
94 ON_COMMAND(ID_EDIT_REDO
, &CMainFrame::OnEditRedo
)
95 ON_UPDATE_COMMAND_UI(ID_EDIT_REDO
, &CMainFrame::OnUpdateEditRedo
)
96 ON_COMMAND(ID_EDIT_ENABLE
, &CMainFrame::OnEditEnable
)
97 ON_UPDATE_COMMAND_UI(ID_EDIT_ENABLE
, &CMainFrame::OnUpdateEditEnable
)
98 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMINETHENTHEIRBLOCK
, &CMainFrame::OnUpdateEditUseminethentheirblock
)
99 ON_UPDATE_COMMAND_UI(ID_EDIT_USEMYBLOCK
, &CMainFrame::OnUpdateEditUsemyblock
)
100 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRBLOCK
, &CMainFrame::OnUpdateEditUsetheirblock
)
101 ON_UPDATE_COMMAND_UI(ID_EDIT_USETHEIRTHENMYBLOCK
, &CMainFrame::OnUpdateEditUsetheirthenmyblock
)
102 ON_COMMAND(ID_VIEW_INLINEDIFFWORD
, &CMainFrame::OnViewInlinediffword
)
103 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFFWORD
, &CMainFrame::OnUpdateViewInlinediffword
)
104 ON_COMMAND(ID_VIEW_INLINEDIFF
, &CMainFrame::OnViewInlinediff
)
105 ON_UPDATE_COMMAND_UI(ID_VIEW_INLINEDIFF
, &CMainFrame::OnUpdateViewInlinediff
)
106 ON_UPDATE_COMMAND_UI(ID_EDIT_CREATEUNIFIEDDIFFFILE
, &CMainFrame::OnUpdateEditCreateunifieddifffile
)
107 ON_COMMAND(ID_EDIT_CREATEUNIFIEDDIFFFILE
, &CMainFrame::OnEditCreateunifieddifffile
)
108 ON_UPDATE_COMMAND_UI(ID_VIEW_LINEDIFFBAR
, &CMainFrame::OnUpdateViewLinediffbar
)
109 ON_COMMAND(ID_VIEW_LINEDIFFBAR
, &CMainFrame::OnViewLinediffbar
)
110 ON_UPDATE_COMMAND_UI(ID_VIEW_BARS
, &CMainFrame::OnUpdateViewBars
)
111 ON_UPDATE_COMMAND_UI(ID_VIEW_LOCATORBAR
, &CMainFrame::OnUpdateViewLocatorbar
)
112 ON_COMMAND(ID_VIEW_LOCATORBAR
, &CMainFrame::OnViewLocatorbar
)
113 ON_COMMAND(ID_EDIT_USELEFTBLOCK
, &CMainFrame::OnEditUseleftblock
)
114 ON_UPDATE_COMMAND_UI(ID_USEBLOCKS
, &CMainFrame::OnUpdateUseBlock
)
115 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTBLOCK
, &CMainFrame::OnUpdateEditUseleftblock
)
116 ON_COMMAND(ID_EDIT_USELEFTFILE
, &CMainFrame::OnEditUseleftfile
)
117 ON_UPDATE_COMMAND_UI(ID_EDIT_USELEFTFILE
, &CMainFrame::OnUpdateEditUseleftfile
)
118 ON_COMMAND(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT
, &CMainFrame::OnEditUseblockfromleftbeforeright
)
119 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMLEFTBEFORERIGHT
, &CMainFrame::OnUpdateEditUseblockfromleftbeforeright
)
120 ON_COMMAND(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT
, &CMainFrame::OnEditUseblockfromrightbeforeleft
)
121 ON_UPDATE_COMMAND_UI(ID_EDIT_USEBLOCKFROMRIGHTBEFORELEFT
, &CMainFrame::OnUpdateEditUseblockfromrightbeforeleft
)
122 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTDIFFERENCE
, &CMainFrame::OnUpdateNavigateNextdifference
)
123 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVIOUSDIFFERENCE
, &CMainFrame::OnUpdateNavigatePreviousdifference
)
124 ON_COMMAND(ID_VIEW_COLLAPSED
, &CMainFrame::OnViewCollapsed
)
125 ON_UPDATE_COMMAND_UI(ID_VIEW_COLLAPSED
, &CMainFrame::OnUpdateViewCollapsed
)
126 ON_COMMAND(ID_VIEW_COMPAREWHITESPACES
, &CMainFrame::OnViewComparewhitespaces
)
127 ON_UPDATE_COMMAND_UI(ID_VIEW_COMPAREWHITESPACES
, &CMainFrame::OnUpdateViewComparewhitespaces
)
128 ON_COMMAND(ID_VIEW_IGNOREWHITESPACECHANGES
, &CMainFrame::OnViewIgnorewhitespacechanges
)
129 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREWHITESPACECHANGES
, &CMainFrame::OnUpdateViewIgnorewhitespacechanges
)
130 ON_COMMAND(ID_VIEW_IGNOREALLWHITESPACECHANGES
, &CMainFrame::OnViewIgnoreallwhitespacechanges
)
131 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNOREALLWHITESPACECHANGES
, &CMainFrame::OnUpdateViewIgnoreallwhitespacechanges
)
132 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_NEXTINLINEDIFF
, &CMainFrame::OnUpdateNavigateNextinlinediff
)
133 ON_UPDATE_COMMAND_UI(ID_NAVIGATE_PREVINLINEDIFF
, &CMainFrame::OnUpdateNavigatePrevinlinediff
)
134 ON_COMMAND(ID_VIEW_WRAPLONGLINES
, &CMainFrame::OnViewWraplonglines
)
135 ON_UPDATE_COMMAND_UI(ID_VIEW_WRAPLONGLINES
, &CMainFrame::OnUpdateViewWraplonglines
)
136 ON_REGISTERED_MESSAGE( TaskBarButtonCreated
, CMainFrame::OnTaskbarButtonCreated
)
137 ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE
, &CMainFrame::OnUpdateEditPaste
)
138 ON_COMMAND(ID_INDICATOR_LEFTVIEW
, &CMainFrame::OnIndicatorLeftview
)
139 ON_COMMAND(ID_INDICATOR_RIGHTVIEW
, &CMainFrame::OnIndicatorRightview
)
140 ON_COMMAND(ID_INDICATOR_BOTTOMVIEW
, &CMainFrame::OnIndicatorBottomview
)
142 ON_COMMAND(ID_VIEW_IGNORECOMMENTS
, &CMainFrame::OnViewIgnorecomments
)
143 ON_UPDATE_COMMAND_UI(ID_VIEW_IGNORECOMMENTS
, &CMainFrame::OnUpdateViewIgnorecomments
)
144 ON_COMMAND_RANGE(ID_REGEXFILTER
, ID_REGEXFILTER
+400, &CMainFrame::OnRegexfilter
)
145 ON_UPDATE_COMMAND_UI_RANGE(ID_REGEXFILTER
, ID_REGEXFILTER
+400, &CMainFrame::OnUpdateViewRegexFilter
)
146 ON_COMMAND(ID_REGEX_NO_FILTER
, &CMainFrame::OnRegexNoFilter
)
147 ON_UPDATE_COMMAND_UI(ID_REGEX_NO_FILTER
, &CMainFrame::OnUpdateRegexNoFilter
)
148 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOENCODING
, &CMainFrame::OnDummyEnabled
)
149 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOENCODING
, &CMainFrame::OnDummyEnabled
)
150 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOENCODING
, &CMainFrame::OnDummyEnabled
)
151 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOEOL
, &CMainFrame::OnDummyEnabled
)
152 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOEOL
, &CMainFrame::OnDummyEnabled
)
153 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOEOL
, &CMainFrame::OnDummyEnabled
)
154 ON_COMMAND(ID_INDICATOR_LEFTVIEWCOMBOTABMODE
, &CMainFrame::OnDummyEnabled
)
155 ON_COMMAND(ID_INDICATOR_RIGHTVIEWCOMBOTABMODE
, &CMainFrame::OnDummyEnabled
)
156 ON_COMMAND(ID_INDICATOR_BOTTOMVIEWCOMBOTABMODE
, &CMainFrame::OnDummyEnabled
)
157 ON_UPDATE_COMMAND_UI(ID_EDIT_THREEWAY_ACTIONS
, &CMainFrame::OnUpdateThreeWayActions
)
158 ON_COMMAND_RANGE(ID_INDICATOR_LEFTENCODINGSTART
, ID_INDICATOR_LEFTENCODINGSTART
+19, &CMainFrame::OnEncodingLeft
)
159 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTENCODINGSTART
, ID_INDICATOR_RIGHTENCODINGSTART
+19, &CMainFrame::OnEncodingRight
)
160 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMENCODINGSTART
, ID_INDICATOR_BOTTOMENCODINGSTART
+19, &CMainFrame::OnEncodingBottom
)
161 ON_COMMAND_RANGE(ID_INDICATOR_LEFTEOLSTART
, ID_INDICATOR_LEFTEOLSTART
+19, &CMainFrame::OnEOLLeft
)
162 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTEOLSTART
, ID_INDICATOR_RIGHTEOLSTART
+19, &CMainFrame::OnEOLRight
)
163 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMEOLSTART
, ID_INDICATOR_BOTTOMEOLSTART
+19, &CMainFrame::OnEOLBottom
)
164 ON_COMMAND_RANGE(ID_INDICATOR_LEFTTABMODESTART
, ID_INDICATOR_LEFTTABMODESTART
+19, &CMainFrame::OnTabModeLeft
)
165 ON_COMMAND_RANGE(ID_INDICATOR_RIGHTTABMODESTART
, ID_INDICATOR_RIGHTTABMODESTART
+19, &CMainFrame::OnTabModeRight
)
166 ON_COMMAND_RANGE(ID_INDICATOR_BOTTOMTABMODESTART
, ID_INDICATOR_BOTTOMTABMODESTART
+19, &CMainFrame::OnTabModeBottom
)
167 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTENCODINGSTART
, ID_INDICATOR_LEFTENCODINGSTART
+19, &CMainFrame::OnUpdateEncodingLeft
)
168 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTENCODINGSTART
, ID_INDICATOR_RIGHTENCODINGSTART
+19, &CMainFrame::OnUpdateEncodingRight
)
169 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMENCODINGSTART
, ID_INDICATOR_BOTTOMENCODINGSTART
+19, &CMainFrame::OnUpdateEncodingBottom
)
170 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTEOLSTART
, ID_INDICATOR_LEFTEOLSTART
+19, &CMainFrame::OnUpdateEOLLeft
)
171 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTEOLSTART
, ID_INDICATOR_RIGHTEOLSTART
+19, &CMainFrame::OnUpdateEOLRight
)
172 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMEOLSTART
, ID_INDICATOR_BOTTOMEOLSTART
+19, &CMainFrame::OnUpdateEOLBottom
)
173 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_LEFTTABMODESTART
, ID_INDICATOR_LEFTTABMODESTART
+19, &CMainFrame::OnUpdateTabModeLeft
)
174 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_RIGHTTABMODESTART
, ID_INDICATOR_RIGHTTABMODESTART
+19, &CMainFrame::OnUpdateTabModeRight
)
175 ON_UPDATE_COMMAND_UI_RANGE(ID_INDICATOR_BOTTOMTABMODESTART
, ID_INDICATOR_BOTTOMTABMODESTART
+19, &CMainFrame::OnUpdateTabModeBottom
)
178 static UINT indicators
[] =
180 ID_SEPARATOR
, // status line indicator
181 ID_INDICATOR_LEFTVIEW
,
182 ID_INDICATOR_RIGHTVIEW
,
183 ID_INDICATOR_BOTTOMVIEW
,
190 // CMainFrame construction/destruction
192 CMainFrame::CMainFrame()
193 : m_bInitSplitter(FALSE
)
194 , m_bReversedPatch(FALSE
)
195 , m_bHasConflicts(false)
196 , m_bInlineWordDiff(true)
198 , m_bLocatorBar(true)
199 , m_nMoveMovesToIgnore(0)
200 , m_pwndLeftView(nullptr)
201 , m_pwndRightView(nullptr)
202 , m_pwndBottomView(nullptr)
205 , m_bCheckReload(false)
206 , m_bSaveRequired(false)
207 , m_bSaveRequiredOnConflicts(false)
208 , m_bDeleteBaseTheirsMineOnClose(false)
210 , resolveMsgWParam(0)
211 , resolveMsgLParam(0)
212 , m_regWrapLines(L
"Software\\TortoiseGitMerge\\WrapLines", 0)
213 , m_regViewModedBlocks(L
"Software\\TortoiseGitMerge\\ViewMovedBlocks", TRUE
)
214 , m_regOneWay(L
"Software\\TortoiseGitMerge\\OnePane")
215 , m_regCollapsed(L
"Software\\TortoiseGitMerge\\Collapsed", 0)
216 , m_regInlineDiff(L
"Software\\TortoiseGitMerge\\DisplayBinDiff", TRUE
)
217 , m_regUseRibbons(L
"Software\\TortoiseGitMerge\\UseRibbons", TRUE
)
218 , m_regIgnoreComments(L
"Software\\TortoiseGitMerge\\IgnoreComments", FALSE
)
221 m_bOneWay
= (0 != ((DWORD
)m_regOneWay
));
222 m_bCollapsed
= !!(DWORD
)m_regCollapsed
;
223 m_bViewMovedBlocks
= !!(DWORD
)m_regViewModedBlocks
;
224 m_bWrapLines
= !!(DWORD
)m_regWrapLines
;
225 m_bInlineDiff
= !!m_regInlineDiff
;
226 m_bUseRibbons
= !!m_regUseRibbons
;
229 CMainFrame::~CMainFrame()
233 LRESULT
CMainFrame::OnTaskbarButtonCreated(WPARAM
/*wParam*/, LPARAM
/*lParam*/)
235 SetUUIDOverlayIcon(m_hWnd
);
240 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct
)
242 if (CFrameWndEx::OnCreate(lpCreateStruct
) == -1)
248 hr
= m_pRibbonFramework
.CoCreateInstance(__uuidof(UIRibbonFramework
));
251 TRACE(L
"Failed to create ribbon framework (%08x)\n", hr
);
252 return -1; // fail to create
255 m_pRibbonApp
.reset(new CNativeRibbonApp(this, m_pRibbonFramework
));
256 m_pRibbonApp
->SetSettingsFileName(CPathUtils::GetAppDataDirectory() + L
"TortoiseGitMerge-RibbonSettings");
258 hr
= m_pRibbonFramework
->Initialize(m_hWnd
, m_pRibbonApp
.get());
261 TRACE(L
"Failed to initialize ribbon framework (%08x)\n", hr
);
262 return -1; // fail to create
265 hr
= m_pRibbonFramework
->LoadUI(AfxGetResourceHandle(), L
"TORTOISEGITMERGERIBBON_RIBBON");
268 TRACE(L
"Failed to load ribbon UI (%08x)\n", hr
);
269 return -1; // fail to create
271 BuildRegexSubitems();
272 if (!m_wndRibbonStatusBar
.Create(this))
274 TRACE0("Failed to create ribbon status bar\n");
275 return -1; // fail to create
277 m_wndRibbonStatusBar
.AddElement(new CMFCRibbonStatusBarPane(ID_SEPARATOR
, CString(MAKEINTRESOURCE(AFX_IDS_IDLEMESSAGE
)), TRUE
), L
"");
279 CString
sTooltip(MAKEINTRESOURCE(IDS_ENCODING_COMBO_TOOLTIP
));
280 auto apBtnGroupLeft
= std::make_unique
<CMFCRibbonButtonsGroup
>();
281 apBtnGroupLeft
->SetID(ID_INDICATOR_LEFTVIEW
);
282 apBtnGroupLeft
->AddButton(new CMFCRibbonStatusBarPane(ID_SEPARATOR
, CString(MAKEINTRESOURCE(IDS_STATUSBAR_LEFTVIEW
)), TRUE
));
283 CMFCRibbonButton
* pButton
= new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOENCODING
, L
"");
284 pButton
->SetToolTipText(sTooltip
);
285 FillEncodingButton(pButton
, ID_INDICATOR_LEFTENCODINGSTART
);
286 apBtnGroupLeft
->AddButton(pButton
);
287 pButton
= new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOEOL
, L
"");
288 FillEOLButton(pButton
, ID_INDICATOR_LEFTEOLSTART
);
289 apBtnGroupLeft
->AddButton(pButton
);
290 pButton
= new CMFCRibbonButton(ID_INDICATOR_LEFTVIEWCOMBOTABMODE
, L
"");
291 FillTabModeButton(pButton
, ID_INDICATOR_LEFTTABMODESTART
);
292 apBtnGroupLeft
->AddButton(pButton
);
293 apBtnGroupLeft
->AddButton(new CMFCRibbonStatusBarPane(ID_INDICATOR_LEFTVIEW
, L
"", TRUE
));
294 m_wndRibbonStatusBar
.AddExtendedElement(apBtnGroupLeft
.release(), L
"");
296 auto apBtnGroupRight
= std::make_unique
<CMFCRibbonButtonsGroup
>();
297 apBtnGroupRight
->SetID(ID_INDICATOR_RIGHTVIEW
);
298 apBtnGroupRight
->AddButton(new CMFCRibbonStatusBarPane(ID_SEPARATOR
, CString(MAKEINTRESOURCE(IDS_STATUSBAR_RIGHTVIEW
)), TRUE
));
299 pButton
= new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOENCODING
, L
"");
300 pButton
->SetToolTipText(sTooltip
);
301 FillEncodingButton(pButton
, ID_INDICATOR_RIGHTENCODINGSTART
);
302 apBtnGroupRight
->AddButton(pButton
);
303 pButton
= new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOEOL
, L
"");
304 FillEOLButton(pButton
, ID_INDICATOR_RIGHTEOLSTART
);
305 apBtnGroupRight
->AddButton(pButton
);
306 pButton
= new CMFCRibbonButton(ID_INDICATOR_RIGHTVIEWCOMBOTABMODE
, L
"");
307 FillTabModeButton(pButton
, ID_INDICATOR_RIGHTTABMODESTART
);
308 apBtnGroupRight
->AddButton(pButton
);
309 apBtnGroupRight
->AddButton(new CMFCRibbonStatusBarPane(ID_INDICATOR_RIGHTVIEW
, L
"", TRUE
));
310 m_wndRibbonStatusBar
.AddExtendedElement(apBtnGroupRight
.release(), L
"");
314 if (!m_wndMenuBar
.Create(this))
316 TRACE0("Failed to create menubar\n");
317 return -1; // fail to create
319 m_wndMenuBar
.SetPaneStyle(m_wndMenuBar
.GetPaneStyle() | CBRS_SIZE_DYNAMIC
| CBRS_TOOLTIPS
| CBRS_FLYBY
);
321 // prevent the menu bar from taking the focus on activation
322 CMFCPopupMenu::SetForceMenuFocus(FALSE
);
323 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
))
325 TRACE0("Failed to create toolbar\n");
326 return -1; // fail to create
328 m_wndToolBar
.SetWindowText(L
"Main");
329 if (!m_wndStatusBar
.Create(this) ||
330 !m_wndStatusBar
.SetIndicators(indicators
,
331 _countof(indicators
)))
333 TRACE0("Failed to create status bar\n");
334 return -1; // fail to create
336 m_wndStatusBar
.EnablePaneDoubleClick();
339 if (!m_wndLocatorBar
.Create(this, IDD_DIFFLOCATOR
,
340 CBRS_ALIGN_LEFT
| CBRS_SIZE_FIXED
, ID_VIEW_LOCATORBAR
))
342 TRACE0("Failed to create dialogbar\n");
343 return -1; // fail to create
345 if (!m_wndLineDiffBar
.Create(this, IDD_LINEDIFF
,
346 CBRS_ALIGN_BOTTOM
| CBRS_SIZE_FIXED
, ID_VIEW_LINEDIFFBAR
))
348 TRACE0("Failed to create dialogbar\n");
349 return -1; // fail to create
351 m_wndLocatorBar
.m_pMainFrm
= this;
352 m_wndLineDiffBar
.m_pMainFrm
= this;
354 EnableDocking(CBRS_ALIGN_ANY
);
357 m_wndMenuBar
.EnableDocking(CBRS_ALIGN_TOP
);
358 m_wndToolBar
.EnableDocking(CBRS_ALIGN_TOP
);
359 DockPane(&m_wndMenuBar
);
360 DockPane(&m_wndToolBar
);
362 DockPane(&m_wndLocatorBar
);
363 DockPane(&m_wndLineDiffBar
);
364 ShowPane(&m_wndLocatorBar
, true, false, true);
365 ShowPane(&m_wndLineDiffBar
, true, false, true);
367 m_wndLocatorBar
.EnableGripper(FALSE
);
368 m_wndLineDiffBar
.EnableGripper(FALSE
);
373 void CMainFrame::OnDestroy()
375 if (m_pRibbonFramework
)
376 m_pRibbonFramework
->Destroy();
378 CFrameWndEx::OnDestroy();
381 BOOL
CMainFrame::PreCreateWindow(CREATESTRUCT
& cs
)
383 if( !CFrameWndEx::PreCreateWindow(cs
) )
388 // CMainFrame diagnostics
391 void CMainFrame::AssertValid() const
393 CFrameWndEx::AssertValid();
396 void CMainFrame::Dump(CDumpContext
& dc
) const
398 CFrameWndEx::Dump(dc
);
404 // CMainFrame message handlers
407 BOOL
CMainFrame::OnCreateClient(LPCREATESTRUCT
/*lpcs*/, CCreateContext
* pContext
)
413 // split into three panes:
422 // create a splitter with 2 rows, 1 column
423 if (!m_wndSplitter
.CreateStatic(this, 2, 1))
425 TRACE0("Failed to CreateStaticSplitter\n");
429 // add the second splitter pane - which is a nested splitter with 2 columns
430 if (!m_wndSplitter2
.CreateStatic(
431 &m_wndSplitter
, // our parent window is the first splitter
432 1, 2, // the new splitter is 1 row, 2 columns
433 WS_CHILD
| WS_VISIBLE
| WS_BORDER
, // style, WS_BORDER is needed
434 m_wndSplitter
.IdFromRowCol(0, 0)
435 // new splitter is in the first row, 1st column of first splitter
438 TRACE0("Failed to create nested splitter\n");
441 // add the first splitter pane - the default view in row 0
442 if (!m_wndSplitter
.CreateView(1, 0,
443 RUNTIME_CLASS(CBottomView
), CSize(cr
.Width(), cr
.Height()), pContext
))
445 TRACE0("Failed to create first pane\n");
448 m_pwndBottomView
= static_cast<CBottomView
*>(m_wndSplitter
.GetPane(1, 0));
449 m_pwndBottomView
->m_pwndLocator
= &m_wndLocatorBar
;
450 m_pwndBottomView
->m_pwndLineDiffBar
= &m_wndLineDiffBar
;
452 m_pwndBottomView
->m_pwndRibbonStatusBar
= &m_wndRibbonStatusBar
;
454 m_pwndBottomView
->m_pwndStatusBar
= &m_wndStatusBar
;
455 m_pwndBottomView
->m_pMainFrame
= this;
457 // now create the two views inside the nested splitter
459 if (!m_wndSplitter2
.CreateView(0, 0,
460 RUNTIME_CLASS(CLeftView
), CSize(cr
.Width()/2, cr
.Height()/2), pContext
))
462 TRACE0("Failed to create second pane\n");
465 m_pwndLeftView
= static_cast<CLeftView
*>(m_wndSplitter2
.GetPane(0, 0));
466 m_pwndLeftView
->m_pwndLocator
= &m_wndLocatorBar
;
467 m_pwndLeftView
->m_pwndLineDiffBar
= &m_wndLineDiffBar
;
469 m_pwndLeftView
->m_pwndRibbonStatusBar
= &m_wndRibbonStatusBar
;
471 m_pwndLeftView
->m_pwndStatusBar
= &m_wndStatusBar
;
472 m_pwndLeftView
->m_pMainFrame
= this;
474 if (!m_wndSplitter2
.CreateView(0, 1,
475 RUNTIME_CLASS(CRightView
), CSize(cr
.Width()/2, cr
.Height()/2), pContext
))
477 TRACE0("Failed to create third pane\n");
480 m_pwndRightView
= static_cast<CRightView
*>(m_wndSplitter2
.GetPane(0, 1));
481 m_pwndRightView
->m_pwndLocator
= &m_wndLocatorBar
;
482 m_pwndRightView
->m_pwndLineDiffBar
= &m_wndLineDiffBar
;
484 m_pwndRightView
->m_pwndRibbonStatusBar
= &m_wndRibbonStatusBar
;
486 m_pwndRightView
->m_pwndStatusBar
= &m_wndStatusBar
;
487 m_pwndRightView
->m_pMainFrame
= this;
488 m_bInitSplitter
= TRUE
;
490 m_dlgFilePatches
.Create(IDD_FILEPATCHES
, this);
496 BOOL
CMainFrame::PatchFile(CString sFilePath
, bool /*bContentMods*/, bool bPropMods
, CString sVersion
, BOOL bAutoPatch
)
498 //"dry run" was successful, so save the patched file somewhere...
499 CString sTempFile
= CTempFiles::Instance().GetTempFilePathString();
500 CString sRejectedFile
, sBasePath
;
501 if (m_Patch
.GetPatchResult(sFilePath
, sTempFile
, sRejectedFile
, sBasePath
) < 0)
503 MessageBox(m_Patch
.GetErrorMessage(), nullptr, MB_ICONERROR
);
506 sFilePath
= m_Patch
.GetTargetPath() + L
'\\' + sFilePath
;
507 sFilePath
.Replace('/', '\\');
508 if (sBasePath
.IsEmpty())
509 sBasePath
= sFilePath
;
510 if (m_bReversedPatch
)
512 m_Data
.m_baseFile
.SetFileName(sTempFile
);
514 temp
.Format(L
"%s %s", (LPCTSTR
)CPathUtils::GetFileNameFromPath(sFilePath
), (LPCTSTR
)m_Data
.m_sPatchPatched
);
515 m_Data
.m_baseFile
.SetDescriptiveName(temp
);
516 m_Data
.m_yourFile
.SetFileName(sFilePath
);
517 temp
.Format(L
"%s %s", (LPCTSTR
)CPathUtils::GetFileNameFromPath(sFilePath
), (LPCTSTR
)m_Data
.m_sPatchOriginal
);
518 m_Data
.m_yourFile
.SetDescriptiveName(temp
);
519 m_Data
.m_theirFile
.SetOutOfUse();
520 m_Data
.m_mergedFile
.SetOutOfUse();
524 if ((!PathFileExists(sBasePath
))||(PathIsDirectory(sBasePath
)))
526 m_Data
.m_baseFile
.SetFileName(CTempFiles::Instance().GetTempFilePathString());
527 m_Data
.m_baseFile
.CreateEmptyFile();
531 m_Data
.m_baseFile
.SetFileName(sBasePath
);
533 CString sDescription
;
534 sDescription
.Format(L
"%s %s", (LPCTSTR
)CPathUtils::GetFileNameFromPath(sBasePath
), (LPCTSTR
)m_Data
.m_sPatchOriginal
);
535 m_Data
.m_baseFile
.SetDescriptiveName(sDescription
);
536 if (sBasePath
== sFilePath
)
538 m_Data
.m_yourFile
.SetFileName(sTempFile
);
540 temp
.Format(L
"%s %s", (LPCTSTR
)CPathUtils::GetFileNameFromPath(sBasePath
), (LPCTSTR
)m_Data
.m_sPatchPatched
);
541 m_Data
.m_yourFile
.SetDescriptiveName(temp
);
542 m_Data
.m_theirFile
.SetOutOfUse();
546 if (!PathFileExists(sFilePath
) || PathIsDirectory(sFilePath
))
548 m_Data
.m_yourFile
.SetFileName(CTempFiles::Instance().GetTempFilePathString());
549 m_Data
.m_yourFile
.CreateEmptyFile();
551 temp
.Format(L
"%s %s", (LPCTSTR
)CPathUtils::GetFileNameFromPath(sFilePath
), (LPCTSTR
)CString(MAKEINTRESOURCE(IDS_NOTFOUNDVIEWTITLEINDICATOR
)));
552 m_Data
.m_yourFile
.SetDescriptiveName(temp
);
555 m_Data
.m_yourFile
.SetFileName(sFilePath
);
556 m_Data
.m_theirFile
.SetFileName(sTempFile
);
558 temp
.Format(L
"%s %s", (LPCTSTR
)CPathUtils::GetFileNameFromPath(sFilePath
), (LPCTSTR
)m_Data
.m_sPatchPatched
);
559 m_Data
.m_theirFile
.SetDescriptiveName(temp
);
561 m_Data
.m_mergedFile
.SetFileName(sFilePath
);
562 m_Data
.m_bPatchRequired
= bPropMods
;
564 TRACE(L
"comparing %s\nwith the patched result %s\n", (LPCTSTR
)sFilePath
, (LPCTSTR
)sTempFile
);
567 if (!sRejectedFile
.IsEmpty())
570 // start TortoiseUDiff with the rejected hunks
572 sTitle
.Format(IDS_TITLE_REJECTEDHUNKS
, (LPCTSTR
)CPathUtils::GetFileNameFromPath(sFilePath
));
573 CAppUtils::StartUnifiedDiffViewer(sRejectedFile
, sTitle
);
578 if (sBasePath
!= sFilePath
&& HasConflictsWontKeep())
587 BOOL
CMainFrame::DiffFiles(CString sURL1
, CString sRev1
, CString sURL2
, CString sRev2
)
589 CString tempfile1
= CTempFiles::Instance().GetTempFilePathString();
590 CString tempfile2
= CTempFiles::Instance().GetTempFilePathString();
592 ASSERT(tempfile1
.Compare(tempfile2
));
595 CSysProgressDlg progDlg
;
596 sTemp
.Format(IDS_GETVERSIONOFFILE
, (LPCTSTR
)sRev1
);
597 progDlg
.SetLine(1, sTemp
, true);
598 progDlg
.SetLine(2, sURL1
, true);
599 sTemp
.LoadString(IDS_GETVERSIONOFFILETITLE
);
600 progDlg
.SetTitle(sTemp
);
601 progDlg
.SetShowProgressBar(true);
602 progDlg
.SetTime(FALSE
);
603 progDlg
.SetProgress(1,100);
604 progDlg
.ShowModeless(this);
605 if (!CAppUtils::GetVersionedFile(sURL1
, sRev1
, tempfile1
, &progDlg
, m_hWnd
))
609 sErrMsg
.FormatMessage(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND
, (LPCTSTR
)sRev1
, (LPCTSTR
)sURL1
);
610 MessageBox(sErrMsg
, nullptr, MB_ICONERROR
);
613 sTemp
.Format(IDS_GETVERSIONOFFILE
, (LPCTSTR
)sRev2
);
614 progDlg
.SetLine(1, sTemp
, true);
615 progDlg
.SetLine(2, sURL2
, true);
616 progDlg
.SetProgress(50, 100);
617 if (!CAppUtils::GetVersionedFile(sURL2
, sRev2
, tempfile2
, &progDlg
, m_hWnd
))
621 sErrMsg
.FormatMessage(IDS_ERR_MAINFRAME_FILEVERSIONNOTFOUND
, (LPCTSTR
)sRev2
, (LPCTSTR
)sURL2
);
622 MessageBox(sErrMsg
, nullptr, MB_ICONERROR
);
625 progDlg
.SetProgress(100,100);
628 temp
.Format(L
"%s Revision %s", (LPCTSTR
)CPathUtils::GetFileNameFromPath(sURL1
), (LPCTSTR
)sRev1
);
629 m_Data
.m_baseFile
.SetFileName(tempfile1
);
630 m_Data
.m_baseFile
.SetDescriptiveName(temp
);
631 temp
.Format(L
"%s Revision %s", (LPCTSTR
)CPathUtils::GetFileNameFromPath(sURL2
), (LPCTSTR
)sRev2
);
632 m_Data
.m_yourFile
.SetFileName(tempfile2
);
633 m_Data
.m_yourFile
.SetDescriptiveName(temp
);
640 void CMainFrame::OnFileOpen()
642 if (CheckForSave(CHFSR_OPEN
)==IDCANCEL
)
644 return OnFileOpen(false);
647 void CMainFrame::OnFileOpen(bool fillyours
)
651 dlg
.m_sBaseFile
= m_Data
.m_yourFile
.GetFilename();
652 if (dlg
.DoModal() != IDOK
)
656 m_dlgFilePatches
.ShowWindow(SW_HIDE
);
657 m_dlgFilePatches
.Init(nullptr, nullptr, CString(), nullptr);
658 TRACE(L
"got the files:\n %s\n %s\n %s\n %s\n %s\n", (LPCTSTR
)dlg
.m_sBaseFile
, (LPCTSTR
)dlg
.m_sTheirFile
, (LPCTSTR
)dlg
.m_sYourFile
,
659 (LPCTSTR
)dlg
.m_sUnifiedDiffFile
, (LPCTSTR
)dlg
.m_sPatchDirectory
);
660 m_Data
.m_baseFile
.SetFileName(dlg
.m_sBaseFile
);
661 m_Data
.m_theirFile
.SetFileName(dlg
.m_sTheirFile
);
662 m_Data
.m_yourFile
.SetFileName(dlg
.m_sYourFile
);
663 m_Data
.m_sDiffFile
= dlg
.m_sUnifiedDiffFile
;
664 m_Data
.m_sPatchPath
= dlg
.m_sPatchDirectory
;
665 m_Data
.m_mergedFile
.SetOutOfUse();
666 CCrashReport::Instance().AddFile2(dlg
.m_sBaseFile
, nullptr, L
"Basefile", CR_AF_MAKE_FILE_COPY
);
667 CCrashReport::Instance().AddFile2(dlg
.m_sTheirFile
, nullptr, L
"Theirfile", CR_AF_MAKE_FILE_COPY
);
668 CCrashReport::Instance().AddFile2(dlg
.m_sYourFile
, nullptr, L
"Yourfile", CR_AF_MAKE_FILE_COPY
);
669 CCrashReport::Instance().AddFile2(dlg
.m_sUnifiedDiffFile
, nullptr, L
"Difffile", CR_AF_MAKE_FILE_COPY
);
671 if (!m_Data
.IsBaseFileInUse() && m_Data
.IsTheirFileInUse() && m_Data
.IsYourFileInUse())
673 // a diff between two files means "Yours" against "Base", not "Theirs" against "Yours"
674 m_Data
.m_baseFile
.TransferDetailsFrom(m_Data
.m_theirFile
);
676 if (m_Data
.IsBaseFileInUse() && m_Data
.IsTheirFileInUse() && !m_Data
.IsYourFileInUse())
678 // a diff between two files means "Yours" against "Base", not "Theirs" against "Base"
679 m_Data
.m_yourFile
.TransferDetailsFrom(m_Data
.m_theirFile
);
681 m_bSaveRequired
= false;
686 void CMainFrame::ClearViewNamesAndPaths()
688 m_pwndLeftView
->m_sWindowName
.Empty();
689 m_pwndLeftView
->m_sFullFilePath
.Empty();
690 m_pwndLeftView
->m_sReflectedName
.Empty();
691 m_pwndRightView
->m_sWindowName
.Empty();
692 m_pwndRightView
->m_sFullFilePath
.Empty();
693 m_pwndRightView
->m_sReflectedName
.Empty();
694 m_pwndBottomView
->m_sWindowName
.Empty();
695 m_pwndBottomView
->m_sFullFilePath
.Empty();
696 m_pwndBottomView
->m_sReflectedName
.Empty();
699 bool CMainFrame::LoadViews(int line
)
701 LoadIgnoreCommentData();
702 m_Data
.SetBlame(m_bBlame
);
703 m_Data
.SetMovedBlocks(m_bViewMovedBlocks
);
704 m_bHasConflicts
= false;
705 CBaseView
* pwndActiveView
= m_pwndLeftView
;
706 int nOldLine
= m_pwndRightView
? m_pwndRightView
->m_nTopLine
: -1;
708 m_pwndRightView
&& m_pwndRightView
->m_pViewData
?
709 m_pwndRightView
->m_pViewData
->GetLineNumber(m_pwndRightView
->m_nTopLine
) : -1;
710 POINT ptOldCaretPos
= {-1, -1};
711 if (m_pwndRightView
&& m_pwndRightView
->IsTarget())
712 ptOldCaretPos
= m_pwndRightView
->GetCaretPosition();
713 if (m_pwndBottomView
&& m_pwndBottomView
->IsTarget())
714 ptOldCaretPos
= m_pwndBottomView
->GetCaretPosition();
715 CString sExt
= CPathUtils::GetFileExtFromPath(m_Data
.m_baseFile
.GetFilename()).MakeLower();
717 auto sC
= m_IgnoreCommentsMap
.find(sExt
);
718 if (sC
== m_IgnoreCommentsMap
.end())
720 sExt
= CPathUtils::GetFileExtFromPath(m_Data
.m_yourFile
.GetFilename()).MakeLower();
721 sC
= m_IgnoreCommentsMap
.find(sExt
);
722 if (sC
== m_IgnoreCommentsMap
.end())
724 sExt
= CPathUtils::GetFileExtFromPath(m_Data
.m_theirFile
.GetFilename()).MakeLower();
725 sC
= m_IgnoreCommentsMap
.find(sExt
);
728 if (sC
!= m_IgnoreCommentsMap
.end())
729 m_Data
.SetCommentTokens(std::get
<0>(sC
->second
), std::get
<1>(sC
->second
), std::get
<2>(sC
->second
));
731 m_Data
.SetCommentTokens(L
"", L
"", L
"");
734 m_pwndLeftView
->BuildAllScreen2ViewVector();
735 m_pwndLeftView
->DocumentUpdated();
736 m_pwndRightView
->DocumentUpdated();
737 m_pwndBottomView
->DocumentUpdated();
738 m_wndLocatorBar
.DocumentUpdated();
739 m_wndLineDiffBar
.DocumentUpdated();
740 ::MessageBox(m_hWnd
, m_Data
.GetError(), L
"TortoiseGitMerge", MB_ICONERROR
);
741 m_Data
.m_mergedFile
.SetOutOfUse();
742 m_bSaveRequired
= false;
746 m_pwndLeftView
->BuildAllScreen2ViewVector();
747 m_pwndLeftView
->DocumentUpdated();
748 m_pwndRightView
->DocumentUpdated();
749 m_pwndBottomView
->DocumentUpdated();
750 m_wndLocatorBar
.DocumentUpdated();
751 m_wndLineDiffBar
.DocumentUpdated();
753 m_pwndLeftView
->SetWritable(false);
754 m_pwndLeftView
->SetWritableIsChangable(false);
755 m_pwndLeftView
->SetTarget(false);
756 m_pwndRightView
->SetWritable(false);
757 m_pwndRightView
->SetWritableIsChangable(false);
758 m_pwndRightView
->SetTarget(false);
759 m_pwndBottomView
->SetWritable(false);
760 m_pwndBottomView
->SetWritableIsChangable(false);
761 m_pwndBottomView
->SetTarget(false);
763 if (!m_Data
.IsBaseFileInUse())
765 CSysProgressDlg progDlg
;
766 if (m_Data
.IsYourFileInUse() && m_Data
.IsTheirFileInUse())
768 m_Data
.m_baseFile
.TransferDetailsFrom(m_Data
.m_theirFile
);
770 else if ((!m_Data
.m_sDiffFile
.IsEmpty())&&(!m_Patch
.Init(m_Data
.m_sDiffFile
, m_Data
.m_sPatchPath
, &progDlg
)))
773 ClearViewNamesAndPaths();
774 MessageBox(m_Patch
.GetErrorMessage(), nullptr, MB_ICONERROR
);
775 m_bSaveRequired
= false;
779 if (m_Patch
.GetNumberOfFiles() > 0)
781 CString betterpatchpath
= m_Patch
.CheckPatchPath(m_Data
.m_sPatchPath
);
782 if (betterpatchpath
.CompareNoCase(m_Data
.m_sPatchPath
)!=0)
785 msg
.FormatMessage(IDS_WARNBETTERPATCHPATHFOUND
, (LPCTSTR
)m_Data
.m_sPatchPath
, (LPCTSTR
)betterpatchpath
);
786 CTaskDialog
taskdlg(msg
,
787 CString(MAKEINTRESOURCE(IDS_WARNBETTERPATCHPATHFOUND_TASK2
)),
790 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
792 WCHAR t3
[MAX_PATH
] = { 0 };
793 CString cp
= betterpatchpath
.Left(MAX_PATH
- 1);
794 PathCompactPathEx(t3
, cp
, 50, 0);
795 task3
.Format(IDS_WARNBETTERPATCHPATHFOUND_TASK3
, t3
);
796 taskdlg
.AddCommandControl(1, task3
);
798 WCHAR t4
[MAX_PATH
] = { 0 };
799 cp
= m_Data
.m_sPatchPath
.Left(MAX_PATH
- 1);
800 PathCompactPathEx(t4
, cp
, 50, 0);
801 task4
.Format(IDS_WARNBETTERPATCHPATHFOUND_TASK4
, t4
);
802 taskdlg
.AddCommandControl(2, task4
);
803 taskdlg
.SetDefaultCommandControl(1);
804 taskdlg
.SetMainIcon(TD_INFORMATION_ICON
);
805 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
806 if (taskdlg
.DoModal(m_hWnd
) == 1)
808 m_Data
.m_sPatchPath
= betterpatchpath
;
809 m_Patch
.Init(m_Data
.m_sDiffFile
, m_Data
.m_sPatchPath
, &progDlg
);
812 m_dlgFilePatches
.Init(&m_Patch
, this, m_Data
.m_sPatchPath
, this);
813 m_dlgFilePatches
.ShowWindow(SW_SHOW
);
814 ClearViewNamesAndPaths();
815 if (!m_wndSplitter
.IsRowHidden(1))
816 m_wndSplitter
.HideRow(1);
817 m_pwndLeftView
->SetHidden(FALSE
);
818 m_pwndRightView
->SetHidden(FALSE
);
819 m_pwndBottomView
->SetHidden(TRUE
);
822 if (m_Data
.IsBaseFileInUse() && !m_Data
.IsYourFileInUse() && m_Data
.IsTheirFileInUse())
824 m_Data
.m_yourFile
.TransferDetailsFrom(m_Data
.m_theirFile
);
826 if (m_Data
.IsBaseFileInUse() && m_Data
.IsYourFileInUse() && !m_Data
.IsTheirFileInUse())
828 //diff between YOUR and BASE
831 pwndActiveView
= m_pwndLeftView
;
832 if (!m_wndSplitter2
.IsColumnHidden(1))
833 m_wndSplitter2
.HideColumn(1);
835 m_pwndLeftView
->m_pViewData
= &m_Data
.m_YourBaseBoth
;
836 m_pwndLeftView
->SetTextType(m_Data
.m_arYourFile
.GetUnicodeType());
837 m_pwndLeftView
->SetLineEndingStyle(m_Data
.m_arYourFile
.GetLineEndings());
838 m_pwndLeftView
->m_sWindowName
= m_Data
.m_baseFile
.GetWindowName() + L
" - " + m_Data
.m_yourFile
.GetWindowName();
839 m_pwndLeftView
->m_sFullFilePath
= m_Data
.m_baseFile
.GetFilename() + L
" - " + m_Data
.m_yourFile
.GetFilename();
840 m_pwndLeftView
->m_sReflectedName
= m_Data
.m_yourFile
.GetReflectedName();
841 m_pwndLeftView
->m_pWorkingFile
= &m_Data
.m_yourFile
;
842 m_pwndLeftView
->SetTarget();
843 m_pwndLeftView
->SetWritableIsChangable(true);
845 m_pwndRightView
->m_pViewData
= nullptr;
846 m_pwndRightView
->m_pWorkingFile
= nullptr;
847 m_pwndBottomView
->m_pViewData
= nullptr;
848 m_pwndBottomView
->m_pWorkingFile
= nullptr;
850 if (!m_wndSplitter
.IsRowHidden(1))
851 m_wndSplitter
.HideRow(1);
852 m_pwndLeftView
->SetHidden(FALSE
);
853 m_pwndRightView
->SetHidden(TRUE
);
854 m_pwndBottomView
->SetHidden(TRUE
);
855 ::SetWindowPos(m_pwndLeftView
->m_hWnd
, nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
);
859 pwndActiveView
= m_pwndRightView
;
860 if (m_wndSplitter2
.IsColumnHidden(1))
861 m_wndSplitter2
.ShowColumn();
863 m_pwndLeftView
->m_pViewData
= &m_Data
.m_YourBaseLeft
;
864 m_pwndLeftView
->SetTextType(m_Data
.m_arBaseFile
.GetUnicodeType());
865 m_pwndLeftView
->SetLineEndingStyle(m_Data
.m_arBaseFile
.GetLineEndings());
866 m_pwndLeftView
->m_sWindowName
= m_Data
.m_baseFile
.GetWindowName();
867 m_pwndLeftView
->m_sFullFilePath
= m_Data
.m_baseFile
.GetFilename();
868 m_pwndLeftView
->m_sConvertedFilePath
= m_Data
.m_baseFile
.GetConvertedFileName();
869 m_pwndLeftView
->m_sReflectedName
= m_Data
.m_baseFile
.GetReflectedName();
870 m_pwndLeftView
->m_pWorkingFile
= &m_Data
.m_baseFile
;
871 m_pwndLeftView
->SetWritableIsChangable(true);
873 m_pwndRightView
->m_pViewData
= &m_Data
.m_YourBaseRight
;
874 m_pwndRightView
->SetTextType(m_Data
.m_arYourFile
.GetUnicodeType());
875 m_pwndRightView
->SetLineEndingStyle(m_Data
.m_arYourFile
.GetLineEndings());
876 m_pwndRightView
->m_sWindowName
= m_Data
.m_yourFile
.GetWindowName();
877 m_pwndRightView
->m_sFullFilePath
= m_Data
.m_yourFile
.GetFilename();
878 m_pwndRightView
->m_sConvertedFilePath
= m_Data
.m_yourFile
.GetConvertedFileName();
879 m_pwndRightView
->m_sReflectedName
= m_Data
.m_yourFile
.GetReflectedName();
880 m_pwndRightView
->m_pWorkingFile
= &m_Data
.m_yourFile
;
881 m_pwndRightView
->SetWritable();
882 m_pwndRightView
->SetTarget();
884 m_pwndBottomView
->m_pViewData
= nullptr;
885 m_pwndBottomView
->m_pWorkingFile
= nullptr;
887 if (!m_wndSplitter
.IsRowHidden(1))
888 m_wndSplitter
.HideRow(1);
889 m_pwndLeftView
->SetHidden(FALSE
);
890 m_pwndRightView
->SetHidden(FALSE
);
891 m_pwndBottomView
->SetHidden(TRUE
);
893 bool hasMods
, hasConflicts
, hasWhitespaceMods
, hasFilteredMods
;
894 pwndActiveView
->CheckModifications(hasMods
, hasConflicts
, hasWhitespaceMods
, hasFilteredMods
);
895 if (!hasMods
&& !hasConflicts
)
897 // files appear identical, show a dialog informing the user that there are or might
898 // be other differences
899 bool hasEncodingDiff
= m_Data
.m_arBaseFile
.GetUnicodeType() != m_Data
.m_arYourFile
.GetUnicodeType();
900 bool hasEOLDiff
= m_Data
.m_arBaseFile
.GetLineEndings() != m_Data
.m_arYourFile
.GetLineEndings();
901 if (hasWhitespaceMods
|| hasEncodingDiff
|| hasEOLDiff
)
903 // text is identical, but the files do not match
904 CString
sWarning(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_MAIN
));
905 CString
sWhitespace(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_WHITESPACE
));
906 CString
sEncoding(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_ENCODING
));
907 CString
sEOL(MAKEINTRESOURCE(IDS_TEXTIDENTICAL_EOL
));
908 if (hasWhitespaceMods
)
911 sWarning
+= sWhitespace
;
916 sWarning
+= sEncoding
;
918 sWarning
+= m_Data
.m_arBaseFile
.GetEncodingName(m_Data
.m_arBaseFile
.GetUnicodeType());
920 sWarning
+= m_Data
.m_arYourFile
.GetEncodingName(m_Data
.m_arYourFile
.GetUnicodeType());
928 AfxMessageBox(sWarning
, MB_ICONINFORMATION
);
932 else if (m_Data
.IsBaseFileInUse() && m_Data
.IsYourFileInUse() && m_Data
.IsTheirFileInUse())
934 //diff between THEIR, YOUR and BASE
935 m_pwndBottomView
->SetWritable();
936 m_pwndBottomView
->SetTarget();
937 pwndActiveView
= m_pwndBottomView
;
939 m_pwndLeftView
->m_pViewData
= &m_Data
.m_TheirBaseBoth
;
940 m_pwndLeftView
->SetTextType(m_Data
.m_arTheirFile
.GetUnicodeType());
941 m_pwndLeftView
->SetLineEndingStyle(m_Data
.m_arTheirFile
.GetLineEndings());
942 m_pwndLeftView
->m_sWindowName
= m_Data
.m_theirFile
.GetWindowName(IDS_VIEWTITLE_THEIRS
);
943 m_pwndLeftView
->m_sFullFilePath
= m_Data
.m_theirFile
.GetFilename();
944 m_pwndLeftView
->m_sConvertedFilePath
= m_Data
.m_theirFile
.GetConvertedFileName();
945 m_pwndLeftView
->m_sReflectedName
= m_Data
.m_theirFile
.GetReflectedName();
946 m_pwndLeftView
->m_pWorkingFile
= &m_Data
.m_theirFile
;
948 m_pwndRightView
->m_pViewData
= &m_Data
.m_YourBaseBoth
;
949 m_pwndRightView
->SetTextType(m_Data
.m_arYourFile
.GetUnicodeType());
950 m_pwndRightView
->SetLineEndingStyle(m_Data
.m_arYourFile
.GetLineEndings());
951 m_pwndRightView
->m_sWindowName
= m_Data
.m_yourFile
.GetWindowName(IDS_VIEWTITLE_MINE
);
952 m_pwndRightView
->m_sFullFilePath
= m_Data
.m_yourFile
.GetFilename();
953 m_pwndRightView
->m_sConvertedFilePath
= m_Data
.m_yourFile
.GetConvertedFileName();
954 m_pwndRightView
->m_sReflectedName
= m_Data
.m_yourFile
.GetReflectedName();
955 m_pwndRightView
->m_pWorkingFile
= &m_Data
.m_yourFile
;
957 m_pwndBottomView
->m_pViewData
= &m_Data
.m_Diff3
;
958 m_pwndBottomView
->SetTextType(m_Data
.m_arTheirFile
.GetUnicodeType());
959 m_pwndBottomView
->SetLineEndingStyle(m_Data
.m_arTheirFile
.GetLineEndings());
960 m_pwndBottomView
->m_sWindowName
.LoadString(IDS_VIEWTITLE_MERGED
);
961 m_pwndBottomView
->m_sWindowName
+= L
" - " + m_Data
.m_mergedFile
.GetWindowName();
962 m_pwndBottomView
->m_sFullFilePath
= m_Data
.m_mergedFile
.GetFilename();
963 m_pwndBottomView
->m_sConvertedFilePath
= m_Data
.m_mergedFile
.GetConvertedFileName();
964 m_pwndBottomView
->m_sReflectedName
= m_Data
.m_mergedFile
.GetReflectedName();
965 m_pwndBottomView
->m_pWorkingFile
= &m_Data
.m_mergedFile
;
967 if (m_wndSplitter2
.IsColumnHidden(1))
968 m_wndSplitter2
.ShowColumn();
969 if (m_wndSplitter
.IsRowHidden(1))
970 m_wndSplitter
.ShowRow();
971 m_pwndLeftView
->SetHidden(FALSE
);
972 m_pwndRightView
->SetHidden(FALSE
);
973 m_pwndBottomView
->SetHidden(FALSE
);
974 // in three pane view, hide the line diff bar
975 m_wndLineDiffBar
.ShowPane(false, false, true);
976 m_wndLineDiffBar
.DocumentUpdated();
978 if (!m_Data
.m_mergedFile
.InUse())
980 m_Data
.m_mergedFile
.SetFileName(m_Data
.m_yourFile
.GetFilename());
982 m_pwndLeftView
->BuildAllScreen2ViewVector();
983 m_pwndLeftView
->DocumentUpdated();
984 m_pwndRightView
->DocumentUpdated();
985 m_pwndBottomView
->DocumentUpdated();
986 m_wndLocatorBar
.DocumentUpdated();
987 m_wndLineDiffBar
.DocumentUpdated();
989 SetActiveView(pwndActiveView
);
991 if ((line
>= -1) && m_pwndRightView
->m_pViewData
)
993 int n
= line
== -1 ? min( nOldLineNumber
, nOldLine
) : line
;
996 n
= m_pwndRightView
->m_pViewData
->FindLineNumber(n
);
999 // adjust the goto-line position if we're collapsed
1000 int step
= m_pwndRightView
->m_nTopLine
> n
? -1 : 1;
1002 for (int i
= m_pwndRightView
->m_nTopLine
; i
!= n
; i
+= step
)
1004 if (m_pwndRightView
->m_pViewData
->GetHideState(i
) == HIDESTATE_HIDDEN
)
1007 if (m_pwndRightView
->m_pViewData
->GetHideState(n
) == HIDESTATE_HIDDEN
)
1008 OnViewTextFoldUnfold();
1010 n
= n
+ (skip
* step
* -1);
1016 m_pwndRightView
->ScrollAllToLine(n
);
1020 if ((ptOldCaretPos
.x
>= 0) || (ptOldCaretPos
.y
>= 0))
1022 m_pwndLeftView
->SetCaretPosition(p
);
1023 m_pwndRightView
->SetCaretPosition(p
);
1024 m_pwndBottomView
->SetCaretPosition(p
);
1025 m_pwndBottomView
->ScrollToChar(0);
1026 m_pwndLeftView
->ScrollToChar(0);
1027 m_pwndRightView
->ScrollToChar(0);
1031 CRegDWORD regFirstDiff
= CRegDWORD(L
"Software\\TortoiseGitMerge\\FirstDiffOnLoad", TRUE
);
1032 CRegDWORD regFirstConflict
= CRegDWORD(L
"Software\\TortoiseGitMerge\\FirstConflictOnLoad", TRUE
);
1033 bool bGoFirstDiff
= (0 != (DWORD
)regFirstDiff
);
1034 bool bGoFirstConflict
= (0 != (DWORD
)regFirstConflict
);
1035 if (bGoFirstConflict
&& (CheckResolved()>=0))
1037 pwndActiveView
->GoToFirstConflict();
1038 // Ignore the first few Mouse Move messages, so that the line diff stays on
1039 // the first diff line until the user actually moves the mouse
1040 m_nMoveMovesToIgnore
= MOVESTOIGNORE
;
1042 else if (bGoFirstDiff
)
1044 pwndActiveView
->GoToFirstDifference();
1045 // Ignore the first few Mouse Move messages, so that the line diff stays on
1046 // the first diff line until the user actually moves the mouse
1047 m_nMoveMovesToIgnore
= MOVESTOIGNORE
;
1051 // Avoid incorrect rendering of active pane.
1052 m_pwndBottomView
->ScrollToChar(0);
1053 m_pwndLeftView
->ScrollToChar(0);
1054 m_pwndRightView
->ScrollToChar(0);
1058 if (m_bHasConflicts
&& !m_bSaveRequiredOnConflicts
)
1059 m_bSaveRequired
= false;
1060 CUndo::GetInstance().Clear();
1064 void CMainFrame::UpdateLayout()
1066 if (m_bInitSplitter
)
1068 m_wndSplitter
.CenterSplitter();
1069 m_wndSplitter2
.CenterSplitter();
1073 void CMainFrame::RecalcLayout(BOOL bNotify
)
1075 GetClientRect(&m_dockManager
.m_rectInPlace
);
1077 m_dockManager
.m_rectInPlace
.top
+= m_pRibbonApp
->GetRibbonHeight();
1078 CFrameWndEx::RecalcLayout(bNotify
);
1081 void CMainFrame::OnSize(UINT nType
, int cx
, int cy
)
1083 CFrameWndEx::OnSize(nType
, cx
, cy
);
1084 if (m_bInitSplitter
&& nType
!= SIZE_MINIMIZED
)
1086 if (m_wndSplitter
.GetSafeHwnd())
1088 if (m_wndSplitter
.HasOldRowSize() && (m_wndSplitter
.GetOldRowCount() == 2))
1090 int oldTotal
= m_wndSplitter
.GetOldRowSize(0) + m_wndSplitter
.GetOldRowSize(1);
1093 int cxCur0
, cxCur1
, cxMin0
, cxMin1
;
1094 m_wndSplitter
.GetRowInfo(0, cxCur0
, cxMin0
);
1095 m_wndSplitter
.GetRowInfo(1, cxCur1
, cxMin1
);
1096 cxCur0
= m_wndSplitter
.GetOldRowSize(0) * (cxCur0
+ cxCur1
) / oldTotal
;
1097 cxCur1
= m_wndSplitter
.GetOldRowSize(1) * (cxCur0
+ cxCur1
) / oldTotal
;
1098 m_wndSplitter
.SetRowInfo(0, cxCur0
, 0);
1099 m_wndSplitter
.SetRowInfo(1, cxCur1
, 0);
1100 m_wndSplitter
.RecalcLayout();
1104 if (m_wndSplitter2
.HasOldColSize() && (m_wndSplitter2
.GetOldColCount() == 2))
1106 int oldTotal
= m_wndSplitter2
.GetOldColSize(0) + m_wndSplitter2
.GetOldColSize(1);
1109 int cyCur0
, cyCur1
, cyMin0
, cyMin1
;
1110 m_wndSplitter2
.GetColumnInfo(0, cyCur0
, cyMin0
);
1111 m_wndSplitter2
.GetColumnInfo(1, cyCur1
, cyMin1
);
1112 cyCur0
= m_wndSplitter2
.GetOldColSize(0) * (cyCur0
+ cyCur1
) / oldTotal
;
1113 cyCur1
= m_wndSplitter2
.GetOldColSize(1) * (cyCur0
+ cyCur1
) / oldTotal
;
1114 m_wndSplitter2
.SetColumnInfo(0, cyCur0
, 0);
1115 m_wndSplitter2
.SetColumnInfo(1, cyCur1
, 0);
1116 m_wndSplitter2
.RecalcLayout();
1121 if ((nType
== SIZE_RESTORED
)&&m_bCheckReload
)
1123 m_bCheckReload
= false;
1128 void CMainFrame::OnViewWhitespaces()
1130 CRegDWORD regViewWhitespaces
= CRegDWORD(L
"Software\\TortoiseGitMerge\\ViewWhitespaces", 1);
1131 BOOL bViewWhitespaces
= regViewWhitespaces
;
1133 bViewWhitespaces
= m_pwndLeftView
->m_bViewWhitespace
;
1135 bViewWhitespaces
= !bViewWhitespaces
;
1136 regViewWhitespaces
= bViewWhitespaces
;
1139 m_pwndLeftView
->m_bViewWhitespace
= bViewWhitespaces
;
1140 m_pwndLeftView
->Invalidate();
1142 if (m_pwndRightView
)
1144 m_pwndRightView
->m_bViewWhitespace
= bViewWhitespaces
;
1145 m_pwndRightView
->Invalidate();
1147 if (m_pwndBottomView
)
1149 m_pwndBottomView
->m_bViewWhitespace
= bViewWhitespaces
;
1150 m_pwndBottomView
->Invalidate();
1154 void CMainFrame::OnUpdateViewWhitespaces(CCmdUI
*pCmdUI
)
1157 pCmdUI
->SetCheck(m_pwndLeftView
->m_bViewWhitespace
);
1160 void CMainFrame::OnViewCollapsed()
1162 m_regCollapsed
= !(DWORD
)m_regCollapsed
;
1163 m_bCollapsed
= !!(DWORD
)m_regCollapsed
;
1165 OnViewTextFoldUnfold();
1166 m_wndLocatorBar
.Invalidate();
1169 void CMainFrame::OnUpdateViewCollapsed(CCmdUI
*pCmdUI
)
1171 pCmdUI
->SetCheck(m_bCollapsed
);
1174 void CMainFrame::OnViewWraplonglines()
1176 m_bWrapLines
= !(DWORD
)m_regWrapLines
;
1177 m_regWrapLines
= m_bWrapLines
;
1179 if (m_pwndLeftView
) m_pwndLeftView
->WrapChanged();
1180 if (m_pwndRightView
) m_pwndRightView
->WrapChanged();
1181 if (m_pwndBottomView
) m_pwndBottomView
->WrapChanged();
1182 OnViewTextFoldUnfold();
1183 m_wndLocatorBar
.DocumentUpdated();
1186 void CMainFrame::OnViewTextFoldUnfold()
1188 OnViewTextFoldUnfold(m_pwndLeftView
);
1189 OnViewTextFoldUnfold(m_pwndRightView
);
1190 OnViewTextFoldUnfold(m_pwndBottomView
);
1193 void CMainFrame::OnViewTextFoldUnfold(CBaseView
* view
)
1197 view
->BuildAllScreen2ViewVector();
1198 view
->UpdateCaret();
1200 view
->EnsureCaretVisible();
1203 void CMainFrame::OnUpdateViewWraplonglines(CCmdUI
*pCmdUI
)
1205 pCmdUI
->SetCheck(m_bWrapLines
);
1208 void CMainFrame::OnViewOnewaydiff()
1210 if (CheckForSave(CHFSR_RELOAD
)==IDCANCEL
)
1212 m_bOneWay
= !m_bOneWay
;
1213 m_regOneWay
= m_bOneWay
;
1214 ShowDiffBar(!m_bOneWay
);
1218 void CMainFrame::DiffLeftToBase()
1220 DiffTwo(m_Data
.m_baseFile
, m_Data
.m_theirFile
);
1223 void CMainFrame::DiffRightToBase()
1225 DiffTwo(m_Data
.m_baseFile
, m_Data
.m_yourFile
);
1228 void CMainFrame::DiffTwo(const CWorkingFile
& file1
, const CWorkingFile
& file2
)
1230 wchar_t ownpath
[MAX_PATH
] = { 0 };
1231 GetModuleFileName(nullptr, ownpath
, MAX_PATH
);
1233 sCmd
.Format(L
"\"%s\"", ownpath
);
1234 sCmd
+= L
" /base:\"";
1235 sCmd
+= file1
.GetFilename();
1236 sCmd
+= L
"\" /mine:\"";
1237 sCmd
+= file2
.GetFilename();
1239 if (!file1
.GetWindowName().IsEmpty())
1240 sCmd
+= L
" /basename:\"" + file1
.GetWindowName() + L
"\"";
1241 if (!file2
.GetWindowName().IsEmpty())
1242 sCmd
+= L
" /yourname:\"" + file2
.GetWindowName() + L
"\"";
1244 CAppUtils::LaunchApplication(sCmd
, 0, false);
1247 void CMainFrame::ShowDiffBar(bool bShow
)
1251 // restore the line diff bar
1252 m_wndLineDiffBar
.ShowPane(m_bLineDiff
, false, true);
1253 m_wndLineDiffBar
.DocumentUpdated();
1254 m_wndLocatorBar
.ShowPane(m_bLocatorBar
, false, true);
1255 m_wndLocatorBar
.DocumentUpdated();
1259 // in one way view, hide the line diff bar
1260 m_wndLineDiffBar
.ShowPane(false, false, true);
1261 m_wndLineDiffBar
.DocumentUpdated();
1265 int CMainFrame::CheckResolved()
1267 //only in three way diffs can be conflicts!
1268 m_bHasConflicts
= true;
1269 if (IsViewGood(m_pwndBottomView
))
1271 CViewData
* viewdata
= m_pwndBottomView
->m_pViewData
;
1274 for (int i
=0; i
<viewdata
->GetCount(); i
++)
1276 const DiffStates state
= viewdata
->GetState(i
);
1277 if ((DIFFSTATE_CONFLICTED
== state
)||(DIFFSTATE_CONFLICTED_IGNORED
== state
))
1282 m_bHasConflicts
= false;
1286 int CMainFrame::SaveFile(const CString
& sFilePath
)
1288 CBaseView
* pView
= nullptr;
1289 CViewData
* pViewData
= nullptr;
1290 CFileTextLines
* pOriginFile
= &m_Data
.m_arBaseFile
;
1291 if (IsViewGood(m_pwndBottomView
))
1293 pView
= m_pwndBottomView
;
1294 pViewData
= m_pwndBottomView
->m_pViewData
;
1296 else if (IsViewGood(m_pwndRightView
))
1298 pView
= m_pwndRightView
;
1299 pViewData
= m_pwndRightView
->m_pViewData
;
1300 if (m_Data
.IsYourFileInUse())
1301 pOriginFile
= &m_Data
.m_arYourFile
;
1302 else if (m_Data
.IsTheirFileInUse())
1303 pOriginFile
= &m_Data
.m_arTheirFile
;
1311 if ((pViewData
)&&(pOriginFile
))
1313 CFileTextLines file
;
1314 pOriginFile
->CopySettings(&file
);
1315 CFileTextLines::SaveParams saveParams
;
1316 saveParams
.m_LineEndings
= pView
->GetLineEndings();
1317 saveParams
.m_UnicodeType
= pView
->GetTextType();
1318 file
.SetSaveParams(saveParams
);
1319 for (int i
=0; i
<pViewData
->GetCount(); i
++)
1321 //only copy non-removed lines
1322 DiffStates state
= pViewData
->GetState(i
);
1325 case DIFFSTATE_CONFLICTED
:
1326 case DIFFSTATE_CONFLICTED_IGNORED
:
1333 } while((last
<pViewData
->GetCount()) && ((pViewData
->GetState(last
)==DIFFSTATE_CONFLICTED
)||(pViewData
->GetState(last
)==DIFFSTATE_CONFLICTED_IGNORED
)));
1334 // TortoiseGitMerge changes here
1335 file
.Add(L
"<<<<<<< .mine", m_pwndRightView
->GetLineEndings());
1336 for (int j
=first
; j
<last
; j
++)
1338 EOL lineending
= m_pwndRightView
->m_pViewData
->GetLineEnding(j
);
1339 if (lineending
== EOL_NOENDING
)
1340 lineending
= m_pwndRightView
->GetLineEndings();
1341 file
.Add(m_pwndRightView
->m_pViewData
->GetLine(j
), lineending
);
1343 file
.Add(L
"=======", m_pwndRightView
->GetLineEndings());
1344 for (int j
=first
; j
<last
; j
++)
1346 EOL lineending
= m_pwndLeftView
->m_pViewData
->GetLineEnding(j
);
1347 if (lineending
== EOL_NOENDING
)
1348 lineending
= m_pwndLeftView
->GetLineEndings();
1349 file
.Add(m_pwndLeftView
->m_pViewData
->GetLine(j
), lineending
);
1351 file
.Add(L
">>>>>>> .theirs", m_pwndRightView
->GetLineEndings());
1355 case DIFFSTATE_EMPTY
:
1356 case DIFFSTATE_CONFLICTEMPTY
:
1357 case DIFFSTATE_IDENTICALREMOVED
:
1358 case DIFFSTATE_REMOVED
:
1359 case DIFFSTATE_THEIRSREMOVED
:
1360 case DIFFSTATE_YOURSREMOVED
:
1361 case DIFFSTATE_CONFLICTRESOLVEDEMPTY
:
1362 // do not save removed lines
1365 file
.Add(pViewData
->GetLine(i
), pViewData
->GetLineEnding(i
));
1369 if (!file
.Save(sFilePath
, false, false))
1371 CMessageBox::Show(m_hWnd
, file
.GetErrorString(), L
"TortoiseGitMerge", MB_ICONERROR
);
1374 if (sFilePath
== m_Data
.m_baseFile
.GetFilename())
1376 m_Data
.m_baseFile
.StoreFileAttributes();
1378 if (sFilePath
== m_Data
.m_theirFile
.GetFilename())
1380 m_Data
.m_theirFile
.StoreFileAttributes();
1382 if (sFilePath
== m_Data
.m_yourFile
.GetFilename())
1384 m_Data
.m_yourFile
.StoreFileAttributes();
1386 /*if (sFilePath == m_Data.m_mergedFile.GetFilename())
1388 m_Data.m_mergedFile.StoreFileAttributes();
1390 m_dlgFilePatches
.SetFileStatusAsPatched(sFilePath
);
1391 if (IsViewGood(m_pwndBottomView
))
1392 m_pwndBottomView
->SetModified(FALSE
);
1393 else if (IsViewGood(m_pwndRightView
))
1394 m_pwndRightView
->SetModified(FALSE
);
1395 CUndo::GetInstance().MarkAsOriginalState(
1397 IsViewGood(m_pwndRightView
) && (pViewData
== m_pwndRightView
->m_pViewData
),
1398 IsViewGood(m_pwndBottomView
) && (pViewData
== m_pwndBottomView
->m_pViewData
));
1399 if (file
.GetCount() == 1 && file
.GetAt(0).IsEmpty() && file
.GetLineEnding(0) == EOL_NOENDING
)
1401 return file
.GetCount();
1406 void CMainFrame::OnFileSave()
1408 // when multiple files are set as writable we have to ask what file to save
1409 int nEditableViewCount
=
1410 (CBaseView::IsViewGood(m_pwndLeftView
) && m_pwndLeftView
->IsWritable() ? 1 : 0)
1411 + (CBaseView::IsViewGood(m_pwndRightView
) && m_pwndRightView
->IsWritable() ? 1 : 0)
1412 + (CBaseView::IsViewGood(m_pwndBottomView
) && m_pwndBottomView
->IsWritable() ? 1 : 0);
1413 bool bLeftIsModified
= CBaseView::IsViewGood(m_pwndLeftView
) && m_pwndLeftView
->IsModified();
1414 bool bRightIsModified
= CBaseView::IsViewGood(m_pwndRightView
) && m_pwndRightView
->IsModified();
1415 bool bBottomIsModified
= CBaseView::IsViewGood(m_pwndBottomView
) && m_pwndBottomView
->IsModified();
1416 int nModifiedViewCount
=
1417 (bLeftIsModified
? 1 : 0)
1418 + (bRightIsModified
? 1 : 0)
1419 + (bBottomIsModified
? 1 : 0);
1420 if (nEditableViewCount
>1)
1422 if (nModifiedViewCount
== 1)
1424 if (bLeftIsModified
)
1425 m_pwndLeftView
->SaveFile(SAVE_REMOVEDLINES
);
1429 else if (nModifiedViewCount
>0)
1432 CTaskDialog
taskdlg(CString(MAKEINTRESOURCE(IDS_SAVE_MORE
)),
1433 CString(MAKEINTRESOURCE(IDS_SAVE
)),
1434 CString(MAKEINTRESOURCE(IDS_APPNAME
)),
1436 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
1438 if (m_pwndLeftView
->m_pWorkingFile
->InUse() && !m_pwndLeftView
->m_pWorkingFile
->IsReadonly())
1439 sTaskTemp
.Format(IDS_ASKFORSAVE_SAVELEFT
, (LPCTSTR
)m_pwndLeftView
->m_pWorkingFile
->GetFilename());
1441 sTaskTemp
= CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS
));
1442 taskdlg
.AddCommandControl(201, sTaskTemp
, bLeftIsModified
);// left
1443 if (bLeftIsModified
)
1444 taskdlg
.SetDefaultCommandControl(201);
1445 if (m_pwndRightView
->m_pWorkingFile
->InUse() && !m_pwndRightView
->m_pWorkingFile
->IsReadonly())
1446 sTaskTemp
.Format(IDS_ASKFORSAVE_SAVERIGHT
, (LPCTSTR
)m_pwndRightView
->m_pWorkingFile
->GetFilename());
1448 sTaskTemp
= CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS
));
1449 taskdlg
.AddCommandControl(202, sTaskTemp
, bRightIsModified
); // right
1450 if (bRightIsModified
)
1451 taskdlg
.SetDefaultCommandControl(202);
1452 taskdlg
.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEALL2
)), nModifiedViewCount
>1); // both
1453 if (nModifiedViewCount
> 1)
1454 taskdlg
.SetDefaultCommandControl(203);
1455 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
1456 taskdlg
.SetMainIcon(TD_WARNING_ICON
);
1457 UINT ret
= (UINT
)taskdlg
.DoModal(m_hWnd
);
1461 m_pwndLeftView
->SaveFile(SAVE_REMOVEDLINES
);
1464 m_pwndLeftView
->SaveFile(SAVE_REMOVEDLINES
);
1466 m_pwndRightView
->SaveFile();
1473 // only target view was modified
1478 void CMainFrame::PatchSave()
1480 bool bDoesNotExist
= !PathFileExists(m_Data
.m_mergedFile
.GetFilename());
1481 if (m_Data
.m_bPatchRequired
)
1483 m_Patch
.PatchPath(m_Data
.m_mergedFile
.GetFilename());
1485 if (!PathIsDirectory(m_Data
.m_mergedFile
.GetFilename()))
1487 int saveret
= SaveFile(m_Data
.m_mergedFile
.GetFilename());
1490 // file was saved with 0 lines, remove it.
1491 m_Patch
.RemoveFile(m_Data
.m_mergedFile
.GetFilename());
1493 DeleteFile(m_Data
.m_mergedFile
.GetFilename());
1495 m_Data
.m_mergedFile
.StoreFileAttributes();
1496 if (m_Data
.m_mergedFile
.GetFilename() == m_Data
.m_yourFile
.GetFilename())
1497 m_Data
.m_yourFile
.StoreFileAttributes();
1498 if (bDoesNotExist
&& (DWORD(CRegDWORD(L
"Software\\TortoiseGitMerge\\AutoAdd", TRUE
))))
1500 // call TortoiseProc to add the new file to version control
1501 CString cmd
= L
"/command:add /noui /path:\"";
1502 cmd
+= m_Data
.m_mergedFile
.GetFilename() + L
'"';
1503 CAppUtils::RunTortoiseGitProc(cmd
);
1508 bool CMainFrame::FileSave(bool bCheckResolved
/*=true*/)
1510 if (HasMarkedBlocks())
1512 CString
sTitle(MAKEINTRESOURCE(IDS_WARNMARKEDBLOCKS
));
1513 CString
sSubTitle(MAKEINTRESOURCE(IDS_ASKFORSAVE_MARKEDBLOCKS
));
1514 CString
sAppName(MAKEINTRESOURCE(IDS_APPNAME
));
1515 CTaskDialog
taskdlg(sTitle
,
1519 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
1520 taskdlg
.AddCommandControl(10, CString(MAKEINTRESOURCE(IDS_MARKEDBLOCKSSAVEINCLUDE
)));
1521 taskdlg
.AddCommandControl(11, CString(MAKEINTRESOURCE(IDS_MARKEDBLOCKSSAVEEXCLUDE
)));
1522 taskdlg
.AddCommandControl(12, CString(MAKEINTRESOURCE(IDS_MARKEDBLCOKSSAVEIGNORE
)));
1523 taskdlg
.AddCommandControl(IDCANCEL
, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_CANCEL_OPEN
)));
1524 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
1525 taskdlg
.SetDefaultCommandControl(10);
1526 taskdlg
.SetMainIcon(TD_WARNING_ICON
);
1527 UINT ret
= (UINT
)taskdlg
.DoModal(m_hWnd
);
1529 m_pwndRightView
->LeaveOnlyMarkedBlocks();
1531 m_pwndRightView
->UseViewFileOfMarked();
1533 m_pwndRightView
->UseViewFileExceptEdited();
1538 if (!m_Data
.m_mergedFile
.InUse())
1539 return FileSaveAs(bCheckResolved
);
1540 // check if the file has the readonly attribute set
1541 bool bDoesNotExist
= false;
1542 DWORD fAttribs
= GetFileAttributes(m_Data
.m_mergedFile
.GetFilename());
1543 if ((fAttribs
!= INVALID_FILE_ATTRIBUTES
)&&(fAttribs
& FILE_ATTRIBUTE_READONLY
))
1544 return FileSaveAs(bCheckResolved
);
1545 if (fAttribs
== INVALID_FILE_ATTRIBUTES
)
1547 bDoesNotExist
= (GetLastError() == ERROR_FILE_NOT_FOUND
);
1549 if (bCheckResolved
&& HasConflictsWontKeep())
1552 if (((DWORD
)CRegDWORD(L
"Software\\TortoiseGitMerge\\Backup")) != 0)
1554 MoveFileEx(m_Data
.m_mergedFile
.GetFilename(), m_Data
.m_mergedFile
.GetFilename() + L
".bak", MOVEFILE_COPY_ALLOWED
| MOVEFILE_REPLACE_EXISTING
| MOVEFILE_WRITE_THROUGH
);
1556 if (m_Data
.m_bPatchRequired
)
1558 m_Patch
.PatchPath(m_Data
.m_mergedFile
.GetFilename());
1560 int saveret
= SaveFile(m_Data
.m_mergedFile
.GetFilename());
1563 // file was saved with 0 lines!
1564 // ask the user if the file should be deleted
1566 msg
.Format(IDS_DELETEWHENEMPTY
, (LPCTSTR
)CPathUtils::GetFileNameFromPath(m_Data
.m_mergedFile
.GetFilename()));
1567 CTaskDialog
taskdlg(msg
,
1568 CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK2
)),
1569 CString(MAKEINTRESOURCE(IDS_APPNAME
)),
1571 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
1572 taskdlg
.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK3
)));
1573 taskdlg
.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_DELETEWHENEMPTY_TASK4
)));
1574 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
1575 taskdlg
.SetDefaultCommandControl(1);
1576 taskdlg
.SetMainIcon(TD_WARNING_ICON
);
1577 if (taskdlg
.DoModal(m_hWnd
) == 1)
1579 m_Patch
.RemoveFile(m_Data
.m_mergedFile
.GetFilename());
1580 DeleteFile(m_Data
.m_mergedFile
.GetFilename());
1583 else if (saveret
< 0)
1585 // error while saving the file
1589 // if we're in conflict resolve mode (three pane view), check if there are no more conflicts
1590 // and if there aren't, ask to mark the file as resolved
1591 if (IsViewGood(m_pwndBottomView
) && !m_bHasConflicts
&& bCheckResolved
)
1593 CString projectRoot
;
1594 if (GitAdminDir::HasAdminDir(m_Data
.m_mergedFile
.GetFilename(), false, &projectRoot
))
1596 CString subpath
= m_Data
.m_mergedFile
.GetFilename();
1597 subpath
.Replace(L
'\\', L
'/');
1598 if (subpath
.GetLength() >= projectRoot
.GetLength())
1600 if (subpath
[projectRoot
.GetLength()] == L
'/')
1601 subpath
= subpath
.Right(subpath
.GetLength() - projectRoot
.GetLength() - 1);
1603 subpath
= subpath
.Right(subpath
.GetLength() - projectRoot
.GetLength());
1606 CAutoRepository
repository(projectRoot
);
1607 bool hasConflictInIndex
= false;
1614 if (git_repository_index(index
.GetPointer(), repository
))
1617 CStringA path
= CUnicodeUtils::GetMulti(subpath
, CP_UTF8
);
1618 hasConflictInIndex
= git_index_get_bypath(index
, path
, 1) || git_index_get_bypath(index
, path
, 2);
1621 if (hasConflictInIndex
)
1624 msg
.Format(IDS_MARKASRESOLVED
, (LPCTSTR
)CPathUtils::GetFileNameFromPath(m_Data
.m_mergedFile
.GetFilename()));
1625 CTaskDialog
taskdlg(msg
,
1626 CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK2
)),
1627 CString(MAKEINTRESOURCE(IDS_APPNAME
)),
1629 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
1630 taskdlg
.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK3
)));
1631 taskdlg
.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_MARKASRESOLVED_TASK4
)));
1632 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
1633 taskdlg
.SetDefaultCommandControl(1);
1634 taskdlg
.SetMainIcon(TD_WARNING_ICON
);
1635 if (taskdlg
.DoModal(m_hWnd
) == 1)
1641 m_bSaveRequired
= false;
1642 m_Data
.m_mergedFile
.StoreFileAttributes();
1644 if (bDoesNotExist
&& (DWORD(CRegDWORD(L
"Software\\TortoiseGitMerge\\AutoAdd", TRUE
))))
1646 // call TortoiseProc to add the new file to version control
1647 CString cmd
= L
"/command:add /noui /path:\"";
1648 cmd
+= m_Data
.m_mergedFile
.GetFilename() + L
'"';
1649 if(!CAppUtils::RunTortoiseGitProc(cmd
))
1655 void CMainFrame::OnFileSaveAs()
1657 // ask what file to save as
1658 bool bHaveConflict
= (CheckResolved() >= 0);
1659 CTaskDialog
taskdlg(
1660 CString(MAKEINTRESOURCE(bHaveConflict
? IDS_ASKFORSAVEAS_MORECONFLICT
: IDS_ASKFORSAVEAS_MORE
)),
1661 CString(MAKEINTRESOURCE(IDS_ASKFORSAVEAS
)),
1662 CString(MAKEINTRESOURCE(IDS_APPNAME
)),
1664 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
1665 // default can be last view (target) as was in 1.7 or actual (where is cursor) as is in most text editor
1666 if (IsViewGood(m_pwndLeftView
))
1668 taskdlg
.AddCommandControl(201, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS
))); // left
1669 taskdlg
.SetDefaultCommandControl(201);
1671 if (IsViewGood(m_pwndRightView
))
1673 taskdlg
.AddCommandControl(202, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS
))); // right
1674 taskdlg
.SetDefaultCommandControl(202);
1676 if (IsViewGood(m_pwndBottomView
))
1678 taskdlg
.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEBOTTOMAS
))); // bottom
1679 taskdlg
.SetDefaultCommandControl(203);
1683 taskdlg
.AddCommandControl(204, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_NEEDRESOLVE
))); // resolve
1684 taskdlg
.SetDefaultCommandControl(204);
1686 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
1687 taskdlg
.SetMainIcon(bHaveConflict
? TD_WARNING_ICON
: TD_INFORMATION_ICON
);
1688 int nCommand
= (int)taskdlg
.DoModal(m_hWnd
);
1693 if (TryGetFileName(sFileName
))
1695 // in 2, 3 view display we want to keep removed lines
1696 m_pwndLeftView
->SaveFileTo(sFileName
, IsViewGood(m_pwndRightView
) ? SAVE_REMOVEDLINES
: 0);
1700 if (TryGetFileName(sFileName
))
1702 m_pwndRightView
->SaveFileTo(sFileName
);
1708 case 204: // continue resolving
1709 if (IsViewGood(m_pwndBottomView
))
1711 m_pwndBottomView
->GoToLine(CheckResolved());
1717 bool CMainFrame::FileSaveAs(bool bCheckResolved
/*=true*/)
1719 if (bCheckResolved
&& HasConflictsWontKeep())
1723 if(!TryGetFileName(fileName
))
1730 void CMainFrame::OnUpdateFileSave(CCmdUI
*pCmdUI
)
1732 BOOL bEnable
= FALSE
;
1733 if (m_Data
.m_mergedFile
.InUse())
1735 if (IsViewGood(m_pwndBottomView
)&&(m_pwndBottomView
->m_pViewData
))
1737 else if ( (IsViewGood(m_pwndRightView
)&&(m_pwndRightView
->m_pViewData
)) &&
1738 (m_pwndRightView
->IsModified() || (m_Data
.m_yourFile
.GetWindowName().Right((int)wcslen(L
": patched")).Compare(L
": patched") == 0)))
1740 else if (IsViewGood(m_pwndLeftView
)
1741 && (m_pwndLeftView
->m_pViewData
)
1742 && (m_pwndLeftView
->IsModified()))
1745 pCmdUI
->Enable(bEnable
);
1748 void CMainFrame::OnUpdateFileSaveAs(CCmdUI
*pCmdUI
)
1750 // any file is open we can save it as
1751 BOOL bEnable
= FALSE
;
1752 if (IsViewGood(m_pwndBottomView
)&&(m_pwndBottomView
->m_pViewData
))
1754 else if (IsViewGood(m_pwndRightView
)&&(m_pwndRightView
->m_pViewData
))
1756 else if (IsViewGood(m_pwndLeftView
)&&(m_pwndLeftView
->m_pViewData
))
1758 pCmdUI
->Enable(bEnable
);
1761 void CMainFrame::OnUpdateViewOnewaydiff(CCmdUI
*pCmdUI
)
1763 pCmdUI
->SetCheck(!m_bOneWay
);
1764 BOOL bEnable
= TRUE
;
1765 if (IsViewGood(m_pwndBottomView
))
1769 pCmdUI
->Enable(bEnable
);
1772 void CMainFrame::OnViewOptions()
1775 sTemp
.LoadString(IDS_SETTINGSTITLE
);
1776 CSettings
dlg(sTemp
);
1778 if (dlg
.IsReloadNeeded())
1780 if (CheckForSave(CHFSR_OPTIONS
)==IDCANCEL
)
1782 CDiffColors::GetInstance().LoadRegistry();
1786 CDiffColors::GetInstance().LoadRegistry();
1787 if (m_pwndBottomView
)
1788 m_pwndBottomView
->DocumentUpdated();
1790 m_pwndLeftView
->DocumentUpdated();
1791 if (m_pwndRightView
)
1792 m_pwndRightView
->DocumentUpdated();
1795 void CMainFrame::OnClose()
1797 if (!IsWindowEnabled())
1798 return; // just in case someone sends a WM_CLOSE to the main window while another window (dialog,...) is open
1799 if (CheckForSave(CHFSR_CLOSE
)!=IDCANCEL
)
1803 // before it is destroyed, save the position of the window
1804 wp
.length
= sizeof wp
;
1806 if (GetWindowPlacement(&wp
))
1810 // never restore to Iconic state
1811 wp
.showCmd
= SW_SHOW
;
1813 if ((wp
.flags
& WPF_RESTORETOMAXIMIZED
) != 0)
1814 // if maximized and maybe iconic restore maximized state
1815 wp
.showCmd
= SW_SHOWMAXIMIZED
;
1818 WriteWindowPlacement(&wp
);
1824 void CMainFrame::OnActivate(UINT nValue
, CWnd
* /*pwnd*/, BOOL
/*bActivated?*/)
1826 if (nValue
!= 0) // activated
1830 m_bCheckReload
= TRUE
;
1834 // use a timer to give other messages time to get processed
1835 // first, like e.g. the WM_CLOSE message in case the user
1836 // clicked the close button and that brought the window
1837 // to the front - in that case checking for reload wouldn't
1839 SetTimer(IDT_RELOADCHECKTIMER
, 300, nullptr);
1844 void CMainFrame::OnViewLinedown()
1846 OnViewLineUpDown(1);
1849 void CMainFrame::OnViewLineup()
1851 OnViewLineUpDown(-1);
1854 void CMainFrame::OnViewLineUpDown(int direction
)
1857 m_pwndLeftView
->ScrollToLine(m_pwndLeftView
->m_nTopLine
+direction
);
1858 if (m_pwndRightView
)
1859 m_pwndRightView
->ScrollToLine(m_pwndRightView
->m_nTopLine
+direction
);
1860 if (m_pwndBottomView
)
1861 m_pwndBottomView
->ScrollToLine(m_pwndBottomView
->m_nTopLine
+direction
);
1862 m_wndLocatorBar
.Invalidate();
1863 m_nMoveMovesToIgnore
= MOVESTOIGNORE
;
1866 void CMainFrame::OnViewLineleft()
1868 OnViewLineLeftRight(-1);
1871 void CMainFrame::OnViewLineright()
1873 OnViewLineLeftRight(1);
1876 void CMainFrame::OnViewLineLeftRight(int direction
)
1879 m_pwndLeftView
->ScrollSide(direction
);
1880 if (m_pwndRightView
)
1881 m_pwndRightView
->ScrollSide(direction
);
1882 if (m_pwndBottomView
)
1883 m_pwndBottomView
->ScrollSide(direction
);
1886 void CMainFrame::OnEditUseTheirs()
1888 if (m_pwndBottomView
)
1889 m_pwndBottomView
->UseTheirTextBlock();
1891 void CMainFrame::OnUpdateEditUsetheirblock(CCmdUI
*pCmdUI
)
1893 pCmdUI
->Enable(m_pwndBottomView
&& m_pwndBottomView
->HasSelection());
1896 void CMainFrame::OnEditUseMine()
1898 if (m_pwndBottomView
)
1899 m_pwndBottomView
->UseMyTextBlock();
1901 void CMainFrame::OnUpdateEditUsemyblock(CCmdUI
*pCmdUI
)
1903 OnUpdateEditUsetheirblock(pCmdUI
);
1906 void CMainFrame::OnEditUseTheirsThenMine()
1908 if (m_pwndBottomView
)
1909 m_pwndBottomView
->UseTheirAndYourBlock();
1912 void CMainFrame::OnUpdateEditUsetheirthenmyblock(CCmdUI
*pCmdUI
)
1914 OnUpdateEditUsetheirblock(pCmdUI
);
1917 void CMainFrame::OnEditUseMineThenTheirs()
1919 if (m_pwndBottomView
)
1920 m_pwndBottomView
->UseYourAndTheirBlock();
1923 void CMainFrame::OnUpdateEditUseminethentheirblock(CCmdUI
*pCmdUI
)
1925 OnUpdateEditUsetheirblock(pCmdUI
);
1928 void CMainFrame::OnEditUseleftblock()
1930 if (m_pwndBottomView
->IsWindowVisible())
1931 m_pwndBottomView
->UseRightBlock();
1933 m_pwndRightView
->UseLeftBlock();
1936 void CMainFrame::OnUpdateEditUseleftblock(CCmdUI
*pCmdUI
)
1938 pCmdUI
->Enable(IsViewGood(m_pwndRightView
) && m_pwndRightView
->IsTarget() && m_pwndRightView
->HasSelection());
1941 void CMainFrame::OnUpdateUseBlock(CCmdUI
*pCmdUI
)
1943 pCmdUI
->Enable(TRUE
);
1946 void CMainFrame::OnEditUseleftfile()
1948 if (m_pwndBottomView
->IsWindowVisible())
1949 m_pwndBottomView
->UseRightFile();
1951 m_pwndRightView
->UseLeftFile();
1954 void CMainFrame::OnUpdateEditUseleftfile(CCmdUI
*pCmdUI
)
1956 pCmdUI
->Enable(IsViewGood(m_pwndRightView
) && m_pwndRightView
->IsTarget());
1959 void CMainFrame::OnEditUseblockfromleftbeforeright()
1961 if (m_pwndRightView
)
1962 m_pwndRightView
->UseBothLeftFirst();
1965 void CMainFrame::OnUpdateEditUseblockfromleftbeforeright(CCmdUI
*pCmdUI
)
1967 OnUpdateEditUseleftblock(pCmdUI
);
1970 void CMainFrame::OnEditUseblockfromrightbeforeleft()
1972 if (m_pwndRightView
)
1973 m_pwndRightView
->UseBothRightFirst();
1976 void CMainFrame::OnUpdateEditUseblockfromrightbeforeleft(CCmdUI
*pCmdUI
)
1978 OnUpdateEditUseleftblock(pCmdUI
);
1981 void CMainFrame::OnFileReload()
1983 if (CheckForSave(CHFSR_RELOAD
)==IDCANCEL
)
1985 CDiffColors::GetInstance().LoadRegistry();
1989 void CMainFrame::ActivateFrame(int nCmdShow
)
1991 // nCmdShow is the normal show mode this frame should be in
1992 // translate default nCmdShow (-1)
1995 if (!IsWindowVisible())
1996 nCmdShow
= SW_SHOWNORMAL
;
1997 else if (IsIconic())
1998 nCmdShow
= SW_RESTORE
;
2001 // bring to top before showing
2002 BringToTop(nCmdShow
);
2006 // show the window as specified
2009 if ( !ReadWindowPlacement(&wp
) )
2011 ShowWindow(nCmdShow
);
2015 if ( nCmdShow
!= SW_SHOWNORMAL
)
2016 wp
.showCmd
= nCmdShow
;
2018 SetWindowPlacement(&wp
);
2021 // and finally, bring to top after showing
2022 BringToTop(nCmdShow
);
2026 BOOL
CMainFrame::ReadWindowPlacement(WINDOWPLACEMENT
* pwp
)
2028 CRegString placement
= CRegString(L
"Software\\TortoiseGitMerge\\WindowPos");
2029 CString sPlacement
= placement
;
2030 if (sPlacement
.IsEmpty())
2032 int nRead
= swscanf_s(sPlacement
, L
"%u,%u,%d,%d,%d,%d,%d,%d,%d,%d",
2033 &pwp
->flags
, &pwp
->showCmd
,
2034 &pwp
->ptMinPosition
.x
, &pwp
->ptMinPosition
.y
,
2035 &pwp
->ptMaxPosition
.x
, &pwp
->ptMaxPosition
.y
,
2036 &pwp
->rcNormalPosition
.left
, &pwp
->rcNormalPosition
.top
,
2037 &pwp
->rcNormalPosition
.right
, &pwp
->rcNormalPosition
.bottom
);
2040 pwp
->length
= sizeof(WINDOWPLACEMENT
);
2045 void CMainFrame::WriteWindowPlacement(WINDOWPLACEMENT
* pwp
)
2047 CRegString
placement(L
"Software\\TortoiseGitMerge\\WindowPos");
2048 TCHAR szBuffer
[_countof("-32767")*8 + sizeof("65535")*2];
2050 swprintf_s(szBuffer
, L
"%u,%u,%d,%d,%d,%d,%d,%d,%d,%d",
2051 pwp
->flags
, pwp
->showCmd
,
2052 pwp
->ptMinPosition
.x
, pwp
->ptMinPosition
.y
,
2053 pwp
->ptMaxPosition
.x
, pwp
->ptMaxPosition
.y
,
2054 pwp
->rcNormalPosition
.left
, pwp
->rcNormalPosition
.top
,
2055 pwp
->rcNormalPosition
.right
, pwp
->rcNormalPosition
.bottom
);
2056 placement
= szBuffer
;
2059 void CMainFrame::OnUpdateMergeMarkasresolved(CCmdUI
*pCmdUI
)
2063 BOOL bEnable
= FALSE
;
2064 if ((!m_bReadOnly
)&&(m_Data
.m_mergedFile
.InUse()))
2066 if (IsViewGood(m_pwndBottomView
)&&(m_pwndBottomView
->m_pViewData
))
2071 pCmdUI
->Enable(bEnable
);
2074 void CMainFrame::OnMergeMarkasresolved()
2076 if(HasConflictsWontKeep())
2079 // now check if the file has already been saved and if not, save it.
2080 if (m_Data
.m_mergedFile
.InUse())
2082 if (IsViewGood(m_pwndBottomView
)&&(m_pwndBottomView
->m_pViewData
))
2084 if (!FileSave(false))
2086 m_bSaveRequired
= false;
2092 BOOL
CMainFrame::MarkAsResolved()
2096 if (!IsViewGood(m_pwndBottomView
))
2099 CString cmd
= L
"/command:resolve /path:\"";
2100 cmd
+= m_Data
.m_mergedFile
.GetFilename();
2101 cmd
+= L
"\" /closeonend:1 /noquestion /skipcheck /silent";
2105 s
.Format(L
" /resolvemsghwnd:%I64d /resolvemsgwparam:%I64d /resolvemsglparam:%I64d", (__int64
)resolveMsgWnd
, (__int64
)resolveMsgWParam
, (__int64
)resolveMsgLParam
);
2108 if(!CAppUtils::RunTortoiseGitProc(cmd
))
2110 m_bSaveRequired
= false;
2114 void CMainFrame::OnUpdateMergeNextconflict(CCmdUI
*pCmdUI
)
2117 if (HasNextConflict(m_pwndBottomView
))
2119 else if (HasNextConflict(m_pwndRightView
))
2121 else if (HasNextConflict(m_pwndLeftView
))
2123 pCmdUI
->Enable(bShow
);
2126 bool CMainFrame::HasNextConflict(CBaseView
* view
)
2130 if (!view
->IsTarget())
2132 return view
->HasNextConflict();
2135 void CMainFrame::OnUpdateMergePreviousconflict(CCmdUI
*pCmdUI
)
2138 if (HasPrevConflict(m_pwndBottomView
))
2140 else if (HasPrevConflict(m_pwndRightView
))
2142 else if (HasPrevConflict(m_pwndLeftView
))
2144 pCmdUI
->Enable(bShow
);
2147 bool CMainFrame::HasPrevConflict(CBaseView
* view
)
2151 if (!view
->IsTarget())
2153 return view
->HasPrevConflict();
2156 void CMainFrame::OnUpdateNavigateNextdifference(CCmdUI
*pCmdUI
)
2158 CBaseView
* baseView
= GetActiveBaseView();
2161 bShow
= baseView
->HasNextDiff();
2162 pCmdUI
->Enable(bShow
);
2165 void CMainFrame::OnUpdateNavigatePreviousdifference(CCmdUI
*pCmdUI
)
2167 CBaseView
* baseView
= GetActiveBaseView();
2170 bShow
= baseView
->HasPrevDiff();
2171 pCmdUI
->Enable(bShow
);
2174 void CMainFrame::OnUpdateNavigateNextinlinediff(CCmdUI
*pCmdUI
)
2177 if (HasNextInlineDiff(m_pwndBottomView
))
2179 else if (HasNextInlineDiff(m_pwndRightView
))
2181 else if (HasNextInlineDiff(m_pwndLeftView
))
2183 pCmdUI
->Enable(bShow
);
2186 bool CMainFrame::HasNextInlineDiff(CBaseView
* view
)
2190 if (!view
->IsTarget())
2192 return view
->HasNextInlineDiff();
2195 void CMainFrame::OnUpdateNavigatePrevinlinediff(CCmdUI
*pCmdUI
)
2198 if (HasPrevInlineDiff(m_pwndBottomView
))
2200 else if (HasPrevInlineDiff(m_pwndRightView
))
2202 else if (HasPrevInlineDiff(m_pwndLeftView
))
2204 pCmdUI
->Enable(bShow
);
2207 bool CMainFrame::HasPrevInlineDiff(CBaseView
* view
)
2211 if (!view
->IsTarget())
2213 return view
->HasPrevInlineDiff();
2216 void CMainFrame::OnMoving(UINT fwSide
, LPRECT pRect
)
2218 // if the pathfilelist dialog is attached to the mainframe,
2219 // move it along with the mainframe
2220 if (::IsWindow(m_dlgFilePatches
.m_hWnd
))
2223 m_dlgFilePatches
.GetWindowRect(&patchrect
);
2224 if (::IsWindow(m_hWnd
))
2227 GetWindowRect(&thisrect
);
2228 if (patchrect
.right
== thisrect
.left
)
2230 m_dlgFilePatches
.SetWindowPos(nullptr, patchrect
.left
- (thisrect
.left
- pRect
->left
), patchrect
.top
- (thisrect
.top
- pRect
->top
),
2231 0, 0, SWP_NOACTIVATE
| SWP_NOOWNERZORDER
| SWP_NOSIZE
| SWP_NOZORDER
);
2235 __super::OnMoving(fwSide
, pRect
);
2238 void CMainFrame::OnUpdateEditCopy(CCmdUI
*pCmdUI
)
2241 if ((m_pwndBottomView
)&&(m_pwndBottomView
->HasSelection()))
2243 else if ((m_pwndRightView
)&&(m_pwndRightView
->HasSelection()))
2245 else if ((m_pwndLeftView
)&&(m_pwndLeftView
->HasSelection()))
2247 pCmdUI
->Enable(bShow
);
2250 void CMainFrame::OnUpdateEditPaste(CCmdUI
*pCmdUI
)
2252 BOOL bWritable
= FALSE
;
2253 if ((m_pwndBottomView
)&&(m_pwndBottomView
->IsWritable()))
2255 else if ((m_pwndRightView
)&&(m_pwndRightView
->IsWritable()))
2257 else if ((m_pwndLeftView
)&&(m_pwndLeftView
->IsWritable()))
2259 pCmdUI
->Enable(bWritable
&& ::IsClipboardFormatAvailable(CF_TEXT
));
2262 void CMainFrame::OnViewSwitchleft()
2264 if (CheckForSave(CHFSR_SWITCH
)!=IDCANCEL
)
2266 CWorkingFile file
= m_Data
.m_baseFile
;
2267 m_Data
.m_baseFile
= m_Data
.m_yourFile
;
2268 m_Data
.m_yourFile
= file
;
2269 if (m_Data
.m_mergedFile
.GetFilename().CompareNoCase(m_Data
.m_yourFile
.GetFilename())==0)
2271 m_Data
.m_mergedFile
= m_Data
.m_baseFile
;
2273 else if (m_Data
.m_mergedFile
.GetFilename().CompareNoCase(m_Data
.m_baseFile
.GetFilename())==0)
2275 m_Data
.m_mergedFile
= m_Data
.m_yourFile
;
2281 void CMainFrame::OnUpdateViewSwitchleft(CCmdUI
*pCmdUI
)
2283 BOOL bEnable
= !IsViewGood(m_pwndBottomView
);
2284 pCmdUI
->Enable(bEnable
);
2287 void CMainFrame::OnUpdateViewShowfilelist(CCmdUI
*pCmdUI
)
2289 BOOL bEnable
= m_dlgFilePatches
.HasFiles();
2290 pCmdUI
->Enable(bEnable
);
2291 pCmdUI
->SetCheck(m_dlgFilePatches
.IsWindowVisible());
2294 void CMainFrame::OnViewShowfilelist()
2296 m_dlgFilePatches
.ShowWindow(m_dlgFilePatches
.IsWindowVisible() ? SW_HIDE
: SW_SHOW
);
2299 void CMainFrame::OnEditUndo()
2301 if (CUndo::GetInstance().CanUndo())
2303 CUndo::GetInstance().Undo(m_pwndLeftView
, m_pwndRightView
, m_pwndBottomView
);
2307 void CMainFrame::OnUpdateEditUndo(CCmdUI
*pCmdUI
)
2309 pCmdUI
->Enable(CUndo::GetInstance().CanUndo());
2312 void CMainFrame::OnEditRedo()
2314 if (CUndo::GetInstance().CanRedo())
2316 CUndo::GetInstance().Redo(m_pwndLeftView
, m_pwndRightView
, m_pwndBottomView
);
2320 void CMainFrame::OnUpdateEditRedo(CCmdUI
*pCmdUI
)
2322 pCmdUI
->Enable(CUndo::GetInstance().CanRedo());
2325 void CMainFrame::OnEditEnable()
2327 CBaseView
* pView
= GetActiveBaseView();
2328 if (pView
&& pView
->IsReadonlyChangable())
2330 bool isReadOnly
= pView
->IsReadonly();
2331 pView
->SetReadonly(!isReadOnly
);
2335 void CMainFrame::OnUpdateEditEnable(CCmdUI
*pCmdUI
)
2337 CBaseView
* pView
= GetActiveBaseView();
2340 pCmdUI
->Enable(pView
->IsReadonlyChangable() || !pView
->IsReadonly());
2341 pCmdUI
->SetCheck(!pView
->IsReadonly());
2345 pCmdUI
->Enable(FALSE
);
2349 void CMainFrame::OnIndicatorLeftview()
2353 if (IsViewGood(m_pwndLeftView
))
2355 m_pwndLeftView
->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_LEFTVIEW
);
2359 void CMainFrame::OnIndicatorRightview()
2363 if (IsViewGood(m_pwndRightView
))
2365 m_pwndRightView
->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_RIGHTVIEW
);
2369 void CMainFrame::OnIndicatorBottomview()
2373 if (IsViewGood(m_pwndBottomView
))
2375 m_pwndBottomView
->AskUserForNewLineEndingsAndTextType(IDS_STATUSBAR_BOTTOMVIEW
);
2379 int CMainFrame::CheckForReload()
2381 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
2387 bool bSourceChanged
=
2388 m_Data
.m_baseFile
.HasSourceFileChanged()
2389 || m_Data
.m_yourFile
.HasSourceFileChanged()
2390 || m_Data
.m_theirFile
.HasSourceFileChanged()
2391 /*|| m_Data.m_mergedFile.HasSourceFileChanged()*/;
2392 if (!bSourceChanged
)
2398 CString msg
= HasUnsavedEdits() ? CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDELOOSECHANGES
)) : CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE
));
2399 CTaskDialog
taskdlg(msg
,
2400 CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE_TASK2
)),
2401 L
"TortoiseGitMerge",
2403 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
2405 if (HasUnsavedEdits())
2406 sTask3
.LoadString(IDS_WARNMODIFIEDOUTSIDE_TASK3
);
2408 sTask3
.LoadString(IDS_WARNMODIFIEDOUTSIDE_TASK4
);
2409 taskdlg
.AddCommandControl(IDYES
, sTask3
);
2410 taskdlg
.AddCommandControl(IDNO
, CString(MAKEINTRESOURCE(IDS_WARNMODIFIEDOUTSIDE_TASK5
)));
2411 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
2412 taskdlg
.SetDefaultCommandControl(IDYES
);
2413 taskdlg
.SetMainIcon(TD_WARNING_ICON
);
2414 UINT ret
= (UINT
)taskdlg
.DoModal(m_hWnd
);
2417 CDiffColors::GetInstance().LoadRegistry();
2422 if (IsViewGood(m_pwndBottomView
)) // three pane view
2424 /*if (m_Data.m_sourceFile.HasSourceFileChanged())
2425 m_pwndBottomView->SetModified();
2426 if (m_Data.m_mergedFile.HasSourceFileChanged())
2427 m_pwndBottomView->SetModified();//*/
2428 if (m_Data
.m_yourFile
.HasSourceFileChanged())
2429 m_pwndRightView
->SetModified();
2430 if (m_Data
.m_theirFile
.HasSourceFileChanged())
2431 m_pwndLeftView
->SetModified();
2433 else if (IsViewGood(m_pwndRightView
)) // two pane view
2435 if (m_Data
.m_baseFile
.HasSourceFileChanged())
2436 m_pwndLeftView
->SetModified();
2437 if (m_Data
.m_yourFile
.HasSourceFileChanged())
2438 m_pwndRightView
->SetModified();
2442 if (m_Data
.m_yourFile
.HasSourceFileChanged())
2443 m_pwndLeftView
->SetModified();
2446 // no reload just store updated file time
2447 m_Data
.m_baseFile
.StoreFileAttributes();
2448 m_Data
.m_theirFile
.StoreFileAttributes();
2449 m_Data
.m_yourFile
.StoreFileAttributes();
2450 //m_Data.m_mergedFile.StoreFileAttributes();
2456 int CMainFrame::CheckForSave(ECheckForSaveReason eReason
)
2458 int idTitle
= IDS_WARNMODIFIEDLOOSECHANGES
;
2459 int idNoSave
= IDS_ASKFORSAVE_TASK7
;
2460 int idCancelAction
= IDS_ASKFORSAVE_CANCEL_OPEN
;
2464 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2465 idNoSave
= IDS_ASKFORSAVE_TASK4
;
2466 idCancelAction
= IDS_ASKFORSAVE_TASK5
;
2469 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2470 //idNoSave = IDS_ASKFORSAVE_TASK7;
2471 idCancelAction
= IDS_ASKFORSAVE_TASK8
;
2474 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2475 //idNoSave = IDS_ASKFORSAVE_TASK7;
2476 idCancelAction
= IDS_ASKFORSAVE_CANCEL_OPEN
;
2479 idTitle
= IDS_WARNMODIFIEDLOOSECHANGESOPTIONS
;
2480 //idNoSave = IDS_ASKFORSAVE_TASK7;
2481 idCancelAction
= IDS_ASKFORSAVE_CANCEL_OPTIONS
;
2484 //idTitle = IDS_WARNMODIFIEDLOOSECHANGES;
2485 idNoSave
= IDS_ASKFORSAVE_NOSAVE_OPEN
;
2486 idCancelAction
= IDS_ASKFORSAVE_CANCEL_OPEN
;
2490 CString
sTitle(MAKEINTRESOURCE(idTitle
));
2491 CString
sSubTitle(MAKEINTRESOURCE(IDS_ASKFORSAVE_TASK2
));
2492 CString
sNoSave(MAKEINTRESOURCE(idNoSave
));
2493 CString
sCancelAction(MAKEINTRESOURCE(idCancelAction
));
2494 CString
sAppName(MAKEINTRESOURCE(IDS_APPNAME
));
2496 // TODO simplify logic, reduce code duplication
2497 if (CBaseView::IsViewGood(m_pwndBottomView
))
2499 // three-way diff - by design only bottom can be changed
2500 // use 1.7 way to do that
2502 else if (CBaseView::IsViewGood(m_pwndRightView
))
2505 // 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
2506 if (HasUnsavedEdits(m_pwndLeftView
))
2509 CTaskDialog
taskdlg(sTitle
,
2513 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
2515 if (m_pwndLeftView
->m_pWorkingFile
->InUse() && !m_pwndLeftView
->m_pWorkingFile
->IsReadonly())
2516 sTaskTemp
.Format(IDS_ASKFORSAVE_SAVELEFT
, (LPCTSTR
)m_pwndLeftView
->m_pWorkingFile
->GetFilename());
2518 sTaskTemp
= CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVELEFTAS
));
2519 taskdlg
.AddCommandControl(201, sTaskTemp
); // left
2520 taskdlg
.SetDefaultCommandControl(201);
2521 if (HasUnsavedEdits(m_pwndRightView
))
2523 if (m_pwndRightView
->m_pWorkingFile
->InUse() && !m_pwndRightView
->m_pWorkingFile
->IsReadonly())
2524 sTaskTemp
.Format(IDS_ASKFORSAVE_SAVERIGHT
, (LPCTSTR
)m_pwndRightView
->m_pWorkingFile
->GetFilename());
2526 sTaskTemp
= CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVERIGHTAS
));
2527 taskdlg
.AddCommandControl(202, sTaskTemp
); // right
2528 taskdlg
.AddCommandControl(203, CString(MAKEINTRESOURCE(IDS_ASKFORSAVE_SAVEALL2
))); // both
2529 taskdlg
.SetDefaultCommandControl(203);
2531 taskdlg
.AddCommandControl(IDNO
, sNoSave
); // none
2532 taskdlg
.AddCommandControl(IDCANCEL
, sCancelAction
); // cancel
2533 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
2534 taskdlg
.SetMainIcon(TD_WARNING_ICON
);
2535 UINT ret
= (UINT
)taskdlg
.DoModal(m_hWnd
);
2539 m_pwndLeftView
->SaveFile(SAVE_REMOVEDLINES
);
2542 m_pwndLeftView
->SaveFile(SAVE_REMOVEDLINES
);
2544 m_pwndRightView
->SaveFile();
2547 if (ret
!= IDCANCEL
&& (eReason
== CHFSR_CLOSE
|| eReason
== CHFSR_OPEN
))
2548 DeleteBaseTheirsMineOnClose();
2553 // only secondary (left) view
2555 // only right view - 1.7 implementation is used
2557 else if (CBaseView::IsViewGood(m_pwndLeftView
))
2559 // only one view - only one to save
2560 // 1.7 FileSave don't support this mode
2561 if (HasUnsavedEdits(m_pwndLeftView
))
2563 CTaskDialog
taskdlg(sTitle
,
2567 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
2569 if (m_Data
.m_mergedFile
.InUse())
2570 sTask3
.Format(IDS_ASKFORSAVE_TASK3
, (LPCTSTR
)m_Data
.m_mergedFile
.GetFilename());
2572 sTask3
.LoadString(IDS_ASKFORSAVE_TASK6
);
2573 taskdlg
.AddCommandControl(IDYES
, sTask3
);
2574 taskdlg
.AddCommandControl(IDNO
, sNoSave
);
2575 taskdlg
.AddCommandControl(IDCANCEL
, sCancelAction
);
2576 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
2577 taskdlg
.SetDefaultCommandControl(IDYES
);
2578 taskdlg
.SetMainIcon(TD_WARNING_ICON
);
2579 if ((UINT
)taskdlg
.DoModal(m_hWnd
) == IDYES
)
2581 if (m_pwndLeftView
->SaveFile()<0)
2585 if (eReason
== CHFSR_CLOSE
|| eReason
== CHFSR_OPEN
)
2586 DeleteBaseTheirsMineOnClose();
2591 if (eReason
== CHFSR_CLOSE
|| eReason
== CHFSR_OPEN
)
2592 DeleteBaseTheirsMineOnClose();
2593 return IDNO
; // nothing to save
2596 // 1.7 implementation
2598 if (HasUnsavedEdits())
2600 CTaskDialog
taskdlg(sTitle
,
2604 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
2606 if (m_Data
.m_mergedFile
.InUse())
2607 sTask3
.Format(IDS_ASKFORSAVE_TASK3
, (LPCTSTR
)m_Data
.m_mergedFile
.GetFilename());
2609 sTask3
.LoadString(IDS_ASKFORSAVE_TASK6
);
2610 taskdlg
.AddCommandControl(IDYES
, sTask3
);
2611 taskdlg
.AddCommandControl(IDNO
, sNoSave
);
2612 taskdlg
.AddCommandControl(IDCANCEL
, sCancelAction
);
2613 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
2614 taskdlg
.SetDefaultCommandControl(IDYES
);
2615 taskdlg
.SetMainIcon(TD_WARNING_ICON
);
2616 ret
= (UINT
)taskdlg
.DoModal(m_hWnd
);
2625 if (ret
!= IDCANCEL
&& (eReason
== CHFSR_CLOSE
|| eReason
== CHFSR_OPEN
))
2626 DeleteBaseTheirsMineOnClose();
2631 void CMainFrame::DeleteBaseTheirsMineOnClose()
2633 if (!m_bDeleteBaseTheirsMineOnClose
)
2636 m_bDeleteBaseTheirsMineOnClose
= false;
2638 DeleteFile(m_Data
.m_baseFile
.GetFilename());
2639 DeleteFile(m_Data
.m_theirFile
.GetFilename());
2640 DeleteFile(m_Data
.m_yourFile
.GetFilename());
2643 bool CMainFrame::HasUnsavedEdits() const
2645 return HasUnsavedEdits(m_pwndBottomView
) || HasUnsavedEdits(m_pwndRightView
) || m_bSaveRequired
;
2648 bool CMainFrame::HasUnsavedEdits(const CBaseView
* view
)
2650 if (!CBaseView::IsViewGood(view
))
2652 return view
->IsModified();
2655 bool CMainFrame::HasMarkedBlocks() const
2657 return CBaseView::IsViewGood(m_pwndRightView
) && m_pwndRightView
->HasMarkedBlocks();
2660 bool CMainFrame::IsViewGood(const CBaseView
* view
)
2662 return CBaseView::IsViewGood(view
);
2665 void CMainFrame::OnViewInlinediffword()
2667 m_bInlineWordDiff
= !m_bInlineWordDiff
;
2670 m_pwndLeftView
->SetInlineWordDiff(m_bInlineWordDiff
);
2671 m_pwndLeftView
->BuildAllScreen2ViewVector();
2672 m_pwndLeftView
->DocumentUpdated();
2674 if (m_pwndRightView
)
2676 m_pwndRightView
->SetInlineWordDiff(m_bInlineWordDiff
);
2677 m_pwndRightView
->BuildAllScreen2ViewVector();
2678 m_pwndRightView
->DocumentUpdated();
2680 if (m_pwndBottomView
)
2682 m_pwndBottomView
->SetInlineWordDiff(m_bInlineWordDiff
);
2683 m_pwndBottomView
->BuildAllScreen2ViewVector();
2684 m_pwndBottomView
->DocumentUpdated();
2686 m_wndLineDiffBar
.DocumentUpdated();
2689 void CMainFrame::OnUpdateViewInlinediffword(CCmdUI
*pCmdUI
)
2691 pCmdUI
->Enable(m_bInlineDiff
&& IsViewGood(m_pwndLeftView
) && IsViewGood(m_pwndRightView
));
2692 pCmdUI
->SetCheck(m_bInlineWordDiff
);
2695 void CMainFrame::OnViewInlinediff()
2697 m_bInlineDiff
= !m_bInlineDiff
;
2700 m_pwndLeftView
->SetInlineDiff(m_bInlineDiff
);
2701 m_pwndLeftView
->BuildAllScreen2ViewVector();
2702 m_pwndLeftView
->DocumentUpdated();
2704 if (m_pwndRightView
)
2706 m_pwndRightView
->SetInlineDiff(m_bInlineDiff
);
2707 m_pwndRightView
->BuildAllScreen2ViewVector();
2708 m_pwndRightView
->DocumentUpdated();
2710 if (m_pwndBottomView
)
2712 m_pwndBottomView
->SetInlineDiff(m_bInlineDiff
);
2713 m_pwndBottomView
->BuildAllScreen2ViewVector();
2714 m_pwndBottomView
->DocumentUpdated();
2716 m_wndLineDiffBar
.DocumentUpdated();
2719 void CMainFrame::OnUpdateViewInlinediff(CCmdUI
*pCmdUI
)
2721 pCmdUI
->Enable(IsViewGood(m_pwndLeftView
) && IsViewGood(m_pwndRightView
));
2722 pCmdUI
->SetCheck(m_bInlineDiff
);
2725 void CMainFrame::OnUpdateEditCreateunifieddifffile(CCmdUI
*pCmdUI
)
2727 // "create unified diff file" is only available if two files
2728 // are diffed, not three.
2729 bool bEnabled
= true;
2730 if (!IsViewGood(m_pwndLeftView
))
2732 else if (!IsViewGood(m_pwndRightView
))
2734 else if (IsViewGood(m_pwndBottomView
)) //no negation here
2736 pCmdUI
->Enable(bEnabled
);
2739 void CMainFrame::OnEditCreateunifieddifffile()
2741 CString origFile
, modifiedFile
;
2742 CString origReflected
, modifiedReflected
;
2743 // the original file is the one on the left
2746 origFile
= m_pwndLeftView
->m_sFullFilePath
;
2747 origReflected
= m_pwndLeftView
->m_sReflectedName
;
2749 if (m_pwndRightView
)
2751 modifiedFile
= m_pwndRightView
->m_sFullFilePath
;
2752 modifiedReflected
= m_pwndRightView
->m_sReflectedName
;
2754 if (origFile
.IsEmpty() || modifiedFile
.IsEmpty())
2758 if(!TryGetFileName(outputFile
))
2761 CRegStdDWORD
regContextLines(L
"Software\\TortoiseGitMerge\\ContextLines", (DWORD
)-1);
2762 CAppUtils::CreateUnifiedDiff(origFile
, modifiedFile
, outputFile
, regContextLines
, true);
2763 // from here a hacky solution exchanges the paths included in the patch, see issue #2541
2764 if (origReflected
.IsEmpty() || modifiedReflected
.IsEmpty())
2766 CString projectDir1
, projectDir2
;
2767 if (!GitAdminDir::HasAdminDir(origReflected
, &projectDir1
) || !GitAdminDir::HasAdminDir(modifiedReflected
, &projectDir2
) || projectDir1
!= projectDir2
)
2769 CStringA origReflectedA
= CUnicodeUtils::GetUTF8(origReflected
.Mid(projectDir1
.GetLength() + 1));
2770 CStringA modifiedReflectedA
= CUnicodeUtils::GetUTF8(modifiedReflected
.Mid(projectDir1
.GetLength() + 1));
2771 origReflectedA
.Replace('\\', '/');
2772 modifiedReflectedA
.Replace('\\', '/');
2776 // w/o typeBinary for some files \r gets dropped
2777 if (!file
.Open(outputFile
, CFile::typeBinary
| CFile::modeReadWrite
| CFile::shareExclusive
))
2780 CStringA filecontent
;
2781 UINT filelength
= (UINT
)file
.GetLength();
2782 int bytesread
= (int)file
.Read(filecontent
.GetBuffer(filelength
), filelength
);
2783 filecontent
.ReleaseBuffer(bytesread
);
2785 if (!CStringUtils::StartsWith(filecontent
, "diff --git "))
2787 int lineend
= filecontent
.Find("\n");
2788 if (lineend
<= (int)strlen("diff --git "))
2790 CStringA newStart
= "diff --git \"a/" + origReflectedA
+ "\" \"b/" + modifiedReflectedA
+ "\"\n";
2791 if (!CStringUtils::StartsWith(filecontent
.GetBuffer() + lineend
, "\nindex "))
2793 int nextlineend
= filecontent
.Find("\n", lineend
+ 1);
2794 if (nextlineend
<= lineend
)
2796 newStart
+= filecontent
.Mid(lineend
+ 1, nextlineend
- lineend
);
2797 lineend
= filecontent
.Find("\n--- ", nextlineend
);
2798 nextlineend
= filecontent
.Find("\n@@ ", lineend
);
2799 if (nextlineend
<= lineend
)
2801 newStart
+= "--- \"a/" + origReflectedA
+ "\"\n+++ \"b/" + modifiedReflectedA
+ "\"";
2802 filecontent
= newStart
+ filecontent
.Mid(nextlineend
);
2804 file
.Write(filecontent
, (UINT
)filecontent
.GetLength());
2805 file
.SetLength(file
.GetPosition());
2808 catch (CFileException
*)
2813 void CMainFrame::OnUpdateViewLinediffbar(CCmdUI
*pCmdUI
)
2815 pCmdUI
->SetCheck(m_bLineDiff
);
2819 void CMainFrame::OnViewLinediffbar()
2821 m_bLineDiff
= !m_bLineDiff
;
2822 m_wndLineDiffBar
.ShowPane(m_bLineDiff
, false, true);
2823 m_wndLineDiffBar
.DocumentUpdated();
2824 m_wndLocatorBar
.ShowPane(m_bLocatorBar
, false, true);
2825 m_wndLocatorBar
.DocumentUpdated();
2828 void CMainFrame::OnUpdateViewLocatorbar(CCmdUI
*pCmdUI
)
2830 pCmdUI
->SetCheck(m_bLocatorBar
);
2834 void CMainFrame::OnUpdateViewBars(CCmdUI
* pCmdUI
)
2839 void CMainFrame::OnViewLocatorbar()
2841 m_bLocatorBar
= !m_bLocatorBar
;
2842 m_wndLocatorBar
.ShowPane(m_bLocatorBar
, false, true);
2843 m_wndLocatorBar
.DocumentUpdated();
2844 m_wndLineDiffBar
.ShowPane(m_bLineDiff
, false, true);
2845 m_wndLineDiffBar
.DocumentUpdated();
2848 void CMainFrame::OnViewComparewhitespaces()
2850 if (CheckForSave(CHFSR_OPTIONS
)==IDCANCEL
)
2852 CRegDWORD
regIgnoreWS(L
"Software\\TortoiseGitMerge\\IgnoreWS");
2857 void CMainFrame::OnUpdateViewComparewhitespaces(CCmdUI
*pCmdUI
)
2859 CRegDWORD
regIgnoreWS(L
"Software\\TortoiseGitMerge\\IgnoreWS");
2860 DWORD dwIgnoreWS
= regIgnoreWS
;
2861 pCmdUI
->SetCheck(dwIgnoreWS
== 0);
2864 void CMainFrame::OnViewIgnorewhitespacechanges()
2866 if (CheckForSave(CHFSR_OPTIONS
)==IDCANCEL
)
2868 CRegDWORD
regIgnoreWS(L
"Software\\TortoiseGitMerge\\IgnoreWS");
2873 void CMainFrame::OnUpdateViewIgnorewhitespacechanges(CCmdUI
*pCmdUI
)
2875 CRegDWORD
regIgnoreWS(L
"Software\\TortoiseGitMerge\\IgnoreWS");
2876 DWORD dwIgnoreWS
= regIgnoreWS
;
2877 pCmdUI
->SetCheck(dwIgnoreWS
== 2);
2880 void CMainFrame::OnViewIgnoreallwhitespacechanges()
2882 if (CheckForSave(CHFSR_OPTIONS
)==IDCANCEL
)
2884 CRegDWORD
regIgnoreWS(L
"Software\\TortoiseGitMerge\\IgnoreWS");
2889 void CMainFrame::OnUpdateViewIgnoreallwhitespacechanges(CCmdUI
*pCmdUI
)
2891 CRegDWORD
regIgnoreWS(L
"Software\\TortoiseGitMerge\\IgnoreWS");
2892 DWORD dwIgnoreWS
= regIgnoreWS
;
2893 pCmdUI
->SetCheck(dwIgnoreWS
== 1);
2896 void CMainFrame::OnViewMovedBlocks()
2898 m_bViewMovedBlocks
= !(DWORD
)m_regViewModedBlocks
;
2899 m_regViewModedBlocks
= m_bViewMovedBlocks
;
2903 void CMainFrame::OnUpdateViewMovedBlocks(CCmdUI
*pCmdUI
)
2905 pCmdUI
->SetCheck(m_bViewMovedBlocks
);
2906 BOOL bEnable
= TRUE
;
2907 if (IsViewGood(m_pwndBottomView
))
2911 pCmdUI
->Enable(bEnable
);
2914 bool CMainFrame::HasConflictsWontKeep()
2916 const int nConflictLine
= CheckResolved();
2917 if (nConflictLine
< 0)
2919 if (!m_pwndBottomView
)
2923 sTemp
.Format(IDS_ERR_MAINFRAME_FILEHASCONFLICTS
, m_pwndBottomView
->m_pViewData
->GetLineNumber(nConflictLine
)+1);
2924 CTaskDialog
taskdlg(sTemp
,
2925 CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK2
)),
2926 L
"TortoiseGitMerge",
2928 TDF_ENABLE_HYPERLINKS
| TDF_USE_COMMAND_LINKS
| TDF_ALLOW_DIALOG_CANCELLATION
| TDF_POSITION_RELATIVE_TO_WINDOW
);
2929 taskdlg
.AddCommandControl(1, CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK3
)));
2930 taskdlg
.AddCommandControl(2, CString(MAKEINTRESOURCE(IDS_ERR_MAINFRAME_FILEHASCONFLICTS_TASK4
)));
2931 taskdlg
.SetCommonButtons(TDCBF_CANCEL_BUTTON
);
2932 taskdlg
.SetDefaultCommandControl(2);
2933 taskdlg
.SetMainIcon(TD_ERROR_ICON
);
2934 if (taskdlg
.DoModal(m_hWnd
) == 1)
2937 m_pwndBottomView
->GoToLine(nConflictLine
);
2941 bool CMainFrame::TryGetFileName(CString
& result
)
2943 return CCommonAppUtils::FileOpenSave(result
, nullptr, IDS_SAVEASTITLE
, IDS_COMMONFILEFILTER
, false, m_hWnd
);
2946 CBaseView
* CMainFrame::GetActiveBaseView() const
2948 CView
* activeView
= GetActiveView();
2949 CBaseView
* activeBase
= dynamic_cast<CBaseView
*>( activeView
);
2953 void CMainFrame::SetWindowTitle()
2955 // try to find a suitable window title
2956 CString sYour
= m_Data
.m_yourFile
.GetDescriptiveName();
2957 if (sYour
.Find(L
" - ") >= 0)
2958 sYour
= sYour
.Left(sYour
.Find(L
" - "));
2959 if (sYour
.Find(L
" : ") >= 0)
2960 sYour
= sYour
.Left(sYour
.Find(L
" : "));
2961 CString sTheir
= m_Data
.m_theirFile
.GetDescriptiveName();
2962 if (sTheir
.IsEmpty())
2963 sTheir
= m_Data
.m_baseFile
.GetDescriptiveName();
2964 if (sTheir
.Find(L
" - ") >= 0)
2965 sTheir
= sTheir
.Left(sTheir
.Find(L
" - "));
2966 if (sTheir
.Find(L
" : ") >= 0)
2967 sTheir
= sTheir
.Left(sTheir
.Find(L
" : "));
2969 if (!sYour
.IsEmpty() && !sTheir
.IsEmpty())
2971 if (sYour
.CompareNoCase(sTheir
)==0)
2972 SetWindowText(sYour
+ L
" - TortoiseGitMerge");
2973 else if ((sYour
.GetLength() < 10) &&
2974 (sTheir
.GetLength() < 10))
2975 SetWindowText(sYour
+ L
" - " + sTheir
+ L
" - TortoiseGitMerge");
2978 // we have two very long descriptive texts here, which
2979 // means we have to find a way to use them as a window
2980 // title in a shorter way.
2981 // for simplicity, we just use the one from "yourfile"
2982 SetWindowText(sYour
+ L
" - TortoiseGitMerge");
2985 else if (!sYour
.IsEmpty())
2986 SetWindowText(sYour
+ L
" - TortoiseGitMerge");
2987 else if (!sTheir
.IsEmpty())
2988 SetWindowText(sTheir
+ L
" - TortoiseGitMerge");
2990 SetWindowText(L
"TortoiseGitMerge");
2993 void CMainFrame::OnTimer(UINT_PTR nIDEvent
)
2997 case IDT_RELOADCHECKTIMER
:
2998 KillTimer(nIDEvent
);
3003 __super::OnTimer(nIDEvent
);
3006 void CMainFrame::LoadIgnoreCommentData()
3008 static bool bLoaded
= false;
3011 CString sPath
= CPathUtils::GetAppDataDirectory() + L
"ignorecomments.txt";
3012 if (!PathFileExists(sPath
))
3014 // ignore comments file does not exist (yet), so create a default one
3015 HRSRC hRes
= FindResource(nullptr, MAKEINTRESOURCE(IDR_IGNORECOMMENTSTXT
), L
"config");
3018 HGLOBAL hResourceLoaded
= LoadResource(nullptr, hRes
);
3019 if (hResourceLoaded
)
3021 char * lpResLock
= (char *) LockResource(hResourceLoaded
);
3022 DWORD dwSizeRes
= SizeofResource(nullptr, hRes
);
3025 HANDLE hFile
= CreateFile(sPath
, GENERIC_WRITE
, 0, nullptr, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, nullptr);
3026 if (hFile
!= INVALID_HANDLE_VALUE
)
3028 DWORD dwWritten
= 0;
3029 WriteFile(hFile
, lpResLock
, dwSizeRes
, &dwWritten
, nullptr);
3040 if (file
.Open(sPath
, CFile::modeRead
))
3043 while (file
.ReadString(sLine
))
3045 int eqpos
= sLine
.Find('=');
3048 CString sExts
= sLine
.Left(eqpos
);
3049 CString sComments
= sLine
.Mid(eqpos
+1);
3051 int pos
= sComments
.Find(',');
3052 CString sLineStart
= sComments
.Left(pos
);
3053 pos
= sComments
.Find(',', pos
);
3054 int pos2
= sComments
.Find(',', pos
+1);
3055 CString sBlockStart
= sComments
.Mid(pos
+1, pos2
-pos
-1);
3056 CString sBlockEnd
= sComments
.Mid(pos2
+1);
3058 auto commentTuple
= std::make_tuple(sLineStart
, sBlockStart
, sBlockEnd
);
3064 temp
= sExts
.Tokenize(L
",", pos
);
3069 ASSERT(m_IgnoreCommentsMap
.find(temp
) == m_IgnoreCommentsMap
.end());
3070 m_IgnoreCommentsMap
[temp
] = commentTuple
;
3076 catch (CFileException
* e
)
3083 void CMainFrame::OnViewIgnorecomments()
3085 if (CheckForSave(CHFSR_OPTIONS
)==IDCANCEL
)
3087 m_regIgnoreComments
= !DWORD(m_regIgnoreComments
);
3091 void CMainFrame::OnUpdateViewIgnorecomments(CCmdUI
*pCmdUI
)
3093 // only enable if we have comments defined for this file extension
3094 CString sExt
= CPathUtils::GetFileExtFromPath(m_Data
.m_baseFile
.GetFilename()).MakeLower();
3095 sExt
.TrimLeft(L
".");
3096 auto sC
= m_IgnoreCommentsMap
.find(sExt
);
3097 if (sC
== m_IgnoreCommentsMap
.end())
3099 sExt
= CPathUtils::GetFileExtFromPath(m_Data
.m_yourFile
.GetFilename()).MakeLower();
3100 sExt
.TrimLeft(L
".");
3101 sC
= m_IgnoreCommentsMap
.find(sExt
);
3102 if (sC
== m_IgnoreCommentsMap
.end())
3104 sExt
= CPathUtils::GetFileExtFromPath(m_Data
.m_theirFile
.GetFilename()).MakeLower();
3105 sExt
.TrimLeft(L
".");
3106 sC
= m_IgnoreCommentsMap
.find(sExt
);
3109 pCmdUI
->Enable(sC
!= m_IgnoreCommentsMap
.end());
3111 pCmdUI
->SetCheck(DWORD(m_regIgnoreComments
) != 0);
3115 void CMainFrame::OnRegexfilter(UINT cmd
)
3117 if ((cmd
== ID_REGEXFILTER
)||(cmd
== (ID_REGEXFILTER
+1)))
3119 CRegexFiltersDlg
dlg(this);
3120 dlg
.SetIniFile(&m_regexIni
);
3121 if (dlg
.DoModal() == IDOK
)
3123 FILE* pFile
= nullptr;
3124 _wfopen_s(&pFile
, CPathUtils::GetAppDataDirectory() + L
"regexfilters.ini", L
"wb");
3125 m_regexIni
.SaveFile(pFile
);
3128 BuildRegexSubitems();
3132 if (cmd
== (UINT
)m_regexIndex
&& !m_bUseRibbons
)
3134 if (CheckForSave(CHFSR_OPTIONS
)==IDCANCEL
)
3136 m_Data
.SetRegexTokens(std::wregex(), L
"");
3140 else if (cmd
!= (UINT
)m_regexIndex
)
3142 CSimpleIni::TNamesDepend sections
;
3143 m_regexIni
.GetAllSections(sections
);
3144 int index
= ID_REGEXFILTER
+ 2;
3146 for (const auto& section
: sections
)
3148 if (cmd
== (UINT
)index
)
3150 if (CheckForSave(CHFSR_OPTIONS
)==IDCANCEL
)
3154 std::wregex
rx(m_regexIni
.GetValue(section
.pItem
, L
"regex", L
""));
3155 m_Data
.SetRegexTokens(rx
, m_regexIni
.GetValue(section
.pItem
, L
"replace", L
""));
3157 catch (std::exception
&ex
)
3159 MessageBox(L
"Regex is invalid!\r\n" + CString(ex
.what()));
3161 m_regexIndex
= index
;
3166 catch (const std::regex_error
& ex
)
3168 MessageBox(L
"Regexp error caught:\r\n" + CString(ex
.what()) + L
"\r\nTrying to recover by unsetting it again.");
3169 m_Data
.SetRegexTokens(std::wregex(), L
"");
3181 void CMainFrame::OnUpdateViewRegexFilter( CCmdUI
*pCmdUI
)
3184 pCmdUI
->SetCheck(pCmdUI
->m_nID
== (UINT
)m_regexIndex
);
3187 void CMainFrame::BuildRegexSubitems(CMFCPopupMenu
* pMenuPopup
)
3189 CString sIniPath
= CPathUtils::GetAppDataDirectory() + L
"regexfilters.ini";
3190 if (!PathFileExists(sIniPath
))
3192 // ini file does not exist (yet), so create a default one
3193 HRSRC hRes
= FindResource(nullptr, MAKEINTRESOURCE(IDR_REGEXFILTERINI
), L
"config");
3196 HGLOBAL hResourceLoaded
= LoadResource(nullptr, hRes
);
3197 if (hResourceLoaded
)
3199 char * lpResLock
= (char *)LockResource(hResourceLoaded
);
3200 DWORD dwSizeRes
= SizeofResource(nullptr, hRes
);
3203 HANDLE hFile
= CreateFile(sIniPath
, GENERIC_WRITE
, 0, nullptr, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, nullptr);
3204 if (hFile
!= INVALID_HANDLE_VALUE
)
3206 DWORD dwWritten
= 0;
3207 WriteFile(hFile
, lpResLock
, dwSizeRes
, &dwWritten
, nullptr);
3215 m_regexIni
.LoadFile(sIniPath
);
3216 CSimpleIni::TNamesDepend sections
;
3217 m_regexIni
.GetAllSections(sections
);
3221 std::list
<CNativeRibbonDynamicItemInfo
> items
;
3223 items
.push_back(CNativeRibbonDynamicItemInfo(ID_REGEX_NO_FILTER
, CString(MAKEINTRESOURCE(ID_REGEX_NO_FILTER
)), IDB_REGEX_FILTER
));
3224 for (const auto& section
: sections
)
3226 items
.emplace_back(ID_REGEXFILTER
+ cmdIndex
, section
.pItem
, IDB_REGEX_FILTER
);
3230 m_pRibbonApp
->SetItems(ID_REGEXFILTER
, items
);
3232 else if (pMenuPopup
)
3235 if (!CMFCToolBar::IsCustomizeMode() &&
3236 (iIndex
= pMenuPopup
->GetMenuBar()->CommandToIndex(ID_REGEXFILTER
)) >= 0)
3238 if (!sections
.empty())
3239 pMenuPopup
->InsertSeparator(iIndex
+ 1); // insert the separator at the end
3241 for (const auto& section
: sections
)
3243 pMenuPopup
->InsertItem(CMFCToolBarMenuButton(ID_REGEXFILTER
+ cmdIndex
, nullptr, -1, (LPCWSTR
)section
.pItem
), iIndex
+ cmdIndex
);
3250 void CMainFrame::FillEncodingButton( CMFCRibbonButton
* pButton
, int start
)
3252 pButton
->SetDefaultCommand(FALSE
);
3253 pButton
->AddSubItem(new CMFCRibbonButton(start
+ CFileTextLines::UnicodeType::ASCII
, L
"ASCII" ));
3254 pButton
->AddSubItem(new CMFCRibbonButton(start
+ CFileTextLines::UnicodeType::BINARY
, L
"BINARY" ));
3255 pButton
->AddSubItem(new CMFCRibbonButton(start
+ CFileTextLines::UnicodeType::UTF16_LE
, L
"UTF-16LE" ));
3256 pButton
->AddSubItem(new CMFCRibbonButton(start
+ CFileTextLines::UnicodeType::UTF16_LEBOM
, L
"UTF-16LE BOM"));
3257 pButton
->AddSubItem(new CMFCRibbonButton(start
+ CFileTextLines::UnicodeType::UTF16_BE
, L
"UTF-16BE" ));
3258 pButton
->AddSubItem(new CMFCRibbonButton(start
+ CFileTextLines::UnicodeType::UTF16_BEBOM
, L
"UTF-16BE BOM"));
3259 pButton
->AddSubItem(new CMFCRibbonButton(start
+ CFileTextLines::UnicodeType::UTF32_LE
, L
"UTF-32LE" ));
3260 pButton
->AddSubItem(new CMFCRibbonButton(start
+ CFileTextLines::UnicodeType::UTF32_BE
, L
"UTF-32BE" ));
3261 pButton
->AddSubItem(new CMFCRibbonButton(start
+ CFileTextLines::UnicodeType::UTF8
, L
"UTF-8" ));
3262 pButton
->AddSubItem(new CMFCRibbonButton(start
+ CFileTextLines::UnicodeType::UTF8BOM
, L
"UTF-8 BOM" ));
3265 void CMainFrame::FillEOLButton( CMFCRibbonButton
* pButton
, int start
)
3267 pButton
->SetDefaultCommand(FALSE
);
3268 pButton
->AddSubItem(new CMFCRibbonButton(start
+ EOL::EOL_LF
, L
"LF" ));
3269 pButton
->AddSubItem(new CMFCRibbonButton(start
+ EOL::EOL_CRLF
, L
"CRLF"));
3270 pButton
->AddSubItem(new CMFCRibbonButton(start
+ EOL::EOL_LFCR
, L
"LRCR"));
3271 pButton
->AddSubItem(new CMFCRibbonButton(start
+ EOL::EOL_CR
, L
"CR" ));
3272 pButton
->AddSubItem(new CMFCRibbonButton(start
+ EOL::EOL_VT
, L
"VT" ));
3273 pButton
->AddSubItem(new CMFCRibbonButton(start
+ EOL::EOL_FF
, L
"FF" ));
3274 pButton
->AddSubItem(new CMFCRibbonButton(start
+ EOL::EOL_NEL
, L
"NEL" ));
3275 pButton
->AddSubItem(new CMFCRibbonButton(start
+ EOL::EOL_LS
, L
"LS" ));
3276 pButton
->AddSubItem(new CMFCRibbonButton(start
+ EOL::EOL_PS
, L
"PS" ));
3279 void CMainFrame::FillTabModeButton(CMFCRibbonButton
* pButton
, int start
)
3281 pButton
->SetDefaultCommand(FALSE
);
3282 pButton
->AddSubItem(new CMFCRibbonButton(start
+ TABMODE_NONE
, L
"Tab"));
3283 pButton
->AddSubItem(new CMFCRibbonButton(start
+ TABMODE_USESPACES
, L
"Space"));
3284 pButton
->AddSubItem(new CMFCRibbonSeparator(TRUE
));
3285 pButton
->AddSubItem(new CMFCRibbonButton(start
+ TABMODE_SMARTINDENT
, L
"Smart tab char"));
3286 pButton
->AddSubItem(new CMFCRibbonSeparator(TRUE
));
3287 pButton
->AddSubItem(new CMFCRibbonButton(start
+ TABSIZEBUTTON1
, L
"1"));
3288 pButton
->AddSubItem(new CMFCRibbonButton(start
+ TABSIZEBUTTON2
, L
"2"));
3289 pButton
->AddSubItem(new CMFCRibbonButton(start
+ TABSIZEBUTTON4
, L
"4"));
3290 pButton
->AddSubItem(new CMFCRibbonButton(start
+ TABSIZEBUTTON8
, L
"8"));
3291 pButton
->AddSubItem(new CMFCRibbonSeparator(TRUE
));
3292 pButton
->AddSubItem(new CMFCRibbonButton(start
+ ENABLEEDITORCONFIG
, L
"EditorConfig"));
3295 bool CMainFrame::AdjustUnicodeTypeForLoad(CFileTextLines::UnicodeType
& type
)
3299 case CFileTextLines::UnicodeType::AUTOTYPE
:
3300 case CFileTextLines::UnicodeType::BINARY
:
3303 case CFileTextLines::UnicodeType::ASCII
:
3304 case CFileTextLines::UnicodeType::UTF16_LE
:
3305 case CFileTextLines::UnicodeType::UTF16_BE
:
3306 case CFileTextLines::UnicodeType::UTF32_LE
:
3307 case CFileTextLines::UnicodeType::UTF32_BE
:
3308 case CFileTextLines::UnicodeType::UTF8
:
3311 case CFileTextLines::UnicodeType::UTF16_LEBOM
:
3312 type
= CFileTextLines::UnicodeType::UTF16_LE
;
3315 case CFileTextLines::UnicodeType::UTF16_BEBOM
:
3316 type
= CFileTextLines::UnicodeType::UTF16_BE
;
3319 case CFileTextLines::UnicodeType::UTF8BOM
:
3320 type
= CFileTextLines::UnicodeType::UTF8
;
3326 void CMainFrame::OnEncodingLeft( UINT cmd
)
3330 if (GetKeyState(VK_CONTROL
) & 0x8000)
3332 // reload with selected encoding
3333 auto saveparams
= m_Data
.m_arBaseFile
.GetSaveParams();
3334 saveparams
.m_UnicodeType
= CFileTextLines::UnicodeType(cmd
- ID_INDICATOR_LEFTENCODINGSTART
);
3335 if (AdjustUnicodeTypeForLoad(saveparams
.m_UnicodeType
))
3337 m_Data
.m_arBaseFile
.SetSaveParams(saveparams
);
3338 m_Data
.m_arBaseFile
.KeepEncoding();
3344 m_pwndLeftView
->SetTextType(CFileTextLines::UnicodeType(cmd
- ID_INDICATOR_LEFTENCODINGSTART
));
3345 m_pwndLeftView
->RefreshViews();
3350 void CMainFrame::OnEncodingRight( UINT cmd
)
3352 if (m_pwndRightView
)
3354 if (GetKeyState(VK_CONTROL
) & 0x8000)
3356 // reload with selected encoding
3357 auto saveparams
= m_Data
.m_arYourFile
.GetSaveParams();
3358 saveparams
.m_UnicodeType
= CFileTextLines::UnicodeType(cmd
- ID_INDICATOR_RIGHTENCODINGSTART
);
3359 if (AdjustUnicodeTypeForLoad(saveparams
.m_UnicodeType
))
3361 m_Data
.m_arYourFile
.SetSaveParams(saveparams
);
3362 m_Data
.m_arYourFile
.KeepEncoding();
3368 m_pwndRightView
->SetTextType(CFileTextLines::UnicodeType(cmd
- ID_INDICATOR_RIGHTENCODINGSTART
));
3369 m_pwndRightView
->RefreshViews();
3374 void CMainFrame::OnEncodingBottom( UINT cmd
)
3376 if (m_pwndBottomView
)
3378 if (GetKeyState(VK_CONTROL
) & 0x8000)
3380 // reload with selected encoding
3381 auto saveparams
= m_Data
.m_arTheirFile
.GetSaveParams();
3382 saveparams
.m_UnicodeType
= CFileTextLines::UnicodeType(cmd
- ID_INDICATOR_BOTTOMENCODINGSTART
);
3383 if (AdjustUnicodeTypeForLoad(saveparams
.m_UnicodeType
))
3385 m_Data
.m_arTheirFile
.SetSaveParams(saveparams
);
3386 m_Data
.m_arTheirFile
.KeepEncoding();
3392 m_pwndBottomView
->SetTextType(CFileTextLines::UnicodeType(cmd
- ID_INDICATOR_BOTTOMENCODINGSTART
));
3393 m_pwndBottomView
->RefreshViews();
3398 void CMainFrame::OnEOLLeft( UINT cmd
)
3402 m_pwndLeftView
->ReplaceLineEndings(EOL(cmd
-ID_INDICATOR_LEFTEOLSTART
));
3403 m_pwndLeftView
->RefreshViews();
3407 void CMainFrame::OnEOLRight( UINT cmd
)
3409 if (m_pwndRightView
)
3411 m_pwndRightView
->ReplaceLineEndings(EOL(cmd
-ID_INDICATOR_RIGHTEOLSTART
));
3412 m_pwndRightView
->RefreshViews();
3416 void CMainFrame::OnEOLBottom( UINT cmd
)
3418 if (m_pwndBottomView
)
3420 m_pwndBottomView
->ReplaceLineEndings(EOL(cmd
-ID_INDICATOR_BOTTOMEOLSTART
));
3421 m_pwndBottomView
->RefreshViews();
3425 void CMainFrame::OnTabModeLeft( UINT cmd
)
3427 OnTabMode(m_pwndLeftView
, (int)cmd
- ID_INDICATOR_LEFTTABMODESTART
);
3430 void CMainFrame::OnTabModeRight( UINT cmd
)
3432 OnTabMode(m_pwndRightView
, (int)cmd
- ID_INDICATOR_RIGHTTABMODESTART
);
3435 void CMainFrame::OnTabModeBottom( UINT cmd
)
3437 OnTabMode(m_pwndBottomView
, (int)cmd
- ID_INDICATOR_BOTTOMTABMODESTART
);
3440 void CMainFrame::OnTabMode(CBaseView
*view
, int cmd
)
3444 int nTabMode
= view
->GetTabMode();
3445 if (cmd
== TABMODE_NONE
|| cmd
== TABMODE_USESPACES
)
3446 view
->SetTabMode((nTabMode
& (~TABMODE_USESPACES
)) | (cmd
& TABMODE_USESPACES
));
3447 else if (cmd
== TABMODE_SMARTINDENT
) // Toggle
3448 view
->SetTabMode((nTabMode
& (~TABMODE_SMARTINDENT
)) | ((nTabMode
& TABMODE_SMARTINDENT
) ? 0 : TABMODE_SMARTINDENT
));
3449 else if (cmd
== TABSIZEBUTTON1
)
3450 view
->SetTabSize(1);
3451 else if (cmd
== TABSIZEBUTTON2
)
3452 view
->SetTabSize(2);
3453 else if (cmd
== TABSIZEBUTTON4
)
3454 view
->SetTabSize(4);
3455 else if (cmd
== TABSIZEBUTTON8
)
3456 view
->SetTabSize(8);
3457 else if (cmd
== ENABLEEDITORCONFIG
)
3458 view
->SetEditorConfigEnabled(!view
->GetEditorConfigEnabled());
3459 view
->RefreshViews();
3462 void CMainFrame::OnUpdateEncodingLeft( CCmdUI
*pCmdUI
)
3466 pCmdUI
->SetCheck(CFileTextLines::UnicodeType(pCmdUI
->m_nID
- ID_INDICATOR_LEFTENCODINGSTART
) == m_pwndLeftView
->GetTextType());
3467 pCmdUI
->Enable(m_pwndLeftView
->IsWritable() || (GetKeyState(VK_CONTROL
)&0x8000));
3470 pCmdUI
->Enable(FALSE
);
3473 void CMainFrame::OnUpdateEncodingRight( CCmdUI
*pCmdUI
)
3475 if (m_pwndRightView
)
3477 pCmdUI
->SetCheck(CFileTextLines::UnicodeType(pCmdUI
->m_nID
- ID_INDICATOR_RIGHTENCODINGSTART
) == m_pwndRightView
->GetTextType());
3478 pCmdUI
->Enable(m_pwndRightView
->IsWritable() || (GetKeyState(VK_CONTROL
) & 0x8000));
3481 pCmdUI
->Enable(FALSE
);
3484 void CMainFrame::OnUpdateEncodingBottom( CCmdUI
*pCmdUI
)
3486 if (m_pwndBottomView
)
3488 pCmdUI
->SetCheck(CFileTextLines::UnicodeType(pCmdUI
->m_nID
- ID_INDICATOR_BOTTOMENCODINGSTART
) == m_pwndBottomView
->GetTextType());
3489 pCmdUI
->Enable(m_pwndBottomView
->IsWritable() || (GetKeyState(VK_CONTROL
) & 0x8000));
3492 pCmdUI
->Enable(FALSE
);
3495 void CMainFrame::OnUpdateEOLLeft( CCmdUI
*pCmdUI
)
3499 pCmdUI
->SetCheck(EOL(pCmdUI
->m_nID
- ID_INDICATOR_LEFTEOLSTART
) == m_pwndLeftView
->GetLineEndings());
3500 pCmdUI
->Enable(m_pwndLeftView
->IsWritable());
3503 pCmdUI
->Enable(FALSE
);
3506 void CMainFrame::OnUpdateEOLRight( CCmdUI
*pCmdUI
)
3508 if (m_pwndRightView
)
3510 pCmdUI
->SetCheck(EOL(pCmdUI
->m_nID
- ID_INDICATOR_RIGHTEOLSTART
) == m_pwndRightView
->GetLineEndings());
3511 pCmdUI
->Enable(m_pwndRightView
->IsWritable());
3514 pCmdUI
->Enable(FALSE
);
3517 void CMainFrame::OnUpdateEOLBottom( CCmdUI
*pCmdUI
)
3519 if (m_pwndBottomView
)
3521 pCmdUI
->SetCheck(EOL(pCmdUI
->m_nID
- ID_INDICATOR_BOTTOMEOLSTART
) == m_pwndBottomView
->GetLineEndings());
3522 pCmdUI
->Enable(m_pwndBottomView
->IsWritable());
3525 pCmdUI
->Enable(FALSE
);
3528 void CMainFrame::OnUpdateTabModeLeft(CCmdUI
*pCmdUI
)
3530 OnUpdateTabMode(m_pwndLeftView
, pCmdUI
, ID_INDICATOR_LEFTTABMODESTART
);
3533 void CMainFrame::OnUpdateTabModeRight(CCmdUI
*pCmdUI
)
3535 OnUpdateTabMode(m_pwndRightView
, pCmdUI
, ID_INDICATOR_RIGHTTABMODESTART
);
3538 void CMainFrame::OnUpdateTabModeBottom(CCmdUI
*pCmdUI
)
3540 OnUpdateTabMode(m_pwndBottomView
, pCmdUI
, ID_INDICATOR_BOTTOMTABMODESTART
);
3543 void CMainFrame::OnUpdateTabMode(CBaseView
*view
, CCmdUI
*pCmdUI
, int startid
)
3547 int cmd
= (int)pCmdUI
->m_nID
- startid
;
3548 if (cmd
== TABMODE_NONE
)
3549 pCmdUI
->SetCheck((view
->GetTabMode() & TABMODE_USESPACES
) == TABMODE_NONE
);
3550 else if (cmd
== TABMODE_USESPACES
)
3551 pCmdUI
->SetCheck(view
->GetTabMode() & TABMODE_USESPACES
);
3552 else if (cmd
== TABMODE_SMARTINDENT
)
3553 pCmdUI
->SetCheck(view
->GetTabMode() & TABMODE_SMARTINDENT
);
3554 else if (cmd
== TABSIZEBUTTON1
)
3555 pCmdUI
->SetCheck(view
->GetTabSize() == 1);
3556 else if (cmd
== TABSIZEBUTTON2
)
3557 pCmdUI
->SetCheck(view
->GetTabSize() == 2);
3558 else if (cmd
== TABSIZEBUTTON4
)
3559 pCmdUI
->SetCheck(view
->GetTabSize() == 4);
3560 else if (cmd
== TABSIZEBUTTON8
)
3561 pCmdUI
->SetCheck(view
->GetTabSize() == 8);
3562 else if (cmd
== ENABLEEDITORCONFIG
)
3563 pCmdUI
->SetCheck(view
->GetEditorConfigEnabled());
3564 pCmdUI
->Enable(view
->IsWritable());
3565 if (cmd
== ENABLEEDITORCONFIG
)
3566 pCmdUI
->Enable(view
->IsWritable() && view
->GetEditorConfigLoaded());
3569 pCmdUI
->Enable(FALSE
);
3572 BOOL
CMainFrame::OnShowPopupMenu(CMFCPopupMenu
* pMenuPopup
)
3574 __super::OnShowPopupMenu(pMenuPopup
);
3580 if (!CMFCToolBar::IsCustomizeMode() &&
3581 (iIndex
= pMenuPopup
->GetMenuBar()->CommandToIndex(ID_REGEXFILTER
)) >= 0)
3583 BuildRegexSubitems(pMenuPopup
);
3589 LRESULT
CMainFrame::OnIdleUpdateCmdUI(WPARAM wParam
, LPARAM lParam
)
3591 __super::OnIdleUpdateCmdUI(wParam
, lParam
);
3595 BOOL bDisableIfNoHandler
= (BOOL
)wParam
;
3596 m_pRibbonApp
->UpdateCmdUI(bDisableIfNoHandler
);
3601 void CMainFrame::OnUpdateThreeWayActions(CCmdUI
* pCmdUI
)
3606 void CMainFrame::OnRegexNoFilter()
3608 if (CheckForSave(CHFSR_OPTIONS
) == IDCANCEL
)
3610 m_Data
.SetRegexTokens(std::wregex(), L
"");
3615 void CMainFrame::OnUpdateRegexNoFilter(CCmdUI
* pCmdUI
)
3617 pCmdUI
->SetCheck(m_regexIndex
< 0);