BrowseRefs: Context menu enhancements
[TortoiseGit.git] / src / TortoiseProc / CopyDlg.cpp
blobc0504114d7ae859536c9c92bf1ab916252fcfe92
1 // TortoiseSVN - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2008 - TortoiseSVN
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 "CopyDlg.h"
22 #include "MessageBox.h"
23 #include "UnicodeUtils.h"
24 #include "RepositoryBrowser.h"
25 #include "BrowseFolder.h"
26 #include "Registry.h"
27 #include "TSVNPath.h"
28 #include "AppUtils.h"
29 #include "HistoryDlg.h"
31 IMPLEMENT_DYNAMIC(CCopyDlg, CResizableStandAloneDialog)
32 CCopyDlg::CCopyDlg(CWnd* pParent /*=NULL*/)
33 : CResizableStandAloneDialog(CCopyDlg::IDD, pParent)
34 , m_URL(_T(""))
35 , m_sLogMessage(_T(""))
36 , m_sBugID(_T(""))
37 , m_CopyRev(SVNRev::REV_HEAD)
38 , m_bDoSwitch(false)
39 , m_bSettingChanged(false)
40 , m_bCancelled(false)
41 , m_pThread(NULL)
42 , m_pLogDlg(NULL)
43 , m_bThreadRunning(0)
47 CCopyDlg::~CCopyDlg()
49 if (m_pLogDlg)
50 delete m_pLogDlg;
53 void CCopyDlg::DoDataExchange(CDataExchange* pDX)
55 CResizableStandAloneDialog::DoDataExchange(pDX);
56 DDX_Control(pDX, IDC_URLCOMBO, m_URLCombo);
57 DDX_Control(pDX, IDC_BROWSE, m_butBrowse);
58 DDX_Text(pDX, IDC_BUGID, m_sBugID);
59 DDX_Control(pDX, IDC_LOGMESSAGE, m_cLogMessage);
60 DDX_Check(pDX, IDC_DOSWITCH, m_bDoSwitch);
64 BEGIN_MESSAGE_MAP(CCopyDlg, CResizableStandAloneDialog)
65 ON_REGISTERED_MESSAGE(WM_REVSELECTED, OnRevSelected)
66 ON_MESSAGE(WM_TSVN_MAXREVFOUND, OnRevFound)
67 ON_BN_CLICKED(IDC_BROWSE, OnBnClickedBrowse)
68 ON_BN_CLICKED(IDHELP, OnBnClickedHelp)
69 ON_BN_CLICKED(IDC_BROWSEFROM, OnBnClickedBrowsefrom)
70 ON_BN_CLICKED(IDC_COPYHEAD, OnBnClickedCopyhead)
71 ON_BN_CLICKED(IDC_COPYREV, OnBnClickedCopyrev)
72 ON_BN_CLICKED(IDC_COPYWC, OnBnClickedCopywc)
73 ON_BN_CLICKED(IDC_HISTORY, OnBnClickedHistory)
74 ON_EN_CHANGE(IDC_LOGMESSAGE, OnEnChangeLogmessage)
75 ON_CBN_EDITCHANGE(IDC_URLCOMBO, &CCopyDlg::OnCbnEditchangeUrlcombo)
76 END_MESSAGE_MAP()
79 BOOL CCopyDlg::OnInitDialog()
81 CResizableStandAloneDialog::OnInitDialog();
83 AdjustControlSize(IDC_COPYHEAD);
84 AdjustControlSize(IDC_COPYREV);
85 AdjustControlSize(IDC_COPYWC);
86 AdjustControlSize(IDC_DOSWITCH);
88 CTSVNPath path(m_path);
90 m_History.SetMaxHistoryItems((LONG)CRegDWORD(_T("Software\\TortoiseGit\\MaxHistoryItems"), 25));
92 SetRevision(m_CopyRev);
94 m_tooltips.Create(this);
95 m_tooltips.AddTool(IDC_HISTORY, IDS_COMMITDLG_HISTORY_TT);
97 if (SVN::PathIsURL(path))
99 DialogEnableWindow(IDC_COPYWC, FALSE);
100 DialogEnableWindow(IDC_DOSWITCH, FALSE);
101 SetDlgItemText(IDC_COPYSTARTLABEL, CString(MAKEINTRESOURCE(IDS_COPYDLG_FROMURL)));
104 m_bFile = !path.IsDirectory();
105 SVN svn;
106 m_wcURL = svn.GetURLFromPath(path);
107 CString sUUID = svn.GetUUIDFromPath(path);
108 if (m_wcURL.IsEmpty())
110 CMessageBox::Show(this->m_hWnd, IDS_ERR_NOURLOFFILE, IDS_APPNAME, MB_ICONERROR);
111 TRACE(_T("could not retrieve the URL of the file!\n"));
112 this->EndDialog(IDCANCEL); //exit
114 m_URLCombo.SetURLHistory(TRUE);
115 m_URLCombo.LoadHistory(_T("Software\\TortoiseGit\\History\\repoURLS\\")+sUUID, _T("url"));
116 m_URLCombo.AddString(CTSVNPath(m_wcURL).GetUIPathString(), 0);
117 m_URLCombo.SelectString(-1, CTSVNPath(m_wcURL).GetUIPathString());
118 SetDlgItemText(IDC_FROMURL, m_wcURL);
119 if (!m_URL.IsEmpty())
120 m_URLCombo.SetWindowText(m_URL);
122 CString reg;
123 reg.Format(_T("Software\\TortoiseGit\\History\\commit%s"), (LPCTSTR)sUUID);
124 m_History.Load(reg, _T("logmsgs"));
126 m_ProjectProperties.ReadProps(m_path);
127 m_cLogMessage.Init(m_ProjectProperties);
128 m_cLogMessage.SetFont((CString)CRegString(_T("Software\\TortoiseGit\\LogFontName"), _T("Courier New")), (DWORD)CRegDWORD(_T("Software\\TortoiseGit\\LogFontSize"), 8));
129 if (m_ProjectProperties.sMessage.IsEmpty())
131 GetDlgItem(IDC_BUGID)->ShowWindow(SW_HIDE);
132 GetDlgItem(IDC_BUGIDLABEL)->ShowWindow(SW_HIDE);
133 GetDlgItem(IDC_LOGMESSAGE)->SetFocus();
135 else
137 GetDlgItem(IDC_BUGID)->ShowWindow(SW_SHOW);
138 GetDlgItem(IDC_BUGIDLABEL)->ShowWindow(SW_SHOW);
139 if (!m_ProjectProperties.sLabel.IsEmpty())
140 SetDlgItemText(IDC_BUGIDLABEL, m_ProjectProperties.sLabel);
141 GetDlgItem(IDC_BUGID)->SetFocus();
143 if (!m_sLogMessage.IsEmpty())
144 m_cLogMessage.SetText(m_sLogMessage);
146 AddAnchor(IDC_REPOGROUP, TOP_LEFT, TOP_RIGHT);
147 AddAnchor(IDC_COPYSTARTLABEL, TOP_LEFT, TOP_RIGHT);
148 AddAnchor(IDC_FROMURL, TOP_LEFT, TOP_RIGHT);
149 AddAnchor(IDC_TOURLLABEL, TOP_LEFT);
150 AddAnchor(IDC_URLCOMBO, TOP_LEFT, TOP_RIGHT);
151 AddAnchor(IDC_BROWSE, TOP_RIGHT);
152 AddAnchor(IDC_FROMGROUP, TOP_LEFT, TOP_RIGHT);
153 AddAnchor(IDC_COPYHEAD, TOP_LEFT);
154 AddAnchor(IDC_COPYREV, TOP_LEFT);
155 AddAnchor(IDC_COPYREVTEXT, TOP_LEFT);
156 AddAnchor(IDC_BROWSEFROM, TOP_LEFT);
157 AddAnchor(IDC_COPYWC, TOP_LEFT);
158 AddAnchor(IDC_MSGGROUP, TOP_LEFT, BOTTOM_RIGHT);
159 AddAnchor(IDC_HISTORY, TOP_LEFT);
160 AddAnchor(IDC_BUGIDLABEL, TOP_RIGHT);
161 AddAnchor(IDC_BUGID, TOP_RIGHT);
162 AddAnchor(IDC_LOGMESSAGE, TOP_LEFT, BOTTOM_RIGHT);
163 AddAnchor(IDC_DOSWITCH, BOTTOM_LEFT);
164 AddAnchor(IDOK, BOTTOM_RIGHT);
165 AddAnchor(IDCANCEL, BOTTOM_RIGHT);
166 AddAnchor(IDHELP, BOTTOM_RIGHT);
168 if ((m_pParentWnd==NULL)&&(hWndExplorer))
169 CenterWindow(CWnd::FromHandle(hWndExplorer));
170 EnableSaveRestore(_T("CopyDlg"));
172 m_bSettingChanged = false;
173 // start a thread to obtain the highest revision number of the working copy
174 // without blocking the dialog
175 if ((m_pThread = AfxBeginThread(FindRevThreadEntry, this))==NULL)
177 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
180 return TRUE;
183 UINT CCopyDlg::FindRevThreadEntry(LPVOID pVoid)
185 return ((CCopyDlg*)pVoid)->FindRevThread();
188 UINT CCopyDlg::FindRevThread()
190 InterlockedExchange(&m_bThreadRunning, TRUE);
191 if (GetWCRevisionStatus(m_path, true, m_minrev, m_maxrev, m_bswitched, m_bmodified, m_bSparse))
193 if (!m_bCancelled)
194 SendMessage(WM_TSVN_MAXREVFOUND);
196 InterlockedExchange(&m_bThreadRunning, FALSE);
197 return 0;
200 void CCopyDlg::OnOK()
202 m_bCancelled = true;
203 // check if the status thread has already finished
204 if (m_pThread)
206 WaitForSingleObject(m_pThread->m_hThread, 1000);
207 if (m_bThreadRunning)
209 // we gave the thread a chance to quit. Since the thread didn't
210 // listen to us we have to kill it.
211 TerminateThread(m_pThread->m_hThread, (DWORD)-1);
212 InterlockedExchange(&m_bThreadRunning, FALSE);
216 CString id;
217 GetDlgItemText(IDC_BUGID, id);
218 CString sRevText;
219 GetDlgItemText(IDC_COPYREVTEXT, sRevText);
220 if (!m_ProjectProperties.CheckBugID(id))
222 ShowBalloon(IDC_BUGID, IDS_COMMITDLG_ONLYNUMBERS);
223 return;
225 m_sLogMessage = m_cLogMessage.GetText();
226 if ((m_ProjectProperties.bWarnIfNoIssue) && (id.IsEmpty() && !m_ProjectProperties.HasBugID(m_sLogMessage)))
228 if (CMessageBox::Show(this->m_hWnd, IDS_COMMITDLG_NOISSUEWARNING, IDS_APPNAME, MB_YESNO | MB_ICONWARNING)!=IDYES)
229 return;
231 UpdateData(TRUE);
233 if (GetCheckedRadioButton(IDC_COPYHEAD, IDC_COPYREV) == IDC_COPYHEAD)
234 m_CopyRev = SVNRev(SVNRev::REV_HEAD);
235 else if (GetCheckedRadioButton(IDC_COPYHEAD, IDC_COPYREV) == IDC_COPYWC)
236 m_CopyRev = SVNRev(SVNRev::REV_WC);
237 else
238 m_CopyRev = SVNRev(sRevText);
240 if (!m_CopyRev.IsValid())
242 ShowBalloon(IDC_COPYREVTEXT, IDS_ERR_INVALIDREV);
243 return;
246 CString combourl;
247 m_URLCombo.GetWindowText(combourl);
248 if ((m_wcURL.CompareNoCase(combourl)==0)&&(m_CopyRev.IsHead()))
250 CString temp;
251 temp.Format(IDS_ERR_COPYITSELF, (LPCTSTR)m_wcURL, (LPCTSTR)m_URLCombo.GetString());
252 CMessageBox::Show(this->m_hWnd, temp, _T("TortoiseSVN"), MB_ICONERROR);
253 return;
256 m_URLCombo.SaveHistory();
257 m_URL = m_URLCombo.GetString();
258 if (!CTSVNPath(m_URL).IsValidOnWindows())
260 if (CMessageBox::Show(this->m_hWnd, IDS_WARN_NOVALIDPATH, IDS_APPNAME, MB_ICONINFORMATION|MB_YESNO) != IDYES)
261 return;
264 m_History.AddEntry(m_sLogMessage);
265 m_History.Save();
267 m_sBugID.Trim();
268 if (!m_sBugID.IsEmpty())
270 m_sBugID.Replace(_T(", "), _T(","));
271 m_sBugID.Replace(_T(" ,"), _T(","));
272 CString sBugID = m_ProjectProperties.sMessage;
273 sBugID.Replace(_T("%BUGID%"), m_sBugID);
274 if (m_ProjectProperties.bAppend)
275 m_sLogMessage += _T("\n") + sBugID + _T("\n");
276 else
277 m_sLogMessage = sBugID + _T("\n") + m_sLogMessage;
278 UpdateData(FALSE);
280 CResizableStandAloneDialog::OnOK();
283 void CCopyDlg::OnBnClickedBrowse()
285 m_tooltips.Pop(); // hide the tooltips
286 SVNRev rev = SVNRev::REV_HEAD;
288 CAppUtils::BrowseRepository(m_URLCombo, this, rev);
291 void CCopyDlg::OnBnClickedHelp()
293 m_tooltips.Pop(); // hide the tooltips
294 OnHelp();
297 void CCopyDlg::OnCancel()
299 m_bCancelled = true;
300 // check if the status thread has already finished
301 if (m_pThread)
303 WaitForSingleObject(m_pThread->m_hThread, INFINITE);
305 if (m_ProjectProperties.sLogTemplate.Compare(m_cLogMessage.GetText()) != 0)
306 m_History.AddEntry(m_cLogMessage.GetText());
307 m_History.Save();
308 CResizableStandAloneDialog::OnCancel();
311 BOOL CCopyDlg::PreTranslateMessage(MSG* pMsg)
313 m_tooltips.RelayEvent(pMsg);
315 if (pMsg->message == WM_KEYDOWN)
317 switch (pMsg->wParam)
319 case VK_RETURN:
321 if (GetAsyncKeyState(VK_CONTROL)&0x8000)
323 if ( GetDlgItem(IDOK)->IsWindowEnabled() )
325 PostMessage(WM_COMMAND, IDOK);
332 return CResizableStandAloneDialog::PreTranslateMessage(pMsg);
335 void CCopyDlg::OnBnClickedBrowsefrom()
337 m_tooltips.Pop(); // hide the tooltips
338 UpdateData(TRUE);
339 if (::IsWindow(m_pLogDlg->GetSafeHwnd())&&(m_pLogDlg->IsWindowVisible()))
340 return;
341 AfxGetApp()->DoWaitCursor(1);
342 //now show the log dialog
343 if (!m_wcURL.IsEmpty())
345 delete m_pLogDlg;
346 m_pLogDlg = new CLogDlg();
347 CRegDWORD reg = CRegDWORD(_T("Software\\TortoiseGit\\NumberOfLogs"), 100);
348 int limit = (int)(LONG)reg;
349 m_pLogDlg->SetParams(CTSVNPath(m_wcURL), SVNRev::REV_HEAD, SVNRev::REV_HEAD, 1, limit, TRUE);
350 m_pLogDlg->SetSelect(true);
351 m_pLogDlg->Create(IDD_LOGMESSAGE, this);
352 m_pLogDlg->ShowWindow(SW_SHOW);
353 m_pLogDlg->m_wParam = 0;
354 m_pLogDlg->m_pNotifyWindow = this;
356 AfxGetApp()->DoWaitCursor(-1);
359 void CCopyDlg::OnEnChangeLogmessage()
361 CString sTemp = m_cLogMessage.GetText();
362 DialogEnableWindow(IDOK, sTemp.GetLength() >= m_ProjectProperties.nMinLogSize);
365 LPARAM CCopyDlg::OnRevSelected(WPARAM /*wParam*/, LPARAM lParam)
367 CString temp;
368 temp.Format(_T("%ld"), lParam);
369 SetDlgItemText(IDC_COPYREVTEXT, temp);
370 CheckRadioButton(IDC_COPYHEAD, IDC_COPYREV, IDC_COPYREV);
371 DialogEnableWindow(IDC_COPYREVTEXT, TRUE);
372 return 0;
375 void CCopyDlg::OnBnClickedCopyhead()
377 m_tooltips.Pop(); // hide the tooltips
378 m_bSettingChanged = true;
379 DialogEnableWindow(IDC_COPYREVTEXT, FALSE);
382 void CCopyDlg::OnBnClickedCopyrev()
384 m_tooltips.Pop(); // hide the tooltips
385 m_bSettingChanged = true;
386 DialogEnableWindow(IDC_COPYREVTEXT, TRUE);
389 void CCopyDlg::OnBnClickedCopywc()
391 m_tooltips.Pop(); // hide the tooltips
392 m_bSettingChanged = true;
393 DialogEnableWindow(IDC_COPYREVTEXT, FALSE);
396 void CCopyDlg::OnBnClickedHistory()
398 m_tooltips.Pop(); // hide the tooltips
399 SVN svn;
400 CHistoryDlg historyDlg;
401 historyDlg.SetHistory(m_History);
402 if (historyDlg.DoModal()==IDOK)
404 if (historyDlg.GetSelectedText().Compare(m_cLogMessage.GetText().Left(historyDlg.GetSelectedText().GetLength()))!=0)
406 if (m_ProjectProperties.sLogTemplate.Compare(m_cLogMessage.GetText())!=0)
407 m_cLogMessage.InsertText(historyDlg.GetSelectedText(), !m_cLogMessage.GetText().IsEmpty());
408 else
409 m_cLogMessage.SetText(historyDlg.GetSelectedText());
411 DialogEnableWindow(IDOK, m_ProjectProperties.nMinLogSize <= m_cLogMessage.GetText().GetLength());
415 LPARAM CCopyDlg::OnRevFound(WPARAM /*wParam*/, LPARAM /*lParam*/)
417 // we have found the highest last-committed revision
418 // in the working copy
419 if ((!m_bSettingChanged)&&(m_maxrev != 0)&&(!m_bCancelled))
421 // we only change the setting automatically if the user hasn't done so
422 // already him/herself, if the highest revision is valid. And of course,
423 // if the thread hasn't been stopped forcefully.
424 if (GetCheckedRadioButton(IDC_COPYHEAD, IDC_COPYREV) == IDC_COPYHEAD)
426 if (m_bmodified)
428 // the working copy has local modifications.
429 // show a warning balloon if the user has selected HEAD as the
430 // source revision
431 ShowBalloon(IDC_COPYHEAD, IDS_WARN_COPYHEADWITHLOCALMODS);
433 else
435 // and of course, we only change it if the radio button for a REPO-to-REPO copy
436 // is enabled for HEAD and if there are no local modifications
437 CString temp;
438 temp.Format(_T("%ld"), m_maxrev);
439 SetDlgItemText(IDC_COPYREVTEXT, temp);
440 CheckRadioButton(IDC_COPYHEAD, IDC_COPYREV, IDC_COPYREV);
441 DialogEnableWindow(IDC_COPYREVTEXT, TRUE);
445 return 0;
448 void CCopyDlg::SetRevision(const SVNRev& rev)
450 if (rev.IsHead())
452 CheckRadioButton(IDC_COPYHEAD, IDC_COPYREV, IDC_COPYHEAD);
453 DialogEnableWindow(IDC_COPYREVTEXT, FALSE);
455 else if (rev.IsWorking())
457 CheckRadioButton(IDC_COPYHEAD, IDC_COPYREV, IDC_COPYWC);
458 DialogEnableWindow(IDC_COPYREVTEXT, FALSE);
460 else
462 CheckRadioButton(IDC_COPYHEAD, IDC_COPYREV, IDC_COPYREV);
463 DialogEnableWindow(IDC_COPYREVTEXT, TRUE);
464 CString temp;
465 temp.Format(_T("%ld"), (LONG)rev);
466 SetDlgItemText(IDC_COPYREVTEXT, temp);
470 void CCopyDlg::OnCbnEditchangeUrlcombo()
472 m_bSettingChanged = true;