1 // TortoiseGit - a Windows shell extension for easy version control
\r
3 // Copyright (C) 2003-2008 - TortoiseGit
\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
21 #include "ShellExt.h"
\r
22 #include "svnpropertypage.h"
\r
23 #include "UnicodeUtils.h"
\r
24 #include "PathUtils.h"
\r
25 #include "GitStatus.h"
\r
27 #define MAX_STRING_LENGTH 4096 //should be big enough
\r
29 // Nonmember function prototypes
\r
30 BOOL CALLBACK PageProc (HWND, UINT, WPARAM, LPARAM);
\r
31 UINT CALLBACK PropPageCallbackProc ( HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp );
\r
33 /////////////////////////////////////////////////////////////////////////////
\r
34 // Dialog procedures and other callback functions
\r
36 BOOL CALLBACK PageProc (HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
\r
38 CGitPropertyPage * sheetpage;
\r
40 if (uMessage == WM_INITDIALOG)
\r
42 sheetpage = (CGitPropertyPage*) ((LPPROPSHEETPAGE) lParam)->lParam;
\r
43 SetWindowLongPtr (hwnd, GWLP_USERDATA, (LONG_PTR) sheetpage);
\r
44 sheetpage->SetHwnd(hwnd);
\r
48 sheetpage = (CGitPropertyPage*) GetWindowLongPtr (hwnd, GWLP_USERDATA);
\r
51 if (sheetpage != 0L)
\r
52 return sheetpage->PageProc(hwnd, uMessage, wParam, lParam);
\r
57 UINT CALLBACK PropPageCallbackProc ( HWND /*hwnd*/, UINT uMsg, LPPROPSHEETPAGE ppsp )
\r
59 // Delete the page before closing.
\r
60 if (PSPCB_RELEASE == uMsg)
\r
62 CGitPropertyPage* sheetpage = (CGitPropertyPage*) ppsp->lParam;
\r
63 if (sheetpage != NULL)
\r
69 // *********************** CGitPropertyPage *************************
\r
71 CGitPropertyPage::CGitPropertyPage(const std::vector<stdstring> &newFilenames)
\r
72 :filenames(newFilenames)
\r
76 CGitPropertyPage::~CGitPropertyPage(void)
\r
80 void CGitPropertyPage::SetHwnd(HWND newHwnd)
\r
85 BOOL CGitPropertyPage::PageProc (HWND /*hwnd*/, UINT uMessage, WPARAM wParam, LPARAM lParam)
\r
96 LPNMHDR point = (LPNMHDR)lParam;
\r
97 int code = point->code;
\r
99 // Respond to notifications.
\r
101 if (code == PSN_APPLY)
\r
104 SetWindowLongPtr (m_hwnd, DWLP_MSGRESULT, FALSE);
\r
112 switch (HIWORD(wParam))
\r
115 if (LOWORD(wParam) == IDC_SHOWLOG)
\r
117 STARTUPINFO startup;
\r
118 PROCESS_INFORMATION process;
\r
119 memset(&startup, 0, sizeof(startup));
\r
120 startup.cb = sizeof(startup);
\r
121 memset(&process, 0, sizeof(process));
\r
122 CRegStdString tortoiseProcPath(_T("Software\\TortoiseGit\\ProcPath"), _T("TortoiseProc.exe"), false, HKEY_LOCAL_MACHINE);
\r
123 stdstring svnCmd = _T(" /command:");
\r
124 svnCmd += _T("log /path:\"");
\r
125 svnCmd += filenames.front().c_str();
\r
126 svnCmd += _T("\"");
\r
127 if (CreateProcess(((stdstring)tortoiseProcPath).c_str(), const_cast<TCHAR*>(svnCmd.c_str()), NULL, NULL, FALSE, 0, 0, 0, &startup, &process))
\r
129 CloseHandle(process.hThread);
\r
130 CloseHandle(process.hProcess);
\r
133 if (LOWORD(wParam) == IDC_EDITPROPERTIES)
\r
135 DWORD pathlength = GetTempPath(0, NULL);
\r
136 TCHAR * path = new TCHAR[pathlength+1];
\r
137 TCHAR * tempFile = new TCHAR[pathlength + 100];
\r
138 GetTempPath (pathlength+1, path);
\r
139 GetTempFileName (path, _T("svn"), 0, tempFile);
\r
140 stdstring retFilePath = stdstring(tempFile);
\r
142 HANDLE file = ::CreateFile (tempFile,
\r
147 FILE_ATTRIBUTE_TEMPORARY,
\r
151 delete [] tempFile;
\r
152 if (file != INVALID_HANDLE_VALUE)
\r
155 for (std::vector<stdstring>::iterator I = filenames.begin(); I != filenames.end(); ++I)
\r
157 ::WriteFile (file, I->c_str(), I->size()*sizeof(TCHAR), &written, 0);
\r
158 ::WriteFile (file, _T("\n"), 2, &written, 0);
\r
160 ::CloseHandle(file);
\r
162 STARTUPINFO startup;
\r
163 PROCESS_INFORMATION process;
\r
164 memset(&startup, 0, sizeof(startup));
\r
165 startup.cb = sizeof(startup);
\r
166 memset(&process, 0, sizeof(process));
\r
167 CRegStdString tortoiseProcPath(_T("Software\\TortoiseGit\\ProcPath"), _T("TortoiseProc.exe"), false, HKEY_LOCAL_MACHINE);
\r
168 stdstring svnCmd = _T(" /command:");
\r
169 svnCmd += _T("properties /pathfile:\"");
\r
170 svnCmd += retFilePath.c_str();
\r
171 svnCmd += _T("\"");
\r
172 svnCmd += _T(" /deletepathfile");
\r
173 if (CreateProcess(((stdstring)tortoiseProcPath).c_str(), const_cast<TCHAR*>(svnCmd.c_str()), NULL, NULL, FALSE, 0, 0, 0, &startup, &process))
\r
175 CloseHandle(process.hThread);
\r
176 CloseHandle(process.hProcess);
\r
181 } // switch (HIWORD(wParam))
\r
182 } // switch (uMessage)
\r
185 void CGitPropertyPage::Time64ToTimeString(__time64_t time, TCHAR * buf, size_t buflen)
\r
188 SYSTEMTIME systime;
\r
189 TCHAR timebuf[MAX_STRING_LENGTH];
\r
190 TCHAR datebuf[MAX_STRING_LENGTH];
\r
192 LCID locale = (WORD)CRegStdWORD(_T("Software\\TortoiseGit\\LanguageID"), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT));
\r
193 locale = MAKELCID(locale, SORT_DEFAULT);
\r
198 _localtime64_s(&newtime, &time);
\r
200 systime.wDay = (WORD)newtime.tm_mday;
\r
201 systime.wDayOfWeek = (WORD)newtime.tm_wday;
\r
202 systime.wHour = (WORD)newtime.tm_hour;
\r
203 systime.wMilliseconds = 0;
\r
204 systime.wMinute = (WORD)newtime.tm_min;
\r
205 systime.wMonth = (WORD)newtime.tm_mon+1;
\r
206 systime.wSecond = (WORD)newtime.tm_sec;
\r
207 systime.wYear = (WORD)newtime.tm_year+1900;
\r
208 if (CRegStdWORD(_T("Software\\TortoiseGit\\LogDateFormat")) == 1)
\r
209 GetDateFormat(locale, DATE_SHORTDATE, &systime, NULL, datebuf, MAX_STRING_LENGTH);
\r
211 GetDateFormat(locale, DATE_LONGDATE, &systime, NULL, datebuf, MAX_STRING_LENGTH);
\r
212 GetTimeFormat(locale, 0, &systime, NULL, timebuf, MAX_STRING_LENGTH);
\r
214 _tcsncat_s(buf, buflen, timebuf, MAX_STRING_LENGTH-1);
\r
215 _tcsncat_s(buf, buflen, _T(", "), MAX_STRING_LENGTH-1);
\r
216 _tcsncat_s(buf, buflen, datebuf, MAX_STRING_LENGTH-1);
\r
220 void CGitPropertyPage::InitWorkfileView()
\r
222 GitStatus svn = GitStatus();
\r
223 TCHAR tbuf[MAX_STRING_LENGTH];
\r
224 if (filenames.size() == 1)
\r
226 if (svn.GetStatus(CTGitPath(filenames.front().c_str()))>(-2))
\r
228 TCHAR buf[MAX_STRING_LENGTH];
\r
230 if (svn.status->entry != NULL)
\r
233 if (svn.status->text_status == svn_wc_status_added)
\r
235 // disable the "show log" button for added files
\r
236 HWND showloghwnd = GetDlgItem(m_hwnd, IDC_SHOWLOG);
\r
237 if (GetFocus() == showloghwnd)
\r
238 ::SendMessage(m_hwnd, WM_NEXTDLGCTL, 0, FALSE);
\r
239 ::EnableWindow(showloghwnd, FALSE);
\r
243 _stprintf_s(buf, MAX_STRING_LENGTH, _T("%d"), svn.status->entry->revision);
\r
244 SetDlgItemText(m_hwnd, IDC_REVISION, buf);
\r
246 if (svn.status->entry->url)
\r
248 size_t len = strlen(svn.status->entry->url);
\r
249 char * unescapedurl = new char[len+1];
\r
250 strcpy_s(unescapedurl, len+1, svn.status->entry->url);
\r
251 CPathUtils::Unescape(unescapedurl);
\r
252 SetDlgItemText(m_hwnd, IDC_REPOURL, UTF8ToWide(unescapedurl).c_str());
\r
253 if (strcmp(unescapedurl, svn.status->entry->url))
\r
255 ShowWindow(GetDlgItem(m_hwnd, IDC_ESCAPEDURLLABEL), SW_SHOW);
\r
256 ShowWindow(GetDlgItem(m_hwnd, IDC_REPOURLUNESCAPED), SW_SHOW);
\r
257 SetDlgItemText(m_hwnd, IDC_REPOURLUNESCAPED, UTF8ToWide(svn.status->entry->url).c_str());
\r
261 ShowWindow(GetDlgItem(m_hwnd, IDC_ESCAPEDURLLABEL), SW_HIDE);
\r
262 ShowWindow(GetDlgItem(m_hwnd, IDC_REPOURLUNESCAPED), SW_HIDE);
\r
264 delete [] unescapedurl;
\r
268 ShowWindow(GetDlgItem(m_hwnd, IDC_ESCAPEDURLLABEL), SW_HIDE);
\r
269 ShowWindow(GetDlgItem(m_hwnd, IDC_REPOURLUNESCAPED), SW_HIDE);
\r
271 if (svn.status->text_status != svn_wc_status_added)
\r
273 _stprintf_s(buf, MAX_STRING_LENGTH, _T("%d"), svn.status->entry->cmt_rev);
\r
274 SetDlgItemText(m_hwnd, IDC_CREVISION, buf);
\r
275 time = (__time64_t)svn.status->entry->cmt_date/1000000L;
\r
276 Time64ToTimeString(time, buf, MAX_STRING_LENGTH);
\r
277 SetDlgItemText(m_hwnd, IDC_CDATE, buf);
\r
279 if (svn.status->entry->cmt_author)
\r
280 SetDlgItemText(m_hwnd, IDC_AUTHOR, UTF8ToWide(svn.status->entry->cmt_author).c_str());
\r
281 GitStatus::GetStatusString(g_hResInst, svn.status->text_status, buf, sizeof(buf)/sizeof(TCHAR), (WORD)CRegStdWORD(_T("Software\\TortoiseGit\\LanguageID"), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)));
\r
282 SetDlgItemText(m_hwnd, IDC_TEXTSTATUS, buf);
\r
283 GitStatus::GetStatusString(g_hResInst, svn.status->prop_status, buf, sizeof(buf)/sizeof(TCHAR), (WORD)CRegStdWORD(_T("Software\\TortoiseGit\\LanguageID"), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)));
\r
284 SetDlgItemText(m_hwnd, IDC_PROPSTATUS, buf);
\r
285 time = (__time64_t)svn.status->entry->text_time/1000000L;
\r
286 Time64ToTimeString(time, buf, MAX_STRING_LENGTH);
\r
287 SetDlgItemText(m_hwnd, IDC_TEXTDATE, buf);
\r
288 time = (__time64_t)svn.status->entry->prop_time/1000000L;
\r
289 Time64ToTimeString(time, buf, MAX_STRING_LENGTH);
\r
290 SetDlgItemText(m_hwnd, IDC_PROPDATE, buf);
\r
292 if (svn.status->entry->lock_owner)
\r
293 SetDlgItemText(m_hwnd, IDC_LOCKOWNER, UTF8ToWide(svn.status->entry->lock_owner).c_str());
\r
294 time = (__time64_t)svn.status->entry->lock_creation_date/1000000L;
\r
295 Time64ToTimeString(time, buf, MAX_STRING_LENGTH);
\r
296 SetDlgItemText(m_hwnd, IDC_LOCKDATE, buf);
\r
298 if (svn.status->entry->uuid)
\r
299 SetDlgItemText(m_hwnd, IDC_REPOUUID, UTF8ToWide(svn.status->entry->uuid).c_str());
\r
300 if (svn.status->entry->changelist)
\r
301 SetDlgItemText(m_hwnd, IDC_CHANGELIST, UTF8ToWide(svn.status->entry->changelist).c_str());
\r
302 GitStatus::GetDepthString(g_hResInst, svn.status->entry->depth, buf, sizeof(buf)/sizeof(TCHAR), (WORD)CRegStdWORD(_T("Software\\TortoiseGit\\LanguageID"), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)));
\r
303 SetDlgItemText(m_hwnd, IDC_DEPTHEDIT, buf);
\r
305 if (svn.status->entry->checksum)
\r
306 SetDlgItemText(m_hwnd, IDC_CHECKSUM, UTF8ToWide(svn.status->entry->checksum).c_str());
\r
308 if (svn.status->locked)
\r
309 MAKESTRING(IDS_YES);
\r
311 MAKESTRING(IDS_NO);
\r
312 SetDlgItemText(m_hwnd, IDC_LOCKED, stringtablebuffer);
\r
314 if (svn.status->copied)
\r
315 MAKESTRING(IDS_YES);
\r
317 MAKESTRING(IDS_NO);
\r
318 SetDlgItemText(m_hwnd, IDC_COPIED, stringtablebuffer);
\r
320 if (svn.status->switched)
\r
321 MAKESTRING(IDS_YES);
\r
323 MAKESTRING(IDS_NO);
\r
324 SetDlgItemText(m_hwnd, IDC_SWITCHED, stringtablebuffer);
\r
325 } // if (svn.status->entry != NULL)
\r
326 } // if (svn.GetStatus(CTGitPath(filenames.front().c_str()))>(-2))
\r
327 } // if (filenames.size() == 1)
\r
328 else if (filenames.size() != 0)
\r
330 //deactivate the show log button
\r
331 HWND logwnd = GetDlgItem(m_hwnd, IDC_SHOWLOG);
\r
332 if (GetFocus() == logwnd)
\r
333 ::SendMessage(m_hwnd, WM_NEXTDLGCTL, 0, FALSE);
\r
334 ::EnableWindow(logwnd, FALSE);
\r
335 //get the handle of the list view
\r
336 if (svn.GetStatus(CTGitPath(filenames.front().c_str()))>(-2))
\r
338 if (svn.status->entry != NULL)
\r
341 if (svn.status->entry->url)
\r
343 CPathUtils::Unescape((char*)svn.status->entry->url);
\r
344 _tcsncpy_s(tbuf, MAX_STRING_LENGTH, UTF8ToWide(svn.status->entry->url).c_str(), 4095);
\r
345 TCHAR * ptr = _tcsrchr(tbuf, '/');
\r
350 SetDlgItemText(m_hwnd, IDC_REPOURL, tbuf);
\r
352 SetDlgItemText(m_hwnd, IDC_LOCKED, _T(""));
\r
353 SetDlgItemText(m_hwnd, IDC_COPIED, _T(""));
\r
354 SetDlgItemText(m_hwnd, IDC_SWITCHED, _T(""));
\r
356 SetDlgItemText(m_hwnd, IDC_DEPTHEDIT, _T(""));
\r
357 SetDlgItemText(m_hwnd, IDC_CHECKSUM, _T(""));
\r
358 SetDlgItemText(m_hwnd, IDC_REPOUUID, _T(""));
\r
360 ShowWindow(GetDlgItem(m_hwnd, IDC_ESCAPEDURLLABEL), SW_HIDE);
\r
361 ShowWindow(GetDlgItem(m_hwnd, IDC_REPOURLUNESCAPED), SW_HIDE);
\r