drop mergeall
[TortoiseGit.git] / src / TortoiseProc / LockDlg.cpp
blob7f16d6ea4bc485d320380eafdb7241b7d758b7b9
1 // TortoiseSVN - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2008 - Stefan Kueng
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "stdafx.h"
20 #include "TortoiseProc.h"
21 #include "MessageBox.h"
22 #include ".\lockdlg.h"
23 #include "UnicodeUtils.h"
24 #include "SVNProperties.h"
25 #include "SVN.h"
26 #include "HistoryDlg.h"
28 #define REFRESHTIMER 100
30 IMPLEMENT_DYNAMIC(CLockDlg, CResizableStandAloneDialog)
31 CLockDlg::CLockDlg(CWnd* pParent /*=NULL*/)
32 : CResizableStandAloneDialog(CLockDlg::IDD, pParent)
33 , m_bBlock(FALSE)
34 , m_bStealLocks(FALSE)
35 , m_pThread(NULL)
36 , m_bCancelled(false)
37 , m_ProjectProperties(NULL)
41 CLockDlg::~CLockDlg()
43 if(m_pThread != NULL)
45 delete m_pThread;
49 void CLockDlg::DoDataExchange(CDataExchange* pDX)
51 CResizableStandAloneDialog::DoDataExchange(pDX);
52 DDX_Check(pDX, IDC_STEALLOCKS, m_bStealLocks);
53 DDX_Control(pDX, IDC_FILELIST, m_cFileList);
54 DDX_Control(pDX, IDC_LOCKMESSAGE, m_cEdit);
55 DDX_Control(pDX, IDC_SELECTALL, m_SelectAll);
59 BEGIN_MESSAGE_MAP(CLockDlg, CResizableStandAloneDialog)
60 ON_BN_CLICKED(IDHELP, OnBnClickedHelp)
61 ON_EN_CHANGE(IDC_LOCKMESSAGE, OnEnChangeLockmessage)
62 ON_REGISTERED_MESSAGE(CSVNStatusListCtrl::SVNSLNM_NEEDSREFRESH, OnSVNStatusListCtrlNeedsRefresh)
63 ON_BN_CLICKED(IDC_SELECTALL, &CLockDlg::OnBnClickedSelectall)
64 ON_BN_CLICKED(IDC_HISTORY, &CLockDlg::OnBnClickedHistory)
65 ON_REGISTERED_MESSAGE(CSVNStatusListCtrl::SVNSLNM_ADDFILE, OnFileDropped)
66 ON_WM_TIMER()
67 END_MESSAGE_MAP()
69 BOOL CLockDlg::OnInitDialog()
71 CResizableStandAloneDialog::OnInitDialog();
73 m_History.SetMaxHistoryItems((LONG)CRegDWORD(_T("Software\\TortoiseGit\\MaxHistoryItems"), 25));
74 m_History.Load(_T("Software\\TortoiseGit\\History\\commit"), _T("logmsgs"));
76 m_cFileList.Init(SVNSLC_COLEXT | SVNSLC_COLLOCK | SVNSLC_COLSVNNEEDSLOCK, _T("LockDlg"));
77 m_cFileList.SetSelectButton(&m_SelectAll);
78 m_cFileList.SetConfirmButton((CButton*)GetDlgItem(IDOK));
79 m_cFileList.SetCancelBool(&m_bCancelled);
80 m_cFileList.EnableFileDrop();
81 m_cFileList.SetBackgroundImage(IDI_LOCK_BKG);
82 if (m_ProjectProperties)
83 m_cEdit.Init(*m_ProjectProperties);
84 else
85 m_cEdit.Init();
86 m_cEdit.SetFont((CString)CRegString(_T("Software\\TortoiseGit\\LogFontName"), _T("Courier New")), (DWORD)CRegDWORD(_T("Software\\TortoiseGit\\LogFontSize"), 8));
88 if (!m_sLockMessage.IsEmpty())
89 m_cEdit.SetText(m_sLockMessage);
91 m_tooltips.Create(this);
92 m_tooltips.AddTool(IDC_LOCKWARNING, IDS_WARN_SVNNEEDSLOCK);
94 m_SelectAll.SetCheck(BST_INDETERMINATE);
96 AdjustControlSize(IDC_STEALLOCKS);
97 AdjustControlSize(IDC_SELECTALL);
99 AddAnchor(IDC_HISTORY, TOP_LEFT);
100 AddAnchor(IDC_LOCKTITLELABEL, TOP_LEFT, TOP_RIGHT);
101 AddAnchor(IDC_LOCKMESSAGE, TOP_LEFT, TOP_RIGHT);
102 AddAnchor(IDC_FILELIST, TOP_LEFT, BOTTOM_RIGHT);
103 AddAnchor(IDC_STEALLOCKS, BOTTOM_LEFT);
104 AddAnchor(IDC_SELECTALL, BOTTOM_LEFT);
105 AddAnchor(IDOK, BOTTOM_RIGHT);
106 AddAnchor(IDCANCEL, BOTTOM_RIGHT);
107 AddAnchor(IDHELP, BOTTOM_RIGHT);
108 AddAnchor(IDC_LOCKWARNING, TOP_RIGHT);
110 if (hWndExplorer)
111 CenterWindow(CWnd::FromHandle(hWndExplorer));
112 EnableSaveRestore(_T("LockDlg"));
114 // start a thread to obtain the file list with the status without
115 // blocking the dialog
116 m_pThread = AfxBeginThread(StatusThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
117 if (m_pThread==NULL)
119 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
121 else
123 m_pThread->m_bAutoDelete = FALSE;
124 m_pThread->ResumeThread();
126 m_bBlock = TRUE;
128 GetDlgItem(IDC_LOCKMESSAGE)->SetFocus();
129 return FALSE;
132 void CLockDlg::OnOK()
134 if (m_bBlock)
135 return;
136 m_cFileList.WriteCheckedNamesToPathList(m_pathList);
137 UpdateData();
138 m_sLockMessage = m_cEdit.GetText();
139 m_History.AddEntry(m_sLockMessage);
140 m_History.Save();
142 CResizableStandAloneDialog::OnOK();
145 void CLockDlg::OnCancel()
147 m_bCancelled = true;
148 if (m_bBlock)
149 return;
150 UpdateData();
151 if ((m_ProjectProperties == 0)||(m_ProjectProperties->sLogTemplate.Compare(m_cEdit.GetText()) != 0))
152 m_sLockMessage = m_cEdit.GetText();
153 m_History.AddEntry(m_sLockMessage);
154 m_History.Save();
155 CResizableStandAloneDialog::OnCancel();
158 UINT CLockDlg::StatusThreadEntry(LPVOID pVoid)
160 return ((CLockDlg*)pVoid)->StatusThread();
163 UINT CLockDlg::StatusThread()
165 // get the status of all selected file/folders recursively
166 // and show the ones which can be locked to the user
167 // in a list control.
168 m_bBlock = TRUE;
169 DialogEnableWindow(IDOK, false);
170 m_bCancelled = false;
171 // Initialise the list control with the status of the files/folders below us
172 if (!m_cFileList.GetStatus(m_pathList))
174 m_cFileList.SetEmptyString(m_cFileList.GetLastErrorMessage());
177 // Check if any file doesn't have svn:needs-lock set in BASE. If at least
178 // one file is found then show the warning that this property should by set.
179 BOOL bShowWarning = FALSE;
180 const int nCount = m_cFileList.GetItemCount();
181 for (int i=0; i<nCount;i++)
183 CSVNStatusListCtrl::FileEntry* entry = m_cFileList.GetListEntry(i);
184 if (entry == NULL)
185 break;
186 if (entry->HasNeedsLock())
188 bShowWarning = TRUE;
189 break;
193 if ( bShowWarning )
195 GetDlgItem(IDC_LOCKWARNING)->ShowWindow(SW_SHOW);
196 DialogEnableWindow(IDC_LOCKWARNING, TRUE);
198 else
200 GetDlgItem(IDC_LOCKWARNING)->ShowWindow(SW_HIDE);
201 DialogEnableWindow(IDC_LOCKWARNING, FALSE);
204 DWORD dwShow = SVNSLC_SHOWNORMAL | SVNSLC_SHOWMODIFIED | SVNSLC_SHOWMERGED | SVNSLC_SHOWLOCKS;
205 m_cFileList.Show(dwShow, dwShow, false);
207 RefreshCursor();
208 CString logmsg;
209 GetDlgItemText(IDC_LOCKMESSAGE, logmsg);
210 DialogEnableWindow(IDOK, m_ProjectProperties ? m_ProjectProperties->nMinLockMsgSize <= logmsg.GetLength() : TRUE);
211 m_bBlock = FALSE;
212 return 0;
215 BOOL CLockDlg::PreTranslateMessage(MSG* pMsg)
217 if (!m_bBlock)
218 m_tooltips.RelayEvent(pMsg);
220 if (pMsg->message == WM_KEYDOWN)
222 switch (pMsg->wParam)
224 case VK_F5:
226 if (m_bBlock)
227 return CResizableStandAloneDialog::PreTranslateMessage(pMsg);
228 Refresh();
230 break;
231 case VK_RETURN:
233 if (GetAsyncKeyState(VK_CONTROL)&0x8000)
235 if ( GetDlgItem(IDOK)->IsWindowEnabled() )
237 PostMessage(WM_COMMAND, IDOK);
239 return TRUE;
242 break;
246 return CResizableStandAloneDialog::PreTranslateMessage(pMsg);
249 void CLockDlg::Refresh()
251 m_bBlock = TRUE;
252 if (AfxBeginThread(StatusThreadEntry, this)==NULL)
254 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
258 void CLockDlg::OnBnClickedHelp()
260 OnHelp();
263 void CLockDlg::OnEnChangeLockmessage()
265 CString sTemp;
266 GetDlgItemText(IDC_LOCKMESSAGE, sTemp);
267 if ((m_ProjectProperties == NULL)||((m_ProjectProperties)&&(sTemp.GetLength() >= m_ProjectProperties->nMinLockMsgSize)))
269 if (!m_bBlock)
270 DialogEnableWindow(IDOK, TRUE);
272 else
274 DialogEnableWindow(IDOK, FALSE);
278 LRESULT CLockDlg::OnSVNStatusListCtrlNeedsRefresh(WPARAM, LPARAM)
280 Refresh();
281 return 0;
284 void CLockDlg::OnBnClickedSelectall()
286 m_tooltips.Pop(); // hide the tooltips
287 UINT state = (m_SelectAll.GetState() & 0x0003);
288 if (state == BST_INDETERMINATE)
290 // It is not at all useful to manually place the checkbox into the indeterminate state...
291 // We will force this on to the unchecked state
292 state = BST_UNCHECKED;
293 m_SelectAll.SetCheck(state);
295 m_cFileList.SelectAll(state == BST_CHECKED);
298 void CLockDlg::OnBnClickedHistory()
300 m_tooltips.Pop(); // hide the tooltips
301 if (m_pathList.GetCount() == 0)
302 return;
303 SVN svn;
304 CHistoryDlg historyDlg;
305 historyDlg.SetHistory(m_History);
306 if (historyDlg.DoModal()==IDOK)
308 if (historyDlg.GetSelectedText().Compare(m_cEdit.GetText().Left(historyDlg.GetSelectedText().GetLength()))!=0)
310 if ((m_ProjectProperties)&&(m_ProjectProperties->sLogTemplate.Compare(m_cEdit.GetText())!=0))
311 m_cEdit.InsertText(historyDlg.GetSelectedText(), !m_cEdit.GetText().IsEmpty());
312 else
313 m_cEdit.SetText(historyDlg.GetSelectedText());
316 OnEnChangeLockmessage();
317 GetDlgItem(IDC_LOCKMESSAGE)->SetFocus();
321 LRESULT CLockDlg::OnFileDropped(WPARAM, LPARAM lParam)
323 BringWindowToTop();
324 SetForegroundWindow();
325 SetActiveWindow();
326 // if multiple files/folders are dropped
327 // this handler is called for every single item
328 // separately.
329 // To avoid creating multiple refresh threads and
330 // causing crashes, we only add the items to the
331 // list control and start a timer.
332 // When the timer expires, we start the refresh thread,
333 // but only if it isn't already running - otherwise we
334 // restart the timer.
335 CTSVNPath path;
336 path.SetFromWin((LPCTSTR)lParam);
338 if (!m_cFileList.HasPath(path))
340 if (m_pathList.AreAllPathsFiles())
342 m_pathList.AddPath(path);
343 m_pathList.RemoveDuplicates();
345 else
347 // if the path list contains folders, we have to check whether
348 // our just (maybe) added path is a child of one of those. If it is
349 // a child of a folder already in the list, we must not add it. Otherwise
350 // that path could show up twice in the list.
351 bool bHasParentInList = false;
352 for (int i=0; i<m_pathList.GetCount(); ++i)
354 if (m_pathList[i].IsAncestorOf(path))
356 bHasParentInList = true;
357 break;
360 if (!bHasParentInList)
362 m_pathList.AddPath(path);
363 m_pathList.RemoveDuplicates();
368 // Always start the timer, since the status of an existing item might have changed
369 SetTimer(REFRESHTIMER, 200, NULL);
370 ATLTRACE(_T("Item %s dropped, timer started\n"), path.GetWinPath());
371 return 0;
374 void CLockDlg::OnTimer(UINT_PTR nIDEvent)
376 switch (nIDEvent)
378 case REFRESHTIMER:
379 if (m_bBlock)
381 SetTimer(REFRESHTIMER, 200, NULL);
382 ATLTRACE("Wait some more before refreshing\n");
384 else
386 KillTimer(REFRESHTIMER);
387 ATLTRACE("Refreshing after items dropped\n");
388 Refresh();
390 break;
392 __super::OnTimer(nIDEvent);