OSDN Git Service

Change Dir Structure to be same as TortoiseSVN'
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / UnlockDlg.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 "UnlockDlg.h"\r
22 #include "messagebox.h"\r
23 \r
24 \r
25 #define REFRESHTIMER   100\r
26 \r
27 IMPLEMENT_DYNAMIC(CUnlockDlg, CResizableStandAloneDialog)\r
28 \r
29 CUnlockDlg::CUnlockDlg(CWnd* pParent /*=NULL*/)\r
30         : CResizableStandAloneDialog(CUnlockDlg::IDD, pParent)\r
31         , m_bThreadRunning(FALSE)\r
32         , m_bCancelled(false)\r
33 {\r
34 \r
35 }\r
36 \r
37 CUnlockDlg::~CUnlockDlg()\r
38 {\r
39 }\r
40 \r
41 void CUnlockDlg::DoDataExchange(CDataExchange* pDX)\r
42 {\r
43         CResizableStandAloneDialog::DoDataExchange(pDX);\r
44         DDX_Control(pDX, IDC_UNLOCKLIST, m_unlockListCtrl);\r
45         DDX_Control(pDX, IDC_SELECTALL, m_SelectAll);\r
46 }\r
47 \r
48 \r
49 BEGIN_MESSAGE_MAP(CUnlockDlg, CResizableStandAloneDialog)\r
50         ON_BN_CLICKED(IDC_SELECTALL, OnBnClickedSelectall)\r
51         ON_BN_CLICKED(IDHELP, OnBnClickedHelp)\r
52         ON_REGISTERED_MESSAGE(CSVNStatusListCtrl::SVNSLNM_NEEDSREFRESH, OnSVNStatusListCtrlNeedsRefresh)\r
53         ON_REGISTERED_MESSAGE(CSVNStatusListCtrl::SVNSLNM_ADDFILE, OnFileDropped)\r
54         ON_WM_TIMER()\r
55 END_MESSAGE_MAP()\r
56 \r
57 \r
58 BOOL CUnlockDlg::OnInitDialog()\r
59 {\r
60         CResizableStandAloneDialog::OnInitDialog();\r
61 \r
62         // initialize the svn status list control\r
63         m_unlockListCtrl.Init(0, _T("UnlockDlg"), SVNSLC_POPALL);\r
64         m_unlockListCtrl.SetIgnoreRemoveOnly(); // when ignoring, don't add the parent folder since we're in the unlock dialog\r
65         m_unlockListCtrl.SetSelectButton(&m_SelectAll);\r
66         m_unlockListCtrl.SetConfirmButton((CButton*)GetDlgItem(IDOK));\r
67         m_unlockListCtrl.SetEmptyString(IDS_ERR_NOTHINGTOUNLOCK);\r
68         m_unlockListCtrl.SetCancelBool(&m_bCancelled);\r
69         m_unlockListCtrl.SetBackgroundImage(IDI_UNLOCK_BKG);\r
70         m_unlockListCtrl.EnableFileDrop();\r
71 \r
72         AdjustControlSize(IDC_SELECTALL);\r
73 \r
74         AddAnchor(IDC_UNLOCKLIST, TOP_LEFT, BOTTOM_RIGHT);\r
75         AddAnchor(IDC_SELECTALL, BOTTOM_LEFT);\r
76         AddAnchor(IDOK, BOTTOM_RIGHT);\r
77         AddAnchor(IDCANCEL, BOTTOM_RIGHT);\r
78         AddAnchor(IDHELP, BOTTOM_RIGHT);\r
79         if (hWndExplorer)\r
80                 CenterWindow(CWnd::FromHandle(hWndExplorer));\r
81         EnableSaveRestore(_T("UnlockDlg"));\r
82 \r
83         //first start a thread to obtain the file list with the status without\r
84         //blocking the dialog\r
85         if(AfxBeginThread(UnlockThreadEntry, this) == NULL)\r
86         {\r
87                 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
88         }\r
89         InterlockedExchange(&m_bThreadRunning, TRUE);\r
90 \r
91         return TRUE;\r
92 }\r
93 \r
94 void CUnlockDlg::OnOK()\r
95 {\r
96         if (m_bThreadRunning)\r
97                 return;\r
98 \r
99         // save only the files the user has selected into the path list\r
100         m_unlockListCtrl.WriteCheckedNamesToPathList(m_pathList);\r
101 \r
102         CResizableStandAloneDialog::OnOK();\r
103 }\r
104 \r
105 void CUnlockDlg::OnCancel()\r
106 {\r
107         m_bCancelled = true;\r
108         if (m_bThreadRunning)\r
109                 return;\r
110 \r
111         CResizableStandAloneDialog::OnCancel();\r
112 }\r
113 \r
114 void CUnlockDlg::OnBnClickedSelectall()\r
115 {\r
116         UINT state = (m_SelectAll.GetState() & 0x0003);\r
117         if (state == BST_INDETERMINATE)\r
118         {\r
119                 // It is not at all useful to manually place the checkbox into the indeterminate state...\r
120                 // We will force this on to the unchecked state\r
121                 state = BST_UNCHECKED;\r
122                 m_SelectAll.SetCheck(state);\r
123         }\r
124         theApp.DoWaitCursor(1);\r
125         m_unlockListCtrl.SelectAll(state == BST_CHECKED);\r
126         theApp.DoWaitCursor(-1);\r
127 }\r
128 \r
129 UINT CUnlockDlg::UnlockThreadEntry(LPVOID pVoid)\r
130 {\r
131         return ((CUnlockDlg*)pVoid)->UnlockThread();\r
132 }\r
133 \r
134 UINT CUnlockDlg::UnlockThread()\r
135 {\r
136         // get the status of all selected file/folders recursively\r
137         // and show the ones which the user can add (i.e. the unversioned ones)\r
138         DialogEnableWindow(IDOK, false);\r
139         m_bCancelled = false;\r
140         if (!m_unlockListCtrl.GetStatus(m_pathList))\r
141         {\r
142                 m_unlockListCtrl.SetEmptyString(m_unlockListCtrl.GetLastErrorMessage());\r
143         }\r
144         m_unlockListCtrl.Show(SVNSLC_SHOWLOCKS | SVNSLC_SHOWDIRECTFILES, \r
145                 SVNSLC_SHOWLOCKS | SVNSLC_SHOWDIRECTFILES);\r
146 \r
147         InterlockedExchange(&m_bThreadRunning, FALSE);\r
148         return 0;\r
149 }\r
150 \r
151 void CUnlockDlg::OnBnClickedHelp()\r
152 {\r
153         OnHelp();\r
154 }\r
155 \r
156 BOOL CUnlockDlg::PreTranslateMessage(MSG* pMsg)\r
157 {\r
158         if (pMsg->message == WM_KEYDOWN)\r
159         {\r
160                 switch (pMsg->wParam)\r
161                 {\r
162                 case VK_RETURN:\r
163                         {\r
164                                 if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
165                                 {\r
166                                         if ( GetDlgItem(IDOK)->IsWindowEnabled() )\r
167                                         {\r
168                                                 PostMessage(WM_COMMAND, IDOK);\r
169                                         }\r
170                                         return TRUE;\r
171                                 }\r
172                         }\r
173                         break;\r
174                 case VK_F5:\r
175                         {\r
176                                 if (!m_bThreadRunning)\r
177                                 {\r
178                                         if(AfxBeginThread(UnlockThreadEntry, this) == NULL)\r
179                                         {\r
180                                                 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
181                                         }\r
182                                         else\r
183                                                 InterlockedExchange(&m_bThreadRunning, TRUE);\r
184                                 }\r
185                         }\r
186                         break;\r
187                 }\r
188         }\r
189 \r
190         return CResizableStandAloneDialog::PreTranslateMessage(pMsg);\r
191 }\r
192 \r
193 LRESULT CUnlockDlg::OnSVNStatusListCtrlNeedsRefresh(WPARAM, LPARAM)\r
194 {\r
195         if(AfxBeginThread(UnlockThreadEntry, this) == NULL)\r
196         {\r
197                 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
198         }\r
199         return 0;\r
200 }\r
201 \r
202 LRESULT CUnlockDlg::OnFileDropped(WPARAM, LPARAM lParam)\r
203 {\r
204         BringWindowToTop();\r
205         SetForegroundWindow();\r
206         SetActiveWindow();\r
207         // if multiple files/folders are dropped\r
208         // this handler is called for every single item\r
209         // separately.\r
210         // To avoid creating multiple refresh threads and\r
211         // causing crashes, we only add the items to the\r
212         // list control and start a timer.\r
213         // When the timer expires, we start the refresh thread,\r
214         // but only if it isn't already running - otherwise we\r
215         // restart the timer.\r
216         CTSVNPath path;\r
217         path.SetFromWin((LPCTSTR)lParam);\r
218 \r
219         if (!m_unlockListCtrl.HasPath(path))\r
220         {\r
221                 if (m_pathList.AreAllPathsFiles())\r
222                 {\r
223                         m_pathList.AddPath(path);\r
224                         m_pathList.RemoveDuplicates();\r
225                 }\r
226                 else\r
227                 {\r
228                         // if the path list contains folders, we have to check whether\r
229                         // our just (maybe) added path is a child of one of those. If it is\r
230                         // a child of a folder already in the list, we must not add it. Otherwise\r
231                         // that path could show up twice in the list.\r
232                         bool bHasParentInList = false;\r
233                         for (int i=0; i<m_pathList.GetCount(); ++i)\r
234                         {\r
235                                 if (m_pathList[i].IsAncestorOf(path))\r
236                                 {\r
237                                         bHasParentInList = true;\r
238                                         break;\r
239                                 }\r
240                         }\r
241                         if (!bHasParentInList)\r
242                         {\r
243                                 m_pathList.AddPath(path);\r
244                                 m_pathList.RemoveDuplicates();\r
245                         }\r
246                 }\r
247         }\r
248 \r
249         // Always start the timer, since the status of an existing item might have changed\r
250         SetTimer(REFRESHTIMER, 200, NULL);\r
251         ATLTRACE(_T("Item %s dropped, timer started\n"), path.GetWinPath());\r
252         return 0;\r
253 }\r
254 \r
255 void CUnlockDlg::OnTimer(UINT_PTR nIDEvent)\r
256 {\r
257         switch (nIDEvent)\r
258         {\r
259         case REFRESHTIMER:\r
260                 if (m_bThreadRunning)\r
261                 {\r
262                         SetTimer(REFRESHTIMER, 200, NULL);\r
263                         ATLTRACE("Wait some more before refreshing\n");\r
264                 }\r
265                 else\r
266                 {\r
267                         KillTimer(REFRESHTIMER);\r
268                         ATLTRACE("Refreshing after items dropped\n");\r
269                         OnSVNStatusListCtrlNeedsRefresh(0, 0);\r
270                 }\r
271                 break;\r
272         }\r
273         __super::OnTimer(nIDEvent);\r
274 }\r