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.
20 #include "TortoiseProc.h"
22 #include "MessageBox.h"
23 #include "UnicodeUtils.h"
24 #include "RepositoryBrowser.h"
25 #include "BrowseFolder.h"
29 #include "HistoryDlg.h"
31 IMPLEMENT_DYNAMIC(CCopyDlg
, CResizableStandAloneDialog
)
32 CCopyDlg::CCopyDlg(CWnd
* pParent
/*=NULL*/)
33 : CResizableStandAloneDialog(CCopyDlg::IDD
, pParent
)
35 , m_sLogMessage(_T(""))
37 , m_CopyRev(SVNRev::REV_HEAD
)
39 , m_bSettingChanged(false)
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
)
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();
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
);
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();
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
);
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
))
194 SendMessage(WM_TSVN_MAXREVFOUND
);
196 InterlockedExchange(&m_bThreadRunning
, FALSE
);
200 void CCopyDlg::OnOK()
203 // check if the status thread has already finished
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
);
217 GetDlgItemText(IDC_BUGID
, id
);
219 GetDlgItemText(IDC_COPYREVTEXT
, sRevText
);
220 if (!m_ProjectProperties
.CheckBugID(id
))
222 ShowBalloon(IDC_BUGID
, IDS_COMMITDLG_ONLYNUMBERS
);
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
)
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
);
238 m_CopyRev
= SVNRev(sRevText
);
240 if (!m_CopyRev
.IsValid())
242 ShowBalloon(IDC_COPYREVTEXT
, IDS_ERR_INVALIDREV
);
247 m_URLCombo
.GetWindowText(combourl
);
248 if ((m_wcURL
.CompareNoCase(combourl
)==0)&&(m_CopyRev
.IsHead()))
251 temp
.Format(IDS_ERR_COPYITSELF
, (LPCTSTR
)m_wcURL
, (LPCTSTR
)m_URLCombo
.GetString());
252 CMessageBox::Show(this->m_hWnd
, temp
, _T("TortoiseSVN"), MB_ICONERROR
);
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
)
264 m_History
.AddEntry(m_sLogMessage
);
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");
277 m_sLogMessage
= sBugID
+ _T("\n") + m_sLogMessage
;
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
297 void CCopyDlg::OnCancel()
300 // check if the status thread has already finished
303 WaitForSingleObject(m_pThread
->m_hThread
, INFINITE
);
305 if (m_ProjectProperties
.sLogTemplate
.Compare(m_cLogMessage
.GetText()) != 0)
306 m_History
.AddEntry(m_cLogMessage
.GetText());
308 CResizableStandAloneDialog::OnCancel();
311 BOOL
CCopyDlg::PreTranslateMessage(MSG
* pMsg
)
313 m_tooltips
.RelayEvent(pMsg
);
315 if (pMsg
->message
== WM_KEYDOWN
)
317 switch (pMsg
->wParam
)
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
339 if (::IsWindow(m_pLogDlg
->GetSafeHwnd())&&(m_pLogDlg
->IsWindowVisible()))
341 AfxGetApp()->DoWaitCursor(1);
342 //now show the log dialog
343 if (!m_wcURL
.IsEmpty())
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
)
368 temp
.Format(_T("%ld"), lParam
);
369 SetDlgItemText(IDC_COPYREVTEXT
, temp
);
370 CheckRadioButton(IDC_COPYHEAD
, IDC_COPYREV
, IDC_COPYREV
);
371 DialogEnableWindow(IDC_COPYREVTEXT
, TRUE
);
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
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());
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
)
428 // the working copy has local modifications.
429 // show a warning balloon if the user has selected HEAD as the
431 ShowBalloon(IDC_COPYHEAD
, IDS_WARN_COPYHEADWITHLOCALMODS
);
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
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
);
448 void CCopyDlg::SetRevision(const SVNRev
& rev
)
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
);
462 CheckRadioButton(IDC_COPYHEAD
, IDC_COPYREV
, IDC_COPYREV
);
463 DialogEnableWindow(IDC_COPYREVTEXT
, TRUE
);
465 temp
.Format(_T("%ld"), (LONG
)rev
);
466 SetDlgItemText(IDC_COPYREVTEXT
, temp
);
470 void CCopyDlg::OnCbnEditchangeUrlcombo()
472 m_bSettingChanged
= true;