1 // TortoiseMerge - a Diff/Patch program
3 // Copyright (C) 2006, 2008 - Stefan Kueng
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "TortoiseMerge.h"
21 #include "FilePatchesDlg.h"
24 #include "PathUtils.h"
25 #include "ProgressDlg.h"
28 IMPLEMENT_DYNAMIC(CFilePatchesDlg
, CDialog
)
29 CFilePatchesDlg::CFilePatchesDlg(CWnd
* pParent
/*=NULL*/)
30 : CDialog(CFilePatchesDlg::IDD
, pParent
)
32 m_ImgList
.Create(16, 16, ILC_COLOR16
| ILC_MASK
, 4, 1);
36 CFilePatchesDlg::~CFilePatchesDlg()
40 void CFilePatchesDlg::DoDataExchange(CDataExchange
* pDX
)
42 CDialog::DoDataExchange(pDX
);
43 DDX_Control(pDX
, IDC_FILELIST
, m_cFileList
);
46 BOOL
CFilePatchesDlg::SetFileStatusAsPatched(CString sPath
)
48 for (int i
=0; i
<m_arFileStates
.GetCount(); i
++)
50 if (sPath
.CompareNoCase(GetFullPath(i
))==0)
52 m_arFileStates
.SetAt(i
, FPDLG_FILESTATE_PATCHED
);
60 CString
CFilePatchesDlg::GetFullPath(int nIndex
)
62 CString temp
= m_pPatch
->GetFilename(nIndex
);
63 temp
.Replace('/', '\\');
64 //temp = temp.Mid(temp.Find('\\')+1);
65 if (PathIsRelative(temp
))
66 temp
= m_sPath
+ temp
;
70 BOOL
CFilePatchesDlg::Init(CPatch
* pPatch
, CPatchFilesDlgCallBack
* pCallBack
, CString sPath
, CWnd
* pParent
)
72 if ((pCallBack
==NULL
)||(pPatch
==NULL
))
74 m_cFileList
.DeleteAllItems();
77 m_arFileStates
.RemoveAll();
79 m_pCallBack
= pCallBack
;
81 if (m_sPath
.IsEmpty())
83 CString
title(MAKEINTRESOURCE(IDS_DIFF_TITLE
));
89 title
.LoadString(IDS_PATCH_TITLE
);
90 title
+= _T(" ") + m_sPath
;
93 PathCompactPath(GetDC()->m_hDC
, title
.GetBuffer(), rect
.Width());
94 title
.ReleaseBuffer();
96 if (m_sPath
.Right(1).Compare(_T("\\"))==0)
97 m_sPath
= m_sPath
.Left(m_sPath
.GetLength()-1);
99 m_sPath
= m_sPath
+ _T("\\");
100 for (int i
=m_ImgList
.GetImageCount();i
>0;i
--)
106 m_cFileList
.SetExtendedStyle(LVS_EX_INFOTIP
| LVS_EX_FULLROWSELECT
| LVS_EX_DOUBLEBUFFER
);
107 m_cFileList
.DeleteAllItems();
108 int c
= ((CHeaderCtrl
*)(m_cFileList
.GetDlgItem(0)))->GetItemCount()-1;
110 m_cFileList
.DeleteColumn(c
--);
111 m_cFileList
.InsertColumn(0, _T(""));
113 m_cFileList
.SetRedraw(false);
115 for(int i
=0; i
<m_pPatch
->GetNumberOfFiles(); i
++)
117 CString sFile
= CPathUtils::GetFileNameFromPath(m_pPatch
->GetFilename(i
));
119 if (m_sPath
.IsEmpty())
120 state
= FPDLG_FILESTATE_GOOD
;
123 if (m_pPatch
->PatchFile(GetFullPath(i
)))
124 state
= FPDLG_FILESTATE_GOOD
;
126 state
= FPDLG_FILESTATE_CONFLICTED
;
128 m_arFileStates
.Add(state
);
132 FILE_ATTRIBUTE_NORMAL
,
135 SHGFI_ICON
| SHGFI_SMALLICON
| SHGFI_USEFILEATTRIBUTES
);
136 m_cFileList
.InsertItem(i
, sFile
, m_ImgList
.Add(sfi
.hIcon
));
140 int maxcol
= ((CHeaderCtrl
*)(m_cFileList
.GetDlgItem(0)))->GetItemCount()-1;
142 for (col
= mincol
; col
<= maxcol
; col
++)
144 m_cFileList
.SetColumnWidth(col
,LVSCW_AUTOSIZE_USEHEADER
);
147 m_cFileList
.SetImageList(&m_ImgList
, LVSIL_SMALL
);
148 m_cFileList
.SetRedraw(true);
151 pParent
->GetWindowRect(&parentrect
);
153 GetWindowRect(&windowrect
);
155 int width
= windowrect
.right
- windowrect
.left
;
156 int height
= windowrect
.bottom
- windowrect
.top
;
157 windowrect
.right
= parentrect
.left
;
158 windowrect
.left
= windowrect
.right
- width
;
159 if (windowrect
.left
< 0)
162 windowrect
.right
= width
;
164 windowrect
.top
= parentrect
.top
;
165 windowrect
.bottom
= windowrect
.top
+ height
;
167 SetWindowPos(NULL
, windowrect
.left
, windowrect
.top
, width
, height
, SWP_NOACTIVATE
| SWP_NOZORDER
);
169 m_nWindowHeight
= windowrect
.bottom
- windowrect
.top
;
170 m_pMainFrame
= pParent
;
174 BEGIN_MESSAGE_MAP(CFilePatchesDlg
, CDialog
)
176 ON_NOTIFY(LVN_GETINFOTIP
, IDC_FILELIST
, OnLvnGetInfoTipFilelist
)
177 ON_NOTIFY(NM_DBLCLK
, IDC_FILELIST
, OnNMDblclkFilelist
)
178 ON_NOTIFY(NM_CUSTOMDRAW
, IDC_FILELIST
, OnNMCustomdrawFilelist
)
179 ON_NOTIFY(NM_RCLICK
, IDC_FILELIST
, OnNMRclickFilelist
)
180 ON_WM_NCLBUTTONDBLCLK()
184 void CFilePatchesDlg::OnSize(UINT nType
, int cx
, int cy
)
186 CDialog::OnSize(nType
, cx
, cy
);
187 if (this->IsWindowVisible())
191 GetDlgItem(IDC_FILELIST
)->MoveWindow(rect
.left
, rect
.top
, cx
, cy
);
192 m_cFileList
.SetColumnWidth(0, cx
);
195 title
.LoadString(IDS_PATCH_TITLE
);
196 title
+= _T(" ") + m_sPath
;
197 PathCompactPath(GetDC()->m_hDC
, title
.GetBuffer(), cx
);
198 title
.ReleaseBuffer();
199 SetWindowText(title
);
202 void CFilePatchesDlg::OnLvnGetInfoTipFilelist(NMHDR
*pNMHDR
, LRESULT
*pResult
)
204 LPNMLVGETINFOTIP pGetInfoTip
= reinterpret_cast<LPNMLVGETINFOTIP
>(pNMHDR
);
206 CString temp
= GetFullPath(pGetInfoTip
->iItem
);
207 _tcsncpy_s(pGetInfoTip
->pszText
, pGetInfoTip
->cchTextMax
, temp
, pGetInfoTip
->cchTextMax
);
211 void CFilePatchesDlg::OnNMDblclkFilelist(NMHDR
*pNMHDR
, LRESULT
*pResult
)
213 LPNMLISTVIEW pNMLV
= reinterpret_cast<LPNMLISTVIEW
>(pNMHDR
);
215 if ((pNMLV
->iItem
< 0) || (pNMLV
->iItem
>= m_arFileStates
.GetCount()))
217 if (m_pCallBack
==NULL
)
219 if (m_sPath
.IsEmpty())
221 m_pCallBack
->DiffFiles(GetFullPath(pNMLV
->iItem
), m_pPatch
->GetRevision(pNMLV
->iItem
),
222 m_pPatch
->GetFilename2(pNMLV
->iItem
), m_pPatch
->GetRevision2(pNMLV
->iItem
));
226 if (m_arFileStates
.GetAt(pNMLV
->iItem
)!=FPDLG_FILESTATE_PATCHED
)
228 m_pCallBack
->PatchFile(GetFullPath(pNMLV
->iItem
), m_pPatch
->GetRevision(pNMLV
->iItem
));
233 void CFilePatchesDlg::OnNMCustomdrawFilelist(NMHDR
*pNMHDR
, LRESULT
*pResult
)
235 NMLVCUSTOMDRAW
* pLVCD
= reinterpret_cast<NMLVCUSTOMDRAW
*>( pNMHDR
);
237 // Take the default processing unless we set this to something else below.
238 *pResult
= CDRF_DODEFAULT
;
240 // First thing - check the draw stage. If it's the control's prepaint
241 // stage, then tell Windows we want messages for every item.
243 if ( CDDS_PREPAINT
== pLVCD
->nmcd
.dwDrawStage
)
245 *pResult
= CDRF_NOTIFYITEMDRAW
;
247 else if ( CDDS_ITEMPREPAINT
== pLVCD
->nmcd
.dwDrawStage
)
249 // This is the prepaint stage for an item. Here's where we set the
250 // item's text color. Our return value will tell Windows to draw the
251 // item itself, but it will use the new color we set here.
253 COLORREF crText
= ::GetSysColor(COLOR_WINDOWTEXT
);
255 if (m_arFileStates
.GetCount() > (INT_PTR
)pLVCD
->nmcd
.dwItemSpec
)
257 if (m_arFileStates
.GetAt(pLVCD
->nmcd
.dwItemSpec
)==FPDLG_FILESTATE_CONFLICTED
)
259 crText
= RGB(200, 0, 0);
261 if (m_arFileStates
.GetAt(pLVCD
->nmcd
.dwItemSpec
)==FPDLG_FILESTATE_PATCHED
)
263 crText
= ::GetSysColor(COLOR_GRAYTEXT
);
265 // Store the color back in the NMLVCUSTOMDRAW struct.
266 pLVCD
->clrText
= crText
;
269 // Tell Windows to paint the control itself.
270 *pResult
= CDRF_DODEFAULT
;
274 void CFilePatchesDlg::OnNMRclickFilelist(NMHDR
* /*pNMHDR*/, LRESULT
*pResult
)
277 if (m_sPath
.IsEmpty())
282 DWORD ptW
= GetMessagePos();
283 point
.x
= GET_X_LPARAM(ptW
);
284 point
.y
= GET_Y_LPARAM(ptW
);
285 if (popup
.CreatePopupMenu())
289 nFlags
= MF_STRING
| (m_cFileList
.GetSelectedCount()==1 ? MF_ENABLED
: MF_DISABLED
| MF_GRAYED
);
290 temp
.LoadString(IDS_PATCH_PREVIEW
);
291 popup
.AppendMenu(nFlags
, ID_PATCHPREVIEW
, temp
);
292 popup
.SetDefaultItem(ID_PATCHPREVIEW
, FALSE
);
294 temp
.LoadString(IDS_PATCH_ALL
);
295 popup
.AppendMenu(MF_STRING
| MF_ENABLED
, ID_PATCHALL
, temp
);
297 nFlags
= MF_STRING
| (m_cFileList
.GetSelectedCount()>0 ? MF_ENABLED
: MF_DISABLED
| MF_GRAYED
);
298 temp
.LoadString(IDS_PATCH_SELECTED
);
299 popup
.AppendMenu(nFlags
, ID_PATCHSELECTED
, temp
);
301 // if the context menu is invoked through the keyboard, we have to use
302 // a calculated position on where to anchor the menu on
303 if ((point
.x
== -1) && (point
.y
== -1))
306 GetWindowRect(&rect
);
307 point
= rect
.CenterPoint();
310 int cmd
= popup
.TrackPopupMenu(TPM_RETURNCMD
| TPM_LEFTALIGN
| TPM_NONOTIFY
, point
.x
, point
.y
, this, 0);
313 case ID_PATCHPREVIEW
:
317 int nIndex
= m_cFileList
.GetSelectionMark();
318 if ( m_arFileStates
.GetAt(nIndex
)!=FPDLG_FILESTATE_PATCHED
)
320 m_pCallBack
->PatchFile(GetFullPath(nIndex
), m_pPatch
->GetRevision(nIndex
));
329 CProgressDlg progDlg
;
330 progDlg
.SetTitle(IDR_MAINFRAME
);
331 progDlg
.SetShowProgressBar(true);
332 progDlg
.SetLine(1, CString(MAKEINTRESOURCE(IDS_PATCH_ALL
)));
333 progDlg
.ShowModeless(m_hWnd
);
335 for (int i
=0; i
<m_arFileStates
.GetCount() && !progDlg
.HasUserCancelled(); i
++)
337 if (m_arFileStates
.GetAt(i
)!= FPDLG_FILESTATE_PATCHED
)
339 progDlg
.SetLine(2, GetFullPath(i
), true);
340 m_pCallBack
->PatchFile(GetFullPath(i
), m_pPatch
->GetRevision(i
), TRUE
);
342 progDlg
.SetProgress64(i
, m_arFileStates
.GetCount());
348 case ID_PATCHSELECTED
:
352 CProgressDlg progDlg
;
353 progDlg
.SetTitle(IDR_MAINFRAME
);
354 progDlg
.SetShowProgressBar(true);
355 progDlg
.SetLine(1, CString(MAKEINTRESOURCE(IDS_PATCH_SELECTED
)));
356 progDlg
.ShowModeless(m_hWnd
);
358 // The list cannot be sorted by user, so the order of the
359 // items in the list is identical to the order in the array
361 int selCount
= m_cFileList
.GetSelectedCount();
363 POSITION pos
= m_cFileList
.GetFirstSelectedItemPosition();
365 while (((index
= m_cFileList
.GetNextSelectedItem(pos
)) >= 0) && (!progDlg
.HasUserCancelled()))
367 if (m_arFileStates
.GetAt(index
)!= FPDLG_FILESTATE_PATCHED
)
369 progDlg
.SetLine(2, GetFullPath(index
), true);
370 m_pCallBack
->PatchFile(GetFullPath(index
), m_pPatch
->GetRevision(index
), TRUE
);
372 progDlg
.SetProgress64(count
++, selCount
);
384 void CFilePatchesDlg::OnNcLButtonDblClk(UINT nHitTest
, CPoint point
)
390 GetWindowRect(&windowrect
);
391 GetClientRect(&clientrect
);
392 m_nWindowHeight
= windowrect
.bottom
- windowrect
.top
;
393 MoveWindow(windowrect
.left
, windowrect
.top
,
394 windowrect
.right
- windowrect
.left
,
395 m_nWindowHeight
- (clientrect
.bottom
- clientrect
.top
));
400 GetWindowRect(&windowrect
);
401 MoveWindow(windowrect
.left
, windowrect
.top
, windowrect
.right
- windowrect
.left
, m_nWindowHeight
);
403 m_bMinimized
= !m_bMinimized
;
404 CDialog::OnNcLButtonDblClk(nHitTest
, point
);
407 void CFilePatchesDlg::OnMoving(UINT fwSide
, LPRECT pRect
)
411 m_pMainFrame
->GetWindowRect(&parentRect
);
412 if (abs(parentRect
.left
- pRect
->right
) < STICKYSIZE
)
414 int width
= pRect
->right
- pRect
->left
;
415 pRect
->right
= parentRect
.left
;
416 pRect
->left
= pRect
->right
- width
;
418 CDialog::OnMoving(fwSide
, pRect
);
421 void CFilePatchesDlg::OnOK()