drop repositorybrowser
[TortoiseGit.git] / src / TortoiseProc / CreatePatchDlg.cpp
blob761bde63fa74bbb7395bbf9ea85d89141d435654
1 // TortoiseSVN - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2008 - TortoiseSVN
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 "stdafx.h"
21 #include "TortoiseProc.h"
22 #include "MessageBox.h"
23 #include "CreatePatchDlg.h"
24 #include "SVN.h"
26 #define REFRESHTIMER 100
28 IMPLEMENT_DYNAMIC(CCreatePatch, CResizableStandAloneDialog)
29 CCreatePatch::CCreatePatch(CWnd* pParent /*=NULL*/)
30 : CResizableStandAloneDialog(CCreatePatch::IDD, pParent)
31 , m_bThreadRunning(FALSE)
32 , m_bCancelled(false)
33 , m_bShowUnversioned(FALSE)
37 CCreatePatch::~CCreatePatch()
41 void CCreatePatch::DoDataExchange(CDataExchange* pDX)
43 CResizableStandAloneDialog::DoDataExchange(pDX);
44 DDX_Control(pDX, IDC_PATCHLIST, m_PatchList);
45 DDX_Control(pDX, IDC_SELECTALL, m_SelectAll);
46 DDX_Check(pDX, IDC_SHOWUNVERSIONED, m_bShowUnversioned);
50 BEGIN_MESSAGE_MAP(CCreatePatch, CResizableStandAloneDialog)
51 ON_BN_CLICKED(IDC_SELECTALL, OnBnClickedSelectall)
52 ON_BN_CLICKED(IDC_SHOWUNVERSIONED, OnBnClickedShowunversioned)
53 ON_BN_CLICKED(IDHELP, OnBnClickedHelp)
54 ON_REGISTERED_MESSAGE(CSVNStatusListCtrl::SVNSLNM_NEEDSREFRESH, OnSVNStatusListCtrlNeedsRefresh)
55 ON_REGISTERED_MESSAGE(CSVNStatusListCtrl::SVNSLNM_ADDFILE, OnFileDropped)
56 ON_WM_TIMER()
57 END_MESSAGE_MAP()
59 BOOL CCreatePatch::OnInitDialog()
61 CResizableStandAloneDialog::OnInitDialog();
63 UpdateData(FALSE);
65 m_PatchList.Init(0, _T("CreatePatchDlg"), SVNSLC_POPALL ^ (SVNSLC_POPIGNORE|SVNSLC_POPCOMMIT));
66 m_PatchList.SetConfirmButton((CButton*)GetDlgItem(IDOK));
67 m_PatchList.SetSelectButton(&m_SelectAll);
68 m_PatchList.SetCancelBool(&m_bCancelled);
69 m_PatchList.EnableFileDrop();
71 AdjustControlSize(IDC_SELECTALL);
72 AdjustControlSize(IDC_SHOWUNVERSIONED);
74 AddAnchor(IDC_PATCHLIST, TOP_LEFT, BOTTOM_RIGHT);
75 AddAnchor(IDC_SELECTALL, BOTTOM_LEFT);
76 AddAnchor(IDC_SHOWUNVERSIONED, BOTTOM_LEFT);
77 AddAnchor(IDOK, BOTTOM_RIGHT);
78 AddAnchor(IDCANCEL, BOTTOM_RIGHT);
79 AddAnchor(IDHELP, BOTTOM_RIGHT);
80 if (hWndExplorer)
81 CenterWindow(CWnd::FromHandle(hWndExplorer));
82 EnableSaveRestore(_T("CreatePatchDlg"));
84 // first start a thread to obtain the file list with the status without
85 // blocking the dialog
86 if(AfxBeginThread(PatchThreadEntry, this) == NULL)
88 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
90 InterlockedExchange(&m_bThreadRunning, TRUE);
92 return TRUE;
95 UINT CCreatePatch::PatchThreadEntry(LPVOID pVoid)
97 return ((CCreatePatch*)pVoid)->PatchThread();
100 DWORD CCreatePatch::ShowMask()
102 return
103 SVNSLC_SHOWVERSIONEDBUTNORMALANDEXTERNALSFROMDIFFERENTREPOS | SVNSLC_SHOWDIRECTFILES |
104 (m_bShowUnversioned ? SVNSLC_SHOWUNVERSIONED : 0);
107 UINT CCreatePatch::PatchThread()
109 // get the status of all selected file/folders recursively
110 // and show the ones which can be included in a patch (i.e. the versioned and not-normal ones)
111 DialogEnableWindow(IDOK, false);
112 DialogEnableWindow(IDC_SHOWUNVERSIONED, false);
113 m_bCancelled = false;
115 if (!m_PatchList.GetStatus(m_pathList))
117 m_PatchList.SetEmptyString(m_PatchList.GetLastErrorMessage());
120 m_PatchList.Show(
121 ShowMask(), SVNSLC_SHOWDIRECTFILES | SVNSLC_SHOWVERSIONEDBUTNORMALANDEXTERNALSFROMDIFFERENTREPOS);
123 DialogEnableWindow(IDC_SHOWUNVERSIONED, true);
124 InterlockedExchange(&m_bThreadRunning, FALSE);
125 return 0;
128 BOOL CCreatePatch::PreTranslateMessage(MSG* pMsg)
130 if (pMsg->message == WM_KEYDOWN)
132 switch (pMsg->wParam)
134 case VK_RETURN:
136 if (GetAsyncKeyState(VK_CONTROL)&0x8000)
138 if ( GetDlgItem(IDOK)->IsWindowEnabled() )
140 PostMessage(WM_COMMAND, IDOK);
142 return TRUE;
145 break;
146 case VK_F5:
148 if (!m_bThreadRunning)
150 if(AfxBeginThread(PatchThreadEntry, this) == NULL)
152 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
154 else
155 InterlockedExchange(&m_bThreadRunning, TRUE);
158 break;
162 return CResizableStandAloneDialog::PreTranslateMessage(pMsg);
165 void CCreatePatch::OnBnClickedSelectall()
167 UINT state = (m_SelectAll.GetState() & 0x0003);
168 if (state == BST_INDETERMINATE)
170 // It is not at all useful to manually place the checkbox into the indeterminate state...
171 // We will force this on to the unchecked state
172 state = BST_UNCHECKED;
173 m_SelectAll.SetCheck(state);
175 theApp.DoWaitCursor(1);
176 m_PatchList.SelectAll(state == BST_CHECKED);
177 theApp.DoWaitCursor(-1);
180 void CCreatePatch::OnBnClickedShowunversioned()
182 UpdateData();
183 if (!m_bThreadRunning)
184 m_PatchList.Show(ShowMask());
187 void CCreatePatch::OnBnClickedHelp()
189 OnHelp();
192 void CCreatePatch::OnCancel()
194 m_bCancelled = true;
195 if (m_bThreadRunning)
196 return;
198 CResizableStandAloneDialog::OnCancel();
201 void CCreatePatch::OnOK()
203 if (m_bThreadRunning)
204 return;
206 int nListItems = m_PatchList.GetItemCount();
207 m_filesToRevert.Clear();
209 for (int j=0; j<nListItems; j++)
211 const CSVNStatusListCtrl::FileEntry * entry = m_PatchList.GetListEntry(j);
212 if (entry->IsChecked())
214 // Unversioned files are not included in the resulting patch file!
215 // We add those files to a list which will be used to add those files
216 // before creating the patch.
217 if ((entry->status == svn_wc_status_none)||(entry->status == svn_wc_status_unversioned))
219 m_filesToRevert.AddPath(entry->GetPath());
224 if (m_filesToRevert.GetCount())
226 // add all unversioned files to version control
227 // so they're included in the resulting patch
228 // NOTE: these files must be reverted after the patch
229 // has been created! Since this dialog doesn't create the patch
230 // itself, the calling function is responsible to revert these files!
231 SVN svn;
232 svn.Add(m_filesToRevert, NULL, svn_depth_empty, false, false, true);
235 //save only the files the user has selected into the path list
236 m_PatchList.WriteCheckedNamesToPathList(m_pathList);
238 CResizableStandAloneDialog::OnOK();
241 LRESULT CCreatePatch::OnSVNStatusListCtrlNeedsRefresh(WPARAM, LPARAM)
243 if(AfxBeginThread(PatchThreadEntry, this) == NULL)
245 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
247 return 0;
250 LRESULT CCreatePatch::OnFileDropped(WPARAM, LPARAM lParam)
252 BringWindowToTop();
253 SetForegroundWindow();
254 SetActiveWindow();
255 // if multiple files/folders are dropped
256 // this handler is called for every single item
257 // separately.
258 // To avoid creating multiple refresh threads and
259 // causing crashes, we only add the items to the
260 // list control and start a timer.
261 // When the timer expires, we start the refresh thread,
262 // but only if it isn't already running - otherwise we
263 // restart the timer.
264 CTSVNPath path;
265 path.SetFromWin((LPCTSTR)lParam);
267 if (!m_PatchList.HasPath(path))
269 if (m_pathList.AreAllPathsFiles())
271 m_pathList.AddPath(path);
272 m_pathList.RemoveDuplicates();
274 else
276 // if the path list contains folders, we have to check whether
277 // our just (maybe) added path is a child of one of those. If it is
278 // a child of a folder already in the list, we must not add it. Otherwise
279 // that path could show up twice in the list.
280 bool bHasParentInList = false;
281 for (int i=0; i<m_pathList.GetCount(); ++i)
283 if (m_pathList[i].IsAncestorOf(path))
285 bHasParentInList = true;
286 break;
289 if (!bHasParentInList)
291 m_pathList.AddPath(path);
292 m_pathList.RemoveDuplicates();
297 // Always start the timer, since the status of an existing item might have changed
298 SetTimer(REFRESHTIMER, 200, NULL);
299 ATLTRACE(_T("Item %s dropped, timer started\n"), path.GetWinPath());
300 return 0;
303 void CCreatePatch::OnTimer(UINT_PTR nIDEvent)
305 switch (nIDEvent)
307 case REFRESHTIMER:
308 if (m_bThreadRunning)
310 SetTimer(REFRESHTIMER, 200, NULL);
311 ATLTRACE("Wait some more before refreshing\n");
313 else
315 KillTimer(REFRESHTIMER);
316 ATLTRACE("Refreshing after items dropped\n");
317 OnSVNStatusListCtrlNeedsRefresh(0, 0);
319 break;
321 __super::OnTimer(nIDEvent);