// *********************** CShellExt ************************* CShellExt::CShellExt(FileState state) : m_crasher(L"TortoiseSVN", false) , regDiffLater(L"Software\\TortoiseMerge\\DiffLater", L"") , itemStates(0) , itemStatesFolder(0) , space(0) , columnrev(0) , filestatus(svn_wc_status_none) , m_State(state) { m_cRef = 0L; InterlockedIncrement(&g_cRefThisDll); { AutoLocker lock(g_csGlobalCOMGuard); g_shellObjects.Insert(this); } INITCOMMONCONTROLSEX used = { sizeof(INITCOMMONCONTROLSEX), ICC_LISTVIEW_CLASSES | ICC_WIN95_CLASSES | ICC_BAR_CLASSES | ICC_USEREX_CLASSES }; InitCommonControlsEx(&used); LoadLangDll(); }
// *********************** CShellExt ************************* CShellExt::CShellExt(FileState state) : m_State(state) , itemStates(0) , itemStatesFolder(0) , space(0) #if ENABLE_CRASHHANLDER , m_crasher(L"TortoiseGit", TGIT_VERMAJOR, TGIT_VERMINOR, TGIT_VERMICRO, TGIT_VERBUILD, TGIT_VERDATE, false) #endif ,regDiffLater(L"Software\\TortoiseGit\\DiffLater", L"") { m_cRef = 0L; InterlockedIncrement(&g_cRefThisDll); { AutoLocker lock(g_csGlobalCOMGuard); g_shellObjects.Insert(this); } INITCOMMONCONTROLSEX used = { sizeof(INITCOMMONCONTROLSEX), ICC_LISTVIEW_CLASSES | ICC_WIN95_CLASSES | ICC_BAR_CLASSES | ICC_USEREX_CLASSES }; InitCommonControlsEx(&used); LoadLangDll(); }
// *********************** CShellExt ************************* CShellExt::CShellExt(FileState state) #if ENABLE_CRASHHANLDER : m_crasher(L"TortoiseGit", TGIT_VERMAJOR, TGIT_VERMINOR, TGIT_VERMICRO, TGIT_VERBUILD, TGIT_VERDATE, false) #endif { m_State = state; m_cRef = 0L; InterlockedIncrement(&g_cRefThisDll); { AutoLocker lock(g_csGlobalCOMGuard); g_shellObjects.Insert(this); } INITCOMMONCONTROLSEX used = { sizeof(INITCOMMONCONTROLSEX), ICC_LISTVIEW_CLASSES | ICC_WIN95_CLASSES | ICC_BAR_CLASSES | ICC_USEREX_CLASSES }; InitCommonControlsEx(&used); LoadLangDll(); if (SysInfo::Instance().IsVistaOrLater()) { HMODULE hUxTheme = ::GetModuleHandle (_T("UXTHEME.DLL")); pfnGetBufferedPaintBits = (FN_GetBufferedPaintBits)::GetProcAddress(hUxTheme, "GetBufferedPaintBits"); pfnBeginBufferedPaint = (FN_BeginBufferedPaint)::GetProcAddress(hUxTheme, "BeginBufferedPaint"); pfnEndBufferedPaint = (FN_EndBufferedPaint)::GetProcAddress(hUxTheme, "EndBufferedPaint"); } }
// *********************** CShellExt ************************* CShellExt::CShellExt(FileState state) { m_State = state; m_cRef = 0L; g_cRefThisDll++; g_exts.insert(this); INITCOMMONCONTROLSEX used = { sizeof(INITCOMMONCONTROLSEX), ICC_LISTVIEW_CLASSES | ICC_WIN95_CLASSES | ICC_BAR_CLASSES | ICC_USEREX_CLASSES }; InitCommonControlsEx(&used); LoadLangDll(); if (SysInfo::Instance().IsVistaOrLater()) { HMODULE hUxTheme = ::GetModuleHandle (_T("UXTHEME.DLL")); pfnGetBufferedPaintBits = (FN_GetBufferedPaintBits)::GetProcAddress(hUxTheme, "GetBufferedPaintBits"); pfnBeginBufferedPaint = (FN_BeginBufferedPaint)::GetProcAddress(hUxTheme, "BeginBufferedPaint"); pfnEndBufferedPaint = (FN_EndBufferedPaint)::GetProcAddress(hUxTheme, "EndBufferedPaint"); } }
// IColumnProvider members STDMETHODIMP CShellExt::GetColumnInfo(DWORD dwIndex, SHCOLUMNINFO *psci) { PreserveChdir preserveChdir; if (dwIndex > 0) // TODO: keep for now to be able to hide unimplemented columns return S_FALSE; ShellCache::CacheType cachetype = g_ShellCache.GetCacheType(); if (cachetype == ShellCache::none) return S_FALSE; LoadLangDll(); switch (dwIndex) { case 0: // Git Status GetColumnInfo(dwIndex, psci, 15, IDS_COLTITLESTATUS, IDS_COLDESCSTATUS); break; case 1: // Git Revision GetColumnInfo(dwIndex, psci, 40, IDS_COLTITLEREV, IDS_COLDESCREV); break; case 2: // Git Url GetColumnInfo(dwIndex, psci, 30, IDS_COLTITLEURL, IDS_COLDESCURL); break; case 3: // Git Short Url GetColumnInfo(dwIndex, psci, 30, IDS_COLTITLESHORTURL, IDS_COLDESCSHORTURL); break; case 4: // Author and Git Author psci->scid.fmtid = FMTID_SummaryInformation; // predefined FMTID psci->scid.pid = PIDSI_AUTHOR; // Predefined - author psci->vt = VT_LPSTR; // We'll return the data as a string psci->fmt = LVCFMT_LEFT; // Text will be left-aligned in the column psci->csFlags = SHCOLSTATE_TYPE_STR; // Data should be sorted as strings psci->cChars = 32; // Default col width in chars MAKESTRING(IDS_COLTITLEAUTHOR); lstrcpynW(psci->wszTitle, stringtablebuffer, MAX_COLUMN_NAME_LEN); MAKESTRING(IDS_COLDESCAUTHOR); lstrcpynW(psci->wszDescription, stringtablebuffer, MAX_COLUMN_DESC_LEN); break; case 5: // SVN eol-style GetColumnInfo(dwIndex, psci, 30, IDS_COLTITLEEOLSTYLE, IDS_COLDESCEOLSTYLE); break; default: return S_FALSE; } return S_OK; }
// *********************** CShellExt ************************* CShellExt::CShellExt(FileState state) : m_State(state) , selectedItemsStatus(0) , currentFolderIsControlled(false) { m_cRef = 0L; InterlockedIncrement(&g_cRefThisDll); { AutoLocker lock(g_csGlobalCOMGuard); g_shellObjects.Insert(this); } INITCOMMONCONTROLSEX used = { sizeof(INITCOMMONCONTROLSEX), ICC_LISTVIEW_CLASSES | ICC_WIN95_CLASSES | ICC_BAR_CLASSES | ICC_USEREX_CLASSES }; InitCommonControlsEx(&used); LoadLangDll(); }
void CShellExt::GetColumnStatus(const TCHAR * path, BOOL bIsDir) { PreserveChdir preserveChdir; if (_tcscmp(path, columnfilepath.c_str())==0) return; LoadLangDll(); columnfilepath = path; const FileStatusCacheEntry * status = NULL; TGITCacheResponse itemStatus; ShellCache::CacheType t = ShellCache::exe; AutoLocker lock(g_csGlobalCOMGuard); t = g_ShellCache.GetCacheType(); switch (t) { case ShellCache::exe: { SecureZeroMemory(&itemStatus, sizeof(itemStatus)); if(m_remoteCacheLink.GetStatusFromRemoteCache(CTGitPath(path), &itemStatus, true)) { filestatus = GitStatus::GetMoreImportant(itemStatus.m_status.text_status, itemStatus.m_status.prop_status); } else { filestatus = git_wc_status_none; columnauthor.clear(); columnrev = GIT_INVALID_REVNUM; itemurl.clear(); itemshorturl.clear(); owner.clear(); return; } } break; case ShellCache::dll: case ShellCache::dllFull: { status = m_CachedStatus.GetFullStatus(CTGitPath(path), bIsDir, TRUE); filestatus = status->status; } break; default: case ShellCache::none: { if (g_ShellCache.HasGITAdminDir(path, bIsDir)) filestatus = git_wc_status_normal; else filestatus = git_wc_status_none; columnauthor.clear(); columnrev = GIT_INVALID_REVNUM; itemurl.clear(); itemshorturl.clear(); owner.clear(); return; } break; } if (t == ShellCache::exe) { columnauthor = UTF8ToWide(itemStatus.m_author); columnrev = itemStatus.m_entry.cmt_rev; itemurl = UTF8ToWide(itemStatus.m_url); owner = UTF8ToWide(itemStatus.m_owner); } else { if (status) { columnauthor = UTF8ToWide(status->author); columnrev = status->rev; itemurl = UTF8ToWide(status->url); owner = UTF8ToWide(status->owner); } } #if 0 TCHAR urlpath[INTERNET_MAX_URL_LENGTH+1]; URL_COMPONENTS urlComponents; memset(&urlComponents, 0, sizeof(URL_COMPONENTS)); urlComponents.dwStructSize = sizeof(URL_COMPONENTS); urlComponents.dwUrlPathLength = INTERNET_MAX_URL_LENGTH; urlComponents.lpszUrlPath = urlpath; if (InternetCrackUrl(itemurl.c_str(), 0, ICU_DECODE, &urlComponents)) { // since the short url is shown as an additional column where the // file/foldername is shown too, we strip that name from the url // to make the url even shorter. TCHAR * ptr = _tcsrchr(urlComponents.lpszUrlPath, '/'); if (ptr == NULL) ptr = _tcsrchr(urlComponents.lpszUrlPath, '\\'); if (ptr) { *ptr = '\0'; // to shorten the url even more, we check for 'trunk', 'branches' and 'tags' // and simply assume that these are the folders attached to the repository // root. If we find those, we strip the whole path before those folders too. // Note: this will strip too much if such a folder is *below* the repository // root - but it's called 'short url' and we're free to shorten it the way we // like :) /*ptr = _tcsstr(urlComponents.lpszUrlPath, _T("/trunk")); if (ptr == NULL) ptr = _tcsstr(urlComponents.lpszUrlPath, _T("\\trunk")); if ((ptr == NULL)||((*(ptr+6) != 0)&&(*(ptr+6) != '/')&&(*(ptr+6) != '\\'))) { ptr = _tcsstr(urlComponents.lpszUrlPath, _T("/branches")); if (ptr == NULL) ptr = _tcsstr(urlComponents.lpszUrlPath, _T("\\branches")); if ((ptr == NULL)||((*(ptr+9) != 0)&&(*(ptr+9) != '/')&&(*(ptr+9) != '\\'))) { ptr = _tcsstr(urlComponents.lpszUrlPath, _T("/tags")); if (ptr == NULL) ptr = _tcsstr(urlComponents.lpszUrlPath, _T("\\tags")); if ((ptr)&&(*(ptr+5) != 0)&&(*(ptr+5) != '/')&&(*(ptr+5) != '\\')) ptr = NULL; } } if (ptr) itemshorturl = ptr; else*/ itemshorturl = urlComponents.lpszUrlPath; } else itemshorturl = _T(" "); } else itemshorturl = _T(" "); if (status) { char url[INTERNET_MAX_URL_LENGTH]; strcpy_s(url, INTERNET_MAX_URL_LENGTH, status->url); CPathUtils::Unescape(url); itemurl = UTF8ToWide(url); } else if (t == ShellCache::exe) { char url[INTERNET_MAX_URL_LENGTH]; strcpy_s(url, INTERNET_MAX_URL_LENGTH, itemStatus.m_url); CPathUtils::Unescape(url); itemurl = UTF8ToWide(url); } #endif }
STDMETHODIMP CShellExt::GetItemData(LPCSHCOLUMNID pscid, LPCSHCOLUMNDATA pscd, VARIANT *pvarData) { PreserveChdir preserveChdir; if (!g_ShellCache.IsPathAllowed((TCHAR *)pscd->wszFile)) { return S_FALSE; } LoadLangDll(); ShellCache::CacheType cachetype = g_ShellCache.GetCacheType(); if (pscid->fmtid == CLSID_Tortoisegit_UPTODATE) { stdstring szInfo; const TCHAR * path = (TCHAR *)pscd->wszFile; // reserve for the path + trailing \0 TCHAR buf[MAX_STATUS_STRING_LENGTH+1]; SecureZeroMemory(buf, MAX_STATUS_STRING_LENGTH); switch (pscid->pid) { case 0: // Git Status GetColumnStatus(path, pscd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); GitStatus::GetStatusString(g_hResInst, filestatus, buf, _countof(buf), (WORD)CRegStdDWORD(_T("Software\\TortoiseGit\\LanguageID"), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT))); szInfo = buf; break; case 1: // Git Revision #if 0 GetColumnStatus(path, pscd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); if (columnrev >= 0) { V_VT(pvarData) = VT_I4; V_I4(pvarData) = columnrev; } #endif return S_OK; break; case 2: // Git Url GetColumnStatus(path, pscd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); szInfo = itemurl; break; case 3: // Git Short Url GetColumnStatus(path, pscd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); szInfo = itemshorturl; break; case 5: // Git eol-style #if 0 if (cachetype == ShellCache::none) return S_FALSE; if (g_ShellCache.IsPathAllowed(path)) { SVNProperties props = SVNProperties(CTSVNPath(path), false); for (int i=0; i<props.GetCount(); i++) { if (props.GetItemName(i).compare(_T("svn:eol-style"))==0) { szInfo = MultibyteToWide((char *)props.GetItemValue(i).c_str()); } } } #endif break; default: return S_FALSE; } const WCHAR * wsInfo = szInfo.c_str(); V_VT(pvarData) = VT_BSTR; V_BSTR(pvarData) = SysAllocString(wsInfo); return S_OK; } if (pscid->fmtid == FMTID_SummaryInformation) { stdstring szInfo; const TCHAR * path = pscd->wszFile; if (cachetype == ShellCache::none) return S_FALSE; switch (pscid->pid) { case PIDSI_AUTHOR: // Author and Git Author GetColumnStatus(path, pscd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); szInfo = columnauthor; break; default: return S_FALSE; } wide_string wsInfo = szInfo; V_VT(pvarData) = VT_BSTR; V_BSTR(pvarData) = SysAllocString(wsInfo.c_str()); return S_OK; } return S_FALSE; }