Example #1
0
BOOL CTortoiseProcApp::InitInstance()
{
	CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": InitInstance\n"));
	CheckUpgrade();
	CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
	CMFCButton::EnableWindowsTheming();
	CHistoryCombo::m_nGitIconIndex = SYS_IMAGE_LIST().AddIcon((HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_GITCONFIG), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE));

	Gdiplus::GdiplusStartupInput gdiplusStartupInput;
	Gdiplus::GdiplusStartup(&m_gdiplusToken,&gdiplusStartupInput,NULL);

	//set the resource dll for the required language
	CRegDWORD loc = CRegDWORD(_T("Software\\TortoiseGit\\LanguageID"), 1033);
	long langId = loc;
	{
		CString langStr;
		langStr.Format(_T("%ld"), langId);
		CCrashReport::Instance().AddUserInfoToReport(L"LanguageID", langStr);
	}
	CString langDll;
	CStringA langpath = CStringA(CPathUtils::GetAppParentDirectory());
	langpath += "Languages";
	do
	{
		langDll.Format(_T("%sLanguages\\TortoiseProc%ld.dll"), (LPCTSTR)CPathUtils::GetAppParentDirectory(), langId);

		CString sVer = _T(STRPRODUCTVER);
		CString sFileVer = CPathUtils::GetVersionFromFile(langDll);
		if (sFileVer == sVer)
		{
			HINSTANCE hInst = LoadLibrary(langDll);
			if (hInst != NULL)
			{
				CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Load Language DLL %s\n"), langDll);
				AfxSetResourceHandle(hInst);
				break;
			}
		}
		{
			DWORD lid = SUBLANGID(langId);
			lid--;
			if (lid > 0)
			{
				langId = MAKELANGID(PRIMARYLANGID(langId), lid);
			}
			else
				langId = 0;
		}
	} while (langId != 0);
	TCHAR buf[6] = { 0 };
	_tcscpy_s(buf, _T("en"));
	langId = loc;
	// MFC uses a help file with the same name as the application by default,
	// which means we have to change that default to our language specific help files
	CString sHelppath = CPathUtils::GetAppDirectory() + _T("TortoiseGit_en.chm");
	free((void*)m_pszHelpFilePath);
	m_pszHelpFilePath=_tcsdup(sHelppath);
	sHelppath = CPathUtils::GetAppParentDirectory() + _T("Languages\\TortoiseGit_en.chm");
	do
	{
		CString sLang = _T("_");
		if (GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO639LANGNAME, buf, _countof(buf)))
		{
			sLang += buf;
			sHelppath.Replace(_T("_en"), sLang);
			if (PathFileExists(sHelppath))
			{
				free((void*)m_pszHelpFilePath);
				m_pszHelpFilePath=_tcsdup(sHelppath);
				break;
			}
		}
		sHelppath.Replace(sLang, _T("_en"));
		if (GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO3166CTRYNAME, buf, _countof(buf)))
		{
			sLang += _T("_");
			sLang += buf;
			sHelppath.Replace(_T("_en"), sLang);
			if (PathFileExists(sHelppath))
			{
				free((void*)m_pszHelpFilePath);
				m_pszHelpFilePath=_tcsdup(sHelppath);
				break;
			}
		}
		sHelppath.Replace(sLang, _T("_en"));

		DWORD lid = SUBLANGID(langId);
		lid--;
		if (lid > 0)
		{
			langId = MAKELANGID(PRIMARYLANGID(langId), lid);
		}
		else
			langId = 0;
	} while (langId);
	CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Set Help Filename %s\n"), m_pszHelpFilePath);
	setlocale(LC_ALL, "");

	if (!g_Git.CheckMsysGitDir())
	{
		UINT ret = CMessageBox::Show(NULL, IDS_PROC_NOMSYSGIT, IDS_APPNAME, 3, IDI_HAND, IDS_PROC_SETMSYSGITPATH, IDS_PROC_GOTOMSYSGITWEBSITE, IDS_ABORTBUTTON);
		if(ret == 2)
		{
			ShellExecute(NULL, NULL, _T("http://msysgit.github.io/"), NULL, NULL, SW_SHOW);
		}
		else if(ret == 1)
		{
			// open settings dialog
			CSinglePropSheetDlg(CString(MAKEINTRESOURCE(IDS_PROC_SETTINGS_TITLE)), new CSetMainPage(), this->GetMainWnd()).DoModal();
		}
		return FALSE;
	}
	if (CAppUtils::GetMsysgitVersion() < 0x01070a00)
	{
		int ret = CMessageBox::ShowCheck(NULL, IDS_PROC_OLDMSYSGIT, IDS_APPNAME, 1, IDI_EXCLAMATION, IDS_PROC_GOTOMSYSGITWEBSITE, IDS_ABORTBUTTON, IDS_IGNOREBUTTON, _T("OldMsysgitVersionWarning"), IDS_PROC_NOTSHOWAGAINIGNORE);
		if (ret == 1)
		{
			CMessageBox::RemoveRegistryKey(_T("OldMsysgitVersionWarning")); // only store answer if it is "Ignore"
			ShellExecute(NULL, NULL, _T("http://msysgit.github.io/"), NULL, NULL, SW_SHOW);
			return FALSE;
		}
		else if (ret == 2)
		{
			CMessageBox::RemoveRegistryKey(_T("OldMsysgitVersionWarning")); // only store answer if it is "Ignore"
			return FALSE;
		}
	}

	{
		CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Registering Crash Report ...\n"));
		CCrashReport::Instance().AddUserInfoToReport(L"msysGitDir", CGit::ms_LastMsysGitDir);
		CString versionString;
		versionString.Format(_T("%d"), CGit::ms_LastMsysGitVersion);
		CCrashReport::Instance().AddUserInfoToReport(L"msysGitVersion", versionString);
	}

	CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Initializing UI components ...\n"));
	// InitCommonControls() is required on Windows XP if an application
	// manifest specifies use of ComCtl32.dll version 6 or later to enable
	// visual styles.  Otherwise, any window creation will fail.

	INITCOMMONCONTROLSEX used = {
		sizeof(INITCOMMONCONTROLSEX),
			ICC_ANIMATE_CLASS | ICC_BAR_CLASSES | ICC_COOL_CLASSES | ICC_DATE_CLASSES |
			ICC_HOTKEY_CLASS | ICC_INTERNET_CLASSES | ICC_LISTVIEW_CLASSES |
			ICC_NATIVEFNTCTL_CLASS | ICC_PAGESCROLLER_CLASS | ICC_PROGRESS_CLASS |
			ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES | ICC_UPDOWN_CLASS |
			ICC_USEREX_CLASSES | ICC_WIN95_CLASSES
	};
	InitCommonControlsEx(&used);
	AfxOleInit();
	AfxEnableControlContainer();
	AfxInitRichEdit5();
	CWinAppEx::InitInstance();
	SetRegistryKey(_T("TortoiseGit"));
	AfxGetApp()->m_pszProfileName = _tcsdup(_T("TortoiseProc")); // w/o this ResizableLib will store data under TortoiseGitProc which is not compatible with older versions

	CCmdLineParser parser(AfxGetApp()->m_lpCmdLine);

	hWndExplorer = NULL;
	CString sVal = parser.GetVal(_T("hwnd"));
	if (!sVal.IsEmpty())
		hWndExplorer = (HWND)_wcstoui64(sVal, nullptr, 16);

	while (GetParent(hWndExplorer)!=NULL)
		hWndExplorer = GetParent(hWndExplorer);
	if (!IsWindow(hWndExplorer))
	{
		hWndExplorer = NULL;
	}

	// if HKCU\Software\TortoiseGit\Debug is not 0, show our command line
	// in a message box
	if (CRegDWORD(_T("Software\\TortoiseGit\\Debug"), FALSE)==TRUE)
		AfxMessageBox(AfxGetApp()->m_lpCmdLine, MB_OK | MB_ICONINFORMATION);

	if (parser.HasKey(_T("urlhandler")))
	{
		CString url = parser.GetVal(_T("urlhandler"));
		if (url.Find(_T("tgit://clone/")) == 0)
		{
			url = url.Mid(13); // 21 = "tgit://clone/".GetLength()
		}
		else if (url.Find(_T("github-windows://openRepo/")) == 0)
		{
			url = url.Mid(26); // 26 = "github-windows://openRepo/".GetLength()
			int questioMark = url.Find('?');
			if (questioMark > 0)
				url = url.Left(questioMark);
		}
		else if (url.Find(_T("smartgit://cloneRepo/")) == 0)
		{
			url = url.Mid(21); // 21 = "smartgit://cloneRepo/".GetLength()
		}
		else
		{
			CMessageBox::Show(NULL, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR);
			return FALSE;
		}
		CString newCmd;
		newCmd.Format(_T("/command:clone /url:\"%s\" /hasurlhandler"), url);
		parser = CCmdLineParser(newCmd);
	}

	if ( parser.HasKey(_T("path")) && parser.HasKey(_T("pathfile")))
	{
		CMessageBox::Show(NULL, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR);
		return FALSE;
	}

	CTGitPath cmdLinePath;
	CTGitPathList pathList;
	if (g_sGroupingUUID.IsEmpty())
		g_sGroupingUUID = parser.GetVal(L"groupuuid");
	if ( parser.HasKey(_T("pathfile")) )
	{

		CString sPathfileArgument = CPathUtils::GetLongPathname(parser.GetVal(_T("pathfile")));

		cmdLinePath.SetFromUnknown(sPathfileArgument);
		if (pathList.LoadFromFile(cmdLinePath)==false)
			return FALSE;		// no path specified!
		if ( parser.HasKey(_T("deletepathfile")) )
		{
			// We can delete the temporary path file, now that we've loaded it
			::DeleteFile(cmdLinePath.GetWinPath());
		}
		// This was a path to a temporary file - it's got no meaning now, and
		// anybody who uses it again is in for a problem...
		cmdLinePath.Reset();

	}
	else
	{

		CString sPathArgument = CPathUtils::GetLongPathname(parser.GetVal(_T("path")));
		if (parser.HasKey(_T("expaths")))
		{
			// an /expaths param means we're started via the buttons in our Win7 library
			// and that means the value of /expaths is the current directory, and
			// the selected paths are then added as additional parameters but without a key, only a value

			// because of the "strange treatment of quotation marks and backslashes by CommandLineToArgvW"
			// we have to escape the backslashes first. Since we're only dealing with paths here, that's
			// a save bet.
			// Without this, a command line like:
			// /command:commit /expaths:"D:\" "D:\Utils"
			// would fail because the "D:\" is treated as the backslash being the escape char for the quotation
			// mark and we'd end up with:
			// argv[1] = /command:commit
			// argv[2] = /expaths:D:" D:\Utils
			// See here for more details: http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx
			CString cmdLine = GetCommandLineW();
			cmdLine.Replace(L"\\", L"\\\\");
			int nArgs = 0;
			LPWSTR *szArglist = CommandLineToArgvW(cmdLine, &nArgs);
			if (szArglist)
			{
				// argument 0 is the process path, so start with 1
				for (int i = 1; i < nArgs; ++i)
				{
					if (szArglist[i][0] != '/')
					{
						if (!sPathArgument.IsEmpty())
							sPathArgument += '*';
						sPathArgument += szArglist[i];
					}
				}
				sPathArgument.Replace(L"\\\\", L"\\");
			}
			LocalFree(szArglist);
		}
		if (sPathArgument.IsEmpty() && parser.HasKey(L"path"))
		{
			CMessageBox::Show(hWndExplorer, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR);
			return FALSE;
		}
		int asterisk = sPathArgument.Find('*');
		cmdLinePath.SetFromUnknown(asterisk >= 0 ? sPathArgument.Left(asterisk) : sPathArgument);
		pathList.LoadFromAsteriskSeparatedString(sPathArgument);
	}

	if (pathList.IsEmpty()) {
		pathList.AddPath(CTGitPath::CTGitPath(g_Git.m_CurrentDir));
	}

	// Set CWD to temporary dir, and restore it later
	{
		DWORD len = GetCurrentDirectory(0, NULL);
		if (len)
		{
			std::unique_ptr<TCHAR[]> originalCurrentDirectory(new TCHAR[len]);
			if (GetCurrentDirectory(len, originalCurrentDirectory.get()))
			{
				sOrigCWD = originalCurrentDirectory.get();
				sOrigCWD = CPathUtils::GetLongPathname(sOrigCWD);
			}
		}
		TCHAR pathbuf[MAX_PATH] = {0};
		GetTortoiseGitTempPath(MAX_PATH, pathbuf);
		SetCurrentDirectory(pathbuf);
	}

	CheckForNewerVersion();

	CAutoGeneralHandle TGitMutex = ::CreateMutex(NULL, FALSE, _T("TortoiseGitProc.exe"));
	if (!g_Git.SetCurrentDir(cmdLinePath.GetWinPathString(), parser.HasKey(_T("submodule")) == TRUE))
	{
		for (int i = 0; i < pathList.GetCount(); ++i)
			if(g_Git.SetCurrentDir(pathList[i].GetWinPath()))
				break;
	}

	if(!g_Git.m_CurrentDir.IsEmpty())
	{
		sOrigCWD = g_Git.m_CurrentDir;
		SetCurrentDirectory(g_Git.m_CurrentDir);
	}

	if (g_sGroupingUUID.IsEmpty())
	{
		CRegStdDWORD groupSetting = CRegStdDWORD(_T("Software\\TortoiseGit\\GroupTaskbarIconsPerRepo"), 3);
		switch (DWORD(groupSetting))
		{
		case 1:
		case 2:
			// implemented differently to TortoiseSVN atm
			break;
		case 3:
		case 4:
			{
				CString wcroot;
				if (g_GitAdminDir.HasAdminDir(g_Git.m_CurrentDir, true, &wcroot))
				{
					git_oid oid;
					CStringA wcRootA(wcroot + CPathUtils::GetAppDirectory());
					if (!git_odb_hash(&oid, wcRootA, wcRootA.GetLength(), GIT_OBJ_BLOB))
					{
						CStringA hash;
						git_oid_tostr(hash.GetBufferSetLength(GIT_OID_HEXSZ + 1), GIT_OID_HEXSZ + 1, &oid);
						hash.ReleaseBuffer();
						g_sGroupingUUID = hash;
					}
					ProjectProperties pp;
					pp.ReadProps();
					CString icon = pp.sIcon;
					icon.Replace('/', '\\');
					if (icon.IsEmpty())
						g_bGroupingRemoveIcon = true;
					g_sGroupingIcon = icon;
				}
			}
		}
	}

	CString sAppID = GetTaskIDPerUUID(g_sGroupingUUID).c_str();
	InitializeJumpList(sAppID);
	EnsureGitLibrary(false);

	{
		CString err;
		try
		{
			// requires CWD to be set
			CGit::m_LogEncode = CAppUtils::GetLogOutputEncode();

			// make sure all config files are read in order to check that none contains an error
			g_Git.GetConfigValue(_T("doesnot.exist"));
		}
		catch (char* msg)
		{
			err = CString(msg);
		}

		if (!err.IsEmpty())
		{
			UINT choice = CMessageBox::Show(hWndExplorer, err, _T("TortoiseGit"), 1, IDI_ERROR, CString(MAKEINTRESOURCE(IDS_PROC_EDITLOCALGITCONFIG)), CString(MAKEINTRESOURCE(IDS_PROC_EDITGLOBALGITCONFIG)), CString(MAKEINTRESOURCE(IDS_ABORTBUTTON)));
			if (choice == 1)
			{
				// open the config file with alternative editor
				CAppUtils::LaunchAlternativeEditor(g_Git.GetGitLocalConfig());
			}
			else if (choice == 2)
			{
				// open the global config file with alternative editor
				CAppUtils::LaunchAlternativeEditor(g_Git.GetGitGlobalConfig());
			}
			return FALSE;
		}
	}

	// execute the requested command
	CommandServer server;
	Command * cmd = server.GetCommand(parser.GetVal(_T("command")));
	if (cmd)
	{
		cmd->SetExplorerHwnd(hWndExplorer);

		cmd->SetParser(parser);
		cmd->SetPaths(pathList, cmdLinePath);

		retSuccess = cmd->Execute();
		delete cmd;
	}

	// Look for temporary files left around by TortoiseSVN and
	// remove them. But only delete 'old' files because some
	// apps might still be needing the recent ones.
	{
		DWORD len = GetTortoiseGitTempPath(0, NULL);
		std::unique_ptr<TCHAR[]> path(new TCHAR[len + 100]);
		len = GetTortoiseGitTempPath (len + 100, path.get());
		if (len != 0)
		{
			CDirFileEnum finder(path.get());
			FILETIME systime_;
			::GetSystemTimeAsFileTime(&systime_);
			__int64 systime = (((_int64)systime_.dwHighDateTime)<<32) | ((__int64)systime_.dwLowDateTime);
			bool isDir;
			CString filepath;
			while (finder.NextFile(filepath, &isDir))
			{
				HANDLE hFile = ::CreateFile(filepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, isDir ? FILE_FLAG_BACKUP_SEMANTICS : NULL, NULL);
				if (hFile != INVALID_HANDLE_VALUE)
				{
					FILETIME createtime_;
					if (::GetFileTime(hFile, &createtime_, NULL, NULL))
					{
						::CloseHandle(hFile);
						__int64 createtime = (((_int64)createtime_.dwHighDateTime)<<32) | ((__int64)createtime_.dwLowDateTime);
						if ((createtime + 864000000000) < systime)		//only delete files older than a day
						{
							::SetFileAttributes(filepath, FILE_ATTRIBUTE_NORMAL);
							if (isDir)
								::RemoveDirectory(filepath);
							else
								::DeleteFile(filepath);
						}
					}
					else
						::CloseHandle(hFile);
				}
			}
		}
	}

	// Since the dialog has been closed, return FALSE so that we exit the
	// application, rather than start the application's message pump.
	return FALSE;
}
Example #2
0
void CBrowseRefsDlg::ShowContextMenu(CPoint point, HTREEITEM hTreePos, VectorPShadowTree& selectedLeafs)
{
	CIconMenu popupMenu;
	popupMenu.CreatePopupMenu();

	bool bAddSeparator = false;
	CString remoteName;

	if(selectedLeafs.size()==1)
	{
		bAddSeparator = true;

		bool bShowReflogOption				= false;
		bool bShowFetchOption				= false;
		bool bShowRenameOption				= false;
		bool bShowCreateBranchOption		= false;
		bool bShowEditBranchDescriptionOption = false;

		CString fetchFromCmd;

		if(selectedLeafs[0]->IsFrom(L"refs/heads/"))
		{
			bShowReflogOption = true;
			bShowRenameOption = true;
			bShowEditBranchDescriptionOption = true;
		}
		else if(selectedLeafs[0]->IsFrom(L"refs/remotes/"))
		{
			bShowReflogOption = true;
			bShowFetchOption  = true;
			bShowCreateBranchOption = true;

			CString remoteBranch;
			if (SplitRemoteBranchName(selectedLeafs[0]->GetRefName(), remoteName, remoteBranch))
				bShowFetchOption = false;
			else
				fetchFromCmd.Format(IDS_PROC_BROWSEREFS_FETCHFROM, (LPCTSTR)remoteName);
		}
		else if(selectedLeafs[0]->IsFrom(L"refs/tags/"))
		{
		}

		CString temp;
		temp.LoadString(IDS_MENULOG);
		popupMenu.AppendMenuIcon(eCmd_ViewLog, temp, IDI_LOG);
		popupMenu.AppendMenuIcon(eCmd_RepoBrowser, IDS_LOG_BROWSEREPO, IDI_REPOBROWSE);
		if(bShowReflogOption)
		{
			temp.LoadString(IDS_MENUREFLOG);
			popupMenu.AppendMenuIcon(eCmd_ShowReflog, temp, IDI_LOG);
		}

		popupMenu.AppendMenu(MF_SEPARATOR);
		bAddSeparator = false;

		if(bShowFetchOption)
		{
			bAddSeparator = true;
			popupMenu.AppendMenuIcon(eCmd_Fetch, fetchFromCmd, IDI_PULL);
		}

		if(bAddSeparator)
			popupMenu.AppendMenu(MF_SEPARATOR);

		bAddSeparator = false;
		if (m_bHasWC)
		{
			CString str;
			if (selectedLeafs[0]->GetRefName() != _T("refs/heads/") + g_Git.GetCurrentBranch())
			{
				str.Format(IDS_LOG_POPUP_MERGEREV, (LPCTSTR)g_Git.GetCurrentBranch());
				popupMenu.AppendMenuIcon(eCmd_Merge, str, IDI_MERGE);
			}
			popupMenu.AppendMenuIcon(eCmd_Switch, CString(MAKEINTRESOURCE(IDS_SWITCH_TO_THIS)), IDI_SWITCH);
			popupMenu.AppendMenu(MF_SEPARATOR);
		}

		if(bShowCreateBranchOption)
		{
			bAddSeparator = true;
			temp.LoadString(IDS_MENUBRANCH);
			popupMenu.AppendMenuIcon(eCmd_CreateBranch, temp, IDI_COPY);
		}

		if (bShowEditBranchDescriptionOption)
		{
			bAddSeparator = true;
			popupMenu.AppendMenuIcon(eCmd_EditBranchDescription, CString(MAKEINTRESOURCE(IDS_PROC_BROWSEREFS_EDITDESCRIPTION)), IDI_RENAME);
		}
		if(bShowRenameOption)
		{
			bAddSeparator = true;
			popupMenu.AppendMenuIcon(eCmd_Rename, CString(MAKEINTRESOURCE(IDS_PROC_BROWSEREFS_RENAME)), IDI_RENAME);
		}

		if (m_bHasWC && selectedLeafs[0]->IsFrom(L"refs/heads/"))
		{
			if (bAddSeparator)
				popupMenu.AppendMenu(MF_SEPARATOR);
			bAddSeparator = true;
			if (!selectedLeafs[0]->m_csUpstream.IsEmpty())
				popupMenu.AppendMenuIcon(eCmd_UpstreamDrop, CString(MAKEINTRESOURCE(IDS_PROC_BROWSEREFS_DROPTRACKEDBRANCH)));
			popupMenu.AppendMenuIcon(eCmd_UpstreamSet, CString(MAKEINTRESOURCE(IDS_PROC_BROWSEREFS_SETTRACKEDBRANCH)));
		}
	}
	else if(selectedLeafs.size() == 2)
	{
		bAddSeparator = true;
		popupMenu.AppendMenuIcon(eCmd_Diff, CString(MAKEINTRESOURCE(IDS_PROC_BROWSEREFS_COMPAREREFS)), IDI_DIFF);
		popupMenu.AppendMenuIcon(eCmd_UnifiedDiff, CString(MAKEINTRESOURCE(IDS_LOG_POPUP_GNUDIFF)), IDI_DIFF);
		CString menu;
		menu.Format(IDS_SHOWLOG_OF, (LPCTSTR)GetTwoSelectedRefs(selectedLeafs, m_sLastSelected, _T("..")));
		popupMenu.AppendMenuIcon(eCmd_ViewLogRange, menu, IDI_LOG);
		menu.Format(IDS_SHOWLOG_OF, (LPCTSTR)GetTwoSelectedRefs(selectedLeafs, m_sLastSelected, _T("...")));
		popupMenu.AppendMenuIcon(eCmd_ViewLogRangeReachableFromOnlyOne, menu, IDI_LOG);
	}

	if(!selectedLeafs.empty())
	{
		if(AreAllFrom(selectedLeafs, L"refs/remotes/"))
		{
			if(bAddSeparator)
				popupMenu.AppendMenu(MF_SEPARATOR);
			CString menuItemName;
			if(selectedLeafs.size() == 1)
				menuItemName.LoadString(IDS_PROC_BROWSEREFS_DELETEREMOTEBRANCH);
			else
				menuItemName.Format(IDS_PROC_BROWSEREFS_DELETEREMOTEBRANCHES, selectedLeafs.size());

			popupMenu.AppendMenuIcon(eCmd_DeleteRemoteBranch, menuItemName, IDI_DELETE);
			bAddSeparator = true;
		}
		else if(AreAllFrom(selectedLeafs, L"refs/heads/"))
		{
			if(bAddSeparator)
				popupMenu.AppendMenu(MF_SEPARATOR);
			CString menuItemName;
			if(selectedLeafs.size() == 1)
				menuItemName.LoadString(IDS_PROC_BROWSEREFS_DELETEBRANCH);
			else
				menuItemName.Format(IDS_PROC_BROWSEREFS_DELETEBRANCHES, selectedLeafs.size());

			popupMenu.AppendMenuIcon(eCmd_DeleteBranch, menuItemName, IDI_DELETE);
			bAddSeparator = true;
		}
		else if(AreAllFrom(selectedLeafs, L"refs/tags/"))
		{
			if(bAddSeparator)
				popupMenu.AppendMenu(MF_SEPARATOR);
			CString menuItemName;
			if(selectedLeafs.size() == 1)
				menuItemName.LoadString(IDS_PROC_BROWSEREFS_DELETETAG);
			else
				menuItemName.Format(IDS_PROC_BROWSEREFS_DELETETAGS, selectedLeafs.size());

			popupMenu.AppendMenuIcon(eCmd_DeleteTag, menuItemName, IDI_DELETE);
			bAddSeparator = true;
		}
	}


	if(hTreePos!=NULL && selectedLeafs.empty())
	{
		CShadowTree* pTree=(CShadowTree*)m_RefTreeCtrl.GetItemData(hTreePos);
		if(pTree->IsFrom(L"refs/remotes"))
		{
			if(bAddSeparator)
				popupMenu.AppendMenu(MF_SEPARATOR);
			popupMenu.AppendMenuIcon(eCmd_ManageRemotes, CString(MAKEINTRESOURCE(IDS_PROC_BROWSEREFS_MANAGEREMOTES)), IDI_SETTINGS);
			bAddSeparator = true;
			if(selectedLeafs.empty())
			{
				CString remoteBranch;
				if (SplitRemoteBranchName(pTree->GetRefName(), remoteName, remoteBranch))
					remoteName = _T("");
				int pos = findVectorPosition(remotes, remoteName);
				if (pos >= 0)
				{
					CString temp;
					temp.Format(IDS_PROC_BROWSEREFS_FETCHFROM, (LPCTSTR)remoteName);
					popupMenu.AppendMenuIcon(eCmd_Fetch, temp, IDI_PULL);

					temp.LoadString(IDS_DELETEREMOTETAG);
					popupMenu.AppendMenuIcon(eCmd_DeleteRemoteTag | (pos << 16), temp, IDI_DELETE);
				}
			}
		}
		if(pTree->IsFrom(L"refs/heads"))
		{
			if(bAddSeparator)
				popupMenu.AppendMenu(MF_SEPARATOR);
			CString temp;
			temp.LoadString(IDS_MENUBRANCH);
			popupMenu.AppendMenuIcon(eCmd_CreateBranch, temp, IDI_COPY);
		}
		if(pTree->IsFrom(L"refs/tags"))
		{
			if(bAddSeparator)
				popupMenu.AppendMenu(MF_SEPARATOR);
			CString temp;
			temp.LoadString(IDS_MENUTAG);
			popupMenu.AppendMenuIcon(eCmd_CreateTag, temp, IDI_TAG);
			temp.LoadString(IDS_PROC_BROWSEREFS_DELETEALLTAGS);
			popupMenu.AppendMenuIcon(eCmd_DeleteAllTags, temp, IDI_DELETE);
			if (!remotes.empty())
			{
				popupMenu.AppendMenu(MF_SEPARATOR);
				int i = 0;
				for (auto it = remotes.cbegin(); it != remotes.cend(); ++it, ++i)
				{
					temp.Format(IDS_DELETEREMOTETAGON, (LPCTSTR)*it);
					popupMenu.AppendMenuIcon(eCmd_DeleteRemoteTag | (i << 16), temp, IDI_DELETE);
				}
			}
		}
	}


	int selection = popupMenu.TrackPopupMenuEx(TPM_LEFTALIGN | TPM_RETURNCMD, point.x, point.y, this, 0);
	switch ((eCmd)(selection & 0xFFFF))
	{
	case eCmd_ViewLog:
		{
			CLogDlg dlg;
			dlg.SetRange(g_Git.FixBranchName(selectedLeafs[0]->GetRefName()));
			dlg.DoModal();
		}
		break;
	case eCmd_ViewLogRange:
		{
			CLogDlg dlg;
			dlg.SetRange(GetTwoSelectedRefs(selectedLeafs, m_sLastSelected, _T("..")));
			dlg.DoModal();
		}
		break;
	case eCmd_ViewLogRangeReachableFromOnlyOne:
		{
			CLogDlg dlg;
			dlg.SetRange(GetTwoSelectedRefs(selectedLeafs, m_sLastSelected, _T("...")));
			dlg.DoModal();
		}
		break;
	case eCmd_RepoBrowser:
		CAppUtils::RunTortoiseGitProc(_T("/command:repobrowser /path:\"") + g_Git.m_CurrentDir + _T("\" /rev:") + selectedLeafs[0]->GetRefName());
		break;
	case eCmd_DeleteBranch:
	case eCmd_DeleteRemoteBranch:
		{
			if(ConfirmDeleteRef(selectedLeafs))
				DoDeleteRefs(selectedLeafs);
			Refresh();
		}
		break;
	case eCmd_DeleteTag:
		{
			if(ConfirmDeleteRef(selectedLeafs))
				DoDeleteRefs(selectedLeafs);
			Refresh();
		}
		break;
	case eCmd_ShowReflog:
		{
			CRefLogDlg refLogDlg(this);
			refLogDlg.m_CurrentBranch = selectedLeafs[0]->GetRefName();
			refLogDlg.DoModal();
		}
		break;
	case eCmd_Fetch:
		{
			CAppUtils::Fetch(remoteName);
			Refresh();
		}
		break;
	case eCmd_DeleteRemoteTag:
		{
			CDeleteRemoteTagDlg deleteRemoteTagDlg;
			int remoteInx = selection >> 16;
			if (remoteInx < 0 || remoteInx >= remotes.size())
				return;
			deleteRemoteTagDlg.m_sRemote = remotes[remoteInx];
			deleteRemoteTagDlg.DoModal();
		}
		break;
	case eCmd_Merge:
		{
			CString ref = selectedLeafs[0]->GetRefName();
			CAppUtils::Merge(&ref);
		}
		break;
	case eCmd_Switch:
		{
			CAppUtils::Switch(selectedLeafs[0]->GetRefName());
		}
		break;
	case eCmd_Rename:
		{
			POSITION pos = m_ListRefLeafs.GetFirstSelectedItemPosition();
			if(pos != NULL)
				m_ListRefLeafs.EditLabel(m_ListRefLeafs.GetNextSelectedItem(pos));
		}
		break;
	case eCmd_AddRemote:
		{
			CAddRemoteDlg(this).DoModal();
			Refresh();
		}
		break;
	case eCmd_ManageRemotes:
		{
			CSinglePropSheetDlg(CString(MAKEINTRESOURCE(IDS_PROCS_TITLE_GITREMOTESETTINGS)), new CSettingGitRemote(), this).DoModal();
//			CSettingGitRemote W_Remotes(m_cmdPath);
//			W_Remotes.DoModal();
			Refresh();
		}
		break;
	case eCmd_CreateBranch:
		{
			CString *commitHash = NULL;
			if (selectedLeafs.size() == 1)
				commitHash = &(selectedLeafs[0]->m_csRefHash);
			CAppUtils::CreateBranchTag(false, commitHash);
			Refresh();
		}
		break;
	case eCmd_CreateTag:
		{
			CAppUtils::CreateBranchTag(true);
			Refresh();
		}
		break;
	case eCmd_DeleteAllTags:
		{
			for (int i = 0; i < m_ListRefLeafs.GetItemCount(); ++i)
			{
				m_ListRefLeafs.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);
				selectedLeafs.push_back((CShadowTree*)m_ListRefLeafs.GetItemData(i));
			}
			if (ConfirmDeleteRef(selectedLeafs))
				DoDeleteRefs(selectedLeafs);
			Refresh();
		}
		break;
	case eCmd_Diff:
		{
			CFileDiffDlg dlg;
			dlg.SetDiff(
				NULL,
				selectedLeafs[1]->GetRefName() + L"^{}",
				selectedLeafs[0]->GetRefName() + L"^{}");
			dlg.DoModal();
		}
		break;
	case eCmd_UnifiedDiff:
		{
			CAppUtils::StartShowUnifiedDiff(nullptr, CTGitPath(), selectedLeafs[0]->m_csRefHash, CTGitPath(), selectedLeafs[1]->m_csRefHash);
		}
		break;
	case eCmd_EditBranchDescription:
		{
			CInputDlg dlg;
			dlg.m_sHintText.LoadString(IDS_PROC_BROWSEREFS_EDITDESCRIPTION);
			dlg.m_sInputText = selectedLeafs[0]->m_csDescription;
			dlg.m_sTitle.LoadString(IDS_PROC_BROWSEREFS_EDITDESCRIPTION);
			dlg.m_bUseLogWidth = true;
			if(dlg.DoModal() == IDOK)
			{
				CString key;
				key.Format(_T("branch.%s.description"), (LPCTSTR)selectedLeafs[0]->GetRefsHeadsName());
				dlg.m_sInputText.Replace(_T("\r"), _T(""));
				dlg.m_sInputText.Trim();
				if (dlg.m_sInputText.IsEmpty())
					g_Git.UnsetConfigValue(key);
				else
					g_Git.SetConfigValue(key, dlg.m_sInputText);
				Refresh();
			}
		}
		break;
	case eCmd_UpstreamDrop:
		{
			CString key;
			key.Format(_T("branch.%s.remote"), (LPCTSTR)selectedLeafs[0]->GetRefsHeadsName());
			g_Git.UnsetConfigValue(key);
			key.Format(_T("branch.%s.merge"), (LPCTSTR)selectedLeafs[0]->GetRefsHeadsName());
			g_Git.UnsetConfigValue(key);
		}
		Refresh();
		break;
	case eCmd_UpstreamSet:
		{
			CString newRef = CBrowseRefsDlg::PickRef(false, _T(""), gPickRef_Remote, false);
			if (newRef.IsEmpty() || newRef.Find(_T("refs/remotes/")) != 0)
				return;
			CString remote, branch;
			if (SplitRemoteBranchName(newRef, remote, branch))
				return;
			CString key;
			key.Format(_T("branch.%s.remote"), (LPCTSTR)selectedLeafs[0]->GetRefsHeadsName());
			g_Git.SetConfigValue(key, remote);
			key.Format(_T("branch.%s.merge"), (LPCTSTR)selectedLeafs[0]->GetRefsHeadsName());
			g_Git.SetConfigValue(key, _T("refs/heads/") + branch);
			Refresh();
		}
		break;
	}
}
void CBrowseRefsDlg::ShowContextMenu(CPoint point, HTREEITEM hTreePos, VectorPShadowTree& selectedLeafs)
{
	CIconMenu popupMenu;
	popupMenu.CreatePopupMenu();

	bool bAddSeparator = false;
	CString remoteName;

	if(selectedLeafs.size()==1)
	{
		bAddSeparator = true;

		bool bShowReflogOption				= false;
		bool bShowFetchOption				= false;
		bool bShowSwitchOption				= false;
		bool bShowRenameOption				= false;
		bool bShowCreateBranchOption		= false;
		bool bShowEditBranchDescriptionOption = false;

		CString fetchFromCmd;

		if(selectedLeafs[0]->IsFrom(L"refs/heads"))
		{
			bShowReflogOption = true;
			bShowSwitchOption = true;
			bShowRenameOption = true;
			bShowEditBranchDescriptionOption = true;
		}
		else if(selectedLeafs[0]->IsFrom(L"refs/remotes"))
		{
			bShowReflogOption = true;
			bShowFetchOption  = true;
			bShowCreateBranchOption = true;

			int dummy = 0;//Needed for tokenize
			remoteName = selectedLeafs[0]->GetRefName();
			remoteName = remoteName.Mid(13);
			remoteName = remoteName.Tokenize(L"/", dummy);
			fetchFromCmd.Format(IDS_PROC_BROWSEREFS_FETCHFROM, remoteName);
		}
		else if(selectedLeafs[0]->IsFrom(L"refs/tags"))
		{
		}

		CString temp;
		temp.LoadString(IDS_MENULOG);
		popupMenu.AppendMenuIcon(eCmd_ViewLog, temp, IDI_LOG);
		popupMenu.AppendMenuIcon(eCmd_RepoBrowser, IDS_LOG_BROWSEREPO, IDI_REPOBROWSE);
		if(bShowReflogOption)
		{
			temp.LoadString(IDS_MENUREFLOG);
			popupMenu.AppendMenuIcon(eCmd_ShowReflog, temp, IDI_LOG);
		}

		popupMenu.AppendMenu(MF_SEPARATOR);
		bAddSeparator = false;

		if(bShowFetchOption)
		{
			bAddSeparator = true;
			popupMenu.AppendMenuIcon(eCmd_Fetch, fetchFromCmd, IDI_PULL);
		}

		if(bAddSeparator)
			popupMenu.AppendMenu(MF_SEPARATOR);

		bAddSeparator = false;
		if (m_bHasWC)
		{
			popupMenu.AppendMenuIcon(eCmd_Switch, CString(MAKEINTRESOURCE(IDS_SWITCH_TO_THIS)), IDI_SWITCH);
			popupMenu.AppendMenu(MF_SEPARATOR);
		}

		if(bShowCreateBranchOption)
		{
			bAddSeparator = true;
			temp.LoadString(IDS_MENUBRANCH);
			popupMenu.AppendMenuIcon(eCmd_CreateBranch, temp, IDI_COPY);
		}

		if (bShowEditBranchDescriptionOption)
		{
			bAddSeparator = true;
			popupMenu.AppendMenuIcon(eCmd_EditBranchDescription, CString(MAKEINTRESOURCE(IDS_PROC_BROWSEREFS_EDITDESCRIPTION)), IDI_RENAME);
		}
		if(bShowRenameOption)
		{
			bAddSeparator = true;
			popupMenu.AppendMenuIcon(eCmd_Rename, CString(MAKEINTRESOURCE(IDS_PROC_BROWSEREFS_RENAME)), IDI_RENAME);
		}
	}
	else if(selectedLeafs.size() == 2)
	{
		bAddSeparator = true;
		popupMenu.AppendMenuIcon(eCmd_Diff, CString(MAKEINTRESOURCE(IDS_PROC_BROWSEREFS_COMPAREREFS)), IDI_DIFF);
	}

	if(!selectedLeafs.empty())
	{
		if(AreAllFrom(selectedLeafs, L"refs/remotes/"))
		{
			if(bAddSeparator)
				popupMenu.AppendMenu(MF_SEPARATOR);
			CString menuItemName;
			if(selectedLeafs.size() == 1)
				menuItemName.LoadString(IDS_PROC_BROWSEREFS_DELETEREMOTEBRANCH);
			else
				menuItemName.Format(IDS_PROC_BROWSEREFS_DELETEREMOTEBRANCHES, selectedLeafs.size());

			popupMenu.AppendMenuIcon(eCmd_DeleteRemoteBranch, menuItemName, IDI_DELETE);
			bAddSeparator = true;
		}
		else if(AreAllFrom(selectedLeafs, L"refs/heads/"))
		{
			if(bAddSeparator)
				popupMenu.AppendMenu(MF_SEPARATOR);
			CString menuItemName;
			if(selectedLeafs.size() == 1)
				menuItemName.LoadString(IDS_PROC_BROWSEREFS_DELETEBRANCH);
			else
				menuItemName.Format(IDS_PROC_BROWSEREFS_DELETEBRANCHES, selectedLeafs.size());

			popupMenu.AppendMenuIcon(eCmd_DeleteBranch, menuItemName, IDI_DELETE);
			bAddSeparator = true;
		}
		else if(AreAllFrom(selectedLeafs, L"refs/tags/"))
		{
			if(bAddSeparator)
				popupMenu.AppendMenu(MF_SEPARATOR);
			CString menuItemName;
			if(selectedLeafs.size() == 1)
				menuItemName.LoadString(IDS_PROC_BROWSEREFS_DELETETAG);
			else
				menuItemName.Format(IDS_PROC_BROWSEREFS_DELETETAGS, selectedLeafs.size());

			popupMenu.AppendMenuIcon(eCmd_DeleteTag, menuItemName, IDI_DELETE);
			bAddSeparator = true;
		}
	}


	if(hTreePos!=NULL && selectedLeafs.empty())
	{
		CShadowTree* pTree=(CShadowTree*)m_RefTreeCtrl.GetItemData(hTreePos);
		if(pTree->IsFrom(L"refs/remotes"))
		{
			if(bAddSeparator)
				popupMenu.AppendMenu(MF_SEPARATOR);
			popupMenu.AppendMenuIcon(eCmd_ManageRemotes, CString(MAKEINTRESOURCE(IDS_PROC_BROWSEREFS_MANAGEREMOTES)), IDI_SETTINGS);
			bAddSeparator = true;
			if(selectedLeafs.empty())
			{
				int dummy = 0;//Needed for tokenize
				remoteName = pTree->GetRefName();
				remoteName = remoteName.Mid(13);
				remoteName = remoteName.Tokenize(L"/", dummy);
				if(!remoteName.IsEmpty())
				{
					CString temp;
					temp.Format(IDS_PROC_BROWSEREFS_FETCHFROM, remoteName);
					popupMenu.AppendMenuIcon(eCmd_Fetch, temp, IDI_PULL);

					temp.LoadString(IDS_DELETEREMOTETAG);
					popupMenu.AppendMenuIcon(eCmd_DeleteRemoteTag, temp, IDI_DELETE);
				}
			}
		}
		if(pTree->IsFrom(L"refs/heads"))
		{
			if(bAddSeparator)
				popupMenu.AppendMenu(MF_SEPARATOR);
			CString temp;
			temp.LoadString(IDS_MENUBRANCH);
			popupMenu.AppendMenuIcon(eCmd_CreateBranch, temp, IDI_COPY);
		}
		if(pTree->IsFrom(L"refs/tags"))
		{
			if(bAddSeparator)
				popupMenu.AppendMenu(MF_SEPARATOR);
			CString temp;
			temp.LoadString(IDS_MENUTAG);
			popupMenu.AppendMenuIcon(eCmd_CreateTag, temp, IDI_TAG);
		}
	}


	eCmd cmd=(eCmd)popupMenu.TrackPopupMenuEx(TPM_LEFTALIGN|TPM_RETURNCMD, point.x, point.y, this, 0);
	switch(cmd)
	{
	case eCmd_ViewLog:
		{
			CLogDlg dlg;
			dlg.SetStartRef(selectedLeafs[0]->GetRefName());
			dlg.DoModal();
		}
		break;
	case eCmd_RepoBrowser:
		CAppUtils::RunTortoiseProc(_T("/command:repobrowser /path:\"") + g_Git.m_CurrentDir + _T("\" /rev:") + selectedLeafs[0]->GetRefName());
		break;
	case eCmd_DeleteBranch:
	case eCmd_DeleteRemoteBranch:
		{
			if(ConfirmDeleteRef(selectedLeafs))
				DoDeleteRefs(selectedLeafs, true);
			Refresh();
		}
		break;
	case eCmd_DeleteTag:
		{
			if(ConfirmDeleteRef(selectedLeafs))
				DoDeleteRefs(selectedLeafs, true);
			Refresh();
		}
		break;
	case eCmd_ShowReflog:
		{
			CRefLogDlg refLogDlg(this);
			refLogDlg.m_CurrentBranch = selectedLeafs[0]->GetRefName();
			refLogDlg.DoModal();
		}
		break;
	case eCmd_Fetch:
		{
			CAppUtils::Fetch(remoteName);
			Refresh();
		}
		break;
	case eCmd_DeleteRemoteTag:
		{
			CDeleteRemoteTagDlg deleteRemoteTagDlg;
			deleteRemoteTagDlg.m_sRemote = remoteName;
			deleteRemoteTagDlg.DoModal();
		}
		break;
	case eCmd_Switch:
		{
			CAppUtils::Switch(selectedLeafs[0]->GetRefName());
		}
		break;
	case eCmd_Rename:
		{
			POSITION pos = m_ListRefLeafs.GetFirstSelectedItemPosition();
			if(pos != NULL)
				m_ListRefLeafs.EditLabel(m_ListRefLeafs.GetNextSelectedItem(pos));
		}
		break;
	case eCmd_AddRemote:
		{
			CAddRemoteDlg(this).DoModal();
			Refresh();
		}
		break;
	case eCmd_ManageRemotes:
		{
			CSinglePropSheetDlg(CString(MAKEINTRESOURCE(IDS_PROCS_TITLE_GITREMOTESETTINGS)), new CSettingGitRemote(g_Git.m_CurrentDir), this).DoModal();
//			CSettingGitRemote W_Remotes(m_cmdPath);
//			W_Remotes.DoModal();
			Refresh();
		}
		break;
	case eCmd_CreateBranch:
		{
			CString *commitHash = NULL;
			if (selectedLeafs.size() == 1)
				commitHash = &(selectedLeafs[0]->m_csRefHash);
			CAppUtils::CreateBranchTag(false, commitHash);
			Refresh();
		}
		break;
	case eCmd_CreateTag:
		{
			CAppUtils::CreateBranchTag(true);
			Refresh();
		}
		break;
	case eCmd_Diff:
		{
			CFileDiffDlg dlg;
			dlg.SetDiff(
				NULL,
				selectedLeafs[0]->m_csRefHash,
				selectedLeafs[1]->m_csRefHash);
			dlg.DoModal();
		}
		break;
	case eCmd_EditBranchDescription:
		{
			CInputDlg dlg;
			dlg.m_sHintText = CString(MAKEINTRESOURCE(IDS_PROC_BROWSEREFS_EDITDESCRIPTION));
			dlg.m_sInputText = selectedLeafs[0]->m_csDescription;
			dlg.m_sTitle = CString(MAKEINTRESOURCE(IDS_PROC_BROWSEREFS_EDITDESCRIPTION));
			dlg.m_bUseLogWidth = true;
			if(dlg.DoModal() == IDOK)
			{
				CString key;
				key.Format(_T("branch.%s.description"), selectedLeafs[0]->m_csRefName);
				dlg.m_sInputText.Replace(_T("\r"), _T(""));
				dlg.m_sInputText.Trim();
				if (dlg.m_sInputText.IsEmpty())
					g_Git.UnsetConfigValue(key);
				else
					g_Git.SetConfigValue(key, dlg.m_sInputText);
				Refresh();
			}
		}
		break;
	}
}