1 // TortoiseMerge - a Diff/Patch program
3 // Copyright (C) 2006, 2008, 2010-2011 - TortoiseSVN
4 // Copyright (C) 2012 - Sven Strickroth <email@cs-ware.de>
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "TortoiseMerge.h"
22 #include "FilePatchesDlg.h"
25 #include "PathUtils.h"
26 #include "SysProgressDlg.h"
29 IMPLEMENT_DYNAMIC(CFilePatchesDlg
, CResizableStandAloneDialog
)
30 CFilePatchesDlg::CFilePatchesDlg(CWnd
* pParent
/*=NULL*/)
31 : CResizableStandAloneDialog(CFilePatchesDlg::IDD
, pParent
)
38 m_ImgList
.Create(16, 16, ILC_COLOR16
| ILC_MASK
, 4, 1);
41 CFilePatchesDlg::~CFilePatchesDlg()
45 void CFilePatchesDlg::DoDataExchange(CDataExchange
* pDX
)
47 CResizableStandAloneDialog::DoDataExchange(pDX
);
48 DDX_Control(pDX
, IDC_FILELIST
, m_cFileList
);
51 BOOL
CFilePatchesDlg::SetFileStatusAsPatched(CString sPath
)
53 for (int i
=0; i
<m_arFileStates
.GetCount(); i
++)
55 if (sPath
.CompareNoCase(m_pPatch
->GetFullPath(m_sPath
, i
)) == 0 || sPath
.CompareNoCase(m_pPatch
->GetFullPath(m_sPath
, i
, 1)) == 0)
57 m_arFileStates
.SetAt(i
, FPDLG_FILESTATE_PATCHED
);
65 BOOL
CFilePatchesDlg::OnInitDialog()
67 CResizableStandAloneDialog::OnInitDialog();
69 // hide the grip since it would overlap with the "path all" button
70 // m_wndGrip.ShowWindow(SW_HIDE); m_nShowCount = -100;
72 AddAnchor(IDC_FILELIST
, TOP_LEFT
, BOTTOM_RIGHT
);
73 AddAnchor(IDC_PATCHSELECTEDBUTTON
, BOTTOM_LEFT
, BOTTOM_RIGHT
);
74 AddAnchor(IDC_PATCHALLBUTTON
, BOTTOM_LEFT
, BOTTOM_RIGHT
);
79 BOOL
CFilePatchesDlg::Init(CPatch
* pPatch
, CPatchFilesDlgCallBack
* pCallBack
, CString sPath
, CWnd
* pParent
)
81 if ((pCallBack
==NULL
)||(pPatch
==NULL
))
83 m_cFileList
.DeleteAllItems();
86 m_arFileStates
.RemoveAll();
88 m_pCallBack
= pCallBack
;
90 if (m_sPath
.IsEmpty())
92 CString
title(MAKEINTRESOURCE(IDS_DIFF_TITLE
));
99 SetTitleWithPath(rect
.Width());
100 if (m_sPath
.Right(1).Compare(_T("\\"))==0)
101 m_sPath
= m_sPath
.Left(m_sPath
.GetLength()-1);
103 m_sPath
= m_sPath
+ _T("\\");
104 for (int i
=m_ImgList
.GetImageCount();i
>0;i
--)
110 m_cFileList
.SetExtendedStyle(LVS_EX_INFOTIP
| LVS_EX_FULLROWSELECT
| LVS_EX_DOUBLEBUFFER
);
111 m_cFileList
.DeleteAllItems();
112 int c
= ((CHeaderCtrl
*)(m_cFileList
.GetDlgItem(0)))->GetItemCount()-1;
114 m_cFileList
.DeleteColumn(c
--);
115 m_cFileList
.InsertColumn(0, _T(""));
117 m_cFileList
.SetRedraw(false);
119 for(int i
=0; i
<m_pPatch
->GetNumberOfFiles(); i
++)
121 CString sFile
= CPathUtils::GetFileNameFromPath(m_pPatch
->GetFilename2(i
));
122 if(sFile
== _T("NUL"))
123 sFile
= CPathUtils::GetFileNameFromPath(m_pPatch
->GetFilename(i
));
126 if (m_sPath
.IsEmpty())
127 state
= FPDLG_FILESTATE_GOOD
;
131 if(m_pPatch
->GetFilename(i
) != m_pPatch
->GetFilename2(i
))
133 if( m_pPatch
->GetFilename(i
) == _T("NUL"))
134 state
= FPDLG_FILESTATE_NEW
;
135 else if (m_pPatch
->GetFilename2(i
) == _T("NUL"))
136 state
= FPDLG_FILESTATE_DELETE
;
138 state
= FPDLG_FILESTATE_RENAME
;
141 int doesApply
= m_pPatch
->PatchFile(i
, m_sPath
);
143 state
= FPDLG_FILESTATE_PATCHED
;
146 if(state
!= FPDLG_FILESTATE_NEW
&&
147 state
!= FPDLG_FILESTATE_RENAME
&&
148 state
!= FPDLG_FILESTATE_DELETE
)
149 state
= FPDLG_FILESTATE_GOOD
;
152 state
= FPDLG_FILESTATE_CONFLICTED
;
154 m_arFileStates
.Add(state
);
157 m_pPatch
->GetFullPath(m_sPath
, i
),
158 FILE_ATTRIBUTE_NORMAL
,
161 SHGFI_ICON
| SHGFI_SMALLICON
| SHGFI_USEFILEATTRIBUTES
);
162 m_cFileList
.InsertItem(i
, sFile
, m_ImgList
.Add(sfi
.hIcon
));
166 int maxcol
= ((CHeaderCtrl
*)(m_cFileList
.GetDlgItem(0)))->GetItemCount()-1;
168 for (col
= mincol
; col
<= maxcol
; col
++)
170 m_cFileList
.SetColumnWidth(col
,LVSCW_AUTOSIZE_USEHEADER
);
173 m_cFileList
.SetImageList(&m_ImgList
, LVSIL_SMALL
);
174 m_cFileList
.SetRedraw(true);
177 pParent
->GetWindowRect(&parentrect
);
179 GetWindowRect(&windowrect
);
181 int width
= windowrect
.right
- windowrect
.left
;
182 int height
= windowrect
.bottom
- windowrect
.top
;
183 windowrect
.right
= parentrect
.left
;
184 windowrect
.left
= windowrect
.right
- width
;
185 if (windowrect
.left
< 0)
188 windowrect
.right
= width
;
190 windowrect
.top
= parentrect
.top
;
191 windowrect
.bottom
= windowrect
.top
+ height
;
193 SetWindowPos(NULL
, windowrect
.left
, windowrect
.top
, width
, height
, SWP_NOACTIVATE
| SWP_NOZORDER
);
195 m_nWindowHeight
= windowrect
.bottom
- windowrect
.top
;
196 m_pMainFrame
= pParent
;
200 BEGIN_MESSAGE_MAP(CFilePatchesDlg
, CResizableStandAloneDialog
)
202 ON_NOTIFY(LVN_GETINFOTIP
, IDC_FILELIST
, OnLvnGetInfoTipFilelist
)
203 ON_NOTIFY(NM_DBLCLK
, IDC_FILELIST
, OnNMDblclkFilelist
)
204 ON_NOTIFY(NM_CUSTOMDRAW
, IDC_FILELIST
, OnNMCustomdrawFilelist
)
205 ON_NOTIFY(NM_RCLICK
, IDC_FILELIST
, OnNMRclickFilelist
)
206 ON_WM_NCLBUTTONDBLCLK()
208 ON_BN_CLICKED(IDC_PATCHSELECTEDBUTTON
, &CFilePatchesDlg::OnBnClickedPatchselectedbutton
)
209 ON_BN_CLICKED(IDC_PATCHALLBUTTON
, &CFilePatchesDlg::OnBnClickedPatchallbutton
)
210 ON_NOTIFY(LVN_ITEMCHANGED
, IDC_FILELIST
, &CFilePatchesDlg::OnLvnItemchangedFilelist
)
213 void CFilePatchesDlg::OnSize(UINT nType
, int cx
, int cy
)
215 CResizableStandAloneDialog::OnSize(nType
, cx
, cy
);
216 if (this->IsWindowVisible())
218 m_cFileList
.SetColumnWidth(0, LVSCW_AUTOSIZE
);
220 SetTitleWithPath(cx
);
223 void CFilePatchesDlg::OnLvnGetInfoTipFilelist(NMHDR
*pNMHDR
, LRESULT
*pResult
)
225 LPNMLVGETINFOTIP pGetInfoTip
= reinterpret_cast<LPNMLVGETINFOTIP
>(pNMHDR
);
227 CString temp
= m_pPatch
->GetFullPath(m_sPath
, pGetInfoTip
->iItem
);
228 CString temp2
= m_pPatch
->GetFullPath(m_sPath
, pGetInfoTip
->iItem
, 1);
232 if(temp
== _T("NUL"))
233 _tcsncpy_s(pGetInfoTip
->pszText
, pGetInfoTip
->cchTextMax
, _T("New file: ") + temp2
, pGetInfoTip
->cchTextMax
);
234 else if(temp2
== _T("NUL"))
235 _tcsncpy_s(pGetInfoTip
->pszText
, pGetInfoTip
->cchTextMax
, _T("Delete file: ") + temp
, pGetInfoTip
->cchTextMax
);
238 _tcsncpy_s(pGetInfoTip
->pszText
, pGetInfoTip
->cchTextMax
, temp
, pGetInfoTip
->cchTextMax
);
242 void CFilePatchesDlg::OnNMDblclkFilelist(NMHDR
*pNMHDR
, LRESULT
*pResult
)
244 LPNMLISTVIEW pNMLV
= reinterpret_cast<LPNMLISTVIEW
>(pNMHDR
);
246 if ((pNMLV
->iItem
< 0) || (pNMLV
->iItem
>= m_arFileStates
.GetCount()))
248 if (m_pCallBack
==NULL
)
250 if (m_sPath
.IsEmpty())
252 m_pCallBack
->DiffFiles(m_pPatch
->GetFullPath(m_sPath
, pNMLV
->iItem
), m_pPatch
->GetRevision(pNMLV
->iItem
),
253 m_pPatch
->GetFilename2(pNMLV
->iItem
), m_pPatch
->GetRevision2(pNMLV
->iItem
));
257 if (m_arFileStates
.GetAt(pNMLV
->iItem
)!=FPDLG_FILESTATE_PATCHED
)
259 m_pCallBack
->PatchFile(pNMLV
->iItem
, false, true);
264 void CFilePatchesDlg::OnNMCustomdrawFilelist(NMHDR
*pNMHDR
, LRESULT
*pResult
)
266 NMLVCUSTOMDRAW
* pLVCD
= reinterpret_cast<NMLVCUSTOMDRAW
*>( pNMHDR
);
268 // Take the default processing unless we set this to something else below.
269 *pResult
= CDRF_DODEFAULT
;
271 // First thing - check the draw stage. If it's the control's prepaint
272 // stage, then tell Windows we want messages for every item.
274 if ( CDDS_PREPAINT
== pLVCD
->nmcd
.dwDrawStage
)
276 *pResult
= CDRF_NOTIFYITEMDRAW
;
278 else if ( CDDS_ITEMPREPAINT
== pLVCD
->nmcd
.dwDrawStage
)
280 // This is the prepaint stage for an item. Here's where we set the
281 // item's text color. Our return value will tell Windows to draw the
282 // item itself, but it will use the new color we set here.
284 COLORREF crText
= ::GetSysColor(COLOR_WINDOWTEXT
);
286 if (m_arFileStates
.GetCount() > (INT_PTR
)pLVCD
->nmcd
.dwItemSpec
)
288 if (m_arFileStates
.GetAt(pLVCD
->nmcd
.dwItemSpec
)==FPDLG_FILESTATE_CONFLICTED
)
290 crText
= RGB(200, 0, 0);
293 if (m_arFileStates
.GetAt(pLVCD
->nmcd
.dwItemSpec
)==FPDLG_FILESTATE_DELETE
)
295 crText
= RGB(200, 0, 0);
298 if (m_arFileStates
.GetAt(pLVCD
->nmcd
.dwItemSpec
)==FPDLG_FILESTATE_RENAME
)
300 crText
= RGB(0, 200, 200);
303 if (m_arFileStates
.GetAt(pLVCD
->nmcd
.dwItemSpec
)==FPDLG_FILESTATE_NEW
)
305 crText
= RGB(0, 0, 200);
308 if (m_arFileStates
.GetAt(pLVCD
->nmcd
.dwItemSpec
)==FPDLG_FILESTATE_PATCHED
)
310 crText
= ::GetSysColor(COLOR_GRAYTEXT
);
312 // Store the color back in the NMLVCUSTOMDRAW struct.
313 pLVCD
->clrText
= crText
;
316 // Tell Windows to paint the control itself.
317 *pResult
= CDRF_DODEFAULT
;
321 void CFilePatchesDlg::OnNMRclickFilelist(NMHDR
* /*pNMHDR*/, LRESULT
*pResult
)
324 if (m_sPath
.IsEmpty())
329 DWORD ptW
= GetMessagePos();
330 point
.x
= GET_X_LPARAM(ptW
);
331 point
.y
= GET_Y_LPARAM(ptW
);
332 if (!popup
.CreatePopupMenu())
335 UINT nFlags
= MF_STRING
| (m_cFileList
.GetSelectedCount() == 1 ? MF_ENABLED
: MF_DISABLED
| MF_GRAYED
);
337 temp
.LoadString(IDS_PATCH_REVIEW
);
338 popup
.AppendMenu(nFlags
, ID_PATCH_REVIEW
, temp
);
339 popup
.SetDefaultItem(ID_PATCH_REVIEW
, FALSE
);
341 temp
.LoadString(IDS_PATCH_PREVIEW
);
342 popup
.AppendMenu(nFlags
, ID_PATCHPREVIEW
, temp
);
344 temp
.LoadString(IDS_PATCH_ALL
);
345 popup
.AppendMenu(MF_STRING
| MF_ENABLED
, ID_PATCHALL
, temp
);
347 nFlags
= MF_STRING
| (m_cFileList
.GetSelectedCount() > 0 ? MF_ENABLED
: MF_DISABLED
| MF_GRAYED
);
348 temp
.LoadString(IDS_PATCH_SELECTED
);
349 popup
.AppendMenu(nFlags
, ID_PATCHSELECTED
, temp
);
351 // if the context menu is invoked through the keyboard, we have to use
352 // a calculated position on where to anchor the menu on
353 if ((point
.x
== -1) && (point
.y
== -1))
356 GetWindowRect(&rect
);
357 point
= rect
.CenterPoint();
362 int cmd
= popup
.TrackPopupMenu(TPM_RETURNCMD
| TPM_LEFTALIGN
| TPM_NONOTIFY
, point
.x
, point
.y
, this, 0);
365 case ID_PATCH_REVIEW
:
368 case ID_PATCHPREVIEW
:
372 int nIndex
= m_cFileList
.GetSelectionMark();
373 if ( m_arFileStates
.GetAt(nIndex
)!=FPDLG_FILESTATE_PATCHED
)
375 m_pCallBack
->PatchFile(nIndex
, false, bReview
);
383 case ID_PATCHSELECTED
:
391 void CFilePatchesDlg::OnNcLButtonDblClk(UINT nHitTest
, CPoint point
)
397 GetWindowRect(&windowrect
);
398 GetClientRect(&clientrect
);
399 m_nWindowHeight
= windowrect
.bottom
- windowrect
.top
;
400 MoveWindow(windowrect
.left
, windowrect
.top
,
401 windowrect
.right
- windowrect
.left
,
402 m_nWindowHeight
- (clientrect
.bottom
- clientrect
.top
));
407 GetWindowRect(&windowrect
);
408 MoveWindow(windowrect
.left
, windowrect
.top
, windowrect
.right
- windowrect
.left
, m_nWindowHeight
);
410 m_bMinimized
= !m_bMinimized
;
411 CResizableStandAloneDialog::OnNcLButtonDblClk(nHitTest
, point
);
414 void CFilePatchesDlg::OnMoving(UINT fwSide
, LPRECT pRect
)
417 m_pMainFrame
->GetWindowRect(&parentRect
);
418 const int stickySize
= 5;
419 if (abs(parentRect
.left
- pRect
->right
) < stickySize
)
421 int width
= pRect
->right
- pRect
->left
;
422 pRect
->right
= parentRect
.left
;
423 pRect
->left
= pRect
->right
- width
;
425 CResizableStandAloneDialog::OnMoving(fwSide
, pRect
);
428 void CFilePatchesDlg::OnOK()
433 void CFilePatchesDlg::SetTitleWithPath(int width
)
436 title
.LoadString(IDS_PATCH_TITLE
);
437 title
+= _T(" ") + m_sPath
;
438 title
= title
.Left(MAX_PATH
-1);
439 PathCompactPath(GetDC()->m_hDC
, title
.GetBuffer(), width
);
440 title
.ReleaseBuffer();
441 SetWindowText(title
);
444 void CFilePatchesDlg::OnBnClickedPatchselectedbutton()
449 void CFilePatchesDlg::OnBnClickedPatchallbutton()
454 void CFilePatchesDlg::PatchAll()
458 CSysProgressDlg progDlg
;
459 progDlg
.SetTitle(IDR_MAINFRAME
);
460 progDlg
.SetShowProgressBar(true);
461 progDlg
.SetLine(1, CString(MAKEINTRESOURCE(IDS_PATCH_ALL
)));
462 progDlg
.ShowModeless(m_hWnd
);
465 for (int i
=0; i
<m_arFileStates
.GetCount() && !progDlg
.HasUserCancelled() && ret
== TRUE
; i
++)
467 if (m_arFileStates
.GetAt(i
)!= FPDLG_FILESTATE_PATCHED
)
469 progDlg
.SetLine(2, m_pPatch
->GetFullPath(m_sPath
, i
), true);
470 ret
= m_pCallBack
->PatchFile(i
, true, false);
472 progDlg
.SetProgress64(i
, m_arFileStates
.GetCount());
478 void CFilePatchesDlg::PatchSelected()
482 CSysProgressDlg progDlg
;
483 progDlg
.SetTitle(IDR_MAINFRAME
);
484 progDlg
.SetShowProgressBar(true);
485 progDlg
.SetLine(1, CString(MAKEINTRESOURCE(IDS_PATCH_SELECTED
)));
486 progDlg
.ShowModeless(m_hWnd
);
488 // The list cannot be sorted by user, so the order of the
489 // items in the list is identical to the order in the array
491 int selCount
= m_cFileList
.GetSelectedCount();
493 POSITION pos
= m_cFileList
.GetFirstSelectedItemPosition();
496 while (((index
= m_cFileList
.GetNextSelectedItem(pos
)) >= 0) && (!progDlg
.HasUserCancelled()) && ret
== TRUE
)
498 if (m_arFileStates
.GetAt(index
)!= FPDLG_FILESTATE_PATCHED
)
500 progDlg
.SetLine(2, m_pPatch
->GetFullPath(m_sPath
, index
), true);
501 ret
= m_pCallBack
->PatchFile(index
, true, false);
503 progDlg
.SetProgress64(count
++, selCount
);
509 void CFilePatchesDlg::OnLvnItemchangedFilelist(NMHDR
* /*pNMHDR*/, LRESULT
*pResult
)
511 DialogEnableWindow(IDC_PATCHSELECTEDBUTTON
, m_cFileList
.GetSelectedCount() > 0);