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