Fixed issue #1507: Submodule Diff Dialog should show dirty state only on working...
[TortoiseGit.git] / src / TortoiseMerge / FilePatchesDlg.cpp
blobaf0f6c16922dd5787d02cae5ffe8e60811a24dc7
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.
20 #include "stdafx.h"
21 #include "TortoiseMerge.h"
22 #include "FilePatchesDlg.h"
23 #include "Patch.h"
24 #include "AppUtils.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)
32 , m_bMinimized(FALSE)
33 , m_pPatch(NULL)
34 , m_pCallBack(NULL)
35 , m_nWindowHeight(-1)
36 , m_pMainFrame(NULL)
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);
58 Invalidate();
59 return TRUE;
62 return FALSE;
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);
76 return TRUE;
79 BOOL CFilePatchesDlg::Init(CPatch * pPatch, CPatchFilesDlgCallBack * pCallBack, CString sPath, CWnd * pParent)
81 if ((pCallBack==NULL)||(pPatch==NULL))
83 m_cFileList.DeleteAllItems();
84 return FALSE;
86 m_arFileStates.RemoveAll();
87 m_pPatch = pPatch;
88 m_pCallBack = pCallBack;
89 m_sPath = sPath;
90 if (m_sPath.IsEmpty())
92 CString title(MAKEINTRESOURCE(IDS_DIFF_TITLE));
93 SetWindowText(title);
95 else
97 CRect rect;
98 GetClientRect(&rect);
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--)
106 m_ImgList.Remove(0);
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;
113 while (c>=0)
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));
125 DWORD state;
126 if (m_sPath.IsEmpty())
127 state = FPDLG_FILESTATE_GOOD;
128 else
130 state = 0;
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;
137 else
138 state = FPDLG_FILESTATE_RENAME;
141 int doesApply = m_pPatch->PatchFile(i, m_sPath);
142 if (doesApply == 2)
143 state = FPDLG_FILESTATE_PATCHED;
144 else if (doesApply)
146 if(state != FPDLG_FILESTATE_NEW &&
147 state != FPDLG_FILESTATE_RENAME &&
148 state != FPDLG_FILESTATE_DELETE)
149 state = FPDLG_FILESTATE_GOOD;
151 else
152 state = FPDLG_FILESTATE_CONFLICTED;
154 m_arFileStates.Add(state);
155 SHFILEINFO sfi;
156 SHGetFileInfo(
157 m_pPatch->GetFullPath(m_sPath, i),
158 FILE_ATTRIBUTE_NORMAL,
159 &sfi,
160 sizeof(SHFILEINFO),
161 SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES);
162 m_cFileList.InsertItem(i, sFile, m_ImgList.Add(sfi.hIcon));
165 int mincol = 0;
166 int maxcol = ((CHeaderCtrl*)(m_cFileList.GetDlgItem(0)))->GetItemCount()-1;
167 int col;
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);
176 RECT parentrect;
177 pParent->GetWindowRect(&parentrect);
178 RECT windowrect;
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)
187 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;
197 return TRUE;
200 BEGIN_MESSAGE_MAP(CFilePatchesDlg, CResizableStandAloneDialog)
201 ON_WM_SIZE()
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()
207 ON_WM_MOVING()
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)
211 END_MESSAGE_MAP()
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);
230 if(temp != temp2)
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);
237 else
238 _tcsncpy_s(pGetInfoTip->pszText, pGetInfoTip->cchTextMax, temp, pGetInfoTip->cchTextMax);
239 *pResult = 0;
242 void CFilePatchesDlg::OnNMDblclkFilelist(NMHDR *pNMHDR, LRESULT *pResult)
244 LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
245 *pResult = 0;
246 if ((pNMLV->iItem < 0) || (pNMLV->iItem >= m_arFileStates.GetCount()))
247 return;
248 if (m_pCallBack==NULL)
249 return;
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));
255 else
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)
323 *pResult = 0;
324 if (m_sPath.IsEmpty())
325 return;
326 CString temp;
327 CMenu popup;
328 POINT point;
329 DWORD ptW = GetMessagePos();
330 point.x = GET_X_LPARAM(ptW);
331 point.y = GET_Y_LPARAM(ptW);
332 if (!popup.CreatePopupMenu())
333 return;
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))
355 CRect rect;
356 GetWindowRect(&rect);
357 point = rect.CenterPoint();
360 bool bReview=false;
362 int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);
363 switch (cmd)
365 case ID_PATCH_REVIEW:
366 bReview = true;
367 //go through case
368 case ID_PATCHPREVIEW:
370 if (m_pCallBack)
372 int nIndex = m_cFileList.GetSelectionMark();
373 if ( m_arFileStates.GetAt(nIndex)!=FPDLG_FILESTATE_PATCHED)
375 m_pCallBack->PatchFile(nIndex, false, bReview);
379 break;
380 case ID_PATCHALL:
381 PatchAll();
382 break;
383 case ID_PATCHSELECTED:
384 PatchSelected();
385 break;
386 default:
387 break;
391 void CFilePatchesDlg::OnNcLButtonDblClk(UINT nHitTest, CPoint point)
393 if (!m_bMinimized)
395 RECT windowrect;
396 RECT clientrect;
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));
404 else
406 RECT windowrect;
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)
416 RECT parentRect;
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()
430 return;
433 void CFilePatchesDlg::SetTitleWithPath(int width)
435 CString title;
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()
446 PatchSelected();
449 void CFilePatchesDlg::OnBnClickedPatchallbutton()
451 PatchAll();
454 void CFilePatchesDlg::PatchAll()
456 if (m_pCallBack)
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);
464 BOOL ret = TRUE;
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());
474 progDlg.Stop();
478 void CFilePatchesDlg::PatchSelected()
480 if (m_pCallBack)
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
490 // m_arFileStates.
491 int selCount = m_cFileList.GetSelectedCount();
492 int count = 1;
493 POSITION pos = m_cFileList.GetFirstSelectedItemPosition();
494 int index;
495 BOOL ret = TRUE;
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);
505 progDlg.Stop();
509 void CFilePatchesDlg::OnLvnItemchangedFilelist(NMHDR * /*pNMHDR*/, LRESULT *pResult)
511 DialogEnableWindow(IDC_PATCHSELECTEDBUTTON, m_cFileList.GetSelectedCount() > 0);
513 *pResult = 0;