OSDN Git Service

Add Version Graph Tree Code but there are some problem
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / LockDlg.cpp
1 // TortoiseSVN - a Windows shell extension for easy version control\r
2 \r
3 // Copyright (C) 2003-2008 - Stefan Kueng\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 ".\lockdlg.h"\r
23 #include "UnicodeUtils.h"\r
24 #include "SVNProperties.h"\r
25 #include "SVN.h"\r
26 #include "HistoryDlg.h"\r
27 \r
28 #define REFRESHTIMER   100\r
29 \r
30 IMPLEMENT_DYNAMIC(CLockDlg, CResizableStandAloneDialog)\r
31 CLockDlg::CLockDlg(CWnd* pParent /*=NULL*/)\r
32         : CResizableStandAloneDialog(CLockDlg::IDD, pParent)\r
33         , m_bBlock(FALSE)\r
34         , m_bStealLocks(FALSE)\r
35         , m_pThread(NULL)\r
36         , m_bCancelled(false)\r
37         , m_ProjectProperties(NULL)\r
38 {\r
39 }\r
40 \r
41 CLockDlg::~CLockDlg()\r
42 {\r
43         if(m_pThread != NULL)\r
44         {\r
45                 delete m_pThread;\r
46         }\r
47 }\r
48 \r
49 void CLockDlg::DoDataExchange(CDataExchange* pDX)\r
50 {\r
51         CResizableStandAloneDialog::DoDataExchange(pDX);\r
52         DDX_Check(pDX, IDC_STEALLOCKS, m_bStealLocks);\r
53         DDX_Control(pDX, IDC_FILELIST, m_cFileList);\r
54         DDX_Control(pDX, IDC_LOCKMESSAGE, m_cEdit);\r
55         DDX_Control(pDX, IDC_SELECTALL, m_SelectAll);\r
56 }\r
57 \r
58 \r
59 BEGIN_MESSAGE_MAP(CLockDlg, CResizableStandAloneDialog)\r
60         ON_BN_CLICKED(IDHELP, OnBnClickedHelp)\r
61         ON_EN_CHANGE(IDC_LOCKMESSAGE, OnEnChangeLockmessage)\r
62         ON_REGISTERED_MESSAGE(CSVNStatusListCtrl::SVNSLNM_NEEDSREFRESH, OnSVNStatusListCtrlNeedsRefresh)\r
63         ON_BN_CLICKED(IDC_SELECTALL, &CLockDlg::OnBnClickedSelectall)\r
64         ON_BN_CLICKED(IDC_HISTORY, &CLockDlg::OnBnClickedHistory)\r
65         ON_REGISTERED_MESSAGE(CSVNStatusListCtrl::SVNSLNM_ADDFILE, OnFileDropped)\r
66         ON_WM_TIMER()\r
67 END_MESSAGE_MAP()\r
68 \r
69 BOOL CLockDlg::OnInitDialog()\r
70 {\r
71         CResizableStandAloneDialog::OnInitDialog();\r
72 \r
73         m_History.SetMaxHistoryItems((LONG)CRegDWORD(_T("Software\\TortoiseSVN\\MaxHistoryItems"), 25));\r
74         m_History.Load(_T("Software\\TortoiseSVN\\History\\commit"), _T("logmsgs"));\r
75 \r
76         m_cFileList.Init(SVNSLC_COLEXT | SVNSLC_COLLOCK | SVNSLC_COLSVNNEEDSLOCK, _T("LockDlg"));\r
77         m_cFileList.SetSelectButton(&m_SelectAll);\r
78         m_cFileList.SetConfirmButton((CButton*)GetDlgItem(IDOK));\r
79         m_cFileList.SetCancelBool(&m_bCancelled);\r
80         m_cFileList.EnableFileDrop();\r
81         m_cFileList.SetBackgroundImage(IDI_LOCK_BKG);\r
82         if (m_ProjectProperties)\r
83                 m_cEdit.Init(*m_ProjectProperties);\r
84         else\r
85                 m_cEdit.Init();\r
86         m_cEdit.SetFont((CString)CRegString(_T("Software\\TortoiseSVN\\LogFontName"), _T("Courier New")), (DWORD)CRegDWORD(_T("Software\\TortoiseSVN\\LogFontSize"), 8));\r
87 \r
88         if (!m_sLockMessage.IsEmpty())\r
89                 m_cEdit.SetText(m_sLockMessage);\r
90                 \r
91         m_tooltips.Create(this);\r
92         m_tooltips.AddTool(IDC_LOCKWARNING, IDS_WARN_SVNNEEDSLOCK);\r
93 \r
94         m_SelectAll.SetCheck(BST_INDETERMINATE);\r
95 \r
96         AdjustControlSize(IDC_STEALLOCKS);\r
97         AdjustControlSize(IDC_SELECTALL);\r
98 \r
99         AddAnchor(IDC_HISTORY, TOP_LEFT);\r
100         AddAnchor(IDC_LOCKTITLELABEL, TOP_LEFT, TOP_RIGHT);\r
101         AddAnchor(IDC_LOCKMESSAGE, TOP_LEFT, TOP_RIGHT);\r
102         AddAnchor(IDC_FILELIST, TOP_LEFT, BOTTOM_RIGHT);\r
103         AddAnchor(IDC_STEALLOCKS, BOTTOM_LEFT);\r
104         AddAnchor(IDC_SELECTALL, BOTTOM_LEFT);\r
105         AddAnchor(IDOK, BOTTOM_RIGHT);\r
106         AddAnchor(IDCANCEL, BOTTOM_RIGHT);\r
107         AddAnchor(IDHELP, BOTTOM_RIGHT);\r
108         AddAnchor(IDC_LOCKWARNING, TOP_RIGHT);\r
109 \r
110         if (hWndExplorer)\r
111                 CenterWindow(CWnd::FromHandle(hWndExplorer));\r
112         EnableSaveRestore(_T("LockDlg"));\r
113 \r
114         // start a thread to obtain the file list with the status without\r
115         // blocking the dialog\r
116         m_pThread = AfxBeginThread(StatusThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);\r
117         if (m_pThread==NULL)\r
118         {\r
119                 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
120         }\r
121         else\r
122         {\r
123                 m_pThread->m_bAutoDelete = FALSE;\r
124                 m_pThread->ResumeThread();\r
125         }\r
126         m_bBlock = TRUE;\r
127         \r
128         GetDlgItem(IDC_LOCKMESSAGE)->SetFocus();\r
129         return FALSE;\r
130 }\r
131 \r
132 void CLockDlg::OnOK()\r
133 {\r
134         if (m_bBlock)\r
135                 return;\r
136         m_cFileList.WriteCheckedNamesToPathList(m_pathList);\r
137         UpdateData();\r
138         m_sLockMessage = m_cEdit.GetText();\r
139         m_History.AddEntry(m_sLockMessage);\r
140         m_History.Save();\r
141 \r
142         CResizableStandAloneDialog::OnOK();\r
143 }\r
144 \r
145 void CLockDlg::OnCancel()\r
146 {\r
147         m_bCancelled = true;\r
148         if (m_bBlock)\r
149                 return;\r
150         UpdateData();\r
151         if ((m_ProjectProperties == 0)||(m_ProjectProperties->sLogTemplate.Compare(m_cEdit.GetText()) != 0))\r
152                 m_sLockMessage = m_cEdit.GetText();\r
153         m_History.AddEntry(m_sLockMessage);\r
154         m_History.Save();\r
155         CResizableStandAloneDialog::OnCancel();\r
156 }\r
157 \r
158 UINT CLockDlg::StatusThreadEntry(LPVOID pVoid)\r
159 {\r
160         return ((CLockDlg*)pVoid)->StatusThread();\r
161 }\r
162 \r
163 UINT CLockDlg::StatusThread()\r
164 {\r
165         // get the status of all selected file/folders recursively\r
166         // and show the ones which can be locked to the user\r
167         // in a list control. \r
168         m_bBlock = TRUE;\r
169         DialogEnableWindow(IDOK, false);\r
170         m_bCancelled = false;\r
171         // Initialise the list control with the status of the files/folders below us\r
172         if (!m_cFileList.GetStatus(m_pathList))\r
173         {\r
174                 m_cFileList.SetEmptyString(m_cFileList.GetLastErrorMessage());\r
175         }\r
176 \r
177         // Check if any file doesn't have svn:needs-lock set in BASE. If at least\r
178         // one file is found then show the warning that this property should by set.\r
179         BOOL bShowWarning = FALSE;\r
180         const int nCount = m_cFileList.GetItemCount();\r
181         for (int i=0; i<nCount;i++)\r
182         {\r
183                 CSVNStatusListCtrl::FileEntry* entry = m_cFileList.GetListEntry(i);\r
184                 if (entry == NULL)\r
185                         break;\r
186                 if (entry->HasNeedsLock())\r
187                 {\r
188                         bShowWarning = TRUE;\r
189                         break;\r
190                 }\r
191         }\r
192 \r
193         if ( bShowWarning )\r
194         {\r
195                 GetDlgItem(IDC_LOCKWARNING)->ShowWindow(SW_SHOW);\r
196                 DialogEnableWindow(IDC_LOCKWARNING, TRUE);\r
197         }\r
198         else\r
199         {\r
200                 GetDlgItem(IDC_LOCKWARNING)->ShowWindow(SW_HIDE);\r
201                 DialogEnableWindow(IDC_LOCKWARNING, FALSE);\r
202         }\r
203 \r
204         DWORD dwShow = SVNSLC_SHOWNORMAL | SVNSLC_SHOWMODIFIED | SVNSLC_SHOWMERGED | SVNSLC_SHOWLOCKS;\r
205         m_cFileList.Show(dwShow, dwShow, false);\r
206 \r
207         RefreshCursor();\r
208         CString logmsg;\r
209         GetDlgItemText(IDC_LOCKMESSAGE, logmsg);\r
210         DialogEnableWindow(IDOK, m_ProjectProperties ? m_ProjectProperties->nMinLockMsgSize <= logmsg.GetLength() : TRUE);\r
211         m_bBlock = FALSE;\r
212         return 0;\r
213 }\r
214 \r
215 BOOL CLockDlg::PreTranslateMessage(MSG* pMsg)\r
216 {\r
217         if (!m_bBlock)\r
218                 m_tooltips.RelayEvent(pMsg);\r
219         \r
220         if (pMsg->message == WM_KEYDOWN)\r
221         {\r
222                 switch (pMsg->wParam)\r
223                 {\r
224                 case VK_F5:\r
225                         {\r
226                                 if (m_bBlock)\r
227                                         return CResizableStandAloneDialog::PreTranslateMessage(pMsg);\r
228                                 Refresh();\r
229                         }\r
230                         break;\r
231                 case VK_RETURN:\r
232                         {\r
233                                 if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
234                                 {\r
235                                         if ( GetDlgItem(IDOK)->IsWindowEnabled() )\r
236                                         {\r
237                                                 PostMessage(WM_COMMAND, IDOK);\r
238                                         }\r
239                                         return 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 void CLockDlg::Refresh()\r
250 {\r
251         m_bBlock = TRUE;\r
252         if (AfxBeginThread(StatusThreadEntry, this)==NULL)\r
253         {\r
254                 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
255         }\r
256 }\r
257 \r
258 void CLockDlg::OnBnClickedHelp()\r
259 {\r
260         OnHelp();\r
261 }\r
262 \r
263 void CLockDlg::OnEnChangeLockmessage()\r
264 {\r
265         CString sTemp;\r
266         GetDlgItemText(IDC_LOCKMESSAGE, sTemp);\r
267         if ((m_ProjectProperties == NULL)||((m_ProjectProperties)&&(sTemp.GetLength() >= m_ProjectProperties->nMinLockMsgSize)))\r
268         {\r
269                 if (!m_bBlock)\r
270                         DialogEnableWindow(IDOK, TRUE);\r
271         }\r
272         else\r
273         {\r
274                 DialogEnableWindow(IDOK, FALSE);\r
275         }\r
276 }\r
277 \r
278 LRESULT CLockDlg::OnSVNStatusListCtrlNeedsRefresh(WPARAM, LPARAM)\r
279 {\r
280         Refresh();\r
281         return 0;\r
282 }\r
283 \r
284 void CLockDlg::OnBnClickedSelectall()\r
285 {\r
286         m_tooltips.Pop();       // hide the tooltips\r
287         UINT state = (m_SelectAll.GetState() & 0x0003);\r
288         if (state == BST_INDETERMINATE)\r
289         {\r
290                 // It is not at all useful to manually place the checkbox into the indeterminate state...\r
291                 // We will force this on to the unchecked state\r
292                 state = BST_UNCHECKED;\r
293                 m_SelectAll.SetCheck(state);\r
294         }\r
295         m_cFileList.SelectAll(state == BST_CHECKED);\r
296 }\r
297 \r
298 void CLockDlg::OnBnClickedHistory()\r
299 {\r
300         m_tooltips.Pop();       // hide the tooltips\r
301         if (m_pathList.GetCount() == 0)\r
302                 return;\r
303         SVN svn;\r
304         CHistoryDlg historyDlg;\r
305         historyDlg.SetHistory(m_History);\r
306         if (historyDlg.DoModal()==IDOK)\r
307         {\r
308                 if (historyDlg.GetSelectedText().Compare(m_cEdit.GetText().Left(historyDlg.GetSelectedText().GetLength()))!=0)\r
309                 {\r
310                         if ((m_ProjectProperties)&&(m_ProjectProperties->sLogTemplate.Compare(m_cEdit.GetText())!=0))\r
311                                 m_cEdit.InsertText(historyDlg.GetSelectedText(), !m_cEdit.GetText().IsEmpty());\r
312                         else\r
313                                 m_cEdit.SetText(historyDlg.GetSelectedText());\r
314                 }\r
315 \r
316                 OnEnChangeLockmessage();\r
317                 GetDlgItem(IDC_LOCKMESSAGE)->SetFocus();\r
318         }\r
319 }\r
320 \r
321 LRESULT CLockDlg::OnFileDropped(WPARAM, LPARAM lParam)\r
322 {\r
323         BringWindowToTop();\r
324         SetForegroundWindow();\r
325         SetActiveWindow();\r
326         // if multiple files/folders are dropped\r
327         // this handler is called for every single item\r
328         // separately.\r
329         // To avoid creating multiple refresh threads and\r
330         // causing crashes, we only add the items to the\r
331         // list control and start a timer.\r
332         // When the timer expires, we start the refresh thread,\r
333         // but only if it isn't already running - otherwise we\r
334         // restart the timer.\r
335         CTSVNPath path;\r
336         path.SetFromWin((LPCTSTR)lParam);\r
337 \r
338         if (!m_cFileList.HasPath(path))\r
339         {\r
340                 if (m_pathList.AreAllPathsFiles())\r
341                 {\r
342                         m_pathList.AddPath(path);\r
343                         m_pathList.RemoveDuplicates();\r
344                 }\r
345                 else\r
346                 {\r
347                         // if the path list contains folders, we have to check whether\r
348                         // our just (maybe) added path is a child of one of those. If it is\r
349                         // a child of a folder already in the list, we must not add it. Otherwise\r
350                         // that path could show up twice in the list.\r
351                         bool bHasParentInList = false;\r
352                         for (int i=0; i<m_pathList.GetCount(); ++i)\r
353                         {\r
354                                 if (m_pathList[i].IsAncestorOf(path))\r
355                                 {\r
356                                         bHasParentInList = true;\r
357                                         break;\r
358                                 }\r
359                         }\r
360                         if (!bHasParentInList)\r
361                         {\r
362                                 m_pathList.AddPath(path);\r
363                                 m_pathList.RemoveDuplicates();\r
364                         }\r
365                 }\r
366         }\r
367 \r
368         // Always start the timer, since the status of an existing item might have changed\r
369         SetTimer(REFRESHTIMER, 200, NULL);\r
370         ATLTRACE(_T("Item %s dropped, timer started\n"), path.GetWinPath());\r
371         return 0;\r
372 }\r
373 \r
374 void CLockDlg::OnTimer(UINT_PTR nIDEvent)\r
375 {\r
376         switch (nIDEvent)\r
377         {\r
378         case REFRESHTIMER:\r
379                 if (m_bBlock)\r
380                 {\r
381                         SetTimer(REFRESHTIMER, 200, NULL);\r
382                         ATLTRACE("Wait some more before refreshing\n");\r
383                 }\r
384                 else\r
385                 {\r
386                         KillTimer(REFRESHTIMER);\r
387                         ATLTRACE("Refreshing after items dropped\n");\r
388                         Refresh();\r
389                 }\r
390                 break;\r
391         }\r
392         __super::OnTimer(nIDEvent);\r
393 }\r