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