OSDN Git Service

Fix when setting ssh client is null. GIT_SSH environment variable is not clear
[tortoisegit/TortoiseGitJp.git] / src / TortoiseShell / ColumnProvider.cpp
1 // TortoiseSVN - a Windows shell extension for easy version control\r
2 \r
3 // Copyright (C) 2003-2008 - TortoiseSVN\r
4 \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
9 \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
14 \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
18 //\r
19 #include "stdafx.h"\r
20 #include "ShellExt.h"\r
21 #include "guids.h"\r
22 #include "PreserveChdir.h"\r
23 //#include "SVNProperties.h"\r
24 #include "UnicodeUtils.h"\r
25 #include "GitStatus.h"\r
26 #include "PathUtils.h"\r
27 //#include "..\TSVNCache\CacheInterface.h"\r
28 \r
29 \r
30 const static int ColumnFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT;\r
31 \r
32 // Defines that revision numbers occupy at most MAX_REV_STRING_LEN characters.\r
33 // There are Perforce repositories out there that have several 100,000 revs.\r
34 // So, don't be too restrictive by limiting this to 6 digits + 1 separator, \r
35 // for instance. \r
36 //\r
37 // Because shorter strings will be extended to have exactly MAX_REV_STRING_LEN \r
38 // characters, large numbers will produce large strings. These, in turn, will\r
39 // affect column auto sizing. This setting is a reasonable compromise.\r
40 //\r
41 // Max rev correctly sorted: 99,999,999 for MAX_REV_STRING_LEN == 10\r
42 \r
43 #define MAX_REV_STRING_LEN 10\r
44 \r
45 // IColumnProvider members\r
46 STDMETHODIMP CShellExt::GetColumnInfo(DWORD dwIndex, SHCOLUMNINFO *psci)\r
47 {\r
48         PreserveChdir preserveChdir;\r
49         if (dwIndex > 8)\r
50                 return S_FALSE;\r
51 \r
52         ShellCache::CacheType cachetype = g_ShellCache.GetCacheType();\r
53         LoadLangDll();\r
54         wide_string ws;\r
55         switch (dwIndex)\r
56         {\r
57                 case 0: // SVN Status\r
58                         if (cachetype == ShellCache::none)\r
59                                 return S_FALSE;\r
60                         psci->scid.fmtid = CLSID_Tortoisegit_UPTODATE;\r
61                         psci->scid.pid = dwIndex;\r
62                         psci->vt = VT_BSTR;\r
63                         psci->fmt = LVCFMT_LEFT;\r
64                         psci->cChars = 15;\r
65                         psci->csFlags = ColumnFlags;\r
66 \r
67                         MAKESTRING(IDS_COLTITLESTATUS);\r
68                         lstrcpynW(psci->wszTitle, stringtablebuffer, MAX_COLUMN_NAME_LEN);\r
69                         MAKESTRING(IDS_COLDESCSTATUS);\r
70                         lstrcpynW(psci->wszDescription, stringtablebuffer, MAX_COLUMN_DESC_LEN);\r
71                         break;\r
72                 case 1: // SVN Revision\r
73                         if (cachetype == ShellCache::none)\r
74                                 return S_FALSE;\r
75                         psci->scid.fmtid = CLSID_Tortoisegit_UPTODATE;\r
76                         psci->scid.pid = dwIndex;\r
77                         psci->vt = VT_I4;\r
78                         psci->fmt = LVCFMT_RIGHT;\r
79                         psci->cChars = 15;\r
80                         psci->csFlags = SHCOLSTATE_TYPE_INT | SHCOLSTATE_ONBYDEFAULT;\r
81 \r
82                         MAKESTRING(IDS_COLTITLEREV);\r
83                         lstrcpynW(psci->wszTitle, stringtablebuffer, MAX_COLUMN_NAME_LEN);\r
84                         MAKESTRING(IDS_COLDESCREV);\r
85                         lstrcpynW(psci->wszDescription, stringtablebuffer, MAX_COLUMN_DESC_LEN);\r
86                         break;\r
87                 case 2: // SVN Url\r
88                         if (cachetype == ShellCache::none)\r
89                                 return S_FALSE;\r
90                         psci->scid.fmtid = CLSID_Tortoisegit_UPTODATE;\r
91                         psci->scid.pid = dwIndex;\r
92                         psci->vt = VT_BSTR;\r
93                         psci->fmt = LVCFMT_LEFT;\r
94                         psci->cChars = 30;\r
95                         psci->csFlags = ColumnFlags;\r
96 \r
97                         MAKESTRING(IDS_COLTITLEURL);\r
98                         lstrcpynW(psci->wszTitle, stringtablebuffer, MAX_COLUMN_NAME_LEN);\r
99                         MAKESTRING(IDS_COLDESCURL);\r
100                         lstrcpynW(psci->wszDescription, stringtablebuffer, MAX_COLUMN_DESC_LEN);\r
101                         break;\r
102                 case 3: // SVN Short Url\r
103                         if (cachetype == ShellCache::none)\r
104                                 return S_FALSE;\r
105                         psci->scid.fmtid = CLSID_Tortoisegit_UPTODATE;\r
106                         psci->scid.pid = dwIndex;\r
107                         psci->vt = VT_BSTR;\r
108                         psci->fmt = LVCFMT_LEFT;\r
109                         psci->cChars = 30;\r
110                         psci->csFlags = ColumnFlags;\r
111 \r
112                         MAKESTRING(IDS_COLTITLESHORTURL);\r
113                         lstrcpynW(psci->wszTitle, stringtablebuffer, MAX_COLUMN_NAME_LEN);\r
114                         MAKESTRING(IDS_COLDESCSHORTURL);\r
115                         lstrcpynW(psci->wszDescription, stringtablebuffer, MAX_COLUMN_DESC_LEN);\r
116                         break;\r
117                 case 4: // Author\r
118                         if (cachetype == ShellCache::none)\r
119                                 return S_FALSE;\r
120                         psci->scid.fmtid = FMTID_SummaryInformation;    // predefined FMTID\r
121                         psci->scid.pid   = PIDSI_AUTHOR;                                // Predefined - author\r
122                         psci->vt         = VT_LPSTR;                                    // We'll return the data as a string\r
123                         psci->fmt        = LVCFMT_LEFT;                                 // Text will be left-aligned in the column\r
124                         psci->csFlags    = SHCOLSTATE_TYPE_STR;                 // Data should be sorted as strings\r
125                         psci->cChars     = 32;                                                  // Default col width in chars\r
126                         break;\r
127                 case 5: // SVN mime-type\r
128                         if (cachetype == ShellCache::none)\r
129                                 return S_FALSE;\r
130                         psci->scid.fmtid = CLSID_Tortoisegit_UPTODATE;\r
131                         psci->scid.pid = dwIndex;\r
132                         psci->vt = VT_BSTR;\r
133                         psci->fmt = LVCFMT_LEFT;\r
134                         psci->cChars = 30;\r
135                         psci->csFlags = ColumnFlags;\r
136 \r
137                         MAKESTRING(IDS_COLTITLEMIMETYPE);\r
138                         lstrcpynW(psci->wszTitle, stringtablebuffer, MAX_COLUMN_NAME_LEN);\r
139                         MAKESTRING(IDS_COLDESCMIMETYPE);\r
140                         lstrcpynW(psci->wszDescription, stringtablebuffer, MAX_COLUMN_DESC_LEN);\r
141                         break;\r
142                 case 6: // SVN Lock Owner\r
143                         if (cachetype == ShellCache::none)\r
144                                 return S_FALSE;\r
145                         psci->scid.fmtid = CLSID_Tortoisegit_UPTODATE;\r
146                         psci->scid.pid = dwIndex;\r
147                         psci->vt = VT_BSTR;\r
148                         psci->fmt = LVCFMT_LEFT;\r
149                         psci->cChars = 30;\r
150                         psci->csFlags = ColumnFlags;\r
151 \r
152                         MAKESTRING(IDS_COLTITLEOWNER);\r
153                         lstrcpynW(psci->wszTitle, stringtablebuffer, MAX_COLUMN_NAME_LEN);\r
154                         MAKESTRING(IDS_COLDESCOWNER);\r
155                         lstrcpynW(psci->wszDescription, stringtablebuffer, MAX_COLUMN_DESC_LEN);\r
156                         break;\r
157                 case 7: // SVN eol-style\r
158                         if (cachetype == ShellCache::none)\r
159                                 return S_FALSE;\r
160                         psci->scid.fmtid = CLSID_Tortoisegit_UPTODATE;\r
161                         psci->scid.pid = dwIndex;\r
162                         psci->vt = VT_BSTR;\r
163                         psci->fmt = LVCFMT_LEFT;\r
164                         psci->cChars = 30;\r
165                         psci->csFlags = ColumnFlags;\r
166 \r
167                         MAKESTRING(IDS_COLTITLEEOLSTYLE);\r
168                         lstrcpynW(psci->wszTitle, stringtablebuffer, MAX_COLUMN_NAME_LEN);\r
169                         MAKESTRING(IDS_COLDESCEOLSTYLE);\r
170                         lstrcpynW(psci->wszDescription, stringtablebuffer, MAX_COLUMN_DESC_LEN);\r
171                         break;\r
172                 case 8: // SVN Author\r
173                         if (cachetype == ShellCache::none)\r
174                                 return S_FALSE;\r
175                         psci->scid.fmtid = CLSID_Tortoisegit_UPTODATE;\r
176                         psci->scid.pid = dwIndex;\r
177                         psci->vt = VT_BSTR;\r
178                         psci->fmt = LVCFMT_LEFT;\r
179                         psci->cChars = 30;\r
180                         psci->csFlags = ColumnFlags;\r
181 \r
182                         MAKESTRING(IDS_COLTITLEAUTHOR);\r
183                         lstrcpynW(psci->wszTitle, stringtablebuffer, MAX_COLUMN_NAME_LEN);\r
184                         MAKESTRING(IDS_COLDESCAUTHOR);\r
185                         lstrcpynW(psci->wszDescription, stringtablebuffer, MAX_COLUMN_DESC_LEN);\r
186                         break;\r
187         }\r
188 \r
189         return S_OK;\r
190 }\r
191 \r
192 STDMETHODIMP CShellExt::GetItemData(LPCSHCOLUMNID pscid, LPCSHCOLUMNDATA pscd, VARIANT *pvarData)\r
193 {\r
194         PreserveChdir preserveChdir;\r
195         if (!g_ShellCache.IsPathAllowed((TCHAR *)pscd->wszFile))\r
196         {\r
197                 return S_FALSE;\r
198         }\r
199         LoadLangDll();\r
200         ShellCache::CacheType cachetype = g_ShellCache.GetCacheType();\r
201         if (pscid->fmtid == CLSID_Tortoisegit_UPTODATE && pscid->pid < 8) \r
202         {\r
203                 stdstring szInfo;\r
204                 const TCHAR * path = (TCHAR *)pscd->wszFile;\r
205 \r
206                 // reserve for the path + trailing \0\r
207 \r
208                 TCHAR buf[MAX_STATUS_STRING_LENGTH+1];\r
209                 SecureZeroMemory(buf, MAX_STATUS_STRING_LENGTH);\r
210                 switch (pscid->pid) \r
211                 {\r
212                         case 0: // SVN Status\r
213                                 GetColumnStatus(path, pscd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);\r
214                                 GitStatus::GetStatusString(g_hResInst, filestatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)CRegStdWORD(_T("Software\\TortoiseGit\\LanguageID"), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)));\r
215                                 szInfo = buf;\r
216                                 break;\r
217                         case 1: // SVN Revision\r
218 #if 0\r
219                                 GetColumnStatus(path, pscd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);\r
220                                 if (columnrev >= 0)\r
221                                 {\r
222                                         V_VT(pvarData) = VT_I4;\r
223                                         V_I4(pvarData) = columnrev;\r
224                                 }\r
225 #endif\r
226                                 return S_OK;\r
227                                 break;\r
228                         case 2: // SVN Url\r
229                                 GetColumnStatus(path, pscd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);\r
230                                 szInfo = itemurl;\r
231                                 break;\r
232                         case 3: // SVN Short Url\r
233                                 GetColumnStatus(path, pscd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);\r
234                                 szInfo = itemshorturl;\r
235                                 break;\r
236                         case 5: // SVN mime-type\r
237 #if 0\r
238                                 if (cachetype == ShellCache::none)\r
239                                         return S_FALSE;\r
240                                 if (g_ShellCache.IsPathAllowed(path))\r
241                                 {\r
242                                         SVNProperties props = SVNProperties(CTSVNPath(path), false);\r
243                                         for (int i=0; i<props.GetCount(); i++)\r
244                                         {\r
245                                                 if (props.GetItemName(i).compare(_T("svn:mime-type"))==0)\r
246                                                 {\r
247                                                         szInfo = MultibyteToWide((char *)props.GetItemValue(i).c_str());\r
248                                                 }\r
249                                         }\r
250                                 }\r
251 #endif\r
252                                 break;\r
253                         case 6: // SVN Lock Owner\r
254                                 GetColumnStatus(path, pscd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);\r
255                                 szInfo = owner;\r
256                                 break;\r
257                         case 7: // SVN eol-style\r
258 #if 0\r
259                                 if (cachetype == ShellCache::none)\r
260                                         return S_FALSE;\r
261                                 if (g_ShellCache.IsPathAllowed(path))\r
262                                 {\r
263                                         SVNProperties props = SVNProperties(CTSVNPath(path), false);\r
264                                         for (int i=0; i<props.GetCount(); i++)\r
265                                         {\r
266                                                 if (props.GetItemName(i).compare(_T("svn:eol-style"))==0)\r
267                                                 {\r
268                                                         szInfo = MultibyteToWide((char *)props.GetItemValue(i).c_str());\r
269                                                 }\r
270                                         }\r
271                                 }\r
272 #endif\r
273                                 break;\r
274                         default:\r
275                                 return S_FALSE;\r
276                 }\r
277                 const WCHAR * wsInfo = szInfo.c_str();\r
278                 V_VT(pvarData) = VT_BSTR;\r
279                 V_BSTR(pvarData) = SysAllocString(wsInfo);\r
280                 return S_OK;\r
281         }\r
282         if ((pscid->fmtid == FMTID_SummaryInformation)||(pscid->pid == 8))\r
283         {\r
284                 stdstring szInfo;\r
285                 const TCHAR * path = pscd->wszFile;\r
286 \r
287                 if (cachetype == ShellCache::none)\r
288                         return S_FALSE;\r
289                 switch (pscid->pid)\r
290                 {\r
291                 case PIDSI_AUTHOR:                      // author\r
292                 case 8:\r
293                         GetColumnStatus(path, pscd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);\r
294                         szInfo = columnauthor;\r
295                         break;\r
296                 default:\r
297                         return S_FALSE;\r
298                 }\r
299                 wide_string wsInfo = szInfo;\r
300                 V_VT(pvarData) = VT_BSTR;\r
301                 V_BSTR(pvarData) = SysAllocString(wsInfo.c_str());\r
302                 return S_OK;\r
303         }\r
304 \r
305         return S_FALSE;\r
306 }\r
307 \r
308 STDMETHODIMP CShellExt::Initialize(LPCSHCOLUMNINIT psci)\r
309 {\r
310         // psci->wszFolder (WCHAR) holds the path to the folder to be displayed\r
311         // Should check to see if its a "SVN" folder and if not return E_FAIL\r
312 \r
313         PreserveChdir preserveChdir;\r
314         if (g_ShellCache.IsColumnsEveryWhere())\r
315                 return S_OK;\r
316         std::wstring path = psci->wszFolder;\r
317         if (!path.empty())\r
318         {\r
319                 if (! g_ShellCache.HasSVNAdminDir(path.c_str(), TRUE))\r
320                         return E_FAIL;\r
321         }\r
322         columnfilepath = _T("");\r
323         return S_OK;\r
324 }\r
325 \r
326 void CShellExt::GetColumnStatus(const TCHAR * path, BOOL bIsDir)\r
327 {\r
328 #if 0\r
329         PreserveChdir preserveChdir;\r
330         if (_tcscmp(path, columnfilepath.c_str())==0)\r
331                 return;\r
332         LoadLangDll();\r
333         columnfilepath = path;\r
334         const FileStatusCacheEntry * status = NULL;\r
335         TSVNCacheResponse itemStatus;\r
336         ShellCache::CacheType t = ShellCache::exe;\r
337         AutoLocker lock(g_csGlobalCOMGuard);\r
338         t = g_ShellCache.GetCacheType();\r
339 \r
340         switch (t)\r
341         {\r
342         case ShellCache::exe:\r
343                 {\r
344                         SecureZeroMemory(&itemStatus, sizeof(itemStatus));\r
345                         if(m_remoteCacheLink.GetStatusFromRemoteCache(CTSVNPath(path), &itemStatus, true))\r
346                         {\r
347                                 filestatus = SVNStatus::GetMoreImportant(itemStatus.m_status.text_status, itemStatus.m_status.prop_status);\r
348                         }\r
349                         else\r
350                         {\r
351                                 filestatus = git_wc_status_none;\r
352                                 columnauthor.clear();\r
353                                 columnrev = 0;\r
354                                 itemurl.clear();\r
355                                 itemshorturl.clear();\r
356                                 owner.clear();\r
357                                 return; \r
358                         }\r
359                 }\r
360                 break;\r
361         case ShellCache::dll:\r
362                 {\r
363                         status = m_CachedStatus.GetFullStatus(CTSVNPath(path), bIsDir, TRUE);\r
364                         filestatus = status->status;\r
365                 }\r
366                 break;\r
367         default:\r
368         case ShellCache::none:\r
369                 {\r
370                         if (g_ShellCache.HasSVNAdminDir(path, bIsDir))\r
371                                 filestatus = git_wc_status_normal;\r
372                         else\r
373                                 filestatus = git_wc_status_none;\r
374                         columnauthor.clear();\r
375                         columnrev = 0;\r
376                         itemurl.clear();\r
377                         itemshorturl.clear();\r
378                         owner.clear();\r
379                         return; \r
380                 }\r
381                 break;\r
382         }\r
383 \r
384         if (t == ShellCache::exe)\r
385         {\r
386                 columnauthor = UTF8ToWide(itemStatus.m_author);\r
387                 columnrev = itemStatus.m_entry.cmt_rev;\r
388                 itemurl = UTF8ToWide(itemStatus.m_url);\r
389                 owner = UTF8ToWide(itemStatus.m_owner);\r
390         }\r
391         else\r
392         {\r
393                 if (status)\r
394                 {\r
395                         columnauthor = UTF8ToWide(status->author);\r
396                         columnrev = status->rev;\r
397                         itemurl = UTF8ToWide(status->url);\r
398                         owner = UTF8ToWide(status->owner);\r
399                 }\r
400         }\r
401         TCHAR urlpath[INTERNET_MAX_URL_LENGTH+1];\r
402 \r
403         URL_COMPONENTS urlComponents;\r
404         memset(&urlComponents, 0, sizeof(URL_COMPONENTS));\r
405         urlComponents.dwStructSize = sizeof(URL_COMPONENTS);\r
406         urlComponents.dwUrlPathLength = INTERNET_MAX_URL_LENGTH;\r
407         urlComponents.lpszUrlPath = urlpath;\r
408         if (InternetCrackUrl(itemurl.c_str(), 0, ICU_DECODE, &urlComponents))\r
409         {\r
410                 // since the short url is shown as an additional column where the\r
411                 // file/foldername is shown too, we strip that name from the url\r
412                 // to make the url even shorter.\r
413                 TCHAR * ptr = _tcsrchr(urlComponents.lpszUrlPath, '/');\r
414                 if (ptr == NULL)\r
415                         ptr = _tcsrchr(urlComponents.lpszUrlPath, '\\');\r
416                 if (ptr)\r
417                 {\r
418                         *ptr = '\0';\r
419                         // to shorten the url even more, we check for 'trunk', 'branches' and 'tags'\r
420                         // and simply assume that these are the folders attached to the repository\r
421                         // root. If we find those, we strip the whole path before those folders too.\r
422                         // Note: this will strip too much if such a folder is *below* the repository\r
423                         // root - but it's called 'short url' and we're free to shorten it the way we\r
424                         // like :)\r
425                         ptr = _tcsstr(urlComponents.lpszUrlPath, _T("/trunk"));\r
426                         if (ptr == NULL)\r
427                                 ptr = _tcsstr(urlComponents.lpszUrlPath, _T("\\trunk"));\r
428                         if ((ptr == NULL)||((*(ptr+6) != 0)&&(*(ptr+6) != '/')&&(*(ptr+6) != '\\')))\r
429                         {\r
430                                 ptr = _tcsstr(urlComponents.lpszUrlPath, _T("/branches"));\r
431                                 if (ptr == NULL)\r
432                                         ptr = _tcsstr(urlComponents.lpszUrlPath, _T("\\branches"));\r
433                                 if ((ptr == NULL)||((*(ptr+9) != 0)&&(*(ptr+9) != '/')&&(*(ptr+9) != '\\')))\r
434                                 {\r
435                                         ptr = _tcsstr(urlComponents.lpszUrlPath, _T("/tags"));\r
436                                         if (ptr == NULL)\r
437                                                 ptr = _tcsstr(urlComponents.lpszUrlPath, _T("\\tags"));\r
438                                         if ((ptr)&&(*(ptr+5) != 0)&&(*(ptr+5) != '/')&&(*(ptr+5) != '\\'))\r
439                                                 ptr = NULL;\r
440                                 }\r
441                         }\r
442                         if (ptr)\r
443                                 itemshorturl = ptr;\r
444                         else\r
445                                 itemshorturl = urlComponents.lpszUrlPath;\r
446                 }\r
447                 else \r
448                         itemshorturl = _T(" ");\r
449         }\r
450         else\r
451                 itemshorturl = _T(" ");\r
452 \r
453         if (status)\r
454         {\r
455                 char url[INTERNET_MAX_URL_LENGTH];\r
456                 strcpy_s(url, INTERNET_MAX_URL_LENGTH, status->url);\r
457                 CPathUtils::Unescape(url);\r
458                 itemurl = UTF8ToWide(url);\r
459         }\r
460         else if (t == ShellCache::exe)\r
461         {\r
462                 char url[INTERNET_MAX_URL_LENGTH];\r
463                 strcpy_s(url, INTERNET_MAX_URL_LENGTH, itemStatus.m_url);\r
464                 CPathUtils::Unescape(url);\r
465                 itemurl = UTF8ToWide(url);\r
466         }\r
467 #endif\r
468 }\r
469 \r