1 // TortoiseGit - 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.
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
);
48 sheetpage
= (CGitPropertyPage
*) GetWindowLongPtr (hwnd
, GWLP_USERDATA
);
52 return sheetpage
->PageProc(hwnd
, uMessage
, wParam
, lParam
);
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
)
69 // *********************** CGitPropertyPage *************************
71 CGitPropertyPage::CGitPropertyPage(const std::vector
<stdstring
> &newFilenames
)
72 :filenames(newFilenames
)
76 CGitPropertyPage::~CGitPropertyPage(void)
80 void CGitPropertyPage::SetHwnd(HWND newHwnd
)
85 BOOL
CGitPropertyPage::PageProc (HWND
/*hwnd*/, UINT uMessage
, WPARAM wParam
, LPARAM lParam
)
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
);
112 switch (HIWORD(wParam
))
115 if (LOWORD(wParam
) == IDC_SHOWLOG
)
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();
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
,
147 FILE_ATTRIBUTE_TEMPORARY
,
152 if (file
!= INVALID_HANDLE_VALUE
)
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);
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();
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
);
181 } // switch (HIWORD(wParam))
182 } // switch (uMessage)
185 void CGitPropertyPage::Time64ToTimeString(__time64_t time
, TCHAR
* buf
, size_t buflen
)
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
);
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
);
211 GetDateFormat(locale
, DATE_LONGDATE
, &systime
, NULL
, datebuf
, MAX_STRING_LENGTH
);
212 GetTimeFormat(locale
, 0, &systime
, NULL
, timebuf
, MAX_STRING_LENGTH
);
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 GitStatus svn
= GitStatus();
223 TCHAR tbuf
[MAX_STRING_LENGTH
];
224 if (filenames
.size() == 1)
226 if (svn
.GetStatus(CTGitPath(filenames
.front().c_str()))>(-2))
228 TCHAR buf
[MAX_STRING_LENGTH
];
230 if (svn
.status
->entry
!= NULL
)
233 if (svn
.status
->text_status
== svn_wc_status_added
)
235 // disable the "show log" button for added files
236 HWND showloghwnd
= GetDlgItem(m_hwnd
, IDC_SHOWLOG
);
237 if (GetFocus() == showloghwnd
)
238 ::SendMessage(m_hwnd
, WM_NEXTDLGCTL
, 0, FALSE
);
239 ::EnableWindow(showloghwnd
, FALSE
);
243 _stprintf_s(buf
, MAX_STRING_LENGTH
, _T("%d"), svn
.status
->entry
->revision
);
244 SetDlgItemText(m_hwnd
, IDC_REVISION
, buf
);
246 if (svn
.status
->entry
->url
)
248 size_t len
= strlen(svn
.status
->entry
->url
);
249 char * unescapedurl
= new char[len
+1];
250 strcpy_s(unescapedurl
, len
+1, svn
.status
->entry
->url
);
251 CPathUtils::Unescape(unescapedurl
);
252 SetDlgItemText(m_hwnd
, IDC_REPOURL
, UTF8ToWide(unescapedurl
).c_str());
253 if (strcmp(unescapedurl
, svn
.status
->entry
->url
))
255 ShowWindow(GetDlgItem(m_hwnd
, IDC_ESCAPEDURLLABEL
), SW_SHOW
);
256 ShowWindow(GetDlgItem(m_hwnd
, IDC_REPOURLUNESCAPED
), SW_SHOW
);
257 SetDlgItemText(m_hwnd
, IDC_REPOURLUNESCAPED
, UTF8ToWide(svn
.status
->entry
->url
).c_str());
261 ShowWindow(GetDlgItem(m_hwnd
, IDC_ESCAPEDURLLABEL
), SW_HIDE
);
262 ShowWindow(GetDlgItem(m_hwnd
, IDC_REPOURLUNESCAPED
), SW_HIDE
);
264 delete [] unescapedurl
;
268 ShowWindow(GetDlgItem(m_hwnd
, IDC_ESCAPEDURLLABEL
), SW_HIDE
);
269 ShowWindow(GetDlgItem(m_hwnd
, IDC_REPOURLUNESCAPED
), SW_HIDE
);
271 if (svn
.status
->text_status
!= svn_wc_status_added
)
273 _stprintf_s(buf
, MAX_STRING_LENGTH
, _T("%d"), svn
.status
->entry
->cmt_rev
);
274 SetDlgItemText(m_hwnd
, IDC_CREVISION
, buf
);
275 time
= (__time64_t
)svn
.status
->entry
->cmt_date
/1000000L;
276 Time64ToTimeString(time
, buf
, MAX_STRING_LENGTH
);
277 SetDlgItemText(m_hwnd
, IDC_CDATE
, buf
);
279 if (svn
.status
->entry
->cmt_author
)
280 SetDlgItemText(m_hwnd
, IDC_AUTHOR
, UTF8ToWide(svn
.status
->entry
->cmt_author
).c_str());
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
)));
282 SetDlgItemText(m_hwnd
, IDC_TEXTSTATUS
, buf
);
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
)));
284 SetDlgItemText(m_hwnd
, IDC_PROPSTATUS
, buf
);
285 time
= (__time64_t
)svn
.status
->entry
->text_time
/1000000L;
286 Time64ToTimeString(time
, buf
, MAX_STRING_LENGTH
);
287 SetDlgItemText(m_hwnd
, IDC_TEXTDATE
, buf
);
288 time
= (__time64_t
)svn
.status
->entry
->prop_time
/1000000L;
289 Time64ToTimeString(time
, buf
, MAX_STRING_LENGTH
);
290 SetDlgItemText(m_hwnd
, IDC_PROPDATE
, buf
);
292 if (svn
.status
->entry
->lock_owner
)
293 SetDlgItemText(m_hwnd
, IDC_LOCKOWNER
, UTF8ToWide(svn
.status
->entry
->lock_owner
).c_str());
294 time
= (__time64_t
)svn
.status
->entry
->lock_creation_date
/1000000L;
295 Time64ToTimeString(time
, buf
, MAX_STRING_LENGTH
);
296 SetDlgItemText(m_hwnd
, IDC_LOCKDATE
, buf
);
298 if (svn
.status
->entry
->uuid
)
299 SetDlgItemText(m_hwnd
, IDC_REPOUUID
, UTF8ToWide(svn
.status
->entry
->uuid
).c_str());
300 if (svn
.status
->entry
->changelist
)
301 SetDlgItemText(m_hwnd
, IDC_CHANGELIST
, UTF8ToWide(svn
.status
->entry
->changelist
).c_str());
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
)));
303 SetDlgItemText(m_hwnd
, IDC_DEPTHEDIT
, buf
);
305 if (svn
.status
->entry
->checksum
)
306 SetDlgItemText(m_hwnd
, IDC_CHECKSUM
, UTF8ToWide(svn
.status
->entry
->checksum
).c_str());
308 if (svn
.status
->locked
)
312 SetDlgItemText(m_hwnd
, IDC_LOCKED
, stringtablebuffer
);
314 if (svn
.status
->copied
)
318 SetDlgItemText(m_hwnd
, IDC_COPIED
, stringtablebuffer
);
320 if (svn
.status
->switched
)
324 SetDlgItemText(m_hwnd
, IDC_SWITCHED
, stringtablebuffer
);
325 } // if (svn.status->entry != NULL)
326 } // if (svn.GetStatus(CTGitPath(filenames.front().c_str()))>(-2))
327 } // if (filenames.size() == 1)
328 else if (filenames
.size() != 0)
330 //deactivate the show log button
331 HWND logwnd
= GetDlgItem(m_hwnd
, IDC_SHOWLOG
);
332 if (GetFocus() == logwnd
)
333 ::SendMessage(m_hwnd
, WM_NEXTDLGCTL
, 0, FALSE
);
334 ::EnableWindow(logwnd
, FALSE
);
335 //get the handle of the list view
336 if (svn
.GetStatus(CTGitPath(filenames
.front().c_str()))>(-2))
338 if (svn
.status
->entry
!= NULL
)
341 if (svn
.status
->entry
->url
)
343 CPathUtils::Unescape((char*)svn
.status
->entry
->url
);
344 _tcsncpy_s(tbuf
, MAX_STRING_LENGTH
, UTF8ToWide(svn
.status
->entry
->url
).c_str(), 4095);
345 TCHAR
* ptr
= _tcsrchr(tbuf
, '/');
350 SetDlgItemText(m_hwnd
, IDC_REPOURL
, tbuf
);
352 SetDlgItemText(m_hwnd
, IDC_LOCKED
, _T(""));
353 SetDlgItemText(m_hwnd
, IDC_COPIED
, _T(""));
354 SetDlgItemText(m_hwnd
, IDC_SWITCHED
, _T(""));
356 SetDlgItemText(m_hwnd
, IDC_DEPTHEDIT
, _T(""));
357 SetDlgItemText(m_hwnd
, IDC_CHECKSUM
, _T(""));
358 SetDlgItemText(m_hwnd
, IDC_REPOUUID
, _T(""));
360 ShowWindow(GetDlgItem(m_hwnd
, IDC_ESCAPEDURLLABEL
), SW_HIDE
);
361 ShowWindow(GetDlgItem(m_hwnd
, IDC_REPOURLUNESCAPED
), SW_HIDE
);