Fixed issue #507: Help Spell error and push wrongly link to sync
[TortoiseGit.git] / src / TortoiseShell / SVNPropertyPage.cpp
blob1c0c2787ac4b5aa1e23307252fa734183671f397
1 // TortoiseSVN - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2008 - TortoiseGit
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"
21 #include "ShellExt.h"
22 #include "svnpropertypage.h"
23 #include "UnicodeUtils.h"
24 #include "PathUtils.h"
25 #include "GitStatus.h"
27 #define MAX_STRING_LENGTH 4096 //should be big enough
29 // Nonmember function prototypes
30 BOOL CALLBACK PageProc (HWND, UINT, WPARAM, LPARAM);
31 UINT CALLBACK PropPageCallbackProc ( HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp );
33 /////////////////////////////////////////////////////////////////////////////
34 // Dialog procedures and other callback functions
36 BOOL CALLBACK PageProc (HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
38 CGitPropertyPage * sheetpage;
40 if (uMessage == WM_INITDIALOG)
42 sheetpage = (CGitPropertyPage*) ((LPPROPSHEETPAGE) lParam)->lParam;
43 SetWindowLongPtr (hwnd, GWLP_USERDATA, (LONG_PTR) sheetpage);
44 sheetpage->SetHwnd(hwnd);
46 else
48 sheetpage = (CGitPropertyPage*) GetWindowLongPtr (hwnd, GWLP_USERDATA);
51 if (sheetpage != 0L)
52 return sheetpage->PageProc(hwnd, uMessage, wParam, lParam);
53 else
54 return FALSE;
57 UINT CALLBACK PropPageCallbackProc ( HWND /*hwnd*/, UINT uMsg, LPPROPSHEETPAGE ppsp )
59 // Delete the page before closing.
60 if (PSPCB_RELEASE == uMsg)
62 CGitPropertyPage* sheetpage = (CGitPropertyPage*) ppsp->lParam;
63 if (sheetpage != NULL)
64 delete sheetpage;
66 return 1;
69 // *********************** CGitPropertyPage *************************
71 CGitPropertyPage::CGitPropertyPage(const std::vector<stdstring> &newFilenames)
72 :filenames(newFilenames)
76 CGitPropertyPage::~CGitPropertyPage(void)
80 void CGitPropertyPage::SetHwnd(HWND newHwnd)
82 m_hwnd = newHwnd;
85 BOOL CGitPropertyPage::PageProc (HWND /*hwnd*/, UINT uMessage, WPARAM wParam, LPARAM lParam)
87 switch (uMessage)
89 case WM_INITDIALOG:
91 InitWorkfileView();
92 return TRUE;
94 case WM_NOTIFY:
96 LPNMHDR point = (LPNMHDR)lParam;
97 int code = point->code;
99 // Respond to notifications.
101 if (code == PSN_APPLY)
104 SetWindowLongPtr (m_hwnd, DWLP_MSGRESULT, FALSE);
105 return TRUE;
108 case WM_DESTROY:
109 return TRUE;
111 case WM_COMMAND:
112 switch (HIWORD(wParam))
114 case BN_CLICKED:
115 if (LOWORD(wParam) == IDC_SHOWLOG)
117 STARTUPINFO startup;
118 PROCESS_INFORMATION process;
119 memset(&startup, 0, sizeof(startup));
120 startup.cb = sizeof(startup);
121 memset(&process, 0, sizeof(process));
122 CRegStdString tortoiseProcPath(_T("Software\\TortoiseGit\\ProcPath"), _T("TortoiseProc.exe"), false, HKEY_LOCAL_MACHINE);
123 stdstring svnCmd = _T(" /command:");
124 svnCmd += _T("log /path:\"");
125 svnCmd += filenames.front().c_str();
126 svnCmd += _T("\"");
127 if (CreateProcess(((stdstring)tortoiseProcPath).c_str(), const_cast<TCHAR*>(svnCmd.c_str()), NULL, NULL, FALSE, 0, 0, 0, &startup, &process))
129 CloseHandle(process.hThread);
130 CloseHandle(process.hProcess);
133 if (LOWORD(wParam) == IDC_EDITPROPERTIES)
135 DWORD pathlength = GetTempPath(0, NULL);
136 TCHAR * path = new TCHAR[pathlength+1];
137 TCHAR * tempFile = new TCHAR[pathlength + 100];
138 GetTempPath (pathlength+1, path);
139 GetTempFileName (path, _T("svn"), 0, tempFile);
140 stdstring retFilePath = stdstring(tempFile);
142 HANDLE file = ::CreateFile (tempFile,
143 GENERIC_WRITE,
144 FILE_SHARE_READ,
146 CREATE_ALWAYS,
147 FILE_ATTRIBUTE_TEMPORARY,
150 delete [] path;
151 delete [] tempFile;
152 if (file != INVALID_HANDLE_VALUE)
154 DWORD written = 0;
155 for (std::vector<stdstring>::iterator I = filenames.begin(); I != filenames.end(); ++I)
157 ::WriteFile (file, I->c_str(), I->size()*sizeof(TCHAR), &written, 0);
158 ::WriteFile (file, _T("\n"), 2, &written, 0);
160 ::CloseHandle(file);
162 STARTUPINFO startup;
163 PROCESS_INFORMATION process;
164 memset(&startup, 0, sizeof(startup));
165 startup.cb = sizeof(startup);
166 memset(&process, 0, sizeof(process));
167 CRegStdString tortoiseProcPath(_T("Software\\TortoiseGit\\ProcPath"), _T("TortoiseProc.exe"), false, HKEY_LOCAL_MACHINE);
168 stdstring svnCmd = _T(" /command:");
169 svnCmd += _T("properties /pathfile:\"");
170 svnCmd += retFilePath.c_str();
171 svnCmd += _T("\"");
172 svnCmd += _T(" /deletepathfile");
173 if (CreateProcess(((stdstring)tortoiseProcPath).c_str(), const_cast<TCHAR*>(svnCmd.c_str()), NULL, NULL, FALSE, 0, 0, 0, &startup, &process))
175 CloseHandle(process.hThread);
176 CloseHandle(process.hProcess);
180 break;
181 } // switch (HIWORD(wParam))
182 } // switch (uMessage)
183 return FALSE;
185 void CGitPropertyPage::Time64ToTimeString(__time64_t time, TCHAR * buf, size_t buflen)
187 struct tm newtime;
188 SYSTEMTIME systime;
189 TCHAR timebuf[MAX_STRING_LENGTH];
190 TCHAR datebuf[MAX_STRING_LENGTH];
192 LCID locale = (WORD)CRegStdWORD(_T("Software\\TortoiseGit\\LanguageID"), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT));
193 locale = MAKELCID(locale, SORT_DEFAULT);
195 *buf = '\0';
196 if (time)
198 _localtime64_s(&newtime, &time);
200 systime.wDay = (WORD)newtime.tm_mday;
201 systime.wDayOfWeek = (WORD)newtime.tm_wday;
202 systime.wHour = (WORD)newtime.tm_hour;
203 systime.wMilliseconds = 0;
204 systime.wMinute = (WORD)newtime.tm_min;
205 systime.wMonth = (WORD)newtime.tm_mon+1;
206 systime.wSecond = (WORD)newtime.tm_sec;
207 systime.wYear = (WORD)newtime.tm_year+1900;
208 if (CRegStdWORD(_T("Software\\TortoiseGit\\LogDateFormat")) == 1)
209 GetDateFormat(locale, DATE_SHORTDATE, &systime, NULL, datebuf, MAX_STRING_LENGTH);
210 else
211 GetDateFormat(locale, DATE_LONGDATE, &systime, NULL, datebuf, MAX_STRING_LENGTH);
212 GetTimeFormat(locale, 0, &systime, NULL, timebuf, MAX_STRING_LENGTH);
213 *buf = '\0';
214 _tcsncat_s(buf, buflen, timebuf, MAX_STRING_LENGTH-1);
215 _tcsncat_s(buf, buflen, _T(", "), MAX_STRING_LENGTH-1);
216 _tcsncat_s(buf, buflen, datebuf, MAX_STRING_LENGTH-1);
220 void CGitPropertyPage::InitWorkfileView()
222 CString username;
223 CGit git;
224 if( filenames.size() ==0)
225 return;
227 CTGitPath path(filenames.front().c_str());
228 CString ProjectTopDir;
230 if(!path.HasAdminDir(&ProjectTopDir))
231 return;
233 git.SetCurrentDir(ProjectTopDir);
234 //can't git.exe when create process
235 git.Run(_T("git.exe config user.name"),&username,CP_ACP);
236 CString useremail;
237 git.Run(_T("git.exe config user.email"),&useremail,CP_ACP);
238 CString autocrlf;
239 git.Run(_T("git.exe config core.autocrlf"),&autocrlf,CP_ACP);
240 CString safecrlf;
241 git.Run(_T("git.exe config core.safecrlf"),&safecrlf,CP_ACP);
243 CString branch;
244 CString headhash;
245 CString remotebranch;
247 git.Run(_T("git.exe symbolic-ref HEAD"),&branch,CP_ACP);
248 CString cmd,log;
250 if(!branch.IsEmpty())
252 if( branch.Find(_T("refs/heads/"),0) >=0 )
254 CString remote;
255 branch=branch.Mid(11);
256 int start=0;
257 branch=branch.Tokenize(_T("\n"),start);
258 start=0;
259 branch=branch.Tokenize(_T("\r"),start);
260 cmd.Format(_T("git.exe config branch.%s.merge"),branch);
261 git.Run(cmd,&remotebranch,CP_ACP);
262 cmd.Format(_T("git.exe config branch.%s.remote"),branch);
263 git.Run(cmd,&remote,CP_ACP);
264 if((!remote.IsEmpty()) && (!remotebranch.IsEmpty()))
266 remotebranch=remotebranch.Mid(11);
267 remotebranch=remote+_T("/")+remotebranch;
273 BYTE_VECTOR logout;
276 cmd=_T("git.exe log -z --topo-order -n1 --parents --pretty=format:\"");
278 git.BuildOutputFormat(log,true);
280 cmd += log;
281 cmd += CString(_T("\" "));
283 git.Run(cmd,&logout);
284 GitRev rev;
285 rev.ParserFromLog(logout);
287 SetDlgItemText(m_hwnd,IDC_CONFIG_USERNAME,username);
288 SetDlgItemText(m_hwnd,IDC_CONFIG_USEREMAIL,useremail);
289 SetDlgItemText(m_hwnd,IDC_CONFIG_AUTOCRLF,autocrlf);
290 SetDlgItemText(m_hwnd,IDC_CONFIG_SAFECRLF,safecrlf);
292 SetDlgItemText(m_hwnd,IDC_SHELL_CURRENT_BRANCH,branch);
293 SetDlgItemText(m_hwnd,IDC_SHELL_REMOTE_BRANCH,remotebranch);
295 SetDlgItemText(m_hwnd,IDC_HEAD_HASH,rev.m_CommitHash.ToString());
296 SetDlgItemText(m_hwnd,IDC_HEAD_SUBJECT,rev.m_Subject);
297 SetDlgItemText(m_hwnd,IDC_HEAD_AUTHOR,rev.m_AuthorName);
298 SetDlgItemText(m_hwnd,IDC_HEAD_DATE,rev.m_AuthorDate.Format(_T("%Y-%m-%d %H:%M:%S")));
300 if (filenames.size() == 1)
302 CTGitPath path(filenames.front().c_str());
303 CTGitPath relatepath;
304 CString strpath=path.GetWinPathString();
305 CString ProjectTopDir;
307 if(!path.HasAdminDir(&ProjectTopDir))
308 return;
310 if(ProjectTopDir[ProjectTopDir.GetLength()-1] == _T('\\'))
312 relatepath.SetFromWin( strpath.Right(strpath.GetLength()-ProjectTopDir.GetLength()));
313 }else
315 relatepath.SetFromWin( strpath.Right(strpath.GetLength()-ProjectTopDir.GetLength()-1));
318 cmd+=_T("-- \"");
319 cmd+=relatepath.GetGitPathString();
320 cmd+=_T("\"");
322 if(! relatepath.GetGitPathString().IsEmpty())
324 logout.clear();
325 git.Run(cmd,&logout);
326 rev.Clear();
327 rev.ParserFromLog(logout);
330 SetDlgItemText(m_hwnd,IDC_LAST_HASH,rev.m_CommitHash.ToString());
331 SetDlgItemText(m_hwnd,IDC_LAST_SUBJECT,rev.m_Subject);
332 SetDlgItemText(m_hwnd,IDC_LAST_AUTHOR,rev.m_AuthorName);
333 SetDlgItemText(m_hwnd,IDC_LAST_DATE,rev.m_AuthorDate.Format(_T("%Y-%m-%d %H:%M:%S")));
335 }else
343 // CShellExt member functions (needed for IShellPropSheetExt)
344 STDMETHODIMP CShellExt::AddPages (LPFNADDPROPSHEETPAGE lpfnAddPage,
345 LPARAM lParam)
348 CString ProjectTopDir;
350 for (std::vector<stdstring>::iterator I = files_.begin(); I != files_.end(); ++I)
353 GitStatus svn = GitStatus();
354 if (svn.GetStatus(CTGitPath(I->c_str())) == (-2))
355 return NOERROR; // file/directory not under version control
357 if (svn.status->entry == NULL)
358 return NOERROR;
360 if( CTGitPath(I->c_str()).HasAdminDir(&ProjectTopDir))
361 break;
362 else
363 return NOERROR;
366 if (files_.size() == 0)
367 return NOERROR;
369 LoadLangDll();
370 PROPSHEETPAGE psp;
371 SecureZeroMemory(&psp, sizeof(PROPSHEETPAGE));
372 HPROPSHEETPAGE hPage;
373 CGitPropertyPage *sheetpage = new CGitPropertyPage(files_);
375 psp.dwSize = sizeof (psp);
376 psp.dwFlags = PSP_USEREFPARENT | PSP_USETITLE | PSP_USEICONID | PSP_USECALLBACK;
377 psp.hInstance = g_hResInst;
378 psp.pszTemplate = MAKEINTRESOURCE(IDD_PROPPAGE);
379 psp.pszIcon = MAKEINTRESOURCE(IDI_APPSMALL);
380 psp.pszTitle = _T("Git");
381 psp.pfnDlgProc = (DLGPROC) PageProc;
382 psp.lParam = (LPARAM) sheetpage;
383 psp.pfnCallback = PropPageCallbackProc;
384 psp.pcRefParent = &g_cRefThisDll;
386 hPage = CreatePropertySheetPage (&psp);
388 if (hPage != NULL)
390 if (!lpfnAddPage (hPage, lParam))
392 delete sheetpage;
393 DestroyPropertySheetPage (hPage);
397 return NOERROR;
402 STDMETHODIMP CShellExt::ReplacePage (UINT /*uPageID*/, LPFNADDPROPSHEETPAGE /*lpfnReplaceWith*/, LPARAM /*lParam*/)
404 return E_FAIL;