OSDN Git Service

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