OSDN Git Service

Progress Bar Show Animate
[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 "Git.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(CGitStatusListCtrl::SVNSLNM_NEEDSREFRESH, OnSVNStatusListCtrlNeedsRefresh)\r
55         ON_REGISTERED_MESSAGE(CGitStatusListCtrl::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         CTGitPath 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\\TortoiseGit\\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                         m_selectedPathList.AddPath(*(CTGitPath*)m_RevertList.GetItemData(i));\r
154 #if 0\r
155                         CGitStatusListCtrl::FileEntry * entry = m_RevertList.GetListEntry(i);\r
156                         // add all selected entries to the list, except the ones with 'added'\r
157                         // status: we later *delete* all the entries in the list before\r
158                         // the actual revert is done (so the user has the reverted files\r
159                         // still in the trash bin to recover from), but it's not good to\r
160                         // delete added files because they're not restored by the revert.\r
161                         if (entry->status != svn_wc_status_added)\r
162                                 m_selectedPathList.AddPath(entry->GetPath());\r
163                         // if an entry inside an external is selected, we can't revert\r
164                         // recursively anymore because the recursive revert stops at the\r
165                         // external boundaries.\r
166                         if (entry->IsInExternal())\r
167                                 m_bRecursive = FALSE;\r
168 #endif\r
169                 }\r
170         }\r
171         if (!m_bRecursive)\r
172         {\r
173                 m_RevertList.WriteCheckedNamesToPathList(m_pathList);\r
174         }\r
175         m_selectedPathList.SortByPathname();\r
176 \r
177         CResizableStandAloneDialog::OnOK();\r
178 }\r
179 \r
180 void CRevertDlg::OnCancel()\r
181 {\r
182         m_bCancelled = true;\r
183         if (m_bThreadRunning)\r
184                 return;\r
185 \r
186         CResizableStandAloneDialog::OnCancel();\r
187 }\r
188 \r
189 void CRevertDlg::OnBnClickedHelp()\r
190 {\r
191         OnHelp();\r
192 }\r
193 \r
194 void CRevertDlg::OnBnClickedSelectall()\r
195 {\r
196         UINT state = (m_SelectAll.GetState() & 0x0003);\r
197         if (state == BST_INDETERMINATE)\r
198         {\r
199                 // It is not at all useful to manually place the checkbox into the indeterminate state...\r
200                 // We will force this on to the unchecked state\r
201                 state = BST_UNCHECKED;\r
202                 m_SelectAll.SetCheck(state);\r
203         }\r
204         theApp.DoWaitCursor(1);\r
205         m_RevertList.SelectAll(state == BST_CHECKED);\r
206         theApp.DoWaitCursor(-1);\r
207 }\r
208 \r
209 BOOL CRevertDlg::PreTranslateMessage(MSG* pMsg)\r
210 {\r
211         if (pMsg->message == WM_KEYDOWN)\r
212         {\r
213                 switch (pMsg->wParam)\r
214                 {\r
215                 case VK_RETURN:\r
216                         {\r
217                                 if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
218                                 {\r
219                                         if ( GetDlgItem(IDOK)->IsWindowEnabled() )\r
220                                         {\r
221                                                 PostMessage(WM_COMMAND, IDOK);\r
222                                         }\r
223                                         return TRUE;\r
224                                 }\r
225                         }\r
226                         break;\r
227                 case VK_F5:\r
228                         {\r
229                                 if (!m_bThreadRunning)\r
230                                 {\r
231                                         if (AfxBeginThread(RevertThreadEntry, this)==0)\r
232                                         {\r
233                                                 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
234                                         }\r
235                                         else\r
236                                                 InterlockedExchange(&m_bThreadRunning, TRUE);\r
237                                 }\r
238                         }\r
239                         break;\r
240                 }\r
241         }\r
242 \r
243         return CResizableStandAloneDialog::PreTranslateMessage(pMsg);\r
244 }\r
245 \r
246 LRESULT CRevertDlg::OnSVNStatusListCtrlNeedsRefresh(WPARAM, LPARAM)\r
247 {\r
248         if (AfxBeginThread(RevertThreadEntry, this)==0)\r
249         {\r
250                 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
251         }\r
252         return 0;\r
253 }\r
254 \r
255 LRESULT CRevertDlg::OnFileDropped(WPARAM, LPARAM lParam)\r
256 {\r
257         BringWindowToTop();\r
258         SetForegroundWindow();\r
259         SetActiveWindow();\r
260         // if multiple files/folders are dropped\r
261         // this handler is called for every single item\r
262         // separately.\r
263         // To avoid creating multiple refresh threads and\r
264         // causing crashes, we only add the items to the\r
265         // list control and start a timer.\r
266         // When the timer expires, we start the refresh thread,\r
267         // but only if it isn't already running - otherwise we\r
268         // restart the timer.\r
269         CTGitPath path;\r
270         path.SetFromWin((LPCTSTR)lParam);\r
271 \r
272         if (!m_RevertList.HasPath(path))\r
273         {\r
274                 if (m_pathList.AreAllPathsFiles())\r
275                 {\r
276                         m_pathList.AddPath(path);\r
277                         m_pathList.RemoveDuplicates();\r
278                 }\r
279                 else\r
280                 {\r
281                         // if the path list contains folders, we have to check whether\r
282                         // our just (maybe) added path is a child of one of those. If it is\r
283                         // a child of a folder already in the list, we must not add it. Otherwise\r
284                         // that path could show up twice in the list.\r
285                         bool bHasParentInList = false;\r
286                         for (int i=0; i<m_pathList.GetCount(); ++i)\r
287                         {\r
288                                 if (m_pathList[i].IsAncestorOf(path))\r
289                                 {\r
290                                         bHasParentInList = true;\r
291                                         break;\r
292                                 }\r
293                         }\r
294                         if (!bHasParentInList)\r
295                         {\r
296                                 m_pathList.AddPath(path);\r
297                                 m_pathList.RemoveDuplicates();\r
298                         }\r
299                 }\r
300         }\r
301 \r
302         // Always start the timer, since the status of an existing item might have changed\r
303         SetTimer(REFRESHTIMER, 200, NULL);\r
304         ATLTRACE(_T("Item %s dropped, timer started\n"), path.GetWinPath());\r
305         return 0;\r
306 }\r
307 \r
308 void CRevertDlg::OnTimer(UINT_PTR nIDEvent)\r
309 {\r
310         switch (nIDEvent)\r
311         {\r
312         case REFRESHTIMER:\r
313                 if (m_bThreadRunning)\r
314                 {\r
315                         SetTimer(REFRESHTIMER, 200, NULL);\r
316                         ATLTRACE("Wait some more before refreshing\n");\r
317                 }\r
318                 else\r
319                 {\r
320                         KillTimer(REFRESHTIMER);\r
321                         ATLTRACE("Refreshing after items dropped\n");\r
322                         OnSVNStatusListCtrlNeedsRefresh(0, 0);\r
323                 }\r
324                 break;\r
325         }\r
326         __super::OnTimer(nIDEvent);\r
327 }\r