OSDN Git Service

1eae551992276645a760fbe7094cc32d36050790
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / RevertDlg.cpp
1 // TortoiseSVN - a Windows shell extension for easy version control\r
2 \r
3 // Copyright (C) 2003-2008 - TortoiseSVN\r
4 \r
5 // This program is free software; you can redistribute it and/or\r
6 // modify it under the terms of the GNU General Public License\r
7 // as published by the Free Software Foundation; either version 2\r
8 // of the License, or (at your option) any later version.\r
9 \r
10 // This program is distributed in the hope that it will be useful,\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 // GNU General Public License for more details.\r
14 \r
15 // You should have received a copy of the GNU General Public License\r
16 // along with this program; if not, write to the Free Software Foundation,\r
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
18 //\r
19 #include "stdafx.h"\r
20 #include "TortoiseProc.h"\r
21 #include "messagebox.h"\r
22 #include "Revertdlg.h"\r
23 #include "SVN.h"\r
24 #include "Registry.h"\r
25 #include ".\revertdlg.h"\r
26 \r
27 #define REFRESHTIMER   100\r
28 \r
29 IMPLEMENT_DYNAMIC(CRevertDlg, CResizableStandAloneDialog)\r
30 CRevertDlg::CRevertDlg(CWnd* pParent /*=NULL*/)\r
31         : CResizableStandAloneDialog(CRevertDlg::IDD, pParent)\r
32         , m_bSelectAll(TRUE)\r
33         , m_bThreadRunning(FALSE)\r
34         , m_bCancelled(false)\r
35 {\r
36 }\r
37 \r
38 CRevertDlg::~CRevertDlg()\r
39 {\r
40 }\r
41 \r
42 void CRevertDlg::DoDataExchange(CDataExchange* pDX)\r
43 {\r
44         CResizableStandAloneDialog::DoDataExchange(pDX);\r
45         DDX_Control(pDX, IDC_REVERTLIST, m_RevertList);\r
46         DDX_Check(pDX, IDC_SELECTALL, m_bSelectAll);\r
47         DDX_Control(pDX, IDC_SELECTALL, m_SelectAll);\r
48 }\r
49 \r
50 \r
51 BEGIN_MESSAGE_MAP(CRevertDlg, CResizableStandAloneDialog)\r
52         ON_BN_CLICKED(IDHELP, OnBnClickedHelp)\r
53         ON_BN_CLICKED(IDC_SELECTALL, OnBnClickedSelectall)\r
54         ON_REGISTERED_MESSAGE(CSVNStatusListCtrl::SVNSLNM_NEEDSREFRESH, OnSVNStatusListCtrlNeedsRefresh)\r
55         ON_REGISTERED_MESSAGE(CSVNStatusListCtrl::SVNSLNM_ADDFILE, OnFileDropped)\r
56         ON_WM_TIMER()\r
57 END_MESSAGE_MAP()\r
58 \r
59 \r
60 \r
61 BOOL CRevertDlg::OnInitDialog()\r
62 {\r
63         CResizableStandAloneDialog::OnInitDialog();\r
64 \r
65         m_RevertList.Init(SVNSLC_COLTEXTSTATUS | SVNSLC_COLPROPSTATUS, _T("RevertDlg"));\r
66         m_RevertList.SetConfirmButton((CButton*)GetDlgItem(IDOK));\r
67         m_RevertList.SetSelectButton(&m_SelectAll);\r
68         m_RevertList.SetCancelBool(&m_bCancelled);\r
69         m_RevertList.SetBackgroundImage(IDI_REVERT_BKG);\r
70         m_RevertList.EnableFileDrop();\r
71 \r
72         GetWindowText(m_sWindowTitle);\r
73         \r
74         AdjustControlSize(IDC_SELECTALL);\r
75 \r
76         AddAnchor(IDC_REVERTLIST, TOP_LEFT, BOTTOM_RIGHT);\r
77         AddAnchor(IDC_SELECTALL, BOTTOM_LEFT);\r
78         AddAnchor(IDC_UNVERSIONEDITEMS, BOTTOM_RIGHT);\r
79         AddAnchor(IDOK, BOTTOM_RIGHT);\r
80         AddAnchor(IDCANCEL, BOTTOM_RIGHT);\r
81         AddAnchor(IDHELP, BOTTOM_RIGHT);\r
82         if (hWndExplorer)\r
83                 CenterWindow(CWnd::FromHandle(hWndExplorer));\r
84         EnableSaveRestore(_T("RevertDlg"));\r
85 \r
86         // first start a thread to obtain the file list with the status without\r
87         // blocking the dialog\r
88         if (AfxBeginThread(RevertThreadEntry, this)==0)\r
89         {\r
90                 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
91         }\r
92         InterlockedExchange(&m_bThreadRunning, TRUE);\r
93 \r
94         return TRUE;\r
95 }\r
96 \r
97 UINT CRevertDlg::RevertThreadEntry(LPVOID pVoid)\r
98 {\r
99         return ((CRevertDlg*)pVoid)->RevertThread();\r
100 }\r
101 \r
102 UINT CRevertDlg::RevertThread()\r
103 {\r
104         // get the status of all selected file/folders recursively\r
105         // and show the ones which can be reverted to the user\r
106         // in a list control. \r
107         DialogEnableWindow(IDOK, false);\r
108         m_bCancelled = false;\r
109 \r
110         if (!m_RevertList.GetStatus(m_pathList))\r
111         {\r
112                 m_RevertList.SetEmptyString(m_RevertList.GetLastErrorMessage());\r
113         }\r
114         m_RevertList.Show(SVNSLC_SHOWVERSIONEDBUTNORMALANDEXTERNALSFROMDIFFERENTREPOS | SVNSLC_SHOWDIRECTFILES | SVNSLC_SHOWEXTERNALFROMDIFFERENTREPO, \r
115                                                 // do not select all files, only the ones the user has selected directly\r
116                                                 SVNSLC_SHOWDIRECTFILES|SVNSLC_SHOWADDED);\r
117 \r
118         CTSVNPath commonDir = m_RevertList.GetCommonDirectory(false);\r
119         SetWindowText(m_sWindowTitle + _T(" - ") + commonDir.GetWinPathString());\r
120 \r
121         if (m_RevertList.HasUnversionedItems())\r
122         {\r
123                 if (DWORD(CRegStdWORD(_T("Software\\TortoiseSVN\\UnversionedAsModified"), FALSE)))\r
124                 {\r
125                         GetDlgItem(IDC_UNVERSIONEDITEMS)->ShowWindow(SW_SHOW);\r
126                 }\r
127                 else\r
128                         GetDlgItem(IDC_UNVERSIONEDITEMS)->ShowWindow(SW_HIDE);\r
129         }\r
130         else\r
131                 GetDlgItem(IDC_UNVERSIONEDITEMS)->ShowWindow(SW_HIDE);\r
132 \r
133         InterlockedExchange(&m_bThreadRunning, FALSE);\r
134         RefreshCursor();\r
135 \r
136         return 0;\r
137 }\r
138 \r
139 void CRevertDlg::OnOK()\r
140 {\r
141         if (m_bThreadRunning)\r
142                 return;\r
143         // save only the files the user has selected into the temporary file\r
144         m_bRecursive = TRUE;\r
145         for (int i=0; i<m_RevertList.GetItemCount(); ++i)\r
146         {\r
147                 if (!m_RevertList.GetCheck(i))\r
148                 {\r
149                         m_bRecursive = FALSE;\r
150                 }\r
151                 else \r
152                 {\r
153                         CSVNStatusListCtrl::FileEntry * entry = m_RevertList.GetListEntry(i);\r
154                         // add all selected entries to the list, except the ones with 'added'\r
155                         // status: we later *delete* all the entries in the list before\r
156                         // the actual revert is done (so the user has the reverted files\r
157                         // still in the trash bin to recover from), but it's not good to\r
158                         // delete added files because they're not restored by the revert.\r
159                         if (entry->status != svn_wc_status_added)\r
160                                 m_selectedPathList.AddPath(entry->GetPath());\r
161                         // if an entry inside an external is selected, we can't revert\r
162                         // recursively anymore because the recursive revert stops at the\r
163                         // external boundaries.\r
164                         if (entry->IsInExternal())\r
165                                 m_bRecursive = FALSE;\r
166                 }\r
167         }\r
168         if (!m_bRecursive)\r
169         {\r
170                 m_RevertList.WriteCheckedNamesToPathList(m_pathList);\r
171         }\r
172         m_selectedPathList.SortByPathname();\r
173 \r
174         CResizableStandAloneDialog::OnOK();\r
175 }\r
176 \r
177 void CRevertDlg::OnCancel()\r
178 {\r
179         m_bCancelled = true;\r
180         if (m_bThreadRunning)\r
181                 return;\r
182 \r
183         CResizableStandAloneDialog::OnCancel();\r
184 }\r
185 \r
186 void CRevertDlg::OnBnClickedHelp()\r
187 {\r
188         OnHelp();\r
189 }\r
190 \r
191 void CRevertDlg::OnBnClickedSelectall()\r
192 {\r
193         UINT state = (m_SelectAll.GetState() & 0x0003);\r
194         if (state == BST_INDETERMINATE)\r
195         {\r
196                 // It is not at all useful to manually place the checkbox into the indeterminate state...\r
197                 // We will force this on to the unchecked state\r
198                 state = BST_UNCHECKED;\r
199                 m_SelectAll.SetCheck(state);\r
200         }\r
201         theApp.DoWaitCursor(1);\r
202         m_RevertList.SelectAll(state == BST_CHECKED);\r
203         theApp.DoWaitCursor(-1);\r
204 }\r
205 \r
206 BOOL CRevertDlg::PreTranslateMessage(MSG* pMsg)\r
207 {\r
208         if (pMsg->message == WM_KEYDOWN)\r
209         {\r
210                 switch (pMsg->wParam)\r
211                 {\r
212                 case VK_RETURN:\r
213                         {\r
214                                 if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
215                                 {\r
216                                         if ( GetDlgItem(IDOK)->IsWindowEnabled() )\r
217                                         {\r
218                                                 PostMessage(WM_COMMAND, IDOK);\r
219                                         }\r
220                                         return TRUE;\r
221                                 }\r
222                         }\r
223                         break;\r
224                 case VK_F5:\r
225                         {\r
226                                 if (!m_bThreadRunning)\r
227                                 {\r
228                                         if (AfxBeginThread(RevertThreadEntry, this)==0)\r
229                                         {\r
230                                                 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
231                                         }\r
232                                         else\r
233                                                 InterlockedExchange(&m_bThreadRunning, TRUE);\r
234                                 }\r
235                         }\r
236                         break;\r
237                 }\r
238         }\r
239 \r
240         return CResizableStandAloneDialog::PreTranslateMessage(pMsg);\r
241 }\r
242 \r
243 LRESULT CRevertDlg::OnSVNStatusListCtrlNeedsRefresh(WPARAM, LPARAM)\r
244 {\r
245         if (AfxBeginThread(RevertThreadEntry, this)==0)\r
246         {\r
247                 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
248         }\r
249         return 0;\r
250 }\r
251 \r
252 LRESULT CRevertDlg::OnFileDropped(WPARAM, LPARAM lParam)\r
253 {\r
254         BringWindowToTop();\r
255         SetForegroundWindow();\r
256         SetActiveWindow();\r
257         // if multiple files/folders are dropped\r
258         // this handler is called for every single item\r
259         // separately.\r
260         // To avoid creating multiple refresh threads and\r
261         // causing crashes, we only add the items to the\r
262         // list control and start a timer.\r
263         // When the timer expires, we start the refresh thread,\r
264         // but only if it isn't already running - otherwise we\r
265         // restart the timer.\r
266         CTSVNPath path;\r
267         path.SetFromWin((LPCTSTR)lParam);\r
268 \r
269         if (!m_RevertList.HasPath(path))\r
270         {\r
271                 if (m_pathList.AreAllPathsFiles())\r
272                 {\r
273                         m_pathList.AddPath(path);\r
274                         m_pathList.RemoveDuplicates();\r
275                 }\r
276                 else\r
277                 {\r
278                         // if the path list contains folders, we have to check whether\r
279                         // our just (maybe) added path is a child of one of those. If it is\r
280                         // a child of a folder already in the list, we must not add it. Otherwise\r
281                         // that path could show up twice in the list.\r
282                         bool bHasParentInList = false;\r
283                         for (int i=0; i<m_pathList.GetCount(); ++i)\r
284                         {\r
285                                 if (m_pathList[i].IsAncestorOf(path))\r
286                                 {\r
287                                         bHasParentInList = true;\r
288                                         break;\r
289                                 }\r
290                         }\r
291                         if (!bHasParentInList)\r
292                         {\r
293                                 m_pathList.AddPath(path);\r
294                                 m_pathList.RemoveDuplicates();\r
295                         }\r
296                 }\r
297         }\r
298 \r
299         // Always start the timer, since the status of an existing item might have changed\r
300         SetTimer(REFRESHTIMER, 200, NULL);\r
301         ATLTRACE(_T("Item %s dropped, timer started\n"), path.GetWinPath());\r
302         return 0;\r
303 }\r
304 \r
305 void CRevertDlg::OnTimer(UINT_PTR nIDEvent)\r
306 {\r
307         switch (nIDEvent)\r
308         {\r
309         case REFRESHTIMER:\r
310                 if (m_bThreadRunning)\r
311                 {\r
312                         SetTimer(REFRESHTIMER, 200, NULL);\r
313                         ATLTRACE("Wait some more before refreshing\n");\r
314                 }\r
315                 else\r
316                 {\r
317                         KillTimer(REFRESHTIMER);\r
318                         ATLTRACE("Refreshing after items dropped\n");\r
319                         OnSVNStatusListCtrlNeedsRefresh(0, 0);\r
320                 }\r
321                 break;\r
322         }\r
323         __super::OnTimer(nIDEvent);\r
324 }\r