--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2008 - TortoiseSVN\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#include "stdafx.h"\r
+#include "BugTraqAssociations.h"\r
+\r
+#include <initguid.h>\r
+\r
+// {3494FA92-B139-4730-9591-01135D5E7831}\r
+DEFINE_GUID(CATID_BugTraqProvider, \r
+ 0x3494fa92, 0xb139, 0x4730, 0x95, 0x91, 0x1, 0x13, 0x5d, 0x5e, 0x78, 0x31);\r
+\r
+#define BUGTRAQ_ASSOCIATIONS_REGPATH _T("Software\\TortoiseSVN\\BugTraq Associations")\r
+\r
+CBugTraqAssociations::~CBugTraqAssociations()\r
+{\r
+ for (inner_t::iterator it = m_inner.begin(); it != m_inner.end(); ++it)\r
+ delete *it;\r
+}\r
+\r
+void CBugTraqAssociations::Load()\r
+{\r
+ HKEY hk;\r
+ if (RegOpenKeyEx(HKEY_CURRENT_USER, BUGTRAQ_ASSOCIATIONS_REGPATH, 0, KEY_READ, &hk) != ERROR_SUCCESS)\r
+ return;\r
+\r
+ for (DWORD dwIndex = 0; /* nothing */; ++dwIndex)\r
+ {\r
+ TCHAR szSubKey[MAX_PATH];\r
+ DWORD cchSubKey = MAX_PATH;\r
+ LSTATUS status = RegEnumKeyEx(hk, dwIndex, szSubKey, &cchSubKey, NULL, NULL, NULL, NULL);\r
+ if (status != ERROR_SUCCESS)\r
+ break;\r
+\r
+ HKEY hk2;\r
+ if (RegOpenKeyEx(hk, szSubKey, 0, KEY_READ, &hk2) == ERROR_SUCCESS)\r
+ {\r
+ TCHAR szWorkingCopy[MAX_PATH];\r
+ DWORD cbWorkingCopy = sizeof(szWorkingCopy);\r
+ RegQueryValueEx(hk2, _T("WorkingCopy"), NULL, NULL, (LPBYTE)szWorkingCopy, &cbWorkingCopy);\r
+\r
+ TCHAR szClsid[MAX_PATH];\r
+ DWORD cbClsid = sizeof(szClsid);\r
+ RegQueryValueEx(hk2, _T("Provider"), NULL, NULL, (LPBYTE)szClsid, &cbClsid);\r
+\r
+ CLSID provider_clsid;\r
+ CLSIDFromString(szClsid, &provider_clsid);\r
+\r
+ DWORD cbParameters = 0;\r
+ RegQueryValueEx(hk2, _T("Parameters"), NULL, NULL, (LPBYTE)NULL, &cbParameters);\r
+ TCHAR * szParameters = new TCHAR[cbParameters+1];\r
+ RegQueryValueEx(hk2, _T("Parameters"), NULL, NULL, (LPBYTE)szParameters, &cbParameters);\r
+ szParameters[cbParameters] = 0;\r
+ m_inner.push_back(new CBugTraqAssociation(szWorkingCopy, provider_clsid, LookupProviderName(provider_clsid), szParameters));\r
+ delete [] szParameters;\r
+\r
+ RegCloseKey(hk2);\r
+ }\r
+ }\r
+\r
+ RegCloseKey(hk);\r
+}\r
+\r
+void CBugTraqAssociations::Add(const CBugTraqAssociation &assoc)\r
+{\r
+ m_inner.push_back(new CBugTraqAssociation(assoc));\r
+}\r
+\r
+bool CBugTraqAssociations::FindProvider(const CTSVNPathList &pathList, CBugTraqAssociation *assoc) const\r
+{\r
+ return FindProviderForPathList(pathList, assoc);\r
+}\r
+\r
+bool CBugTraqAssociations::FindProviderForPathList(const CTSVNPathList &pathList, CBugTraqAssociation *assoc) const\r
+{\r
+ for (int i = 0; i < pathList.GetCount(); ++i)\r
+ {\r
+ CTSVNPath path = pathList[i];\r
+ if (FindProviderForPath(path, assoc))\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+}\r
+\r
+bool CBugTraqAssociations::FindProviderForPath(CTSVNPath path, CBugTraqAssociation *assoc) const\r
+{\r
+ do\r
+ {\r
+ inner_t::const_iterator it = std::find_if(m_inner.begin(), m_inner.end(), FindByPathPred(path));\r
+ if (it != m_inner.end())\r
+ {\r
+ *assoc = *(*it);\r
+ return true;\r
+ }\r
+ \r
+ path = path.GetContainingDirectory();\r
+ } while(!path.IsEmpty());\r
+\r
+ return false;\r
+}\r
+\r
+/* static */\r
+CString CBugTraqAssociations::LookupProviderName(const CLSID &provider_clsid)\r
+{\r
+ OLECHAR szClsid[40];\r
+ StringFromGUID2(provider_clsid, szClsid, ARRAYSIZE(szClsid));\r
+\r
+ TCHAR szSubKey[MAX_PATH];\r
+ _stprintf_s(szSubKey, _T("CLSID\\%ls"), szClsid);\r
+ \r
+ CString provider_name = CString(szClsid);\r
+\r
+ HKEY hk;\r
+ if (RegOpenKeyEx(HKEY_CLASSES_ROOT, szSubKey, 0, KEY_READ, &hk) == ERROR_SUCCESS)\r
+ {\r
+ TCHAR szClassName[MAX_PATH];\r
+ DWORD cbClassName = sizeof(szClassName);\r
+\r
+ if (RegQueryValueEx(hk, NULL, NULL, NULL, (LPBYTE)szClassName, &cbClassName) == ERROR_SUCCESS)\r
+ provider_name = CString(szClassName);\r
+\r
+ RegCloseKey(hk);\r
+ }\r
+\r
+ return provider_name;\r
+}\r
+\r
+LSTATUS RegSetValueFromCString(HKEY hKey, LPCTSTR lpValueName, CString str)\r
+{\r
+ LPCTSTR lpsz = str;\r
+ DWORD cb = (str.GetLength() + 1) * sizeof(TCHAR);\r
+ return RegSetValueEx(hKey, lpValueName, 0, REG_SZ, (const BYTE *)lpsz, cb);\r
+}\r
+\r
+void CBugTraqAssociations::Save() const\r
+{\r
+ SHDeleteKey(HKEY_CURRENT_USER, BUGTRAQ_ASSOCIATIONS_REGPATH);\r
+\r
+ HKEY hk;\r
+ if (RegCreateKeyEx(HKEY_CURRENT_USER, BUGTRAQ_ASSOCIATIONS_REGPATH, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hk, NULL) != ERROR_SUCCESS)\r
+ return;\r
+\r
+ DWORD dwIndex = 0;\r
+ for (const_iterator it = begin(); it != end(); ++it)\r
+ {\r
+ TCHAR szSubKey[MAX_PATH];\r
+ _stprintf_s(szSubKey, _T("%d"), dwIndex);\r
+\r
+ HKEY hk2;\r
+ if (RegCreateKeyEx(hk, szSubKey, 0, NULL, 0, KEY_WRITE, NULL, &hk2, NULL) == ERROR_SUCCESS)\r
+ {\r
+ RegSetValueFromCString(hk2, _T("Provider"), (*it)->GetProviderClassAsString());\r
+ RegSetValueFromCString(hk2, _T("WorkingCopy"), (*it)->GetPath().GetWinPath());\r
+ RegSetValueFromCString(hk2, _T("Parameters"), (*it)->GetParameters());\r
+ \r
+ RegCloseKey(hk2);\r
+ }\r
+\r
+ ++dwIndex;\r
+ }\r
+\r
+ RegCloseKey(hk);\r
+}\r
+\r
+void CBugTraqAssociations::RemoveByPath(const CTSVNPath &path)\r
+{\r
+ inner_t::iterator it = std::find_if(m_inner.begin(), m_inner.end(), FindByPathPred(path));\r
+ if (it != m_inner.end())\r
+ {\r
+ delete *it;\r
+ m_inner.erase(it);\r
+ }\r
+}\r
+\r
+CString CBugTraqAssociation::GetProviderClassAsString() const\r
+{\r
+ OLECHAR szTemp[40];\r
+ StringFromGUID2(m_provider.clsid, szTemp, ARRAYSIZE(szTemp));\r
+\r
+ return CString(szTemp);\r
+}\r
+\r
+/* static */\r
+std::vector<CBugTraqProvider> CBugTraqAssociations::GetAvailableProviders()\r
+{\r
+ std::vector<CBugTraqProvider> results;\r
+\r
+ ICatInformation *pCatInformation = NULL;\r
+\r
+ HRESULT hr;\r
+ if (SUCCEEDED(hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_ALL, IID_ICatInformation, (void **)&pCatInformation)))\r
+ {\r
+ IEnumGUID *pEnum = NULL;\r
+ if (SUCCEEDED(hr = pCatInformation->EnumClassesOfCategories(1, &CATID_BugTraqProvider, 0, NULL, &pEnum)))\r
+ {\r
+ HRESULT hrEnum;\r
+ do\r
+ {\r
+ CLSID clsids[5];\r
+ ULONG cClsids;\r
+\r
+ hrEnum = pEnum->Next(ARRAYSIZE(clsids), clsids, &cClsids);\r
+ if (SUCCEEDED(hrEnum))\r
+ {\r
+ for (ULONG i = 0; i < cClsids; ++i)\r
+ {\r
+ CBugTraqProvider provider;\r
+ provider.clsid = clsids[i];\r
+ provider.name = LookupProviderName(clsids[i]);\r
+ results.push_back(provider);\r
+ }\r
+ }\r
+ } while (hrEnum == S_OK);\r
+ }\r
+\r
+ if (pEnum)\r
+ pEnum->Release();\r
+ pEnum = NULL;\r
+ }\r
+\r
+ if (pCatInformation)\r
+ pCatInformation->Release();\r
+ pCatInformation = NULL;\r
+\r
+ return results;\r
+}\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2008 - TortoiseSVN\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#pragma once\r
+#include "TSVNPath.h"\r
+\r
+struct CBugTraqProvider\r
+{\r
+ CLSID clsid;\r
+ CString name;\r
+};\r
+\r
+/* TODO: It's less of an association and more of a "token" or "memento".\r
+ */\r
+class CBugTraqAssociation\r
+{\r
+ CTSVNPath m_path;\r
+ CBugTraqProvider m_provider;\r
+ CString m_parameters;\r
+\r
+public:\r
+ CBugTraqAssociation()\r
+ {\r
+ m_provider.clsid = GUID_NULL;\r
+ }\r
+\r
+ CBugTraqAssociation(LPCTSTR szWorkingCopy, const CLSID &provider_clsid, LPCTSTR szProviderName, LPCTSTR szParameters)\r
+ : m_path(szWorkingCopy), m_parameters(szParameters)\r
+ {\r
+ m_provider.clsid = provider_clsid;\r
+ m_provider.name = szProviderName;\r
+ }\r
+\r
+ const CTSVNPath &GetPath() const { return m_path; }\r
+ CString GetProviderName() const { return m_provider.name; }\r
+ CLSID GetProviderClass() const { return m_provider.clsid; }\r
+ CString GetProviderClassAsString() const;\r
+ CString GetParameters() const { return m_parameters; }\r
+};\r
+\r
+class CBugTraqAssociations\r
+{\r
+ typedef std::vector< CBugTraqAssociation * > inner_t;\r
+ inner_t m_inner;\r
+\r
+public:\r
+ ~CBugTraqAssociations();\r
+\r
+ void Load();\r
+ void Save() const;\r
+\r
+ void Add(const CBugTraqAssociation &assoc);\r
+ void RemoveByPath(const CTSVNPath &path);\r
+\r
+ bool FindProvider(const CTSVNPathList &pathList, CBugTraqAssociation *assoc) const;\r
+\r
+ typedef inner_t::const_iterator const_iterator;\r
+ const_iterator begin() const { return m_inner.begin(); }\r
+ const_iterator end() const { return m_inner.end(); }\r
+\r
+ static std::vector<CBugTraqProvider> GetAvailableProviders();\r
+ static CString LookupProviderName(const CLSID &provider_clsid);\r
+\r
+private:\r
+ bool FindProviderForPathList(const CTSVNPathList &pathList, CBugTraqAssociation *assoc) const;\r
+ bool FindProviderForPath(CTSVNPath path, CBugTraqAssociation *assoc) const;\r
+\r
+ struct FindByPathPred\r
+ {\r
+ const CTSVNPath &m_path;\r
+\r
+ FindByPathPred(const CTSVNPath &path)\r
+ : m_path(path) { }\r
+\r
+ bool operator() (const CBugTraqAssociation *assoc) const\r
+ {\r
+ return (assoc->GetPath().IsEquivalentToWithoutCase(m_path));\r
+ }\r
+ };\r
+};\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2006 - Stefan Kueng\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#include "stdafx.h"\r
+#include "CmdLineParser.h"\r
+#include <locale>\r
+#include <algorithm>\r
+\r
+const TCHAR CCmdLineParser::m_sDelims[] = _T("-/");\r
+const TCHAR CCmdLineParser::m_sQuotes[] = _T("\"");\r
+const TCHAR CCmdLineParser::m_sValueSep[] = _T(" :"); // don't forget space!!\r
+\r
+\r
+CCmdLineParser::CCmdLineParser(LPCTSTR sCmdLine)\r
+{\r
+ if(sCmdLine) \r
+ {\r
+ Parse(sCmdLine);\r
+ }\r
+}\r
+\r
+CCmdLineParser::~CCmdLineParser()\r
+{\r
+ m_valueMap.clear();\r
+}\r
+\r
+BOOL CCmdLineParser::Parse(LPCTSTR sCmdLine) \r
+{\r
+ const stdstring sEmpty = _T(""); //use this as a value if no actual value is given in commandline\r
+ int nArgs = 0;\r
+\r
+ if(!sCmdLine) \r
+ return false;\r
+ \r
+ m_valueMap.clear();\r
+ m_sCmdLine = sCmdLine;\r
+\r
+ LPCTSTR sCurrent = sCmdLine;\r
+\r
+ for(;;)\r
+ {\r
+ //format is -Key:"arg"\r
+ \r
+ if (_tcslen(sCurrent) == 0)\r
+ break; // no more data, leave loop\r
+\r
+ LPCTSTR sArg = _tcspbrk(sCurrent, m_sDelims);\r
+ if(!sArg) \r
+ break; // no (more) delimiters found\r
+ sArg = _tcsinc(sArg);\r
+\r
+ if(_tcslen(sArg) == 0) \r
+ break; // ends with delim\r
+ \r
+ LPCTSTR sVal = _tcspbrk(sArg, m_sValueSep);\r
+ if(sVal == NULL) \r
+ { \r
+ stdstring Key(sArg);\r
+ std::transform(Key.begin(), Key.end(), Key.begin(), ::tolower);\r
+ m_valueMap.insert(CValsMap::value_type(Key, sEmpty));\r
+ break;\r
+ } \r
+ else if (sVal[0] == _T(' ') || _tcslen(sVal) == 1 ) \r
+ { \r
+ // cmdline ends with /Key: or a key with no value \r
+ stdstring Key(sArg, (int)(sVal - sArg));\r
+ if(!Key.empty()) \r
+ { \r
+ std::transform(Key.begin(), Key.end(), Key.begin(), ::tolower);\r
+ m_valueMap.insert(CValsMap::value_type(Key, sEmpty));\r
+ }\r
+ sCurrent = _tcsinc(sVal);\r
+ continue;\r
+ }\r
+ else \r
+ { \r
+ // key has value\r
+ stdstring Key(sArg, (int)(sVal - sArg));\r
+ std::transform(Key.begin(), Key.end(), Key.begin(), ::tolower);\r
+\r
+ sVal = _tcsinc(sVal);\r
+\r
+ LPCTSTR sQuote = _tcspbrk(sVal, m_sQuotes), sEndQuote(NULL);\r
+ if(sQuote == sVal) \r
+ { \r
+ // string with quotes (defined in m_sQuotes, e.g. '")\r
+ sQuote = _tcsinc(sVal);\r
+ sEndQuote = _tcspbrk(sQuote, m_sQuotes);\r
+ } \r
+ else \r
+ {\r
+ sQuote = sVal;\r
+ sEndQuote = _tcschr(sQuote, _T(' '));\r
+ }\r
+\r
+ if(sEndQuote == NULL) \r
+ { \r
+ // no end quotes or terminating space, take the rest of the string to its end\r
+ stdstring csVal(sQuote);\r
+ if(!Key.empty()) \r
+ { \r
+ m_valueMap.insert(CValsMap::value_type(Key, csVal));\r
+ }\r
+ break;\r
+ } \r
+ else \r
+ { \r
+ // end quote\r
+ if(!Key.empty()) \r
+ { \r
+ stdstring csVal(sQuote, (int)(sEndQuote - sQuote));\r
+ m_valueMap.insert(CValsMap::value_type(Key, csVal));\r
+ }\r
+ sCurrent = _tcsinc(sEndQuote);\r
+ continue;\r
+ }\r
+ }\r
+ }\r
+ \r
+ return (nArgs > 0); //TRUE if arguments were found\r
+}\r
+\r
+CCmdLineParser::CValsMap::const_iterator CCmdLineParser::findKey(LPCTSTR sKey) const \r
+{\r
+ stdstring s(sKey);\r
+ std::transform(s.begin(), s.end(), s.begin(), ::tolower);\r
+ return m_valueMap.find(s);\r
+}\r
+\r
+BOOL CCmdLineParser::HasKey(LPCTSTR sKey) const \r
+{\r
+ CValsMap::const_iterator it = findKey(sKey);\r
+ if(it == m_valueMap.end()) \r
+ return false;\r
+ return true;\r
+}\r
+\r
+\r
+BOOL CCmdLineParser::HasVal(LPCTSTR sKey) const \r
+{\r
+ CValsMap::const_iterator it = findKey(sKey);\r
+ if(it == m_valueMap.end()) \r
+ return false;\r
+ if(it->second.empty()) \r
+ return false;\r
+ return true;\r
+}\r
+\r
+LPCTSTR CCmdLineParser::GetVal(LPCTSTR sKey) const \r
+{\r
+ CValsMap::const_iterator it = findKey(sKey);\r
+ if (it == m_valueMap.end()) \r
+ return 0;\r
+ return it->second.c_str();\r
+}\r
+\r
+LONG CCmdLineParser::GetLongVal(LPCTSTR sKey) const\r
+{\r
+ CValsMap::const_iterator it = findKey(sKey);\r
+ if (it == m_valueMap.end())\r
+ return 0;\r
+ return _tstol(it->second.c_str());\r
+}\r
+\r
+\r
+CCmdLineParser::ITERPOS CCmdLineParser::begin() const \r
+{\r
+ return m_valueMap.begin();\r
+}\r
+\r
+CCmdLineParser::ITERPOS CCmdLineParser::getNext(ITERPOS& pos, stdstring& sKey, stdstring& sValue) const \r
+{\r
+ if (m_valueMap.end() == pos)\r
+ {\r
+ sKey.clear();\r
+ return pos;\r
+ } \r
+ else \r
+ {\r
+ sKey = pos->first;\r
+ sValue = pos->second;\r
+ pos ++;\r
+ return pos;\r
+ }\r
+}\r
+\r
+BOOL CCmdLineParser::isLast(const ITERPOS& pos) const \r
+{\r
+ return (pos == m_valueMap.end());\r
+}\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2007 - Stefan Kueng\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#pragma once\r
+#include <map>\r
+#include <string>\r
+\r
+using std::map;\r
+\r
+#pragma warning (push,1)\r
+typedef std::wstring wide_string;\r
+#ifndef stdstring\r
+#ifdef UNICODE\r
+# define stdstring wide_string\r
+#else\r
+# define stdstring std::string\r
+#endif\r
+#endif\r
+#pragma warning (pop)\r
+\r
+/**\r
+ * \ingroup Utils\r
+ *\r
+ * A helper class for parsing command lines.\r
+ * It provides methods to extract 'key' and 'value'\r
+ * pairs of the form -keyname:value or /keyname:value.\r
+ * Parameter examples:\n\r
+ * \code\r
+ * "/key1 /key2:myvalue -key3:anothervalue -key4:"this could be a path with spaces"\r
+ * \endcode\r
+ * /key is the same as -key\n\r
+ * all keys and values are case-insensitive.\r
+ * Please note that both keys and values are strings although the class\r
+ * provides a method to get a long as a value.\r
+ * Example:\n\r
+ * \code\r
+ * CCmdLineParser parser(::GetCommandLine());\r
+ * if (parser.HasKey("r"))\r
+ * {\r
+ * // the key -r or /r is there (could mean e.g. 'recurse')\r
+ * }\r
+ * //now assume the command line is /open:"c:\test.txt" /wait:30\r
+ * CString file = parser.GetVal("open");\r
+ * //file contains now c:\test.txt\r
+ * long number = parser.GetLongVal("seconds");\r
+ * //number has now the value 30\r
+ * \endcode\r
+ */\r
+class CCmdLineParser \r
+{\r
+public:\r
+ typedef map<stdstring, stdstring> CValsMap;\r
+ typedef CValsMap::const_iterator ITERPOS;\r
+public:\r
+ /**\r
+ * Creates a CCmdLineParser object and parses the parameters in.\r
+ * \param sCmdLine the command line\r
+ */\r
+ CCmdLineParser(LPCTSTR sCmdLine = NULL);\r
+ virtual ~CCmdLineParser();\r
+\r
+ /**\r
+ * returns the command line string this object was created on.\r
+ * \return the command line\r
+ */\r
+ LPCTSTR getCmdLine() const { return m_sCmdLine.c_str(); }\r
+\r
+ /**\r
+ * Starts an iteration over all command line parameters.\r
+ * \return the first position\r
+ */\r
+ ITERPOS begin() const; \r
+\r
+ /**\r
+ * Get the next key/value pair. If no more keys are available then\r
+ * an empty key is returned.\r
+ * \param the position from where to get. To get the first pair use the\r
+ * begin() method. \a pos is incremented by 1 on return.\r
+ * \param sKey returns the key\r
+ * \param sValue returns the value\r
+ * \return the next position\r
+ */\r
+ ITERPOS getNext(ITERPOS& pos, stdstring& sKey, stdstring& sValue) const;\r
+ \r
+ /**\r
+ * Checks if the position is the last or if there are more key/value pairs in the command line.\r
+ * \param pos the position to check\r
+ * \return TRUE if no more key/value pairs are available\r
+ */\r
+ BOOL isLast(const ITERPOS& pos) const;\r
+\r
+ /**\r
+ * Checks if the given key is in the command line.\r
+ * \param sKey the key to check for\r
+ * \return TRUE if the key exists, FALSE if the key is not in command line\r
+ */\r
+ BOOL HasKey(LPCTSTR sKey) const;\r
+\r
+ /**\r
+ * Checks if a key also has a value or not.\r
+ * \param sKey the key to check for a value\r
+ * \return TRUE if the key has a value, FALSE if no value (or no key) was found\r
+ */\r
+ BOOL HasVal(LPCTSTR sKey) const;\r
+\r
+ /**\r
+ * Reads the value for a key. If the key has no value then NULL is returned.\r
+ * \param sKey the key to get the value from\r
+ * \return the value string of the key\r
+ */\r
+ LPCTSTR GetVal(LPCTSTR sKey) const;\r
+ \r
+ /**\r
+ * Reads the value for a key as a long. If the value is a string which can't be\r
+ * converted to a number then 0 is returned.\r
+ * \param the key to get the value from\r
+ * \return the value converted to a long\r
+ */\r
+ LONG GetLongVal(LPCTSTR sKey) const;\r
+\r
+private:\r
+ BOOL Parse(LPCTSTR sCmdLine);\r
+ CValsMap::const_iterator findKey(LPCTSTR sKey) const;\r
+ const CValsMap& getVals() const { return m_valueMap; }\r
+private:\r
+ stdstring m_sCmdLine;\r
+ CValsMap m_valueMap;\r
+\r
+ static const TCHAR m_sDelims[];\r
+ static const TCHAR m_sValueSep[];\r
+ static const TCHAR m_sQuotes[];\r
+};\r
+\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2007 - TortoiseSVN\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#include "Debug.h"\r
+#include <tchar.h>\r
+\r
+#if defined(_DEBUG) || defined(DEBUG)\r
+#include <stdlib.h>\r
+#include <stdarg.h>\r
+void TRACE(LPCTSTR str, ...)\r
+{\r
+ static TCHAR buf[20*1024];\r
+\r
+ va_list ap;\r
+ va_start(ap, str);\r
+\r
+ _vstprintf_s(buf, 20*1024, str, ap);\r
+ OutputDebugString(buf);\r
+ va_end(ap);\r
+\r
+};\r
+#else\r
+void TRACE(LPCTSTR str, ...) {UNREFERENCED_PARAMETER(str);}\r
+#endif
\ No newline at end of file
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2007 - TortoiseSVN\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#pragma once\r
+#include <Windows.h>\r
+\r
+/**\r
+ * \ingroup Utils\r
+ * Trace macro for win32 applications where the MFC or ATL trace macro is\r
+ * not available.\r
+ */\r
+void TRACE(LPCTSTR str, ...);\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2006 - Stefan Kueng\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#include "StdAfx.h"\r
+#include "debughelpers.h"\r
+\r
+CString GetLastErrorMessageString(int err)\r
+{\r
+ LPVOID lpMsgBuf;\r
+ FormatMessage( \r
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | \r
+ FORMAT_MESSAGE_FROM_SYSTEM | \r
+ FORMAT_MESSAGE_IGNORE_INSERTS,\r
+ NULL,\r
+ err,\r
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language\r
+ (LPTSTR) &lpMsgBuf,\r
+ 0,\r
+ NULL \r
+ );\r
+ CString temp = CString((LPCTSTR)lpMsgBuf);\r
+ LocalFree(lpMsgBuf);\r
+ return temp;\r
+};\r
+\r
+CString GetLastErrorMessageString()\r
+{\r
+ LPVOID lpMsgBuf;\r
+ FormatMessage( \r
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | \r
+ FORMAT_MESSAGE_FROM_SYSTEM | \r
+ FORMAT_MESSAGE_IGNORE_INSERTS,\r
+ NULL,\r
+ GetLastError(),\r
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language\r
+ (LPTSTR) &lpMsgBuf,\r
+ 0,\r
+ NULL \r
+ );\r
+ CString temp = CString((LPCTSTR)lpMsgBuf);\r
+ LocalFree(lpMsgBuf);\r
+ return temp;\r
+};\r
+\r
+void SetThreadName(DWORD dwThreadID, LPCTSTR szThreadName)\r
+{\r
+#ifdef _UNICODE\r
+ char narrow[_MAX_PATH * 3];\r
+ BOOL defaultCharUsed;\r
+ int ret = WideCharToMultiByte(CP_ACP, 0, szThreadName, (int)_tcslen(szThreadName), narrow, _MAX_PATH*3 - 1, ".", &defaultCharUsed);\r
+ narrow[ret] = 0;\r
+#endif\r
+ THREADNAME_INFO info;\r
+ info.dwType = 0x1000;\r
+#ifdef _UNICODE\r
+ info.szName = narrow;\r
+#else\r
+ info.szName = szThreadName;\r
+#endif\r
+ info.dwThreadID = dwThreadID;\r
+ info.dwFlags = 0;\r
+\r
+ __try\r
+ {\r
+ RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(DWORD),\r
+ (DWORD *)&info);\r
+ }\r
+ __except (EXCEPTION_CONTINUE_EXECUTION)\r
+ {\r
+ }\r
+}\r
+\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2006 - Stefan Kueng\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#pragma once\r
+\r
+#ifdef _DEBUG\r
+# define BEGIN_TICK { DWORD dwTickMeasureBegin = ::GetTickCount();\r
+# define END_TICK(s) DWORD dwTickMeasureEnd = ::GetTickCount(); TRACE("%s: tick count = %d\n", s, dwTickMeasureEnd-dwTickMeasureBegin); }\r
+#else\r
+# define BEGIN_TICK\r
+# define END_TICK(s)\r
+#endif\r
+\r
+/**\r
+ * \ingroup CommonClasses\r
+ * returns the string to the given error number.\r
+ * \param err the error number, obtained with GetLastError() or WSAGetLastError() or ...\r
+ */\r
+CString GetLastErrorMessageString(int err);\r
+/*\r
+ * \ingroup CommonClasses\r
+ * returns the string to the GetLastError() function.\r
+ */\r
+CString GetLastErrorMessageString();\r
+\r
+#define MS_VC_EXCEPTION 0x406d1388\r
+\r
+typedef struct tagTHREADNAME_INFO\r
+{\r
+ DWORD dwType; // must be 0x1000\r
+ LPCSTR szName; // pointer to name (in same addr space)\r
+ DWORD dwThreadID; // thread ID (-1 caller thread)\r
+ DWORD dwFlags; // reserved for future use, most be zero\r
+} THREADNAME_INFO;\r
+\r
+/**\r
+ * Sets a name for a thread. The Thread name must not exceed 9 characters!\r
+ * Inside the current thread you can use -1 for dwThreadID.\r
+ * \param dwThreadID The Thread ID\r
+ * \param szThreadName A name for the thread.\r
+ */ \r
+void SetThreadName(DWORD dwThreadID, LPCTSTR szThreadName);\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2005 - 2006 - Jon Foster\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+#include "StdAfx.h"\r
+#include "DirFileEnum.h"\r
+\r
+\r
+CSimpleFileFind::CSimpleFileFind(const CString &sPath, LPCTSTR pPattern) :\r
+ m_dError(ERROR_SUCCESS),\r
+ m_bFirst(TRUE),\r
+ m_sPathPrefix(sPath)\r
+{\r
+ // Add a trailing \ to m_sPathPrefix if it is missing.\r
+ // Do not add one to "C:" since "C:" and "C:\" are different.\r
+ {\r
+ int len = m_sPathPrefix.GetLength();\r
+ if (len != 0) {\r
+ TCHAR ch = sPath[len-1];\r
+ if (ch != '\\' && (ch != ':' || len != 2)) {\r
+ m_sPathPrefix += "\\";\r
+ }\r
+ }\r
+ }\r
+\r
+ m_hFindFile = ::FindFirstFile((LPCTSTR)(m_sPathPrefix + pPattern), &m_FindFileData); \r
+ if (m_hFindFile == INVALID_HANDLE_VALUE) {\r
+ m_dError = ::GetLastError();\r
+ }\r
+}\r
+\r
+CSimpleFileFind::~CSimpleFileFind()\r
+{\r
+ if (m_hFindFile != INVALID_HANDLE_VALUE) {\r
+ ::FindClose(m_hFindFile);\r
+ }\r
+}\r
+\r
+BOOL CSimpleFileFind::FindNextFile()\r
+{\r
+ if (m_dError) {\r
+ return FALSE;\r
+ }\r
+\r
+ if (m_bFirst) {\r
+ m_bFirst = FALSE;\r
+ return TRUE;\r
+ }\r
+\r
+ if (!::FindNextFile(m_hFindFile, &m_FindFileData)) {\r
+ m_dError = ::GetLastError();\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+BOOL CSimpleFileFind::FindNextFileNoDots()\r
+{\r
+ BOOL result;\r
+ do {\r
+ result = FindNextFile();\r
+ } while (result && IsDots());\r
+\r
+ return result;\r
+}\r
+\r
+BOOL CSimpleFileFind::FindNextFileNoDirectories()\r
+{\r
+ BOOL result;\r
+ do {\r
+ result = FindNextFile();\r
+ } while (result && IsDirectory());\r
+\r
+ return result;\r
+}\r
+\r
+\r
+/*\r
+ * Implementation notes:\r
+ *\r
+ * This is a depth-first traversal. Directories are visited before\r
+ * their contents.\r
+ *\r
+ * We keep a stack of directories. The deepest directory is at the top\r
+ * of the stack, the originally-requested directory is at the bottom.\r
+ * If we come across a directory, we first return it to the user, then\r
+ * recurse into it. The finder at the bottom of the stack always points\r
+ * to the file or directory last returned to the user (except immediately\r
+ * after creation, when the finder points to the first valid thing we need\r
+ * to return, but we haven't actually returned anything yet - hence the\r
+ * m_bIsNew variable).\r
+ *\r
+ * Errors reading a directory are assumed to be end-of-directory, and\r
+ * are otherwise ignored.\r
+ *\r
+ * The "." and ".." psedo-directories are ignored for obvious reasons.\r
+ */\r
+\r
+\r
+CDirFileEnum::CDirStackEntry::CDirStackEntry(CDirStackEntry * seNext,\r
+ const CString& sDirName)\r
+ : CSimpleFileFind(sDirName),\r
+ m_seNext(seNext)\r
+{\r
+}\r
+\r
+CDirFileEnum::CDirStackEntry::~CDirStackEntry()\r
+{\r
+}\r
+\r
+inline void CDirFileEnum::PopStack()\r
+{\r
+ CDirStackEntry * seToDelete = m_seStack;\r
+ m_seStack = seToDelete->m_seNext;\r
+ delete seToDelete;\r
+}\r
+\r
+inline void CDirFileEnum::PushStack(const CString& sDirName)\r
+{\r
+ m_seStack = new CDirStackEntry(m_seStack,sDirName);\r
+}\r
+\r
+CDirFileEnum::CDirFileEnum(const CString& sDirName) :\r
+ m_seStack(NULL),\r
+ m_bIsNew(TRUE)\r
+{\r
+ PushStack(sDirName);\r
+}\r
+\r
+CDirFileEnum::~CDirFileEnum()\r
+{\r
+ while (m_seStack != NULL) {\r
+ PopStack();\r
+ }\r
+}\r
+\r
+BOOL CDirFileEnum::NextFile(CString &sResult, bool* pbIsDirectory)\r
+{\r
+ if (m_bIsNew) {\r
+ // Special-case first time - haven't found anything yet,\r
+ // so don't do recurse-into-directory check.\r
+ m_bIsNew = FALSE;\r
+ } else if (m_seStack && m_seStack->IsDirectory()) {\r
+ PushStack(m_seStack->GetFilePath());\r
+ }\r
+\r
+ while (m_seStack && !m_seStack->FindNextFileNoDots()) {\r
+ // No more files in this directory, try parent.\r
+ PopStack();\r
+ }\r
+\r
+ if (m_seStack) \r
+ {\r
+ sResult = m_seStack->GetFilePath();\r
+ if(pbIsDirectory != NULL)\r
+ {\r
+ *pbIsDirectory = m_seStack->IsDirectory();\r
+ }\r
+ return TRUE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+}\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2005 - 2006 - Jon Foster\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+#pragma once\r
+\r
+/**\r
+ * \ingroup Utils\r
+ * Enumerates over a directory tree, non-recursively.\r
+ * Advantages over CFileFind:\r
+ * 1) Return values are not broken. An error return from\r
+ * CFileFind::FindNext() indicates that the *next*\r
+ * call to CFileFind::FindNext() will fail.\r
+ * A failure from CSimpleFileFind means *that* call\r
+ * failed, which is what I'd expect.\r
+ * 2) Error handling. If you use CFileFind, you are\r
+ * required to call ::GetLastError() yourself, there\r
+ * is no abstraction.\r
+ * 3) Support for ignoring the "." and ".." directories\r
+ * automatically.\r
+ * 4) No dynamic memory allocation.\r
+ */\r
+class CSimpleFileFind {\r
+private:\r
+ /**\r
+ * Windows FindFirstFile() handle.\r
+ */\r
+ HANDLE m_hFindFile;\r
+\r
+ /**\r
+ * Windows error code - if all is well, ERROR_SUCCESS.\r
+ * At end of directory, ERROR_NO_MORE_FILES.\r
+ */\r
+ DWORD m_dError;\r
+\r
+ /**\r
+ * Flag indicating that FindNextFile() has not yet been\r
+ * called.\r
+ */\r
+ BOOL m_bFirst;\r
+\r
+protected:\r
+ /**\r
+ * The prefix for files in this directory.\r
+ * Ends with a "\", unless it's a drive letter only\r
+ * ("C:" is different from "C:\", and "C:filename" is\r
+ * legal anyway.)\r
+ */\r
+ CString m_sPathPrefix;\r
+\r
+ /**\r
+ * The file data returned by FindFirstFile()/FindNextFile().\r
+ */\r
+ WIN32_FIND_DATA m_FindFileData;\r
+\r
+public:\r
+\r
+ /**\r
+ * Constructor.\r
+ *\r
+ * \param sPath The path to search in.\r
+ * \param sPattern The filename pattern - default all files.\r
+ */\r
+ CSimpleFileFind(const CString &sPath, LPCTSTR pPattern = _T("*.*"));\r
+ ~CSimpleFileFind();\r
+\r
+ /**\r
+ * Advance to the next file.\r
+ * Note that the state of this object is undefined until\r
+ * this method is called the first time.\r
+ *\r
+ * \return TRUE if a file was found, FALSE on error or\r
+ * end-of-directory (use IsError() and IsPastEnd() to\r
+ * disambiguate).\r
+ */\r
+ BOOL FindNextFile();\r
+\r
+ /**\r
+ * Advance to the next file, ignoring the "." and ".."\r
+ * pseudo-directories (if seen).\r
+ *\r
+ * Behaves like FindNextFile(), apart from ignoring "."\r
+ * and "..".\r
+ *\r
+ * \return TRUE if a file was found, FALSE on error or\r
+ * end-of-directory.\r
+ */\r
+ BOOL FindNextFileNoDots();\r
+\r
+ /**\r
+ * Advance to the next file, ignoring all directories.\r
+ *\r
+ * Behaves like FindNextFile(), apart from ignoring\r
+ * directories.\r
+ *\r
+ * \return TRUE if a file was found, FALSE on error or\r
+ * end-of-directory.\r
+ */\r
+ BOOL FindNextFileNoDirectories();\r
+\r
+ /**\r
+ * Get the Windows error code.\r
+ * Only useful when IsError() returns true.\r
+ *\r
+ * \return Windows error code.\r
+ */\r
+ inline DWORD GetError() const\r
+ {\r
+ return m_dError;\r
+ }\r
+\r
+ /**\r
+ * Check if the current file data is valid.\r
+ * (I.e. there has not been an error and we are not past\r
+ * the end of the directory).\r
+ *\r
+ * \return TRUE iff the current file data is valid.\r
+ */\r
+ inline BOOL IsValid() const\r
+ {\r
+ return (m_dError == ERROR_SUCCESS);\r
+ }\r
+\r
+ /**\r
+ * Check if we have passed the end of the directory.\r
+ *\r
+ * \return TRUE iff we have passed the end of the directory.\r
+ */\r
+ inline BOOL IsPastEnd() const\r
+ {\r
+ return (m_dError == ERROR_NO_MORE_FILES);\r
+ }\r
+\r
+ /**\r
+ * Check if there has been an unexpected error - i.e.\r
+ * any error other than passing the end of the directory.\r
+ *\r
+ * \return TRUE iff there has been an unexpected error.\r
+ */\r
+ inline BOOL IsError() const\r
+ {\r
+ return (m_dError != ERROR_SUCCESS)\r
+ && (m_dError != ERROR_NO_MORE_FILES);\r
+ }\r
+\r
+ /**\r
+ * Check if the current file is a directory.\r
+ *\r
+ * \return TRUE iff the current file is a directory.\r
+ */\r
+ inline bool IsDirectory() const\r
+ {\r
+ return !!(m_FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);\r
+ }\r
+\r
+ /**\r
+ * Get the current file name (excluding the path).\r
+ *\r
+ * \return the current file name.\r
+ */\r
+ inline CString GetFileName() const\r
+ {\r
+ return m_FindFileData.cFileName;\r
+ }\r
+\r
+ /*\r
+ * Get the current file name, including the path.\r
+ *\r
+ * \return the current file path.\r
+ */\r
+ inline CString GetFilePath() const\r
+ {\r
+ return m_sPathPrefix + m_FindFileData.cFileName;\r
+ }\r
+\r
+ /**\r
+ * Check if the current file is the "." or ".."\r
+ * pseudo-directory.\r
+ *\r
+ * \return TRUE iff the current file is the "." or ".."\r
+ * pseudo-directory.\r
+ */\r
+ inline BOOL IsDots() const \r
+ {\r
+ return IsDirectory()\r
+ && m_FindFileData.cFileName[0] == _T('.')\r
+ && ( (m_FindFileData.cFileName[1] == 0)\r
+ || (m_FindFileData.cFileName[1] == _T('.')\r
+ && m_FindFileData.cFileName[2] == 0) );\r
+ }\r
+};\r
+\r
+/**\r
+ * \ingroup Utils\r
+ * Enumerates over a directory tree, recursively.\r
+ *\r
+ * \par requirements\r
+ * win95 or later\r
+ * winNT4 or later\r
+ * MFC\r
+ *\r
+ * \version 1.0\r
+ * first version\r
+ *\r
+ * \date 18-Feb-2004\r
+ *\r
+ * \author Jon Foster\r
+ *\r
+ * \par license\r
+ * This code is GPL'd.\r
+ */\r
+class CDirFileEnum\r
+{\r
+private:\r
+\r
+ class CDirStackEntry : public CSimpleFileFind {\r
+ public:\r
+ CDirStackEntry(CDirStackEntry * seNext, const CString& sDirName);\r
+ ~CDirStackEntry();\r
+\r
+ CDirStackEntry * m_seNext;\r
+ };\r
+\r
+ CDirStackEntry * m_seStack;\r
+ BOOL m_bIsNew;\r
+\r
+ inline void PopStack();\r
+ inline void PushStack(const CString& sDirName);\r
+\r
+public:\r
+ /**\r
+ * Iterate through the specified directory and all subdirectories.\r
+ * It does not matter whether or not the specified directory ends\r
+ * with a slash. Both relative and absolute paths are allowed,\r
+ * the results of this iterator will be consistent with the style\r
+ * passed to this constructor.\r
+ *\r
+ * @param dirName The directory to search in.\r
+ */\r
+ CDirFileEnum(const CString& dirName);\r
+\r
+ /**\r
+ * Destructor. Frees all resources.\r
+ */\r
+ ~CDirFileEnum();\r
+\r
+ /**\r
+ * Get the next file from this iterator.\r
+ *\r
+ * \param result On successful return, holds the full path to the found\r
+ * file. (If this function returns FALSE, the value of\r
+ * result is unspecified).\r
+ * \param pbIsDirectory Pointer to a bool variable which will hold\r
+ * TRUE if the \c result path is a directory, FALSE\r
+ * if it's a file. Pass NULL if you don't need that information.\r
+ * \return TRUE iff a file was found, false at end of the iteration.\r
+ */\r
+ BOOL NextFile(CString &result, bool* pbIsDirectory);\r
+};\r
+\r
--- /dev/null
+/**************************************************************************\r
+ THIS CODE AND INFORMATION IS PROVIDED 'AS IS' WITHOUT WARRANTY OF\r
+ ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO\r
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A\r
+ PARTICULAR PURPOSE.\r
+ Author: Leon Finker 1/2001\r
+**************************************************************************/\r
+// IDataObjectImpl.cpp: implementation of the CIDataObjectImpl class.\r
+//////////////////////////////////////////////////////////////////////\r
+#include <shlobj.h>\r
+#include <atlbase.h>\r
+#include "DragDropImpl.h"\r
+\r
+//////////////////////////////////////////////////////////////////////\r
+// CIDataObject Class\r
+//////////////////////////////////////////////////////////////////////\r
+\r
+CIDataObject::CIDataObject(CIDropSource* pDropSource):\r
+m_cRefCount(0), m_pDropSource(pDropSource)\r
+{\r
+}\r
+\r
+CIDataObject::~CIDataObject()\r
+{\r
+ for(int i = 0; i < m_StgMedium.GetSize(); ++i)\r
+ {\r
+ ReleaseStgMedium(m_StgMedium[i]);\r
+ delete m_StgMedium[i];\r
+ }\r
+ for(int j = 0; j < m_ArrFormatEtc.GetSize(); ++j)\r
+ delete m_ArrFormatEtc[j];\r
+}\r
+\r
+STDMETHODIMP CIDataObject::QueryInterface(/* [in] */ REFIID riid,\r
+/* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)\r
+{\r
+ *ppvObject = NULL;\r
+ if (IID_IUnknown==riid || IID_IDataObject==riid)\r
+ *ppvObject=this;\r
+ /*if(riid == IID_IAsyncOperation)\r
+ *ppvObject=(IAsyncOperation*)this;*/\r
+ if (NULL!=*ppvObject)\r
+ {\r
+ ((LPUNKNOWN)*ppvObject)->AddRef();\r
+ return S_OK;\r
+ }\r
+ return E_NOINTERFACE;\r
+}\r
+\r
+STDMETHODIMP_(ULONG) CIDataObject::AddRef( void)\r
+{\r
+ return ++m_cRefCount;\r
+}\r
+\r
+STDMETHODIMP_(ULONG) CIDataObject::Release( void)\r
+{\r
+ long nTemp;\r
+ nTemp = --m_cRefCount;\r
+ if(nTemp==0)\r
+ delete this;\r
+ return nTemp;\r
+}\r
+\r
+STDMETHODIMP CIDataObject::GetData( \r
+ /* [unique][in] */ FORMATETC __RPC_FAR *pformatetcIn,\r
+ /* [out] */ STGMEDIUM __RPC_FAR *pmedium)\r
+{ \r
+ if(pformatetcIn == NULL || pmedium == NULL)\r
+ return E_INVALIDARG;\r
+ pmedium->hGlobal = NULL;\r
+\r
+ ATLASSERT(m_StgMedium.GetSize() == m_ArrFormatEtc.GetSize());\r
+ for(int i=0; i < m_ArrFormatEtc.GetSize(); ++i)\r
+ {\r
+ if(pformatetcIn->tymed & m_ArrFormatEtc[i]->tymed &&\r
+ pformatetcIn->dwAspect == m_ArrFormatEtc[i]->dwAspect &&\r
+ pformatetcIn->cfFormat == m_ArrFormatEtc[i]->cfFormat)\r
+ {\r
+ CopyMedium(pmedium, m_StgMedium[i], m_ArrFormatEtc[i]);\r
+ return S_OK;\r
+ }\r
+ }\r
+ return DV_E_FORMATETC;\r
+}\r
+\r
+STDMETHODIMP CIDataObject::GetDataHere( \r
+ /* [unique][in] */ FORMATETC __RPC_FAR * /*pformatetc*/,\r
+ /* [out][in] */ STGMEDIUM __RPC_FAR * /*pmedium*/)\r
+{\r
+ return E_NOTIMPL;\r
+}\r
+\r
+STDMETHODIMP CIDataObject::QueryGetData( \r
+ /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc)\r
+{ \r
+ if(pformatetc == NULL)\r
+ return E_INVALIDARG;\r
+\r
+ //support others if needed DVASPECT_THUMBNAIL //DVASPECT_ICON //DVASPECT_DOCPRINT\r
+ if (!(DVASPECT_CONTENT & pformatetc->dwAspect))\r
+ return (DV_E_DVASPECT);\r
+ HRESULT hr = DV_E_TYMED;\r
+ for(int i = 0; i < m_ArrFormatEtc.GetSize(); ++i)\r
+ {\r
+ if(pformatetc->tymed & m_ArrFormatEtc[i]->tymed)\r
+ {\r
+ if(pformatetc->cfFormat == m_ArrFormatEtc[i]->cfFormat)\r
+ return S_OK;\r
+ else\r
+ hr = DV_E_CLIPFORMAT;\r
+ }\r
+ else\r
+ hr = DV_E_TYMED;\r
+ }\r
+ return hr;\r
+}\r
+\r
+STDMETHODIMP CIDataObject::GetCanonicalFormatEtc( \r
+ /* [unique][in] */ FORMATETC __RPC_FAR * /*pformatectIn*/,\r
+ /* [out] */ FORMATETC __RPC_FAR *pformatetcOut)\r
+{ \r
+ if (pformatetcOut == NULL)\r
+ return E_INVALIDARG;\r
+ return DATA_S_SAMEFORMATETC;\r
+}\r
+\r
+STDMETHODIMP CIDataObject::SetData( \r
+ /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc,\r
+ /* [unique][in] */ STGMEDIUM __RPC_FAR *pmedium,\r
+ /* [in] */ BOOL fRelease)\r
+{ \r
+ if(pformatetc == NULL || pmedium == NULL)\r
+ return E_INVALIDARG;\r
+\r
+ ATLASSERT(pformatetc->tymed == pmedium->tymed);\r
+ FORMATETC* fetc=new FORMATETC;\r
+ STGMEDIUM* pStgMed = new STGMEDIUM;\r
+\r
+ if(fetc == NULL || pStgMed == NULL)\r
+ return E_OUTOFMEMORY;\r
+\r
+ SecureZeroMemory(fetc,sizeof(FORMATETC));\r
+ SecureZeroMemory(pStgMed,sizeof(STGMEDIUM));\r
+\r
+ *fetc = *pformatetc;\r
+ m_ArrFormatEtc.Add(fetc);\r
+\r
+ if(fRelease)\r
+ *pStgMed = *pmedium;\r
+ else\r
+ {\r
+ CopyMedium(pStgMed, pmedium, pformatetc);\r
+ }\r
+ m_StgMedium.Add(pStgMed);\r
+\r
+ return S_OK;\r
+}\r
+void CIDataObject::CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc)\r
+{\r
+ switch(pMedSrc->tymed)\r
+ {\r
+ case TYMED_HGLOBAL:\r
+ pMedDest->hGlobal = (HGLOBAL)OleDuplicateData(pMedSrc->hGlobal,pFmtSrc->cfFormat, NULL);\r
+ break;\r
+ case TYMED_GDI:\r
+ pMedDest->hBitmap = (HBITMAP)OleDuplicateData(pMedSrc->hBitmap,pFmtSrc->cfFormat, NULL);\r
+ break;\r
+ case TYMED_MFPICT:\r
+ pMedDest->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(pMedSrc->hMetaFilePict,pFmtSrc->cfFormat, NULL);\r
+ break;\r
+ case TYMED_ENHMF:\r
+ pMedDest->hEnhMetaFile = (HENHMETAFILE)OleDuplicateData(pMedSrc->hEnhMetaFile,pFmtSrc->cfFormat, NULL);\r
+ break;\r
+ case TYMED_FILE:\r
+ pMedSrc->lpszFileName = (LPOLESTR)OleDuplicateData(pMedSrc->lpszFileName,pFmtSrc->cfFormat, NULL);\r
+ break;\r
+ case TYMED_ISTREAM:\r
+ pMedDest->pstm = pMedSrc->pstm;\r
+ pMedSrc->pstm->AddRef();\r
+ break;\r
+ case TYMED_ISTORAGE:\r
+ pMedDest->pstg = pMedSrc->pstg;\r
+ pMedSrc->pstg->AddRef();\r
+ break;\r
+ case TYMED_NULL:\r
+ default:\r
+ break;\r
+ }\r
+ pMedDest->tymed = pMedSrc->tymed;\r
+ pMedDest->pUnkForRelease = NULL;\r
+ if(pMedSrc->pUnkForRelease != NULL)\r
+ {\r
+ pMedDest->pUnkForRelease = pMedSrc->pUnkForRelease;\r
+ pMedSrc->pUnkForRelease->AddRef();\r
+ }\r
+}\r
+STDMETHODIMP CIDataObject::EnumFormatEtc(\r
+ /* [in] */ DWORD dwDirection,\r
+ /* [out] */ IEnumFORMATETC __RPC_FAR *__RPC_FAR *ppenumFormatEtc)\r
+{ \r
+ if(ppenumFormatEtc == NULL)\r
+ return E_POINTER;\r
+\r
+ *ppenumFormatEtc=NULL;\r
+ switch (dwDirection)\r
+ {\r
+ case DATADIR_GET:\r
+ *ppenumFormatEtc= new CEnumFormatEtc(m_ArrFormatEtc);\r
+ if(*ppenumFormatEtc == NULL)\r
+ return E_OUTOFMEMORY;\r
+ (*ppenumFormatEtc)->AddRef(); \r
+ break;\r
+ \r
+ case DATADIR_SET:\r
+ default:\r
+ return E_NOTIMPL;\r
+ break;\r
+ }\r
+\r
+ return S_OK;\r
+}\r
+\r
+STDMETHODIMP CIDataObject::DAdvise( \r
+ /* [in] */ FORMATETC __RPC_FAR * /*pformatetc*/,\r
+ /* [in] */ DWORD /*advf*/,\r
+ /* [unique][in] */ IAdviseSink __RPC_FAR * /*pAdvSink*/,\r
+ /* [out] */ DWORD __RPC_FAR * /*pdwConnection*/)\r
+{ \r
+ return OLE_E_ADVISENOTSUPPORTED;\r
+}\r
+\r
+STDMETHODIMP CIDataObject::DUnadvise( \r
+ /* [in] */ DWORD /*dwConnection*/)\r
+{\r
+ return E_NOTIMPL;\r
+}\r
+\r
+HRESULT STDMETHODCALLTYPE CIDataObject::EnumDAdvise( \r
+ /* [out] */ IEnumSTATDATA __RPC_FAR *__RPC_FAR * /*ppenumAdvise*/)\r
+{\r
+ return OLE_E_ADVISENOTSUPPORTED;\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////\r
+// CIDropSource Class\r
+//////////////////////////////////////////////////////////////////////\r
+\r
+STDMETHODIMP CIDropSource::QueryInterface(/* [in] */ REFIID riid,\r
+ /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)\r
+{\r
+ *ppvObject = NULL;\r
+ if (IID_IUnknown==riid || IID_IDropSource==riid)\r
+ *ppvObject=this;\r
+\r
+ if (*ppvObject != NULL)\r
+ {\r
+ ((LPUNKNOWN)*ppvObject)->AddRef();\r
+ return S_OK;\r
+ }\r
+ return E_NOINTERFACE;\r
+}\r
+\r
+STDMETHODIMP_(ULONG) CIDropSource::AddRef( void)\r
+{\r
+ return ++m_cRefCount;\r
+}\r
+\r
+STDMETHODIMP_(ULONG) CIDropSource::Release( void)\r
+{\r
+ long nTemp;\r
+ nTemp = --m_cRefCount;\r
+ ATLASSERT(nTemp >= 0);\r
+ if(nTemp==0)\r
+ delete this;\r
+ return nTemp;\r
+}\r
+\r
+STDMETHODIMP CIDropSource::QueryContinueDrag( \r
+ /* [in] */ BOOL fEscapePressed,\r
+ /* [in] */ DWORD grfKeyState)\r
+{\r
+ if(fEscapePressed)\r
+ return DRAGDROP_S_CANCEL;\r
+ if(!(grfKeyState & (MK_LBUTTON|MK_RBUTTON)))\r
+ {\r
+ m_bDropped = true;\r
+ return DRAGDROP_S_DROP;\r
+ }\r
+\r
+ return S_OK;\r
+\r
+}\r
+\r
+STDMETHODIMP CIDropSource::GiveFeedback(\r
+ /* [in] */ DWORD /*dwEffect*/)\r
+{\r
+ return DRAGDROP_S_USEDEFAULTCURSORS;\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////\r
+// CEnumFormatEtc Class\r
+//////////////////////////////////////////////////////////////////////\r
+\r
+CEnumFormatEtc::CEnumFormatEtc(const CSimpleArray<FORMATETC>& ArrFE):\r
+m_cRefCount(0),m_iCur(0)\r
+{\r
+ ATLTRACE("CEnumFormatEtc::CEnumFormatEtc()\n");\r
+ for(int i = 0; i < ArrFE.GetSize(); ++i)\r
+ m_pFmtEtc.Add(ArrFE[i]);\r
+}\r
+\r
+CEnumFormatEtc::CEnumFormatEtc(const CSimpleArray<FORMATETC*>& ArrFE):\r
+m_cRefCount(0),m_iCur(0)\r
+{\r
+ for(int i = 0; i < ArrFE.GetSize(); ++i)\r
+ m_pFmtEtc.Add(*ArrFE[i]);\r
+}\r
+\r
+STDMETHODIMP CEnumFormatEtc::QueryInterface(REFIID refiid, void FAR* FAR* ppv)\r
+{\r
+ *ppv = NULL;\r
+ if (IID_IUnknown==refiid || IID_IEnumFORMATETC==refiid)\r
+ *ppv=this;\r
+\r
+ if (*ppv != NULL)\r
+ {\r
+ ((LPUNKNOWN)*ppv)->AddRef();\r
+ return S_OK;\r
+ }\r
+ return E_NOINTERFACE;\r
+}\r
+\r
+STDMETHODIMP_(ULONG) CEnumFormatEtc::AddRef(void)\r
+{\r
+ return ++m_cRefCount;\r
+}\r
+\r
+STDMETHODIMP_(ULONG) CEnumFormatEtc::Release(void)\r
+{\r
+ long nTemp = --m_cRefCount;\r
+ ATLASSERT(nTemp >= 0);\r
+ if(nTemp == 0)\r
+ delete this;\r
+\r
+ return nTemp; \r
+}\r
+\r
+STDMETHODIMP CEnumFormatEtc::Next( ULONG celt,LPFORMATETC lpFormatEtc, ULONG FAR *pceltFetched)\r
+{\r
+ if(pceltFetched != NULL)\r
+ *pceltFetched=0;\r
+ \r
+ ULONG cReturn = celt;\r
+\r
+ if(celt <= 0 || lpFormatEtc == NULL || m_iCur >= m_pFmtEtc.GetSize())\r
+ return S_FALSE;\r
+\r
+ if(pceltFetched == NULL && celt != 1) // pceltFetched can be NULL only for 1 item request\r
+ return S_FALSE;\r
+\r
+ while (m_iCur < m_pFmtEtc.GetSize() && cReturn > 0)\r
+ {\r
+ *lpFormatEtc++ = m_pFmtEtc[m_iCur++];\r
+ --cReturn;\r
+ }\r
+ if (pceltFetched != NULL)\r
+ *pceltFetched = celt - cReturn;\r
+\r
+ return (cReturn == 0) ? S_OK : S_FALSE;\r
+}\r
+ \r
+STDMETHODIMP CEnumFormatEtc::Skip(ULONG celt)\r
+{\r
+ if((m_iCur + int(celt)) >= m_pFmtEtc.GetSize())\r
+ return S_FALSE;\r
+ m_iCur += celt;\r
+ return S_OK;\r
+}\r
+\r
+STDMETHODIMP CEnumFormatEtc::Reset(void)\r
+{\r
+ m_iCur = 0;\r
+ return S_OK;\r
+}\r
+ \r
+STDMETHODIMP CEnumFormatEtc::Clone(IEnumFORMATETC FAR * FAR*ppCloneEnumFormatEtc)\r
+{\r
+ if(ppCloneEnumFormatEtc == NULL)\r
+ return E_POINTER;\r
+ \r
+ CEnumFormatEtc *newEnum = new CEnumFormatEtc(m_pFmtEtc);\r
+ if(newEnum ==NULL)\r
+ return E_OUTOFMEMORY; \r
+ newEnum->AddRef();\r
+ newEnum->m_iCur = m_iCur;\r
+ *ppCloneEnumFormatEtc = newEnum;\r
+ return S_OK;\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////\r
+// CIDropTarget Class\r
+//////////////////////////////////////////////////////////////////////\r
+CIDropTarget::CIDropTarget(HWND hTargetWnd): \r
+ m_hTargetWnd(hTargetWnd),\r
+ m_cRefCount(0), m_bAllowDrop(false),\r
+ m_pDropTargetHelper(NULL), m_pSupportedFrmt(NULL)\r
+{\r
+ if(FAILED(CoCreateInstance(CLSID_DragDropHelper,NULL,CLSCTX_INPROC_SERVER,\r
+ IID_IDropTargetHelper,(LPVOID*)&m_pDropTargetHelper)))\r
+ m_pDropTargetHelper = NULL;\r
+}\r
+\r
+CIDropTarget::~CIDropTarget()\r
+{\r
+ if(m_pDropTargetHelper != NULL)\r
+ {\r
+ m_pDropTargetHelper->Release();\r
+ m_pDropTargetHelper = NULL;\r
+ }\r
+}\r
+\r
+HRESULT STDMETHODCALLTYPE CIDropTarget::QueryInterface( /* [in] */ REFIID riid,\r
+ /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)\r
+{\r
+ *ppvObject = NULL;\r
+ if (IID_IUnknown==riid || IID_IDropTarget==riid)\r
+ *ppvObject=this;\r
+\r
+ if (*ppvObject != NULL)\r
+ {\r
+ ((LPUNKNOWN)*ppvObject)->AddRef();\r
+ return S_OK;\r
+ }\r
+ return E_NOINTERFACE;\r
+}\r
+\r
+ULONG STDMETHODCALLTYPE CIDropTarget::Release( void)\r
+{\r
+ long nTemp;\r
+ nTemp = --m_cRefCount;\r
+ ATLASSERT(nTemp >= 0);\r
+ if(nTemp==0)\r
+ delete this;\r
+ return nTemp;\r
+}\r
+\r
+bool CIDropTarget::QueryDrop(DWORD grfKeyState, LPDWORD pdwEffect)\r
+{ \r
+ DWORD dwOKEffects = *pdwEffect; \r
+\r
+ if(!m_bAllowDrop)\r
+ {\r
+ *pdwEffect = DROPEFFECT_NONE;\r
+ return false;\r
+ }\r
+ //CTRL+SHIFT -- DROPEFFECT_LINK\r
+ //CTRL -- DROPEFFECT_COPY\r
+ //SHIFT -- DROPEFFECT_MOVE\r
+ //no modifier -- DROPEFFECT_MOVE or whatever is allowed by src\r
+ *pdwEffect = (grfKeyState & MK_CONTROL) ?\r
+ ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_LINK : DROPEFFECT_COPY ):\r
+ ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_MOVE : 0 );\r
+ if(*pdwEffect == 0) \r
+ {\r
+ // No modifier keys used by user while dragging. \r
+ if (DROPEFFECT_MOVE & dwOKEffects)\r
+ *pdwEffect = DROPEFFECT_MOVE;\r
+ else if (DROPEFFECT_COPY & dwOKEffects)\r
+ *pdwEffect = DROPEFFECT_COPY; \r
+ else if (DROPEFFECT_LINK & dwOKEffects)\r
+ *pdwEffect = DROPEFFECT_LINK; \r
+ else \r
+ {\r
+ *pdwEffect = DROPEFFECT_NONE;\r
+ }\r
+ } \r
+ else\r
+ {\r
+ // Check if the drag source application allows the drop effect desired by user.\r
+ // The drag source specifies this in DoDragDrop\r
+ if(!(*pdwEffect & dwOKEffects))\r
+ *pdwEffect = DROPEFFECT_NONE;\r
+ } \r
+\r
+ return (DROPEFFECT_NONE == *pdwEffect)?false:true;\r
+} \r
+\r
+HRESULT STDMETHODCALLTYPE CIDropTarget::DragEnter(\r
+ /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,\r
+ /* [in] */ DWORD grfKeyState,\r
+ /* [in] */ POINTL pt,\r
+ /* [out][in] */ DWORD __RPC_FAR *pdwEffect)\r
+{\r
+ if(pDataObj == NULL)\r
+ return E_INVALIDARG;\r
+\r
+ if(m_pDropTargetHelper)\r
+ m_pDropTargetHelper->DragEnter(m_hTargetWnd, pDataObj, (LPPOINT)&pt, *pdwEffect);\r
+ //IEnumFORMATETC* pEnum;\r
+ //pDataObj->EnumFormatEtc(DATADIR_GET,&pEnum);\r
+ //FORMATETC ftm;\r
+ //for()\r
+ //pEnum->Next(1,&ftm,0);\r
+ //pEnum->Release();\r
+ m_pSupportedFrmt = NULL;\r
+ for(int i =0; i<m_formatetc.GetSize(); ++i)\r
+ {\r
+ m_bAllowDrop = (pDataObj->QueryGetData(&m_formatetc[i]) == S_OK)?true:false;\r
+ if(m_bAllowDrop)\r
+ {\r
+ m_pSupportedFrmt = &m_formatetc[i];\r
+ break;\r
+ }\r
+ }\r
+\r
+ QueryDrop(grfKeyState, pdwEffect);\r
+ return S_OK;\r
+}\r
+\r
+HRESULT STDMETHODCALLTYPE CIDropTarget::DragOver( \r
+ /* [in] */ DWORD grfKeyState,\r
+ /* [in] */ POINTL pt,\r
+ /* [out][in] */ DWORD __RPC_FAR *pdwEffect)\r
+{\r
+ if(m_pDropTargetHelper)\r
+ m_pDropTargetHelper->DragOver((LPPOINT)&pt, *pdwEffect);\r
+ QueryDrop(grfKeyState, pdwEffect);\r
+ return S_OK;\r
+}\r
+\r
+HRESULT STDMETHODCALLTYPE CIDropTarget::DragLeave( void)\r
+{\r
+ if(m_pDropTargetHelper)\r
+ m_pDropTargetHelper->DragLeave();\r
+ \r
+ m_bAllowDrop = false;\r
+ m_pSupportedFrmt = NULL;\r
+ return S_OK;\r
+}\r
+\r
+HRESULT STDMETHODCALLTYPE CIDropTarget::Drop(\r
+ /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,\r
+ /* [in] */ DWORD grfKeyState, /* [in] */ POINTL pt, \r
+ /* [out][in] */ DWORD __RPC_FAR *pdwEffect)\r
+{\r
+ if (pDataObj == NULL)\r
+ return E_INVALIDARG; \r
+\r
+ if(m_pDropTargetHelper)\r
+ m_pDropTargetHelper->Drop(pDataObj, (LPPOINT)&pt, *pdwEffect);\r
+\r
+ if(QueryDrop(grfKeyState, pdwEffect))\r
+ {\r
+ if(m_bAllowDrop && m_pSupportedFrmt != NULL)\r
+ {\r
+ STGMEDIUM medium;\r
+ if(pDataObj->GetData(m_pSupportedFrmt, &medium) == S_OK)\r
+ {\r
+ if(OnDrop(m_pSupportedFrmt, medium, pdwEffect, pt)) //does derive class wants us to free medium?\r
+ ReleaseStgMedium(&medium);\r
+ }\r
+ }\r
+ }\r
+ m_bAllowDrop=false;\r
+ *pdwEffect = DROPEFFECT_NONE;\r
+ m_pSupportedFrmt = NULL;\r
+ return S_OK;\r
+}\r
+\r
+//////////////////////////////////////////////////////////////////////\r
+// CIDragSourceHelper Class\r
+//////////////////////////////////////////////////////////////////////\r
--- /dev/null
+// IDataObjectImpl.h: interface for the CIDataObjectImpl class.\r
+/**************************************************************************\r
+ THIS CODE AND INFORMATION IS PROVIDED 'AS IS' WITHOUT WARRANTY OF\r
+ ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO\r
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A\r
+ PARTICULAR PURPOSE.\r
+ Author: Leon Finker 1/2001\r
+**************************************************************************/\r
+#ifndef __DRAGDROPIMPL_H__\r
+#define __DRAGDROPIMPL_H__\r
+//#include <ShlDisp.h>\r
+///////////////////////////////////////////////////////////////////////////////////////////////\r
+class CEnumFormatEtc : public IEnumFORMATETC\r
+{\r
+ private:\r
+ ULONG m_cRefCount;\r
+ CSimpleArray<FORMATETC> m_pFmtEtc;\r
+ int m_iCur;\r
+\r
+ public:\r
+ CEnumFormatEtc(const CSimpleArray<FORMATETC>& ArrFE);\r
+ CEnumFormatEtc(const CSimpleArray<FORMATETC*>& ArrFE);\r
+ //IUnknown members\r
+ STDMETHOD(QueryInterface)(REFIID, void FAR* FAR*);\r
+ STDMETHOD_(ULONG, AddRef)(void);\r
+ STDMETHOD_(ULONG, Release)(void);\r
+\r
+ //IEnumFORMATETC members\r
+ STDMETHOD(Next)(ULONG, LPFORMATETC, ULONG FAR *);\r
+ STDMETHOD(Skip)(ULONG);\r
+ STDMETHOD(Reset)(void);\r
+ STDMETHOD(Clone)(IEnumFORMATETC FAR * FAR*);\r
+};\r
+\r
+///////////////////////////////////////////////////////////////////////////////////////////////\r
+class CIDropSource : public IDropSource\r
+{\r
+ long m_cRefCount;\r
+public:\r
+ bool m_bDropped;\r
+\r
+ CIDropSource::CIDropSource():m_cRefCount(0),m_bDropped(false) {}\r
+ //IUnknown\r
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(\r
+ /* [in] */ REFIID riid,\r
+ /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); \r
+ virtual ULONG STDMETHODCALLTYPE AddRef( void);\r
+ virtual ULONG STDMETHODCALLTYPE Release( void);\r
+ //IDropSource\r
+ virtual HRESULT STDMETHODCALLTYPE QueryContinueDrag( \r
+ /* [in] */ BOOL fEscapePressed,\r
+ /* [in] */ DWORD grfKeyState);\r
+ \r
+ virtual HRESULT STDMETHODCALLTYPE GiveFeedback( \r
+ /* [in] */ DWORD dwEffect);\r
+};\r
+\r
+///////////////////////////////////////////////////////////////////////////////////////////////\r
+class CIDataObject : public IDataObject//,public IAsyncOperation\r
+{\r
+ CIDropSource* m_pDropSource;\r
+ long m_cRefCount;\r
+ CSimpleArray<FORMATETC*> m_ArrFormatEtc;\r
+ CSimpleArray<STGMEDIUM*> m_StgMedium;\r
+public:\r
+ CIDataObject(CIDropSource* pDropSource);\r
+ ~CIDataObject();\r
+ void CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc);\r
+ //IUnknown\r
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(\r
+ /* [in] */ REFIID riid,\r
+ /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject); \r
+ virtual ULONG STDMETHODCALLTYPE AddRef( void);\r
+ virtual ULONG STDMETHODCALLTYPE Release( void);\r
+\r
+ //IDataObject\r
+ virtual /* [local] */ HRESULT STDMETHODCALLTYPE GetData( \r
+ /* [unique][in] */ FORMATETC __RPC_FAR *pformatetcIn,\r
+ /* [out] */ STGMEDIUM __RPC_FAR *pmedium);\r
+ \r
+ virtual /* [local] */ HRESULT STDMETHODCALLTYPE GetDataHere( \r
+ /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc,\r
+ /* [out][in] */ STGMEDIUM __RPC_FAR *pmedium);\r
+ \r
+ virtual HRESULT STDMETHODCALLTYPE QueryGetData( \r
+ /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc);\r
+ \r
+ virtual HRESULT STDMETHODCALLTYPE GetCanonicalFormatEtc( \r
+ /* [unique][in] */ FORMATETC __RPC_FAR *pformatectIn,\r
+ /* [out] */ FORMATETC __RPC_FAR *pformatetcOut);\r
+ \r
+ virtual /* [local] */ HRESULT STDMETHODCALLTYPE SetData( \r
+ /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc,\r
+ /* [unique][in] */ STGMEDIUM __RPC_FAR *pmedium,\r
+ /* [in] */ BOOL fRelease);\r
+ \r
+ virtual HRESULT STDMETHODCALLTYPE EnumFormatEtc( \r
+ /* [in] */ DWORD dwDirection,\r
+ /* [out] */ IEnumFORMATETC __RPC_FAR *__RPC_FAR *ppenumFormatEtc);\r
+ \r
+ virtual HRESULT STDMETHODCALLTYPE DAdvise( \r
+ /* [in] */ FORMATETC __RPC_FAR *pformatetc,\r
+ /* [in] */ DWORD advf,\r
+ /* [unique][in] */ IAdviseSink __RPC_FAR *pAdvSink,\r
+ /* [out] */ DWORD __RPC_FAR *pdwConnection);\r
+ \r
+ virtual HRESULT STDMETHODCALLTYPE DUnadvise( \r
+ /* [in] */ DWORD dwConnection);\r
+ \r
+ virtual HRESULT STDMETHODCALLTYPE EnumDAdvise( \r
+ /* [out] */ IEnumSTATDATA __RPC_FAR *__RPC_FAR *ppenumAdvise);\r
+\r
+ //IAsyncOperation\r
+ //virtual HRESULT STDMETHODCALLTYPE SetAsyncMode( \r
+ // /* [in] */ BOOL fDoOpAsync)\r
+ //{\r
+ // return E_NOTIMPL;\r
+ //}\r
+ //\r
+ //virtual HRESULT STDMETHODCALLTYPE GetAsyncMode( \r
+ // /* [out] */ BOOL __RPC_FAR *pfIsOpAsync)\r
+ //{\r
+ // return E_NOTIMPL;\r
+ //}\r
+ //\r
+ //virtual HRESULT STDMETHODCALLTYPE StartOperation( \r
+ // /* [optional][unique][in] */ IBindCtx __RPC_FAR *pbcReserved)\r
+ //{\r
+ // return E_NOTIMPL;\r
+ //}\r
+ //\r
+ //virtual HRESULT STDMETHODCALLTYPE InOperation( \r
+ // /* [out] */ BOOL __RPC_FAR *pfInAsyncOp)\r
+ //{\r
+ // return E_NOTIMPL;\r
+ //}\r
+ //\r
+ //virtual HRESULT STDMETHODCALLTYPE EndOperation( \r
+ // /* [in] */ HRESULT hResult,\r
+ // /* [unique][in] */ IBindCtx __RPC_FAR *pbcReserved,\r
+ // /* [in] */ DWORD dwEffects)\r
+ //{\r
+ // return E_NOTIMPL;\r
+ //}\r
+};\r
+\r
+///////////////////////////////////////////////////////////////////////////////////////////////\r
+class CIDropTarget : public IDropTarget\r
+{\r
+ DWORD m_cRefCount;\r
+ bool m_bAllowDrop;\r
+ struct IDropTargetHelper *m_pDropTargetHelper;\r
+ CSimpleArray<FORMATETC> m_formatetc;\r
+ FORMATETC* m_pSupportedFrmt;\r
+protected:\r
+ HWND m_hTargetWnd;\r
+public:\r
+ \r
+ CIDropTarget(HWND m_hTargetWnd);\r
+ virtual ~CIDropTarget();\r
+ void AddSuportedFormat(FORMATETC& ftetc) { m_formatetc.Add(ftetc); }\r
+ \r
+ //return values: true - release the medium. false - don't release the medium \r
+ virtual bool OnDrop(FORMATETC* pFmtEtc, STGMEDIUM& medium,DWORD *pdwEffect, POINTL pt) = 0;\r
+\r
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface( \r
+ /* [in] */ REFIID riid,\r
+ /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject);\r
+ virtual ULONG STDMETHODCALLTYPE AddRef( void) { ATLTRACE("CIDropTarget::AddRef\n"); return ++m_cRefCount; }\r
+ virtual ULONG STDMETHODCALLTYPE Release( void);\r
+\r
+ bool QueryDrop(DWORD grfKeyState, LPDWORD pdwEffect);\r
+ virtual HRESULT STDMETHODCALLTYPE DragEnter(\r
+ /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,\r
+ /* [in] */ DWORD grfKeyState,\r
+ /* [in] */ POINTL pt,\r
+ /* [out][in] */ DWORD __RPC_FAR *pdwEffect);\r
+ virtual HRESULT STDMETHODCALLTYPE DragOver( \r
+ /* [in] */ DWORD grfKeyState,\r
+ /* [in] */ POINTL pt,\r
+ /* [out][in] */ DWORD __RPC_FAR *pdwEffect);\r
+ virtual HRESULT STDMETHODCALLTYPE DragLeave( void); \r
+ virtual HRESULT STDMETHODCALLTYPE Drop(\r
+ /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,\r
+ /* [in] */ DWORD grfKeyState,\r
+ /* [in] */ POINTL pt,\r
+ /* [out][in] */ DWORD __RPC_FAR *pdwEffect);\r
+};\r
+\r
+class CDragSourceHelper\r
+{\r
+ IDragSourceHelper* pDragSourceHelper;\r
+public:\r
+ CDragSourceHelper()\r
+ {\r
+ pDragSourceHelper = NULL;\r
+ if(FAILED(CoCreateInstance(CLSID_DragDropHelper,\r
+ NULL,\r
+ CLSCTX_INPROC_SERVER,\r
+ IID_IDragSourceHelper,\r
+ (void**)&pDragSourceHelper)))\r
+ pDragSourceHelper = NULL;\r
+ }\r
+ virtual ~CDragSourceHelper()\r
+ {\r
+ if( pDragSourceHelper!= NULL )\r
+ {\r
+ pDragSourceHelper->Release();\r
+ pDragSourceHelper=NULL;\r
+ }\r
+ }\r
+ \r
+ // IDragSourceHelper\r
+ HRESULT InitializeFromBitmap(HBITMAP hBitmap, \r
+ POINT& pt, // cursor position in client coords of the window\r
+ RECT& rc, // selected item's bounding rect\r
+ IDataObject* pDataObject,\r
+ COLORREF crColorKey=GetSysColor(COLOR_WINDOW)// color of the window used for transparent effect.\r
+ )\r
+ {\r
+ if(pDragSourceHelper == NULL)\r
+ return E_FAIL;\r
+\r
+ SHDRAGIMAGE di;\r
+ BITMAP bm;\r
+ GetObject(hBitmap, sizeof(bm), &bm);\r
+ di.sizeDragImage.cx = bm.bmWidth;\r
+ di.sizeDragImage.cy = bm.bmHeight;\r
+ di.hbmpDragImage = hBitmap;\r
+ di.crColorKey = crColorKey; \r
+ di.ptOffset.x = pt.x - rc.left;\r
+ di.ptOffset.y = pt.y - rc.top;\r
+ return pDragSourceHelper->InitializeFromBitmap(&di, pDataObject);\r
+ }\r
+ HRESULT InitializeFromWindow(HWND hwnd, POINT& pt,IDataObject* pDataObject)\r
+ { \r
+ if(pDragSourceHelper == NULL)\r
+ return E_FAIL;\r
+ return pDragSourceHelper->InitializeFromWindow(hwnd, &pt, pDataObject);\r
+ }\r
+};\r
+#endif //__DRAGDROPIMPL_H__
\ No newline at end of file
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2006, 2008 - TortoiseSVN\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#include "stdafx.h"\r
+#include "DropFiles.h"\r
+\r
+CDropFiles::CDropFiles()\r
+{\r
+ m_pBuffer = NULL;\r
+ m_nBufferSize = 0;\r
+}\r
+\r
+CDropFiles::~CDropFiles()\r
+{\r
+ delete [] m_pBuffer;\r
+}\r
+\r
+void CDropFiles::AddFile(const CString &sFile)\r
+{\r
+ m_arFiles.Add(sFile);\r
+}\r
+\r
+INT_PTR CDropFiles::GetCount()\r
+{\r
+ return m_arFiles.GetCount();\r
+}\r
+\r
+void CDropFiles::CreateBuffer()\r
+{\r
+ ASSERT(m_pBuffer == NULL);\r
+ ASSERT(m_nBufferSize == 0);\r
+ ASSERT(m_arFiles.GetCount()>0);\r
+\r
+ int nLength = 0;\r
+\r
+ for(int i=0;i<m_arFiles.GetSize();i++)\r
+ {\r
+ nLength += m_arFiles[i].GetLength();\r
+ nLength += 1; // '\0' separator\r
+ }\r
+\r
+ m_nBufferSize = sizeof(DROPFILES) + (nLength+1)*sizeof(TCHAR);\r
+ m_pBuffer = new char[m_nBufferSize];\r
+ \r
+ SecureZeroMemory(m_pBuffer, m_nBufferSize);\r
+\r
+ DROPFILES* df = (DROPFILES*)m_pBuffer;\r
+ df->pFiles = sizeof(DROPFILES);\r
+ df->fWide = 1;\r
+\r
+ TCHAR* pFilenames = (TCHAR*)(m_pBuffer + sizeof(DROPFILES));\r
+ TCHAR* pCurrentFilename = pFilenames;\r
+\r
+ for(int i=0;i<m_arFiles.GetSize();i++)\r
+ {\r
+ CString str = m_arFiles[i];\r
+ wcscpy_s(pCurrentFilename,str.GetLength()+1,str.GetBuffer());\r
+ pCurrentFilename += str.GetLength(); \r
+ *pCurrentFilename = '\0'; // separator between file names\r
+ pCurrentFilename++;\r
+ }\r
+ *pCurrentFilename = '\0'; // terminate array\r
+}\r
+\r
+void* CDropFiles::GetBuffer() const\r
+{\r
+ return (void*)m_pBuffer;\r
+}\r
+\r
+int CDropFiles::GetBufferSize() const\r
+{\r
+ return m_nBufferSize;\r
+}\r
+\r
+void CDropFiles::CreateStructure()\r
+{\r
+ CreateBuffer();\r
+ \r
+ COleDataSource dropData;\r
+ HGLOBAL hMem = ::GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_DDESHARE, GetBufferSize()); \r
+ memcpy( ::GlobalLock(hMem), GetBuffer(), GetBufferSize() );\r
+ ::GlobalUnlock(hMem);\r
+ dropData.CacheGlobalData( CF_HDROP, hMem );\r
+ dropData.DoDragDrop(DROPEFFECT_COPY|DROPEFFECT_MOVE|DROPEFFECT_LINK,NULL);\r
+}\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2006-2007 - TortoiseSVN\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#pragma once\r
+\r
+#ifndef __DROPFILES_H__\r
+#define __DROPFILES_H__\r
+\r
+#include <shlobj.h>\r
+#include <afxcoll.h>\r
+\r
+/**\r
+ * \ingroup Utils\r
+ * Use this class to create the DROPFILES structure which is needed to\r
+ * support drag and drop of file names to other applications.\r
+ * Based on an example by Thomas Blenkers.\r
+ */\r
+class CDropFiles\r
+{\r
+public:\r
+ CDropFiles();\r
+ ~CDropFiles();\r
+\r
+ /**\r
+ * Add a file with an absolute file name. This file will later be\r
+ * included the DROPFILES structure.\r
+ */\r
+ void AddFile(const CString &sFile);\r
+\r
+ /**\r
+ * Returns the number of files which have been added\r
+ */\r
+ INT_PTR GetCount();\r
+\r
+ /**\r
+ * Call this method when dragging begins. It will fill\r
+ * the DROPFILES structure with the files previously\r
+ * added with AddFile(...)\r
+ */\r
+ void CreateStructure();\r
+\r
+protected:\r
+ /**\r
+ * CreateBuffer must be called once when all files have been added\r
+ */\r
+ void CreateBuffer();\r
+\r
+ /**\r
+ * Returns a pointer to the buffer containing the DROPFILES\r
+ * structure\r
+ */\r
+ void* GetBuffer() const;\r
+\r
+ /**\r
+ * Returns the size of the buffer in bytes\r
+ */\r
+ int GetBufferSize() const;\r
+\r
+protected:\r
+ CStringArray m_arFiles;\r
+ \r
+ char* m_pBuffer;\r
+ int m_nBufferSize;\r
+};\r
+\r
+#endif\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2007-2007 - TortoiseSVN\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#pragma once\r
+\r
+///////////////////////////////////////////////////////////////\r
+//\r
+// CHighResClock\r
+//\r
+// high resolution clock for performance measurement.\r
+// Depending on the hardware it will provide µsec \r
+// resolution and accuracy.\r
+//\r
+// May not be available on all machines.\r
+//\r
+///////////////////////////////////////////////////////////////\r
+\r
+class CHighResClock\r
+{\r
+private:\r
+\r
+ LARGE_INTEGER start;\r
+ LARGE_INTEGER taken;\r
+\r
+public:\r
+\r
+ // construction (starts measurement) / destruction\r
+\r
+ CHighResClock() \r
+ {\r
+ taken.QuadPart = 0;\r
+ Start();\r
+ }\r
+\r
+ ~CHighResClock()\r
+ {\r
+ }\r
+\r
+ // (re-start)\r
+\r
+ void Start()\r
+ {\r
+ QueryPerformanceCounter(&start);\r
+ }\r
+\r
+ // set "taken" to time since last Start()\r
+\r
+ void Stop()\r
+ {\r
+ QueryPerformanceCounter(&taken);\r
+ taken.QuadPart -= start.QuadPart;\r
+ }\r
+\r
+ // time in microseconds between last Start() and last Stop()\r
+\r
+ DWORD GetMusecsTaken() const\r
+ {\r
+ LARGE_INTEGER frequency;\r
+ QueryPerformanceFrequency(&frequency);\r
+ return (DWORD)((taken.QuadPart * 1000000) / frequency.QuadPart);\r
+ }\r
+};\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2007-2008 - TortoiseSVN\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#include "stdafx.h"\r
+#include "Hooks.h"\r
+#include "registry.h"\r
+#include "StringUtils.h"\r
+#include "TempFile.h"\r
+\r
+CHooks* CHooks::m_pInstance;\r
+\r
+CHooks::CHooks()\r
+{\r
+}\r
+\r
+CHooks::~CHooks()\r
+{\r
+};\r
+\r
+bool CHooks::Create()\r
+{\r
+ if (m_pInstance == NULL)\r
+ m_pInstance = new CHooks();\r
+ CRegString reghooks = CRegString(_T("Software\\TortoiseSVN\\hooks"));\r
+ CString strhooks = reghooks;\r
+ // now fill the map with all the hooks defined in the string\r
+ // the string consists of multiple lines, where one hook script is defined\r
+ // as four lines:\r
+ // line 1: the hook type\r
+ // line 2: path to working copy where to apply the hook script\r
+ // line 3: command line to execute\r
+ // line 4: 'true' or 'false' for waiting for the script to finish\r
+ // line 5: 'show' or 'hide' on how to start the hook script\r
+ hookkey key;\r
+ int pos = 0;\r
+ hookcmd cmd;\r
+ while ((pos = strhooks.Find('\n')) >= 0)\r
+ {\r
+ // line 1\r
+ key.htype = GetHookType(strhooks.Mid(0, pos));\r
+ if (pos+1 < strhooks.GetLength())\r
+ strhooks = strhooks.Mid(pos+1);\r
+ else\r
+ strhooks.Empty();\r
+ bool bComplete = false;\r
+ if ((pos = strhooks.Find('\n')) >= 0)\r
+ {\r
+ // line 2\r
+ key.path = CTSVNPath(strhooks.Mid(0, pos));\r
+ if (pos+1 < strhooks.GetLength())\r
+ strhooks = strhooks.Mid(pos+1);\r
+ else\r
+ strhooks.Empty();\r
+ if ((pos = strhooks.Find('\n')) >= 0)\r
+ {\r
+ // line 3\r
+ cmd.commandline = strhooks.Mid(0, pos);\r
+ if (pos+1 < strhooks.GetLength())\r
+ strhooks = strhooks.Mid(pos+1);\r
+ else\r
+ strhooks.Empty();\r
+ if ((pos = strhooks.Find('\n')) >= 0)\r
+ {\r
+ // line 4\r
+ cmd.bWait = (strhooks.Mid(0, pos).CompareNoCase(_T("true"))==0);\r
+ if (pos+1 < strhooks.GetLength())\r
+ strhooks = strhooks.Mid(pos+1);\r
+ else\r
+ strhooks.Empty();\r
+ if ((pos = strhooks.Find('\n')) >= 0)\r
+ {\r
+ // line 5\r
+ cmd.bShow = (strhooks.Mid(0, pos).CompareNoCase(_T("show"))==0);\r
+ if (pos+1 < strhooks.GetLength())\r
+ strhooks = strhooks.Mid(pos+1);\r
+ else\r
+ strhooks.Empty();\r
+ bComplete = true;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ if (bComplete)\r
+ {\r
+ m_pInstance->insert(std::pair<hookkey, hookcmd>(key, cmd));\r
+ }\r
+ } \r
+ return true;\r
+}\r
+\r
+CHooks& CHooks::Instance()\r
+{\r
+ return *m_pInstance;\r
+}\r
+\r
+void CHooks::Destroy()\r
+{\r
+ delete m_pInstance;\r
+}\r
+\r
+bool CHooks::Save()\r
+{\r
+ CString strhooks;\r
+ for (hookiterator it = begin(); it != end(); ++it)\r
+ {\r
+ strhooks += GetHookTypeString(it->first.htype);\r
+ strhooks += '\n';\r
+ strhooks += it->first.path.GetWinPathString();\r
+ strhooks += '\n';\r
+ strhooks += it->second.commandline;\r
+ strhooks += '\n';\r
+ strhooks += (it->second.bWait ? _T("true") : _T("false"));\r
+ strhooks += '\n';\r
+ strhooks += (it->second.bShow ? _T("show") : _T("hide"));\r
+ strhooks += '\n';\r
+ }\r
+ CRegString reghooks = CRegString(_T("Software\\TortoiseSVN\\hooks"));\r
+ reghooks = strhooks;\r
+ if (reghooks.LastError)\r
+ return false;\r
+ return true;\r
+}\r
+\r
+bool CHooks::Remove(hookkey key)\r
+{\r
+ return (erase(key) > 0);\r
+}\r
+\r
+void CHooks::Add(hooktype ht, const CTSVNPath& Path, LPCTSTR szCmd, bool bWait, bool bShow)\r
+{\r
+ hookkey key;\r
+ key.htype = ht;\r
+ key.path = Path;\r
+ hookiterator it = find(key);\r
+ if (it!=end())\r
+ erase(it);\r
+\r
+ hookcmd cmd;\r
+ cmd.commandline = szCmd;\r
+ cmd.bWait = bWait;\r
+ cmd.bShow = bShow;\r
+ insert(std::pair<hookkey, hookcmd>(key, cmd));\r
+}\r
+\r
+CString CHooks::GetHookTypeString(hooktype t)\r
+{\r
+ switch (t)\r
+ {\r
+ case start_commit_hook:\r
+ return _T("start_commit_hook");\r
+ case pre_commit_hook:\r
+ return _T("pre_commit_hook");\r
+ case post_commit_hook:\r
+ return _T("post_commit_hook");\r
+ case start_update_hook:\r
+ return _T("start_update_hook");\r
+ case pre_update_hook:\r
+ return _T("pre_update_hook");\r
+ case post_update_hook:\r
+ return _T("post_update_hook");\r
+ }\r
+ return _T("");\r
+}\r
+\r
+hooktype CHooks::GetHookType(const CString& s)\r
+{\r
+ if (s.Compare(_T("start_commit_hook"))==0)\r
+ return start_commit_hook;\r
+ if (s.Compare(_T("pre_commit_hook"))==0)\r
+ return pre_commit_hook;\r
+ if (s.Compare(_T("post_commit_hook"))==0)\r
+ return post_commit_hook;\r
+ if (s.Compare(_T("start_update_hook"))==0)\r
+ return start_update_hook;\r
+ if (s.Compare(_T("pre_update_hook"))==0)\r
+ return pre_update_hook;\r
+ if (s.Compare(_T("post_update_hook"))==0)\r
+ return post_update_hook;\r
+ return unknown_hook;\r
+}\r
+\r
+void CHooks::AddParam(CString& sCmd, const CString& param)\r
+{\r
+ sCmd += _T(" \"");\r
+ sCmd += param;\r
+ sCmd += _T("\"");\r
+}\r
+\r
+void CHooks::AddPathParam(CString& sCmd, const CTSVNPathList& pathList)\r
+{\r
+ CTSVNPath temppath = CTempFiles::Instance().GetTempFilePath(true);\r
+ pathList.WriteToFile(temppath.GetWinPathString(), true);\r
+ AddParam(sCmd, temppath.GetWinPathString());\r
+}\r
+\r
+void CHooks::AddCWDParam(CString& sCmd, const CTSVNPathList& pathList)\r
+{\r
+ AddParam(sCmd, pathList.GetCommonRoot().GetDirectory().GetWinPathString());\r
+}\r
+\r
+void CHooks::AddDepthParam(CString& sCmd, svn_depth_t depth)\r
+{\r
+ CString sTemp;\r
+ sTemp.Format(_T("%d"), depth);\r
+ AddParam(sCmd, sTemp);\r
+}\r
+\r
+void CHooks::AddErrorParam(CString& sCmd, const CString& error)\r
+{\r
+ CTSVNPath tempPath;\r
+ tempPath = CTempFiles::Instance().GetTempFilePath(true);\r
+ CStringUtils::WriteStringToTextFile(tempPath.GetWinPath(), (LPCTSTR)error);\r
+ AddParam(sCmd, tempPath.GetWinPathString());\r
+}\r
+\r
+CTSVNPath CHooks::AddMessageFileParam(CString& sCmd, const CString& message)\r
+{\r
+ CTSVNPath tempPath;\r
+ tempPath = CTempFiles::Instance().GetTempFilePath(true);\r
+ CStringUtils::WriteStringToTextFile(tempPath.GetWinPath(), (LPCTSTR)message);\r
+ AddParam(sCmd, tempPath.GetWinPathString());\r
+ return tempPath;\r
+}\r
+\r
+bool CHooks::StartCommit(const CTSVNPathList& pathList, CString& message, DWORD& exitcode, CString& error)\r
+{\r
+ hookiterator it = FindItem(start_commit_hook, pathList);\r
+ if (it == end())\r
+ return false;\r
+ CString sCmd = it->second.commandline;\r
+ AddPathParam(sCmd, pathList);\r
+ CTSVNPath temppath = AddMessageFileParam(sCmd, message);\r
+ AddCWDParam(sCmd, pathList);\r
+ exitcode = RunScript(sCmd, pathList.GetCommonRoot().GetDirectory().GetWinPath(), error, it->second.bWait, it->second.bShow);\r
+ if (!exitcode && !temppath.IsEmpty())\r
+ {\r
+ CStringUtils::ReadStringFromTextFile(temppath.GetWinPathString(), message);\r
+ }\r
+ return true;\r
+}\r
+\r
+bool CHooks::PreCommit(const CTSVNPathList& pathList, svn_depth_t depth, const CString& message, DWORD& exitcode, CString& error)\r
+{\r
+ hookiterator it = FindItem(pre_commit_hook, pathList);\r
+ if (it == end())\r
+ return false;\r
+ CString sCmd = it->second.commandline;\r
+ AddPathParam(sCmd, pathList);\r
+ AddDepthParam(sCmd, depth);\r
+ AddMessageFileParam(sCmd, message);\r
+ AddCWDParam(sCmd, pathList);\r
+ exitcode = RunScript(sCmd, pathList.GetCommonRoot().GetDirectory().GetWinPath(), error, it->second.bWait, it->second.bShow);\r
+ return true;\r
+}\r
+\r
+bool CHooks::PostCommit(const CTSVNPathList& pathList, svn_depth_t depth, SVNRev rev, const CString& message, DWORD& exitcode, CString& error)\r
+{\r
+ hookiterator it = FindItem(post_commit_hook, pathList);\r
+ if (it == end())\r
+ return false;\r
+ CString sCmd = it->second.commandline;\r
+ AddPathParam(sCmd, pathList);\r
+ AddDepthParam(sCmd, depth);\r
+ AddMessageFileParam(sCmd, message);\r
+ AddParam(sCmd, rev.ToString());\r
+ AddErrorParam(sCmd, error);\r
+ AddCWDParam(sCmd, pathList);\r
+ exitcode = RunScript(sCmd, pathList.GetCommonRoot().GetDirectory().GetWinPath(), error, it->second.bWait, it->second.bShow);\r
+ return true;\r
+}\r
+\r
+bool CHooks::StartUpdate(const CTSVNPathList& pathList, DWORD& exitcode, CString& error)\r
+{\r
+ hookiterator it = FindItem(start_update_hook, pathList);\r
+ if (it == end())\r
+ return false;\r
+ CString sCmd = it->second.commandline;\r
+ AddPathParam(sCmd, pathList);\r
+ AddCWDParam(sCmd, pathList);\r
+ exitcode = RunScript(sCmd, pathList.GetCommonRoot().GetDirectory().GetWinPath(), error, it->second.bWait, it->second.bShow);\r
+ return true;\r
+}\r
+\r
+bool CHooks::PreUpdate(const CTSVNPathList& pathList, svn_depth_t depth, SVNRev rev, DWORD& exitcode, CString& error)\r
+{\r
+ hookiterator it = FindItem(pre_update_hook, pathList);\r
+ if (it == end())\r
+ return false;\r
+ CString sCmd = it->second.commandline;\r
+ AddPathParam(sCmd, pathList);\r
+ AddDepthParam(sCmd, depth);\r
+ AddParam(sCmd, rev.ToString());\r
+ AddCWDParam(sCmd, pathList);\r
+ exitcode = RunScript(sCmd, pathList.GetCommonRoot().GetDirectory().GetWinPath(), error, it->second.bWait, it->second.bShow);\r
+ return true;\r
+}\r
+\r
+bool CHooks::PostUpdate(const CTSVNPathList& pathList, svn_depth_t depth, SVNRev rev, DWORD& exitcode, CString& error)\r
+{\r
+ hookiterator it = FindItem(post_update_hook, pathList);\r
+ if (it == end())\r
+ return false;\r
+ CString sCmd = it->second.commandline;\r
+ AddPathParam(sCmd, pathList);\r
+ AddDepthParam(sCmd, depth);\r
+ AddParam(sCmd, rev.ToString());\r
+ AddErrorParam(sCmd, error);\r
+ AddCWDParam(sCmd, pathList);\r
+ exitcode = RunScript(sCmd, pathList.GetCommonRoot().GetDirectory().GetWinPath(), error, it->second.bWait, it->second.bShow);\r
+ return true;\r
+}\r
+\r
+hookiterator CHooks::FindItem(hooktype t, const CTSVNPathList& pathList)\r
+{\r
+ hookkey key;\r
+ for (int i=0; i<pathList.GetCount(); ++i)\r
+ {\r
+ CTSVNPath path = pathList[i];\r
+ do \r
+ {\r
+ key.htype = t;\r
+ key.path = path;\r
+ hookiterator it = find(key);\r
+ if (it != end())\r
+ {\r
+ return it;\r
+ }\r
+ path = path.GetContainingDirectory();\r
+ } while(!path.IsEmpty());\r
+ }\r
+ // look for a script with a path as '*'\r
+ key.htype = t;\r
+ key.path = CTSVNPath(_T("*"));\r
+ hookiterator it = find(key);\r
+ if (it != end())\r
+ {\r
+ return it;\r
+ }\r
+\r
+ return end();\r
+}\r
+\r
+DWORD CHooks::RunScript(CString cmd, LPCTSTR currentDir, CString& error, bool bWait, bool bShow)\r
+{\r
+ DWORD exitcode = 0;\r
+ SECURITY_ATTRIBUTES sa;\r
+ SecureZeroMemory(&sa, sizeof(sa));\r
+ sa.nLength = sizeof(sa);\r
+ sa.bInheritHandle = TRUE;\r
+\r
+ HANDLE hOut = INVALID_HANDLE_VALUE;\r
+ HANDLE hRedir = INVALID_HANDLE_VALUE;\r
+ HANDLE hErr = INVALID_HANDLE_VALUE;\r
+\r
+ // clear the error string\r
+ error.Empty();\r
+\r
+ // Create Temp File for redirection\r
+ TCHAR szTempPath[MAX_PATH];\r
+ TCHAR szOutput[MAX_PATH];\r
+ TCHAR szErr[MAX_PATH];\r
+ GetTempPath(sizeof(szTempPath)/sizeof(TCHAR),szTempPath);\r
+ GetTempFileName(szTempPath, _T("svn"), 0, szErr);\r
+\r
+ // setup redirection handles\r
+ // output handle must be WRITE mode, share READ\r
+ // redirect handle must be READ mode, share WRITE\r
+ hErr = CreateFile(szErr, GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, 0);\r
+\r
+ if (hErr == INVALID_HANDLE_VALUE) \r
+ {\r
+ return (DWORD)-1;\r
+ }\r
+\r
+ hRedir = CreateFile(szErr, GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);\r
+\r
+ if (hRedir == INVALID_HANDLE_VALUE) \r
+ {\r
+ CloseHandle(hErr);\r
+ return (DWORD)-1;\r
+ }\r
+\r
+ GetTempFileName(szTempPath, _T("svn"), 0, szOutput);\r
+ hOut = CreateFile(szOutput, GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, 0);\r
+\r
+ if (hOut == INVALID_HANDLE_VALUE) \r
+ {\r
+ CloseHandle(hErr);\r
+ CloseHandle(hRedir);\r
+ return (DWORD)-1;\r
+ }\r
+\r
+ // setup startup info, set std out/err handles\r
+ // hide window\r
+ STARTUPINFO si;\r
+ SecureZeroMemory(&si, sizeof(si));\r
+ si.cb = sizeof(si);\r
+ if (hOut != INVALID_HANDLE_VALUE) \r
+ {\r
+ si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;\r
+ si.hStdOutput = hOut;\r
+ si.hStdError = hErr;\r
+ si.wShowWindow = bShow ? SW_SHOW : SW_HIDE;\r
+ }\r
+\r
+ PROCESS_INFORMATION pi;\r
+ SecureZeroMemory(&pi, sizeof(pi));\r
+\r
+ DWORD dwFlags = 0;\r
+\r
+ if (!CreateProcess(NULL, cmd.GetBuffer(), NULL, NULL, TRUE, dwFlags, NULL, currentDir, &si, &pi)) \r
+ {\r
+ int err = GetLastError(); // preserve the CreateProcess error\r
+ if (hErr != INVALID_HANDLE_VALUE) \r
+ {\r
+ CloseHandle(hErr);\r
+ CloseHandle(hRedir);\r
+ }\r
+ SetLastError(err);\r
+ cmd.ReleaseBuffer();\r
+ return (DWORD)-1;\r
+ }\r
+ cmd.ReleaseBuffer();\r
+\r
+ CloseHandle(pi.hThread);\r
+\r
+ // wait for process to finish, capture redirection and\r
+ // send it to the parent window/console\r
+ if (bWait)\r
+ {\r
+ DWORD dw;\r
+ char buf[256];\r
+ do \r
+ {\r
+ SecureZeroMemory(&buf,sizeof(buf));\r
+ while (ReadFile(hRedir, &buf, sizeof(buf)-1, &dw, NULL)) \r
+ {\r
+ if (dw == 0) \r
+ break;\r
+ error += CString(CStringA(buf,dw));\r
+ SecureZeroMemory(&buf,sizeof(buf));\r
+ }\r
+ } while (WaitForSingleObject(pi.hProcess, 0) != WAIT_OBJECT_0);\r
+\r
+ // perform any final flushing\r
+ while (ReadFile(hRedir, &buf, sizeof(buf)-1, &dw, NULL)) \r
+ {\r
+ if (dw == 0) \r
+ break;\r
+\r
+ error += CString(CStringA(buf, dw));\r
+ SecureZeroMemory(&buf,sizeof(buf));\r
+ }\r
+ WaitForSingleObject(pi.hProcess, INFINITE);\r
+ GetExitCodeProcess(pi.hProcess, &exitcode);\r
+ }\r
+ CloseHandle(pi.hProcess);\r
+ CloseHandle(hErr);\r
+ CloseHandle(hOut);\r
+ CloseHandle(hRedir);\r
+ DeleteFile(szOutput);\r
+ DeleteFile(szErr);\r
+\r
+ return exitcode;\r
+}\r
+\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2006-2008 - TortoiseSVN\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#pragma once\r
+#include <map>\r
+#include "registry.h"\r
+#include "TSVNPath.h"\r
+#include "SVNRev.h"\r
+\r
+/**\r
+ * \ingroup TortoiseProc\r
+ * enumeration of all client hook types\r
+ */\r
+typedef enum hooktype\r
+{\r
+ unknown_hook,\r
+ start_commit_hook,\r
+ pre_commit_hook,\r
+ post_commit_hook,\r
+ start_update_hook,\r
+ pre_update_hook,\r
+ post_update_hook,\r
+ issue_tracker_hook\r
+} hooktype;\r
+\r
+/**\r
+ * \ingroup TortoiseProc\r
+ * helper class, used as the key to the std::map we store\r
+ * the data for the client hook scripts in.\r
+ */\r
+class hookkey\r
+{\r
+public:\r
+ hooktype htype;\r
+ CTSVNPath path;\r
+\r
+ bool operator < (const hookkey& hk) const \r
+ {\r
+ if (htype == hk.htype) \r
+ return (path < hk.path); \r
+ else \r
+ return htype < hk.htype;\r
+ }\r
+};\r
+\r
+/**\r
+ * \ingroup TortoiseProc\r
+ * helper struct, used as the value to the std::map we\r
+ * store the data for the client hook scripts in.\r
+ */\r
+typedef struct hookcmd\r
+{\r
+ CString commandline;\r
+ bool bWait;\r
+ bool bShow;\r
+} hookcmd;\r
+\r
+typedef std::map<hookkey, hookcmd>::iterator hookiterator;\r
+\r
+/**\r
+ * \ingroup TortoiseProc\r
+ * Singleton class which deals with the client hook scripts.\r
+ */\r
+class CHooks : public std::map<hookkey, hookcmd>\r
+{\r
+private:\r
+ CHooks();\r
+ ~CHooks();\r
+ void AddPathParam(CString& sCmd, const CTSVNPathList& pathList);\r
+ void AddDepthParam(CString& sCmd, svn_depth_t depth);\r
+ void AddCWDParam(CString& sCmd, const CTSVNPathList& pathList);\r
+ void AddErrorParam(CString& sCmd, const CString& error);\r
+ void AddParam(CString& sCmd, const CString& param);\r
+ CTSVNPath AddMessageFileParam(CString& sCmd, const CString& message);\r
+public:\r
+ /// Create the singleton. Call this at the start of the program.\r
+ static bool Create();\r
+ /// Returns the singleton instance\r
+ static CHooks& Instance();\r
+ /// Destroys the singleton object. Call this at the end of the program.\r
+ static void Destroy();\r
+\r
+public:\r
+ /// Saves the hook script information to the registry.\r
+ bool Save();\r
+ /**\r
+ * Removes the hook script identified by \c key. To make the change persistent\r
+ * call Save().\r
+ */\r
+ bool Remove(hookkey key);\r
+ /**\r
+ * Adds a new hook script. To make the change persistent, call Save().\r
+ */\r
+ void Add(hooktype ht, const CTSVNPath& Path, LPCTSTR szCmd, \r
+ bool bWait, bool bShow);\r
+\r
+ /// returns the string representation of the hook type.\r
+ static CString GetHookTypeString(hooktype t);\r
+ /// returns the hooktype from a string representation of the same.\r
+ static hooktype GetHookType(const CString& s);\r
+\r
+ /**\r
+ * Executes the Start-Update-Hook that first matches one of the paths in\r
+ * \c pathList.\r
+ * \param pathList a list of paths to look for the hook scripts\r
+ * \param exitcode on return, contains the exit code of the hook script\r
+ * \param error the data the hook script outputs to stderr\r
+ * \remark the string "%PATHS% in the command line of the hook script is \r
+ * replaced with the path to a temporary file which contains a list of files\r
+ * in \c pathList, separated by newlines. The hook script can parse this\r
+ * file to get all the paths the update is about to be done on.\r
+ */\r
+ bool StartUpdate(const CTSVNPathList& pathList, DWORD& exitcode, \r
+ CString& error);\r
+ /**\r
+ * Executes the Pre-Update-Hook that first matches one of the paths in\r
+ * \c pathList.\r
+ * \param pathList a list of paths to look for the hook scripts\r
+ * \param depth the depth of the commit\r
+ * \param rev the revision the update is done to\r
+ * \param exitcode on return, contains the exit code of the hook script\r
+ * \param error the data the hook script outputs to stderr\r
+ * \remark the string "%PATHS% in the command line of the hook script is \r
+ * replaced with the path to a temporary file which contains a list of files\r
+ * in \c pathList, separated by newlines. The hook script can parse this\r
+ * file to get all the paths the update is about to be done on.\r
+ * The string "%RECURSIVE%" is replaced with either "recursive" or "nonrecursive" according\r
+ * to the \c bRecursive parameter. And the string "%REVISION%" is replaced with\r
+ * the string representation of \c rev.\r
+ */\r
+ bool PreUpdate(const CTSVNPathList& pathList, svn_depth_t depth, \r
+ SVNRev rev, DWORD& exitcode, CString& error);\r
+ /**\r
+ * Executes the Post-Update-Hook that first matches one of the paths in\r
+ * \c pathList.\r
+ * \param pathList a list of paths to look for the hook scripts\r
+ * \param depth the depth of the commit\r
+ * \param rev the revision the update was done to\r
+ * \param exitcode on return, contains the exit code of the hook script\r
+ * \param error the data the hook script outputs to stderr\r
+ * \remark the string "%PATHS% in the command line of the hook script is \r
+ * replaced with the path to a temporary file which contains a list of files\r
+ * in \c pathList, separated by newlines. The hook script can parse this\r
+ * file to get all the paths the update is about to be done on.\r
+ * The string "%RECURSIVE%" is replaced with either "recursive" or "nonrecursive" according\r
+ * to the \c bRecursive parameter. And the string "%REVISION%" is replaced with\r
+ * the string representation of \c rev.\r
+ */\r
+ bool PostUpdate(const CTSVNPathList& pathList, svn_depth_t depth, \r
+ SVNRev rev, DWORD& exitcode, CString& error);\r
+\r
+ /**\r
+ * Executes the Start-Commit-Hook that first matches one of the paths in\r
+ * \c pathList.\r
+ * \param pathList a list of paths to look for the hook scripts\r
+ * \param message a commit message\r
+ * \param exitcode on return, contains the exit code of the hook script\r
+ * \param error the data the hook script outputs to stderr\r
+ * \remark the string "%PATHS% in the command line of the hook script is \r
+ * replaced with the path to a temporary file which contains a list of files\r
+ * in \c pathList, separated by newlines. The hook script can parse this\r
+ * file to get all the paths the commit is about to be done on.\r
+ * The string %MESSAGEFILE% is replaced with path to temporary file containing\r
+ * \c message. If the script finishes successfully, contents of this file\r
+ * is read back into \c message parameter.\r
+ */\r
+ bool StartCommit(const CTSVNPathList& pathList, CString& message,\r
+ DWORD& exitcode, CString& error);\r
+ /**\r
+ * Executes the Pre-Commit-Hook that first matches one of the paths in\r
+ * \c pathList.\r
+ * \param pathList a list of paths to look for the hook scripts\r
+ * \param depth the depth of the commit\r
+ * \param message the commit message\r
+ * \param exitcode on return, contains the exit code of the hook script\r
+ * \param error the data the hook script outputs to stderr\r
+ * \remark the string "%PATHS% in the command line of the hook script is \r
+ * replaced with the path to a temporary file which contains a list of files\r
+ * in \c pathList, separated by newlines. The hook script can parse this\r
+ * file to get all the paths the update is about to be done on.\r
+ * The string "%DEPTH%" is replaced with the numerical value (string) of the\r
+ * svn_depth_t parameter. See the Subversion source documentation about the\r
+ * values.\r
+ */\r
+ bool PreCommit(const CTSVNPathList& pathList, svn_depth_t depth, \r
+ const CString& message, DWORD& exitcode, \r
+ CString& error);\r
+ /**\r
+ * Executes the Post-Commit-Hook that first matches one of the paths in\r
+ * \c pathList.\r
+ * \param pathList a list of paths to look for the hook scripts\r
+ * \param depth the depth of the commit\r
+ * \param message the commit message\r
+ * \param rev the revision the commit was done to\r
+ * \param exitcode on return, contains the exit code of the hook script\r
+ * \param error the data the hook script outputs to stderr\r
+ * \remark the string "%PATHS% in the command line of the hook script is \r
+ * replaced with the path to a temporary file which contains a list of files\r
+ * in \c pathList, separated by newlines. The hook script can parse this\r
+ * file to get all the paths the commit is about to be done on.\r
+ * The string "%DEPTH%" is replaced with the numerical value (string) of the\r
+ * svn_depth_t parameter. See the Subversion source documentation about the\r
+ * values.\r
+ */\r
+ bool PostCommit(const CTSVNPathList& pathList, svn_depth_t depth, \r
+ SVNRev rev, const CString& message, \r
+ DWORD& exitcode, CString& error);\r
+\r
+private:\r
+ /**\r
+ * Starts a new process, specified in \c cmd.\r
+ * \param error the data the process writes to stderr\r
+ * \param bWait if true, then this method waits until the created process has finished. If false, then the return\r
+ * value will always be 0 and \c error will be an empty string.\r
+ * \param bShow set to true if the process should be started visible.\r
+ * \return the exit code of the process if \c bWait is true, zero otherwise.\r
+ */\r
+ DWORD RunScript(CString cmd, LPCTSTR currentDir, CString& error, bool bWait, bool bShow);\r
+ /**\r
+ * Find the hook script information for the hook type \c t which matches a\r
+ * path in \c pathList.\r
+ */\r
+ hookiterator FindItem(hooktype t, const CTSVNPathList& pathList);\r
+ static CHooks * m_pInstance;\r
+};\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2006,2008 - TortoiseSVN\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#include "stdafx.h"\r
+#include <assert.h>\r
+#include "LangDll.h"\r
+#include "..\version.h"\r
+\r
+#pragma comment(lib, "Version.lib")\r
+\r
+CLangDll::CLangDll()\r
+{\r
+ m_hInstance = NULL;\r
+}\r
+\r
+CLangDll::~CLangDll()\r
+{\r
+\r
+}\r
+\r
+HINSTANCE CLangDll::Init(LPCTSTR appname, unsigned long langID)\r
+{\r
+ TCHAR langpath[MAX_PATH];\r
+ TCHAR langdllpath[MAX_PATH];\r
+ TCHAR sVer[MAX_PATH];\r
+ _tcscpy_s(sVer, MAX_PATH, _T(STRPRODUCTVER));\r
+ GetModuleFileName(NULL, langpath, MAX_PATH);\r
+ TCHAR * pSlash = _tcsrchr(langpath, '\\');\r
+ if (pSlash)\r
+ {\r
+ *pSlash = 0;\r
+ pSlash = _tcsrchr(langpath, '\\');\r
+ if (pSlash)\r
+ {\r
+ *pSlash = 0;\r
+ _tcscat_s(langpath, MAX_PATH, _T("\\Languages\\"));\r
+ assert(m_hInstance == NULL);\r
+ do\r
+ {\r
+ _stprintf_s(langdllpath, MAX_PATH, _T("%s%s%d.dll"), langpath, appname, langID);\r
+\r
+ m_hInstance = LoadLibrary(langdllpath);\r
+\r
+ if (!DoVersionStringsMatch(sVer, langdllpath))\r
+ {\r
+ FreeLibrary(m_hInstance);\r
+ m_hInstance = NULL;\r
+ }\r
+ if (m_hInstance == NULL)\r
+ {\r
+ DWORD lid = SUBLANGID(langID);\r
+ lid--;\r
+ if (lid > 0)\r
+ {\r
+ langID = MAKELANGID(PRIMARYLANGID(langID), lid);\r
+ }\r
+ else\r
+ langID = 0;\r
+ }\r
+ } while ((m_hInstance == NULL) && (langID != 0));\r
+ }\r
+ }\r
+ return m_hInstance;\r
+}\r
+\r
+void CLangDll::Close()\r
+{\r
+ if (m_hInstance)\r
+ {\r
+ FreeLibrary(m_hInstance);\r
+ m_hInstance = NULL;\r
+ }\r
+}\r
+\r
+bool CLangDll::DoVersionStringsMatch(LPCTSTR sVer, LPCTSTR langDll)\r
+{\r
+ struct TRANSARRAY\r
+ {\r
+ WORD wLanguageID;\r
+ WORD wCharacterSet;\r
+ };\r
+\r
+ bool bReturn = false;\r
+ DWORD dwReserved,dwBufferSize;\r
+ dwBufferSize = GetFileVersionInfoSize((LPTSTR)langDll,&dwReserved);\r
+\r
+ if (dwBufferSize > 0)\r
+ {\r
+ LPVOID pBuffer = (void*) malloc(dwBufferSize);\r
+\r
+ if (pBuffer != (void*) NULL)\r
+ {\r
+ UINT nInfoSize = 0,\r
+ nFixedLength = 0;\r
+ LPSTR lpVersion = NULL;\r
+ VOID* lpFixedPointer;\r
+ TRANSARRAY* lpTransArray;\r
+ TCHAR strLangProduktVersion[MAX_PATH];\r
+\r
+ GetFileVersionInfo((LPTSTR)langDll,\r
+ dwReserved,\r
+ dwBufferSize,\r
+ pBuffer);\r
+\r
+ VerQueryValue( pBuffer,\r
+ _T("\\VarFileInfo\\Translation"),\r
+ &lpFixedPointer,\r
+ &nFixedLength);\r
+ lpTransArray = (TRANSARRAY*) lpFixedPointer;\r
+\r
+ _stprintf_s(strLangProduktVersion, MAX_PATH, \r
+ _T("\\StringFileInfo\\%04x%04x\\ProductVersion"),\r
+ lpTransArray[0].wLanguageID,\r
+ lpTransArray[0].wCharacterSet);\r
+\r
+ VerQueryValue(pBuffer,\r
+ (LPTSTR)strLangProduktVersion,\r
+ (LPVOID *)&lpVersion,\r
+ &nInfoSize);\r
+\r
+ bReturn = (_tcscmp(sVer, (LPCTSTR)lpVersion)==0);\r
+ free(pBuffer);\r
+ }\r
+ } \r
+\r
+ return bReturn;\r
+}\r
+\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2007 - TortoiseSVN\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#pragma once\r
+\r
+/**\r
+ * \ingroup Utils\r
+ * Helper class to load language dependent resource dlls.\r
+ */\r
+class CLangDll\r
+{\r
+public:\r
+ CLangDll();\r
+ ~CLangDll();\r
+\r
+ HINSTANCE Init(LPCTSTR appname, unsigned long langID);\r
+ void Close();\r
+private:\r
+ bool DoVersionStringsMatch(LPCTSTR sVer, LPCTSTR langDll);\r
+ HINSTANCE m_hInstance;\r
+};\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2008 - TortoiseSVN\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#include "stdafx.h"\r
+#include "Balloon.h"\r
+\r
+tagBALLOON_INFO::tagBALLOON_INFO()\r
+ : hIcon(NULL), \r
+ sBalloonTip(),\r
+ nMask(0),\r
+ nStyles(0),\r
+ nDirection(0),\r
+ nEffect(0),\r
+ nBehaviour(0),\r
+ crBegin(0),\r
+ crMid(0),\r
+ crEnd(0)\r
+{\r
+}\r
+\r
+CBalloon::CBalloon()\r
+ : m_nStyles (0)\r
+{\r
+ m_pParentWnd = NULL;\r
+ m_hCurrentWnd = NULL;\r
+ m_hDisplayedWnd = NULL;\r
+\r
+ m_rgnShadow.CreateRectRgn(0, 0, 1, 1);\r
+ m_rgnBalloon.CreateRectRgn(0, 0, 1, 1);\r
+\r
+ m_ptOriginal.x = -1;\r
+ m_ptOriginal.y = -1;\r
+\r
+ SetDelayTime(TTDT_INITIAL, 500);\r
+ SetDelayTime(TTDT_AUTOPOP, 30000);\r
+ SetNotify(FALSE);\r
+ SetDirection();\r
+ SetBehaviour();\r
+ SetDefaultStyles();\r
+ SetDefaultColors();\r
+ SetDefaultSizes();\r
+ SetEffectBk(BALLOON_EFFECT_SOLID);\r
+ RemoveAllTools();\r
+ m_bButtonPushed = FALSE;\r
+\r
+ // Register the window class if it has not already been registered.\r
+ WNDCLASS wndcls;\r
+ HINSTANCE hInst = AfxGetInstanceHandle();\r
+ if(!(::GetClassInfo(hInst, BALLOON_CLASSNAME, &wndcls)))\r
+ {\r
+ // otherwise we need to register a new class\r
+ wndcls.style = CS_SAVEBITS;\r
+ wndcls.lpfnWndProc = ::DefWindowProc;\r
+ wndcls.cbClsExtra = wndcls.cbWndExtra = 0;\r
+ wndcls.hInstance = hInst;\r
+ wndcls.hIcon = NULL;\r
+ wndcls.hCursor = LoadCursor(hInst, IDC_ARROW );\r
+ wndcls.hbrBackground = NULL;\r
+ wndcls.lpszMenuName = NULL;\r
+ wndcls.lpszClassName = BALLOON_CLASSNAME;\r
+\r
+ if (!AfxRegisterClass(&wndcls))\r
+ AfxThrowResourceException();\r
+ }\r
+}\r
+\r
+CBalloon::~CBalloon()\r
+{\r
+ RemoveAllTools();\r
+\r
+ m_rgnBalloon.DeleteObject();\r
+ m_rgnShadow.DeleteObject();\r
+\r
+ if (IsWindow(m_hWnd))\r
+ DestroyWindow();\r
+}\r
+\r
+\r
+BEGIN_MESSAGE_MAP(CBalloon, CWnd)\r
+ //{{AFX_MSG_MAP(CBalloon)\r
+ ON_WM_PAINT()\r
+ ON_WM_TIMER()\r
+ ON_WM_DESTROY()\r
+ ON_WM_KILLFOCUS()\r
+ //}}AFX_MSG_MAP\r
+ ON_WM_MOUSEMOVE()\r
+ ON_WM_LBUTTONDOWN()\r
+ ON_WM_LBUTTONUP()\r
+END_MESSAGE_MAP()\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// CBalloon message handlers\r
+\r
+BOOL CBalloon::Create(CWnd* pParentWnd) \r
+{\r
+ DWORD dwStyle = WS_POPUP; \r
+ DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_TOPMOST;\r
+\r
+ m_pParentWnd = pParentWnd;\r
+\r
+ if (!CreateEx(dwExStyle, BALLOON_CLASSNAME, NULL, dwStyle, 0, 0, 0, 0, m_pParentWnd->GetSafeHwnd(), NULL, NULL))\r
+ {\r
+ return FALSE;\r
+ }\r
+ SetDefaultFont();\r
+ \r
+ return TRUE;\r
+}\r
+\r
+void CBalloon::OnDestroy() \r
+{\r
+ TRACE("OnDestroy()\n");\r
+ KillTimers();\r
+ \r
+ CWnd::OnDestroy();\r
+}\r
+\r
+\r
+\r
+void CBalloon::OnKillFocus(CWnd* pNewWnd) \r
+{\r
+ CWnd::OnKillFocus(pNewWnd);\r
+ Pop();\r
+}\r
+\r
+\r
+BOOL CBalloon::PreTranslateMessage(MSG* pMsg) \r
+{\r
+ RelayEvent(pMsg);\r
+\r
+ return CWnd::PreTranslateMessage(pMsg);\r
+}\r
+\r
+LRESULT CBalloon::SendNotify(CWnd * pWnd, CPoint * pt, BALLOON_INFO & bi)\r
+{\r
+ //make sure this is a valid window\r
+ if (!IsWindow(GetSafeHwnd()))\r
+ return 0L;\r
+\r
+ //see if the user wants to be notified\r
+ if (!GetNotify())\r
+ return 0L;\r
+\r
+ NM_BALLOON_DISPLAY lpnm;\r
+ \r
+ lpnm.pWnd = pWnd;\r
+ lpnm.pt = pt;\r
+ lpnm.bi = &bi;\r
+ lpnm.hdr.hwndFrom = m_hWnd;\r
+ lpnm.hdr.idFrom = GetDlgCtrlID();\r
+ lpnm.hdr.code = UDM_TOOLTIP_DISPLAY;\r
+ \r
+ ::SendMessage(m_hNotifyWnd, WM_NOTIFY, lpnm.hdr.idFrom, (LPARAM)&lpnm);\r
+\r
+ return 0L;\r
+}\r
+\r
+void CBalloon::OnPaint() \r
+{\r
+ //if (!m_pCurrentWnd)\r
+ // return;\r
+\r
+ m_hDisplayedWnd = m_hCurrentWnd;\r
+\r
+ CPaintDC dc(this); // device context for painting\r
+\r
+ CRect rect;\r
+ GetClientRect(&rect);\r
+ rect.DeflateRect(0, 0, 1, 1);\r
+\r
+ //create a memory device-context. This is done to help reduce\r
+ //screen flicker, since we will paint the entire control to the\r
+ //off screen device context first.CDC memDC;\r
+ CDC memDC;\r
+ CBitmap bitmap;\r
+ memDC.CreateCompatibleDC(&dc);\r
+ bitmap.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height());\r
+ CBitmap* pOldBitmap = memDC.SelectObject(&bitmap); \r
+ \r
+ memDC.BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &dc, 0, 0, SRCCOPY);\r
+ \r
+ //draw the tooltip\r
+ OnDraw(&memDC, rect);\r
+\r
+ //Copy the memory device context back into the original DC.\r
+ dc.BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &memDC, 0,0, SRCCOPY);\r
+ \r
+ //Cleanup resources.\r
+ memDC.SelectObject(pOldBitmap);\r
+ memDC.DeleteDC();\r
+ bitmap.DeleteObject(); \r
+}\r
+\r
+void CBalloon::OnDraw(CDC * pDC, CRect rect)\r
+{\r
+ CBrush brBackground(m_crColor [BALLOON_COLOR_BK_BEGIN]);\r
+ CBrush brShadow(m_crColor [BALLOON_COLOR_SHADOW]);\r
+ CBrush brBorder(m_crColor [BALLOON_COLOR_BORDER]);\r
+ \r
+ pDC->SetBkMode(TRANSPARENT); \r
+ pDC->SetTextColor(m_crColor [BALLOON_COLOR_FG]);\r
+ //set clip region of the tooltip and draw the shadow if needed\r
+ if (m_pToolInfo.nStyles & BALLOON_SHADOW)\r
+ {\r
+ //draw the shadow for the tooltip\r
+ int nRop2Mode = pDC->SetROP2(R2_MASKPEN);\r
+ pDC->FillRgn(&m_rgnShadow, &brShadow);\r
+ pDC->SetROP2(nRop2Mode);\r
+ rect.DeflateRect(0, 0, m_nSizes[XBLSZ_SHADOW_CX], m_nSizes[XBLSZ_SHADOW_CY]);\r
+ }\r
+ pDC->SelectClipRgn(&m_rgnBalloon);\r
+\r
+ OnDrawBackground(pDC, &rect);\r
+\r
+ //draw the main region's border of the tooltip\r
+ pDC->FrameRgn(&m_rgnBalloon, &brBorder, m_nSizes[XBLSZ_BORDER_CX], m_nSizes[XBLSZ_BORDER_CY]);\r
+\r
+ if ((m_nLastDirection == BALLOON_RIGHT_BOTTOM) || (m_nLastDirection == BALLOON_LEFT_BOTTOM))\r
+ rect.top += m_nSizes[XBLSZ_HEIGHT_ANCHOR];\r
+ else\r
+ rect.bottom -= m_nSizes[XBLSZ_HEIGHT_ANCHOR];\r
+\r
+ if (m_pToolInfo.nStyles & BALLOON_CLOSEBUTTON)\r
+ {\r
+ m_rtCloseButton = CRect(\r
+ rect.right - m_szCloseButton.cx - m_nSizes[XBLSZ_BUTTON_MARGIN_CX] , rect.top + m_nSizes[XBLSZ_BUTTON_MARGIN_CY], \r
+ rect.right - m_nSizes[XBLSZ_BUTTON_MARGIN_CX], rect.top + m_szCloseButton.cy + m_nSizes[XBLSZ_BUTTON_MARGIN_CY]);\r
+ pDC->DrawFrameControl(m_rtCloseButton, DFC_CAPTION, DFCS_CAPTIONCLOSE|DFCS_FLAT|DFCS_TRANSPARENT);\r
+ rect.right -= (m_szCloseButton.cx + m_nSizes[XBLSZ_BUTTON_MARGIN_CX]);\r
+ }\r
+\r
+ //get the rectangle to draw the tooltip text\r
+ rect.DeflateRect(m_nSizes[XBLSZ_MARGIN_CX], m_nSizes[XBLSZ_MARGIN_CY]);\r
+\r
+ //draw the icon\r
+ if (m_pToolInfo.hIcon != NULL)\r
+ {\r
+ DrawIconEx(pDC->m_hDC, m_nSizes[XBLSZ_MARGIN_CX], rect.top + (rect.Height() - m_szBalloonIcon.cy) / 2, \r
+ m_pToolInfo.hIcon, m_szBalloonIcon.cx, m_szBalloonIcon.cy, 0, NULL, DI_NORMAL);\r
+\r
+ rect.left += m_szBalloonIcon.cx + m_nSizes[XBLSZ_MARGIN_CX]; \r
+ }\r
+\r
+\r
+ //aligns tool tip's text\r
+ if (m_pToolInfo.nStyles & BALLOON_BOTTOM_ALIGN)\r
+ rect.top = rect.bottom - m_szBalloonText.cy;\r
+ else if (m_pToolInfo.nStyles & BALLOON_VCENTER_ALIGN)\r
+ rect.top += (rect.Height() - m_szBalloonText.cy) / 2;\r
+\r
+ //prints the tool tip's text\r
+ DrawHTML(pDC, rect, m_pToolInfo.sBalloonTip, m_LogFont, FALSE);\r
+\r
+ //free resources\r
+ brBackground.DeleteObject();\r
+ brShadow.DeleteObject();\r
+ brBorder.DeleteObject();\r
+}\r
+\r
+void CBalloon::OnDrawBackground(CDC * pDC, CRect * pRect)\r
+{\r
+#ifdef USE_GDI_GRADIENT\r
+ #define DRAW CGradient::DrawGDI\r
+#else\r
+ #define DRAW CGradient::Draw\r
+#endif\r
+ switch (m_pToolInfo.nEffect)\r
+ {\r
+ case BALLOON_EFFECT_HGRADIENT:\r
+ DRAW(pDC, pRect, m_crColor[BALLOON_COLOR_BK_BEGIN], m_crColor[BALLOON_COLOR_BK_END]);\r
+ break;\r
+ case BALLOON_EFFECT_VGRADIENT:\r
+ DRAW(pDC, pRect, m_crColor[BALLOON_COLOR_BK_BEGIN], m_crColor[BALLOON_COLOR_BK_END], FALSE);\r
+ break;\r
+ case BALLOON_EFFECT_HCGRADIENT:\r
+ DRAW(pDC, pRect, m_crColor[BALLOON_COLOR_BK_BEGIN], m_crColor[BALLOON_COLOR_BK_END], m_crColor[BALLOON_COLOR_BK_BEGIN]);\r
+ break;\r
+ case BALLOON_EFFECT_VCGRADIENT:\r
+ DRAW(pDC, pRect, m_crColor[BALLOON_COLOR_BK_BEGIN], m_crColor[BALLOON_COLOR_BK_END], m_crColor[BALLOON_COLOR_BK_BEGIN], FALSE);\r
+ break;\r
+ case BALLOON_EFFECT_3HGRADIENT:\r
+ DRAW(pDC, pRect, m_crColor[BALLOON_COLOR_BK_BEGIN], m_crColor[BALLOON_COLOR_BK_MID], m_crColor[BALLOON_COLOR_BK_END]);\r
+ break;\r
+ case BALLOON_EFFECT_3VGRADIENT:\r
+ DRAW(pDC, pRect, m_crColor[BALLOON_COLOR_BK_BEGIN], m_crColor[BALLOON_COLOR_BK_MID], m_crColor[BALLOON_COLOR_BK_END], FALSE);\r
+ break;\r
+#undef DRAW\r
+ default:\r
+ pDC->FillSolidRect(pRect, m_crColor[BALLOON_COLOR_BK_BEGIN]);\r
+ break;\r
+ }\r
+}\r
+\r
+CRect CBalloon::GetWindowRegion(CRgn * rgn, CSize sz, CPoint pt) const\r
+{\r
+ CRect rect;\r
+ rect.SetRect(0, 0, sz.cx, sz.cy);\r
+ CRgn rgnRect;\r
+ CRgn rgnAnchor;\r
+ CPoint ptAnchor [3];\r
+ ptAnchor [0] = pt;\r
+ ScreenToClient(&ptAnchor [0]);\r
+\r
+ switch (m_nLastDirection)\r
+ {\r
+ case BALLOON_LEFT_TOP:\r
+ case BALLOON_RIGHT_TOP:\r
+ rect.bottom -= m_nSizes[XBLSZ_HEIGHT_ANCHOR];\r
+ ptAnchor [1].y = ptAnchor [2].y = rect.bottom;\r
+ break;\r
+ case BALLOON_LEFT_BOTTOM:\r
+ case BALLOON_RIGHT_BOTTOM:\r
+ rect.top += m_nSizes[XBLSZ_HEIGHT_ANCHOR];\r
+ ptAnchor [1].y = ptAnchor [2].y = rect.top;\r
+ break;\r
+ }\r
+\r
+ //get the region for rectangle with the text\r
+ if (m_pToolInfo.nStyles & BALLOON_ROUNDED)\r
+ rgnRect.CreateRoundRectRgn(rect.left, rect.top, rect.right + 1, rect.bottom + 1, \r
+ m_nSizes[XBLSZ_ROUNDED_CX], m_nSizes[XBLSZ_ROUNDED_CY]);\r
+ else rgnRect.CreateRectRgn(rect.left, rect.top, rect.right + 1, rect.bottom + 1);\r
+\r
+ //gets the region for the anchor\r
+ if (m_pToolInfo.nStyles & BALLOON_ANCHOR)\r
+ {\r
+ switch (m_nLastDirection)\r
+ {\r
+ case BALLOON_LEFT_TOP:\r
+ case BALLOON_LEFT_BOTTOM:\r
+ ptAnchor [1].x = rect.right - m_nSizes[XBLSZ_MARGIN_ANCHOR];\r
+ ptAnchor [2].x = ptAnchor [1].x - m_nSizes[XBLSZ_WIDTH_ANCHOR];\r
+ break;\r
+ case BALLOON_RIGHT_TOP:\r
+ case BALLOON_RIGHT_BOTTOM:\r
+ ptAnchor [1].x = rect.left + m_nSizes[XBLSZ_MARGIN_ANCHOR];\r
+ ptAnchor [2].x = ptAnchor [1].x + m_nSizes[XBLSZ_WIDTH_ANCHOR];\r
+ break;\r
+ }\r
+ rgnAnchor.CreatePolygonRgn(ptAnchor, 3, ALTERNATE);\r
+ }\r
+ else\r
+ rgnAnchor.CreateRectRgn(0, 0, 0, 0);\r
+ \r
+ rgn->CreateRectRgn(0, 0, 1, 1);\r
+ rgn->CombineRgn(&rgnRect, &rgnAnchor, RGN_OR);\r
+ \r
+ rgnAnchor.DeleteObject();\r
+ rgnRect.DeleteObject();\r
+\r
+ return rect;\r
+}\r
+\r
+void CBalloon::RelayEvent(MSG* pMsg)\r
+{\r
+ HWND hWnd = NULL;\r
+ CPoint pt;\r
+ CString str;\r
+ CRect rect;\r
+\r
+ BALLOON_INFO Info;\r
+ \r
+ switch(pMsg->message)\r
+ {\r
+ case WM_MOUSEMOVE:\r
+ if (m_ptOriginal == pMsg->pt)\r
+ return;\r
+\r
+ m_ptOriginal = pMsg->pt; \r
+ \r
+ //get the real window under the mouse pointer\r
+ pt = pMsg->pt;\r
+ if (m_pParentWnd)\r
+ m_pParentWnd->ScreenToClient(&pt);\r
+ hWnd = GetChildWindowFromPoint(pt);\r
+\r
+ if (!hWnd)\r
+ {\r
+ if (!(GetBehaviour() & BALLOON_DIALOG))\r
+ {\r
+ Pop();\r
+ m_hCurrentWnd = NULL;\r
+ m_hDisplayedWnd = NULL;\r
+ return;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ UINT behaviour = GetBehaviour(CWnd::FromHandle(hWnd));\r
+ if (hWnd == m_hDisplayedWnd)\r
+ {\r
+ if (IsWindowVisible())\r
+ {\r
+ if ((behaviour & BALLOON_TRACK_MOUSE)&&(!(behaviour & BALLOON_DIALOG)))\r
+ {\r
+ //mouse moved, so move the tooltip too\r
+ CRect rect;\r
+ GetWindowRect(rect);\r
+ CalculateInfoBoxRect(&m_ptOriginal, &rect);\r
+ SetWindowPos(NULL, rect.left, rect.top, 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);\r
+ }\r
+ else\r
+ return;\r
+ }\r
+ else if ((behaviour & BALLOON_MULTIPLE_SHOW)&&(!(behaviour & BALLOON_DIALOG)))\r
+ {\r
+ SetNewToolTip(CWnd::FromHandle(hWnd));\r
+ }\r
+ else\r
+ Pop();\r
+ }\r
+ else\r
+ {\r
+ SetNewToolTip(CWnd::FromHandle(hWnd));\r
+ }\r
+ }\r
+ break;\r
+ }\r
+}\r
+\r
+void CBalloon::SetNewToolTip(CWnd * pWnd)\r
+{\r
+ m_hDisplayedWnd = NULL;\r
+ Pop();\r
+\r
+ if (!pWnd->IsWindowEnabled())\r
+ return;\r
+\r
+ if (!GetTool(pWnd, m_pToolInfo))\r
+ return;\r
+\r
+ m_hCurrentWnd = pWnd->GetSafeHwnd();\r
+\r
+ SetTimer(BALLOON_SHOW, m_nTimeInitial, NULL);\r
+}\r
+\r
+void CBalloon::OnTimer(UINT_PTR nIDEvent) \r
+{\r
+ CPoint pt, point;\r
+ CString str;\r
+ HWND hWnd;\r
+\r
+ switch (nIDEvent)\r
+ {\r
+ case BALLOON_SHOW:\r
+ KillTimers(BALLOON_SHOW);\r
+ //check if mouse pointer is still over the right window\r
+ GetCursorPos(&pt);\r
+ point = pt;\r
+ if (m_pParentWnd)\r
+ m_pParentWnd->ScreenToClient(&point);\r
+ hWnd = GetChildWindowFromPoint(point);\r
+ if (hWnd == m_hCurrentWnd)\r
+ {\r
+ DisplayToolTip(&pt);\r
+ SetTimer(BALLOON_HIDE, m_nTimeAutoPop, NULL);\r
+ }\r
+ break;\r
+ case BALLOON_HIDE:\r
+ KillTimers(BALLOON_HIDE);\r
+ Pop();\r
+ if (GetBehaviour() & BALLOON_DIALOG_DESTROY)\r
+ {\r
+ CWnd::OnTimer(nIDEvent);\r
+ DestroyWindow();\r
+ return;\r
+ }\r
+ break;\r
+ }\r
+ \r
+ CWnd::OnTimer(nIDEvent);\r
+}\r
+\r
+HWND CBalloon::GetChildWindowFromPoint(CPoint & point) const\r
+{\r
+ if (!m_pParentWnd)\r
+ return NULL;\r
+ CPoint pt = point;\r
+ m_pParentWnd->ClientToScreen(&pt);\r
+ HWND hWnd = ::WindowFromPoint(pt);\r
+\r
+ //::WindowFromPoint misses disabled windows and such - go for a more\r
+ //comprehensive search in this case.\r
+ if (hWnd == m_pParentWnd->GetSafeHwnd())\r
+ hWnd = m_pParentWnd->ChildWindowFromPoint(point, CWP_ALL)->GetSafeHwnd();\r
+\r
+ //check that we aren't over the parent or out of client area\r
+ if (!hWnd || hWnd == m_pParentWnd->GetSafeHwnd())\r
+ return NULL;\r
+\r
+ //if it's not part of the main parent window hierarchy, then we are\r
+ //not interested\r
+ if (!::IsChild(m_pParentWnd->GetSafeHwnd(), hWnd))\r
+ return NULL;\r
+\r
+ return hWnd;\r
+}\r
+\r
+BOOL CBalloon::IsCursorInToolTip() const\r
+{\r
+ if (!IsVisible() || !IsWindow(m_hWnd))\r
+ return FALSE;\r
+\r
+ CPoint pt;\r
+ GetCursorPos(&pt);\r
+\r
+ CBalloon * pWnd = (CBalloon*)WindowFromPoint(pt);\r
+\r
+ return (pWnd == this);\r
+}\r
+\r
+void CBalloon::KillTimers(UINT nIDTimer /* = NULL */)\r
+{\r
+ if (nIDTimer == NULL)\r
+ {\r
+ KillTimer(BALLOON_SHOW);\r
+ KillTimer(BALLOON_HIDE);\r
+ }\r
+ else if (nIDTimer == BALLOON_SHOW)\r
+ KillTimer(BALLOON_SHOW);\r
+ else if (nIDTimer == BALLOON_HIDE)\r
+ KillTimer(BALLOON_HIDE);\r
+}\r
+\r
+void CBalloon::DisplayToolTip(CPoint * pt /* = NULL */)\r
+{\r
+ if(!GetTool(CWnd::FromHandle(m_hCurrentWnd), m_pToolInfo) || m_pToolInfo.sBalloonTip.IsEmpty())\r
+ return;\r
+ //if a mask is set then use the default values for the tooltip\r
+ if (!(m_pToolInfo.nMask & BALLOON_MASK_STYLES))\r
+ m_pToolInfo.nStyles = m_nStyles;\r
+ if (!(m_pToolInfo.nMask & BALLOON_MASK_EFFECT))\r
+ {\r
+ m_pToolInfo.nEffect = m_nEffect;\r
+ }\r
+ if (!(m_pToolInfo.nMask & BALLOON_MASK_COLORS))\r
+ {\r
+ m_pToolInfo.crBegin = m_crColor[BALLOON_COLOR_BK_BEGIN];\r
+ m_pToolInfo.crMid = m_crColor[BALLOON_COLOR_BK_MID];\r
+ m_pToolInfo.crEnd = m_crColor[BALLOON_COLOR_BK_END];\r
+ }\r
+ if (!(m_pToolInfo.nMask & BALLOON_MASK_DIRECTION))\r
+ m_pToolInfo.nDirection = m_nDirection;\r
+\r
+ //send notification\r
+ SendNotify(CWnd::FromHandle(m_hCurrentWnd), pt, m_pToolInfo);\r
+\r
+ //calculate the width and height of the box dynamically\r
+ CSize sz = GetTooltipSize(m_pToolInfo.sBalloonTip);\r
+ m_szBalloonText = sz;\r
+ \r
+ //get the size of the current icon\r
+ m_szBalloonIcon = GetSizeIcon(m_pToolInfo.hIcon);\r
+ if (m_szBalloonIcon.cx || m_szBalloonIcon.cy)\r
+ {\r
+ sz.cx += m_szBalloonIcon.cx + m_nSizes[XBLSZ_MARGIN_CX];\r
+ sz.cy = max(m_szBalloonIcon.cy, sz.cy);\r
+ }\r
+\r
+ //get the size of the close button\r
+ m_szCloseButton = CSize(::GetSystemMetrics(SM_CXMENUSIZE), ::GetSystemMetrics(SM_CYMENUSIZE));\r
+ if (m_pToolInfo.nStyles & BALLOON_CLOSEBUTTON)\r
+ {\r
+ sz.cx += m_szCloseButton.cx + m_nSizes[XBLSZ_BUTTON_MARGIN_CX];\r
+ }\r
+\r
+ //get size of the tooltip with margins\r
+ sz.cx += m_nSizes[XBLSZ_MARGIN_CX] * 2;\r
+ sz.cy += m_nSizes[XBLSZ_MARGIN_CY] * 2 + m_nSizes[XBLSZ_HEIGHT_ANCHOR];\r
+ if (m_pToolInfo.nStyles & BALLOON_SHADOW)\r
+ {\r
+ sz.cx += m_nSizes[XBLSZ_SHADOW_CX];\r
+ sz.cy += m_nSizes[XBLSZ_SHADOW_CY];\r
+ }\r
+ \r
+ CRect rect (0, 0, sz.cx, sz.cy);\r
+ \r
+ DisplayToolTip(pt, &rect);\r
+}\r
+\r
+void CBalloon::DisplayToolTip(CPoint * pt, CRect * rect)\r
+{\r
+ CalculateInfoBoxRect(pt, rect);\r
+\r
+ SetWindowPos(\r
+ NULL, rect->left, rect->top, rect->Width() + 2, rect->Height() + 2,\r
+ SWP_SHOWWINDOW|SWP_NOCOPYBITS|SWP_NOACTIVATE|SWP_NOZORDER);\r
+\r
+ CRgn rgn;\r
+ rgn.CreateRectRgn(0, 0, 1, 1);\r
+ if (m_pToolInfo.nStyles & BALLOON_SHADOW)\r
+ {\r
+ rect->right -= m_nSizes[XBLSZ_SHADOW_CX];\r
+ rect->bottom -= m_nSizes[XBLSZ_SHADOW_CY];\r
+ }\r
+\r
+ m_rgnBalloon.DeleteObject();\r
+ GetWindowRegion(&m_rgnBalloon, CSize (rect->Width(), rect->Height()), *pt);\r
+ rgn.CopyRgn(&m_rgnBalloon);\r
+ if (m_pToolInfo.nStyles & BALLOON_SHADOW)\r
+ {\r
+ m_rgnShadow.DeleteObject();\r
+ m_rgnShadow.CreateRectRgn(0, 0, 1, 1);\r
+ m_rgnShadow.CopyRgn(&m_rgnBalloon);\r
+ m_rgnShadow.OffsetRgn(m_nSizes[XBLSZ_SHADOW_CX], m_nSizes[XBLSZ_SHADOW_CY]);\r
+ rgn.CombineRgn(&rgn, &m_rgnShadow, RGN_OR);\r
+ }\r
+ SetWindowRgn(rgn, FALSE);\r
+\r
+ rgn.DeleteObject();\r
+}\r
+\r
+void CBalloon::Pop()\r
+{\r
+ KillTimers(); \r
+ ShowWindow(SW_HIDE);\r
+ m_bButtonPushed = FALSE;\r
+}\r
+\r
+CSize CBalloon::GetTooltipSize(const CString& str)\r
+{\r
+ CRect rect;\r
+ GetWindowRect(&rect);\r
+\r
+ CDC * pDC = GetDC();\r
+\r
+ CDC memDC;\r
+ CBitmap bitmap;\r
+ memDC.CreateCompatibleDC(pDC);\r
+ bitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());\r
+ CBitmap* pOldBitmap = memDC.SelectObject(&bitmap);\r
+\r
+ //get the minimum size of the rectangle of the tooltip\r
+ CSize sz = DrawHTML(&memDC, rect, str, m_LogFont, TRUE);\r
+\r
+ memDC.SelectObject(pOldBitmap);\r
+ memDC.DeleteDC();\r
+ bitmap.DeleteObject();\r
+\r
+ ReleaseDC(pDC);\r
+\r
+ return sz;\r
+}\r
+\r
+CSize CBalloon::GetSizeIcon(HICON hIcon) const\r
+{\r
+ ICONINFO ii;\r
+ CSize sz (0, 0);\r
+\r
+ if (hIcon != NULL)\r
+ {\r
+ //get icon dimensions\r
+ ::SecureZeroMemory(&ii, sizeof(ICONINFO));\r
+ if (::GetIconInfo(hIcon, &ii))\r
+ {\r
+ sz.cx = (DWORD)(ii.xHotspot * 2);\r
+ sz.cy = (DWORD)(ii.yHotspot * 2);\r
+ //release icon mask bitmaps\r
+ if(ii.hbmMask)\r
+ ::DeleteObject(ii.hbmMask);\r
+ if(ii.hbmColor)\r
+ ::DeleteObject(ii.hbmColor);\r
+ }\r
+ }\r
+ return sz;\r
+}\r
+\r
+void CBalloon::CalculateInfoBoxRect(CPoint * pt, CRect * rect)\r
+{\r
+ CRect monitorRect;\r
+ GetMonitorWorkArea(*pt, monitorRect);\r
+\r
+ CPoint ptEnd;\r
+ m_nLastDirection = m_pToolInfo.nDirection;\r
+ BOOL horzAdjusted = TestHorizDirection(pt->x, rect->Width(), monitorRect, m_nLastDirection, rect);\r
+ if (!horzAdjusted)\r
+ {\r
+ m_nLastDirection = GetNextHorizDirection(m_nLastDirection);\r
+ horzAdjusted = TestHorizDirection(pt->x, rect->Width(), monitorRect, m_nLastDirection, rect);\r
+ }\r
+ BOOL vertAdjusted = TestVertDirection(pt->y, rect->Height(), monitorRect, m_nLastDirection, rect);\r
+ if (!vertAdjusted)\r
+ {\r
+ m_nLastDirection = GetNextVertDirection(m_nLastDirection);\r
+ vertAdjusted = TestVertDirection(pt->y, rect->Height(), monitorRect, m_nLastDirection, rect);\r
+ }\r
+ // in case the rectangle wasn't adjusted which can happen if the tooltip is\r
+ // larger than half the monitor size, we center the tooltip around the mouse pointer\r
+ if (!horzAdjusted)\r
+ {\r
+ int cx = rect->Width() / 2;\r
+ rect->right = pt->x + cx;\r
+ rect->left = pt->x - cx;\r
+ }\r
+ if (!vertAdjusted)\r
+ {\r
+ int cy = rect->Height() / 2;\r
+ rect->bottom = pt->y + cy;\r
+ rect->top = pt->y - cy;\r
+ }\r
+ if ((m_pToolInfo.nStyles & BALLOON_SHADOW) && \r
+ ((m_nLastDirection == BALLOON_LEFT_TOP) || (m_nLastDirection == BALLOON_LEFT_BOTTOM)))\r
+ rect->OffsetRect(m_nSizes[XBLSZ_SHADOW_CX], m_nSizes[XBLSZ_SHADOW_CY]);\r
+}\r
+\r
+\r
+int CBalloon::GetNextHorizDirection(int nDirection) const\r
+{\r
+ switch (nDirection)\r
+ {\r
+ case BALLOON_LEFT_TOP:\r
+ nDirection = BALLOON_RIGHT_TOP;\r
+ break;\r
+ case BALLOON_RIGHT_TOP:\r
+ nDirection = BALLOON_LEFT_TOP;\r
+ break;\r
+ case BALLOON_LEFT_BOTTOM:\r
+ nDirection = BALLOON_RIGHT_BOTTOM;\r
+ break;\r
+ case BALLOON_RIGHT_BOTTOM:\r
+ nDirection = BALLOON_LEFT_BOTTOM;\r
+ break;\r
+ }\r
+ return nDirection;\r
+}\r
+\r
+int CBalloon::GetNextVertDirection(int nDirection) const\r
+{\r
+ switch (nDirection)\r
+ {\r
+ case BALLOON_LEFT_TOP:\r
+ nDirection = BALLOON_LEFT_BOTTOM;\r
+ break;\r
+ case BALLOON_LEFT_BOTTOM:\r
+ nDirection = BALLOON_LEFT_TOP;\r
+ break;\r
+ case BALLOON_RIGHT_TOP:\r
+ nDirection = BALLOON_RIGHT_BOTTOM;\r
+ break;\r
+ case BALLOON_RIGHT_BOTTOM:\r
+ nDirection = BALLOON_RIGHT_TOP;\r
+ break;\r
+ }\r
+ return nDirection;\r
+}\r
+\r
+BOOL CBalloon::TestHorizDirection(int x, int cx, const CRect& monitorRect,\r
+ int nDirection, LPRECT rect)\r
+{\r
+ int left = 0;\r
+ int right = 0;\r
+ int anchorMarginSize = (int)m_nSizes[XBLSZ_MARGIN_ANCHOR];\r
+\r
+ switch (nDirection)\r
+ {\r
+ case BALLOON_LEFT_TOP:\r
+ case BALLOON_LEFT_BOTTOM:\r
+ right = ((x + anchorMarginSize) > monitorRect.right) ? monitorRect.right : (x + anchorMarginSize);\r
+ left = right - cx;\r
+ break;\r
+ case BALLOON_RIGHT_TOP:\r
+ case BALLOON_RIGHT_BOTTOM:\r
+ left = (x - anchorMarginSize)<monitorRect.left ? monitorRect.left : (x - anchorMarginSize);\r
+ right = left + cx;\r
+ break;\r
+ }\r
+\r
+ BOOL bTestOk = ((left >= monitorRect.left) && (right <= monitorRect.right)) ? TRUE : FALSE;\r
+ if (bTestOk)\r
+ {\r
+ rect->left = left;\r
+ rect->right = right;\r
+ }\r
+\r
+ return bTestOk;\r
+}\r
+\r
+BOOL CBalloon::TestVertDirection(int y, int cy, const CRect& monitorRect,\r
+ int nDirection, LPRECT rect)\r
+{\r
+ int top = 0;\r
+ int bottom = 0;\r
+\r
+ switch (nDirection)\r
+ {\r
+ case BALLOON_LEFT_TOP:\r
+ case BALLOON_RIGHT_TOP:\r
+ bottom = y;\r
+ top = bottom - cy;\r
+ break;\r
+ case BALLOON_LEFT_BOTTOM:\r
+ case BALLOON_RIGHT_BOTTOM:\r
+ top = y;\r
+ bottom = top + cy;\r
+ break;\r
+ }\r
+\r
+ BOOL bTestOk = ((top >= monitorRect.top) && (bottom <= monitorRect.bottom)) ? TRUE : FALSE;\r
+ if (bTestOk)\r
+ {\r
+ rect->top = top;\r
+ rect->bottom = bottom;\r
+ }\r
+\r
+ return bTestOk;\r
+}\r
+\r
+LPLOGFONT CBalloon::GetSystemToolTipFont() const\r
+{\r
+ static LOGFONT LogFont;\r
+\r
+ NONCLIENTMETRICS ncm;\r
+ ncm.cbSize = sizeof(NONCLIENTMETRICS);\r
+ if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0))\r
+ return FALSE;\r
+\r
+ memcpy(&LogFont, &(ncm.lfStatusFont), sizeof(LOGFONT));\r
+\r
+ return &LogFont; \r
+}\r
+\r
+\r
+void CBalloon::Redraw(BOOL /*bRedraw*/ /* = TRUE */)\r
+{\r
+}\r
+\r
+void CBalloon::SetStyles(DWORD nStyles, CWnd * pWnd /* = NULL */)\r
+{\r
+ ModifyStyles(nStyles, (DWORD)-1, pWnd);\r
+}\r
+\r
+void CBalloon::ModifyStyles(DWORD nAddStyles, DWORD nRemoveStyles, CWnd * pWnd /* = NULL */)\r
+{\r
+ if (!pWnd)\r
+ {\r
+ m_nStyles &= ~nRemoveStyles;\r
+ m_nStyles |= nAddStyles;\r
+ }\r
+ else\r
+ {\r
+ BALLOON_INFO bi;\r
+ if (GetTool(pWnd, bi))\r
+ {\r
+ if (!(bi.nMask & BALLOON_MASK_STYLES))\r
+ bi.nStyles = m_nStyles;\r
+ bi.nStyles &= ~nRemoveStyles;\r
+ bi.nStyles |= nAddStyles;\r
+ bi.nMask |= BALLOON_MASK_STYLES;\r
+ AddTool(pWnd, bi);\r
+ }\r
+ }\r
+} \r
+\r
+DWORD CBalloon::GetStyles(CWnd * pWnd /* = NULL */) const\r
+{\r
+ if (pWnd)\r
+ {\r
+ BALLOON_INFO bi;\r
+ if (GetTool(pWnd, bi))\r
+ {\r
+ if (bi.nMask & BALLOON_MASK_STYLES)\r
+ return bi.nStyles;\r
+ }\r
+ }\r
+ return m_nStyles;\r
+} \r
+\r
+void CBalloon::SetDefaultStyles(CWnd * pWnd /* = NULL */)\r
+{\r
+ SetStyles(BALLOON_RSA, pWnd);\r
+}\r
+\r
+void CBalloon::SetColor(int nIndex, COLORREF crColor)\r
+{\r
+ if (nIndex >= BALLOON_MAX_COLORS)\r
+ return;\r
+\r
+ m_crColor [nIndex] = crColor;\r
+}\r
+\r
+COLORREF CBalloon::GetColor(int nIndex) const\r
+{\r
+ if (nIndex >= BALLOON_MAX_COLORS)\r
+ nIndex = BALLOON_COLOR_FG;\r
+\r
+ return m_crColor [nIndex];\r
+}\r
+\r
+void CBalloon::SetDefaultColors()\r
+{\r
+ SetColor(BALLOON_COLOR_FG, ::GetSysColor(COLOR_INFOTEXT));\r
+ SetColor(BALLOON_COLOR_BK_BEGIN, ::GetSysColor(COLOR_INFOBK));\r
+ SetColor(BALLOON_COLOR_BK_MID, ::GetSysColor(COLOR_INFOBK));\r
+ SetColor(BALLOON_COLOR_BK_END, ::GetSysColor(COLOR_INFOBK));\r
+ SetColor(BALLOON_COLOR_SHADOW, ::GetSysColor(COLOR_3DSHADOW));\r
+ SetColor(BALLOON_COLOR_BORDER, ::GetSysColor(COLOR_WINDOWFRAME));\r
+}\r
+\r
+void CBalloon::SetGradientColors(COLORREF crBegin, COLORREF crMid, COLORREF crEnd, CWnd * pWnd /* = NULL */)\r
+{\r
+ if (!pWnd)\r
+ {\r
+ SetColor(BALLOON_COLOR_BK_BEGIN, crBegin);\r
+ SetColor(BALLOON_COLOR_BK_MID, crMid);\r
+ SetColor(BALLOON_COLOR_BK_END, crEnd);\r
+ }\r
+ else\r
+ {\r
+ BALLOON_INFO bi;\r
+ if (GetTool(pWnd, bi))\r
+ {\r
+ bi.crBegin = crBegin;\r
+ bi.crMid = crMid;\r
+ bi.crEnd = crEnd;\r
+ bi.nMask |= BALLOON_MASK_COLORS;\r
+ AddTool(pWnd, bi);\r
+ }\r
+ }\r
+}\r
+\r
+void CBalloon::GetGradientColors(COLORREF & crBegin, COLORREF & crMid, COLORREF & crEnd, CWnd * pWnd /* = NULL */) const\r
+{\r
+ if (pWnd)\r
+ {\r
+ BALLOON_INFO bi;\r
+ if (GetTool(pWnd, bi))\r
+ {\r
+ if (bi.nMask & BALLOON_MASK_COLORS)\r
+ {\r
+ crBegin = bi.crBegin;\r
+ crMid = bi.crMid;\r
+ crEnd = bi.crEnd;\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ crBegin = GetColor(BALLOON_COLOR_BK_BEGIN);\r
+ crMid = GetColor(BALLOON_COLOR_BK_MID);\r
+ crEnd = GetColor(BALLOON_COLOR_BK_END);\r
+} \r
+\r
+void CBalloon::ShowBalloon(CWnd * pWnd, CPoint pt, UINT nIdText, BOOL showCloseButton, LPCTSTR szIcon)\r
+{\r
+ CString str;\r
+ str.LoadString(nIdText);\r
+ HICON hIcon = (HICON)::LoadImage(NULL, szIcon, IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE);\r
+ ShowBalloon(pWnd, pt, str, showCloseButton, hIcon);\r
+}\r
+\r
+void CBalloon::ShowBalloon(\r
+ CWnd * pWnd, CPoint pt, const CString& sText, BOOL showCloseButton, HICON hIcon, \r
+ UINT nDirection, UINT nEffect, COLORREF crStart, COLORREF crMid, COLORREF crEnd)\r
+{\r
+ BALLOON_INFO Info;\r
+ Info.hIcon = hIcon;\r
+ Info.sBalloonTip = sText;\r
+ Info.nMask = 0;\r
+\r
+ CBalloon * pSB = new CBalloon();\r
+ if (pWnd == NULL)\r
+ pWnd = GetDesktopWindow();\r
+ pSB->Create(pWnd);\r
+ pSB->AddTool(pWnd, Info);\r
+ pSB->m_hCurrentWnd = pWnd->GetSafeHwnd();\r
+ pSB->SetDirection(nDirection);\r
+ pSB->SetEffectBk(nEffect);\r
+ if (crStart == NULL)\r
+ crStart = ::GetSysColor(COLOR_INFOBK);\r
+ if (crMid == NULL)\r
+ crMid = ::GetSysColor(COLOR_INFOBK);\r
+ if (crEnd == NULL)\r
+ crEnd = ::GetSysColor(COLOR_INFOBK);\r
+ pSB->SetGradientColors(crStart, crMid, crEnd);\r
+ pSB->SetBehaviour(BALLOON_DIALOG | BALLOON_DIALOG_DESTROY);\r
+ if (showCloseButton)\r
+ {\r
+ pSB->ModifyStyles(BALLOON_CLOSEBUTTON, 0);\r
+ }\r
+ pSB->DisplayToolTip(&pt);\r
+ if (!showCloseButton)\r
+ pSB->SetTimer(BALLOON_HIDE, 5000, NULL); //auto close the dialog if no close button is shown\r
+}\r
+\r
+void CBalloon::AddTool(int nIdWnd, UINT nIdText, HICON hIcon/* = NULL*/)\r
+{\r
+ AddTool(m_pParentWnd->GetDlgItem(nIdWnd), nIdText, hIcon);\r
+}\r
+void CBalloon::AddTool(int nIdWnd, UINT nIdText, UINT nIdIcon)\r
+{\r
+ AddTool(m_pParentWnd->GetDlgItem(nIdWnd), nIdText, nIdIcon);\r
+}\r
+void CBalloon::AddTool(int nIdWnd, const CString& sBalloonTipText, HICON hIcon/* = NULL*/)\r
+{\r
+ AddTool(m_pParentWnd->GetDlgItem(nIdWnd), sBalloonTipText, hIcon);\r
+}\r
+void CBalloon::AddTool(int nIdWnd, const CString& sBalloonTipText, UINT nIdIcon)\r
+{\r
+ AddTool(m_pParentWnd->GetDlgItem(nIdWnd), sBalloonTipText, nIdIcon);\r
+}\r
+\r
+void CBalloon::AddTool(CWnd * pWnd, UINT nIdText, HICON hIcon /* = NULL */)\r
+{\r
+ CString str;\r
+ str.LoadString(nIdText);\r
+ AddTool(pWnd, str, hIcon);\r
+}\r
+\r
+void CBalloon::AddTool(CWnd * pWnd, UINT nIdText, UINT nIdIcon)\r
+{\r
+ CString str;\r
+ str.LoadString(nIdText);\r
+ AddTool(pWnd, str, nIdIcon);\r
+} \r
+\r
+void CBalloon::AddTool(CWnd * pWnd, const CString& sBalloonTipText, UINT nIdIcon)\r
+{\r
+ HICON hIcon = NULL;\r
+ HINSTANCE hInstResource = NULL;\r
+\r
+ if (nIdIcon >= 0)\r
+ {\r
+ hInstResource = AfxFindResourceHandle(MAKEINTRESOURCE(nIdIcon), RT_GROUP_ICON);\r
+ \r
+ hIcon = (HICON)::LoadImage(hInstResource, MAKEINTRESOURCE(nIdIcon), IMAGE_ICON, 0, 0, 0);\r
+ }\r
+\r
+ AddTool(pWnd, sBalloonTipText, hIcon);\r
+} \r
+\r
+void CBalloon::AddTool(CWnd * pWnd, const CString& sBalloonTipText, HICON hIcon /* = NULL */)\r
+{\r
+ //store the tool information\r
+ BALLOON_INFO Info;\r
+ Info.hIcon = hIcon;\r
+ Info.sBalloonTip = sBalloonTipText;\r
+ Info.nMask = 0;\r
+\r
+ AddTool(pWnd, Info);\r
+}\r
+\r
+void CBalloon::AddTool(CWnd * pWnd, BALLOON_INFO & bi)\r
+{\r
+ if (pWnd)\r
+ m_ToolMap.SetAt(pWnd->m_hWnd, bi);\r
+ else\r
+ m_ToolMap.SetAt(NULL, bi);\r
+} \r
+\r
+BOOL CBalloon::GetTool(CWnd * pWnd, CString & sBalloonTipText, HICON & hIcon) const\r
+{\r
+ BALLOON_INFO bi;\r
+ BOOL bFound = GetTool(pWnd, bi);\r
+ if (bFound)\r
+ {\r
+ sBalloonTipText = bi.sBalloonTip;\r
+ hIcon = bi.hIcon;\r
+ }\r
+\r
+ return bFound;\r
+}\r
+\r
+BOOL CBalloon::GetTool(CWnd * pWnd, BALLOON_INFO & bi) const\r
+{\r
+ if (pWnd)\r
+ return m_ToolMap.Lookup(pWnd->m_hWnd, bi);\r
+ return m_ToolMap.Lookup(NULL, bi);\r
+}\r
+\r
+void CBalloon::RemoveTool(CWnd * pWnd)\r
+{\r
+ if (pWnd)\r
+ m_ToolMap.RemoveKey(pWnd->m_hWnd);\r
+ m_ToolMap.RemoveKey(NULL);\r
+}\r
+\r
+void CBalloon::RemoveAllTools()\r
+{\r
+ m_ToolMap.RemoveAll();\r
+}\r
+\r
+void CBalloon::SetMaskTool(CWnd * pWnd, UINT nMask /* = 0 */)\r
+{\r
+ ModifyMaskTool(pWnd, nMask, (UINT)-1);\r
+}\r
+\r
+void CBalloon::ModifyMaskTool(CWnd * pWnd, UINT nAddMask, UINT nRemoveMask)\r
+{\r
+ ASSERT(pWnd);\r
+\r
+ BALLOON_INFO bi;\r
+ if (GetTool(pWnd, bi))\r
+ {\r
+ bi.nMask &= ~nRemoveMask;\r
+ bi.nMask |= nAddMask;\r
+ AddTool(pWnd, bi);\r
+ }\r
+}\r
+\r
+UINT CBalloon::GetMaskTool(CWnd * pWnd) const\r
+{\r
+ ASSERT(pWnd);\r
+\r
+ UINT nMask = 0;\r
+ BALLOON_INFO bi;\r
+ if (GetTool(pWnd, bi))\r
+ nMask = bi.nMask;\r
+ return nMask;\r
+}\r
+\r
+void CBalloon::SetEffectBk(UINT nEffect, CWnd * pWnd /* = NULL */)\r
+{\r
+ if (!pWnd)\r
+ {\r
+ m_nEffect = nEffect;\r
+ }\r
+ else\r
+ {\r
+ BALLOON_INFO bi;\r
+ if (GetTool(pWnd, bi))\r
+ {\r
+ bi.nEffect = nEffect;\r
+ bi.nMask |= BALLOON_MASK_EFFECT;\r
+ AddTool(pWnd, bi);\r
+ }\r
+ }\r
+}\r
+\r
+UINT CBalloon::GetEffectBk(CWnd * pWnd /* = NULL */) const\r
+{\r
+ if (pWnd)\r
+ {\r
+ BALLOON_INFO bi;\r
+ if (GetTool(pWnd, bi))\r
+ {\r
+ if (bi.nMask & BALLOON_MASK_EFFECT)\r
+ {\r
+ return bi.nEffect;\r
+ }\r
+ }\r
+ }\r
+ return m_nEffect;\r
+}\r
+\r
+void CBalloon::SetNotify(BOOL bParentNotify /* = TRUE */)\r
+{\r
+ HWND hWnd = NULL;\r
+\r
+ if (bParentNotify)\r
+ hWnd = m_pParentWnd->GetSafeHwnd();\r
+\r
+ SetNotify(hWnd);\r
+}\r
+\r
+void CBalloon::SetNotify(HWND hWnd)\r
+{\r
+ m_hNotifyWnd = hWnd;\r
+}\r
+\r
+BOOL CBalloon::GetNotify() const\r
+{\r
+ return (m_hNotifyWnd != NULL);\r
+} \r
+\r
+void CBalloon::SetDelayTime(DWORD dwDuration, UINT nTime)\r
+{\r
+ switch (dwDuration)\r
+ {\r
+ case TTDT_AUTOPOP:\r
+ m_nTimeAutoPop = nTime;\r
+ break;\r
+ case TTDT_INITIAL :\r
+ m_nTimeInitial = nTime;\r
+ break;\r
+ }\r
+}\r
+\r
+UINT CBalloon::GetDelayTime(DWORD dwDuration) const\r
+{\r
+ UINT nTime = 0;\r
+ switch (dwDuration)\r
+ {\r
+ case TTDT_AUTOPOP:\r
+ nTime = m_nTimeAutoPop;\r
+ break;\r
+ case TTDT_INITIAL:\r
+ nTime = m_nTimeInitial;\r
+ break;\r
+ }\r
+\r
+ return nTime;\r
+} \r
+\r
+void CBalloon::SetSize(int nSizeIndex, UINT nValue)\r
+{\r
+ if (nSizeIndex >= XBLSZ_MAX_SIZES)\r
+ return;\r
+\r
+ m_nSizes [nSizeIndex] = nValue;\r
+}\r
+\r
+UINT CBalloon::GetSize(int nSizeIndex) const\r
+{\r
+ if (nSizeIndex >= XBLSZ_MAX_SIZES)\r
+ return 0;\r
+\r
+ return m_nSizes [nSizeIndex];\r
+}\r
+\r
+void CBalloon::SetDefaultSizes()\r
+{\r
+ SetSize(XBLSZ_ROUNDED_CX, 16);\r
+ SetSize(XBLSZ_ROUNDED_CY, 16);\r
+ SetSize(XBLSZ_MARGIN_CX, 12);\r
+ SetSize(XBLSZ_MARGIN_CY, 12);\r
+ SetSize(XBLSZ_SHADOW_CX, 4);\r
+ SetSize(XBLSZ_SHADOW_CY, 4);\r
+ SetSize(XBLSZ_WIDTH_ANCHOR, 12);\r
+ SetSize(XBLSZ_HEIGHT_ANCHOR, 16);\r
+ SetSize(XBLSZ_MARGIN_ANCHOR, 16);\r
+ SetSize(XBLSZ_BORDER_CX, 1);\r
+ SetSize(XBLSZ_BORDER_CY, 1);\r
+ SetSize(XBLSZ_BUTTON_MARGIN_CX, 5);\r
+ SetSize(XBLSZ_BUTTON_MARGIN_CY, 5);\r
+}\r
+\r
+void CBalloon::SetDirection(UINT nDirection /* = BALLOON_RIGHT_TOP */, CWnd * pWnd /* = NULL */)\r
+{\r
+ if (nDirection >= BALLOON_MAX_DIRECTIONS)\r
+ return;\r
+\r
+ if (!pWnd)\r
+ {\r
+ m_nDirection = nDirection;\r
+ }\r
+ else\r
+ {\r
+ BALLOON_INFO bi;\r
+ if (GetTool(pWnd, bi))\r
+ {\r
+ bi.nDirection = nDirection;\r
+ bi.nMask |= BALLOON_MASK_DIRECTION;\r
+ AddTool(pWnd, bi);\r
+ }\r
+ }\r
+}\r
+\r
+UINT CBalloon::GetDirection(CWnd * pWnd /* = NULL */) const\r
+{\r
+ if (pWnd)\r
+ {\r
+ BALLOON_INFO bi;\r
+ if (GetTool(pWnd, bi))\r
+ {\r
+ if (bi.nMask & BALLOON_MASK_DIRECTION)\r
+ return bi.nDirection;\r
+ }\r
+ }\r
+ return m_nDirection;\r
+}\r
+\r
+void CBalloon::SetBehaviour(UINT nBehaviour /* = 0 */, CWnd * pWnd /* = NULL */)\r
+{\r
+ if (!pWnd)\r
+ {\r
+ m_nBehaviour = nBehaviour;\r
+ }\r
+ else\r
+ {\r
+ BALLOON_INFO bi;\r
+ if (GetTool(pWnd, bi))\r
+ {\r
+ bi.nBehaviour = nBehaviour;\r
+ bi.nMask |= BALLOON_MASK_BEHAVIOUR;\r
+ AddTool(pWnd, bi);\r
+ }\r
+ }\r
+}\r
+\r
+UINT CBalloon::GetBehaviour(CWnd * pWnd /* = NULL */) const\r
+{\r
+ if (pWnd)\r
+ {\r
+ BALLOON_INFO bi;\r
+ if (GetTool(pWnd, bi))\r
+ {\r
+ if (bi.nMask & BALLOON_MASK_BEHAVIOUR)\r
+ return bi.nBehaviour;\r
+ }\r
+ }\r
+ return m_nBehaviour;\r
+}\r
+\r
+BOOL CBalloon::SetFont(CFont & font)\r
+{\r
+ LOGFONT lf;\r
+ font.GetLogFont (&lf);\r
+\r
+ return SetFont(&lf);\r
+}\r
+\r
+BOOL CBalloon::SetFont(LPLOGFONT lf)\r
+{\r
+ memcpy(&m_LogFont, lf, sizeof(LOGFONT));\r
+\r
+ return TRUE; \r
+}\r
+\r
+BOOL CBalloon::SetFont(LPCTSTR lpszFaceName, int nSizePoints /* = 8 */,\r
+ BOOL bUnderline /* = FALSE */, BOOL bBold /* = FALSE */,\r
+ BOOL bStrikeOut /* = FALSE */, BOOL bItalic /* = FALSE */)\r
+{\r
+ CDC* pDC = GetDC();\r
+ LOGFONT lf;\r
+ memset (&lf, 0, sizeof(LOGFONT));\r
+\r
+ _tcscpy_s (lf.lfFaceName, 32, lpszFaceName);\r
+ lf.lfHeight = -MulDiv (nSizePoints, GetDeviceCaps (pDC->m_hDC, LOGPIXELSY), 72);\r
+ lf.lfUnderline = (BYTE)bUnderline;\r
+ lf.lfWeight = bBold ? FW_BOLD : FW_NORMAL;\r
+ lf.lfStrikeOut = (BYTE)bStrikeOut;\r
+ lf.lfItalic = (BYTE)bItalic;\r
+\r
+ if (pDC)\r
+ ReleaseDC(pDC);\r
+\r
+ return SetFont(&lf);\r
+}\r
+\r
+void CBalloon::SetDefaultFont()\r
+{\r
+ LPLOGFONT lpSysFont = GetSystemToolTipFont();\r
+\r
+ SetFont(lpSysFont);\r
+} \r
+\r
+void CBalloon::GetFont(CFont & font) const\r
+{\r
+ font.CreateFontIndirect(&m_LogFont);\r
+}\r
+\r
+void CBalloon::GetFont(LPLOGFONT lf) const\r
+{\r
+ memcpy(lf, &m_LogFont, sizeof(LOGFONT));\r
+}\r
+\r
+void CBalloon::OnMouseMove(UINT nFlags, CPoint point)\r
+{\r
+ if (m_pToolInfo.nStyles & BALLOON_CLOSEBUTTON)\r
+ {\r
+ UINT nState = DFCS_CAPTIONCLOSE | DFCS_FLAT | DFCS_TRANSPARENT;\r
+ if (m_rtCloseButton.PtInRect(point))\r
+ {\r
+ nState |= DFCS_HOT;\r
+ if (m_bButtonPushed)\r
+ nState |= DFCS_PUSHED;\r
+ }\r
+ CClientDC dc(this);\r
+ dc.DrawFrameControl(m_rtCloseButton, DFC_CAPTION, nState);\r
+\r
+ if (IsPointOverALink(point))\r
+ m_Cursor.SetCursor(IDC_HAND);\r
+ else\r
+ m_Cursor.Restore(); \r
+ }\r
+\r
+ CWnd::OnMouseMove(nFlags, point);\r
+}\r
+\r
+void CBalloon::OnLButtonDown(UINT nFlags, CPoint point)\r
+{\r
+ if ((m_pToolInfo.nStyles & BALLOON_CLOSEBUTTON) && m_rtCloseButton.PtInRect(point))\r
+ {\r
+ m_bButtonPushed = TRUE;\r
+ OnMouseMove(0, point);\r
+ }\r
+\r
+ CWnd::OnLButtonDown(nFlags, point);\r
+}\r
+\r
+void CBalloon::OnLButtonUp(UINT nFlags, CPoint point)\r
+{\r
+ if (IsPointOverALink(point))\r
+ {\r
+ CString url = GetLinkForPoint(point);\r
+ ShellExecute(NULL, _T("open"), url, NULL,NULL, 0);\r
+ }\r
+ else if (\r
+ // Dialog has close button, but user has clicked somewhere else.\r
+ (m_pToolInfo.nStyles & BALLOON_CLOSEBUTTON) &&\r
+ (!m_rtCloseButton.PtInRect(point) || !m_bButtonPushed))\r
+ {\r
+ m_bButtonPushed = FALSE;\r
+ }\r
+ else\r
+ {\r
+ Pop();\r
+ if (GetBehaviour() & BALLOON_DIALOG_DESTROY)\r
+ {\r
+ CWnd::OnLButtonUp(nFlags, point);\r
+ DestroyWindow();\r
+ return;\r
+ }\r
+ }\r
+ CWnd::OnLButtonUp(nFlags, point);\r
+}\r
+\r
+void CBalloon::PostNcDestroy()\r
+{\r
+ CWnd::PostNcDestroy();\r
+ TRACE("CBalloon: PostNcDestroy()\n");\r
+\r
+ if (GetBehaviour() & BALLOON_DIALOG_DESTROY)\r
+ {\r
+ TRACE("CBalloon: object deleted\n");\r
+ delete this;\r
+ }\r
+}\r
+\r
+void CBalloon::GetMonitorWorkArea(const CPoint& sourcePoint, CRect& monitorRect) const\r
+{\r
+ // identify the monitor that contains the sourcePoint\r
+ // and return the work area (the portion of the screen \r
+ // not obscured by the system task bar or by application \r
+ // desktop tool bars) of that monitor\r
+ OSVERSIONINFOEX VersionInformation;\r
+ SecureZeroMemory(&VersionInformation, sizeof(OSVERSIONINFOEX));\r
+ VersionInformation.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);\r
+ GetVersionEx((OSVERSIONINFO *)&VersionInformation);\r
+\r
+ ::GetWindowRect(GetDesktopWindow()->m_hWnd, &monitorRect);\r
+ \r
+ if (VersionInformation.dwMajorVersion >= 5)\r
+ {\r
+ MONITORINFO mi;\r
+\r
+ //\r
+ // get the work area\r
+ //\r
+ mi.cbSize = sizeof(mi);\r
+ HMODULE hUser32 = ::GetModuleHandle (_T("USER32.DLL"));\r
+ if (hUser32 != NULL)\r
+ {\r
+ typedef HMONITOR (WINAPI *FN_MonitorFromPoint) (POINT pt, DWORD dwFlags);\r
+ typedef BOOL (WINAPI *FN_GetMonitorInfo) (HMONITOR hMonitor, LPMONITORINFO lpmi);\r
+ FN_MonitorFromPoint pfnMonitorFromPoint = (FN_MonitorFromPoint)\r
+ ::GetProcAddress (hUser32, "MonitorFromPoint");\r
+ FN_GetMonitorInfo pfnGetMonitorInfo = (FN_GetMonitorInfo)\r
+ ::GetProcAddress (hUser32, "GetMonitorInfoW");\r
+ if (pfnMonitorFromPoint != NULL && pfnGetMonitorInfo != NULL)\r
+ {\r
+ MONITORINFO mi;\r
+ HMONITOR hMonitor = pfnMonitorFromPoint (sourcePoint, \r
+ MONITOR_DEFAULTTONEAREST);\r
+ mi.cbSize = sizeof (mi);\r
+ pfnGetMonitorInfo (hMonitor, &mi);\r
+ monitorRect = mi.rcWork;\r
+ }\r
+ }\r
+ }\r
+\r
+}\r
+\r
+CPoint \r
+CBalloon::GetCtrlCentre(CWnd* pDlgWnd, UINT ctrlId)\r
+{\r
+ CWnd* pCtrl = pDlgWnd->GetDlgItem(ctrlId);\r
+ if(pCtrl == NULL)\r
+ {\r
+ ASSERT(FALSE);\r
+ return CPoint(200,200);\r
+ }\r
+ CRect ctrlRect;\r
+ pCtrl->GetWindowRect(ctrlRect);\r
+ return ctrlRect.CenterPoint();\r
+}\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2008 - TortoiseSVN\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#pragma once\r
+\r
+#include "gradient.h"\r
+#include "htmlformatter.h"\r
+#include "cursor.h"\r
+\r
+//The styles\r
+#define BALLOON_ANCHOR 0x0001\r
+#define BALLOON_SHADOW 0x0002\r
+#define BALLOON_ROUNDED 0x0004\r
+#define BALLOON_RSA 0x0007\r
+#define BALLOON_VCENTER_ALIGN 0x0008\r
+#define BALLOON_BOTTOM_ALIGN 0x0010\r
+#define BALLOON_CLOSEBUTTON 0x0020\r
+\r
+//The behaviors\r
+#define BALLOON_MULTIPLE_SHOW 0x0001 //Multiple show for single control\r
+#define BALLOON_TRACK_MOUSE 0x0002 //ToolTip follows the mouse cursor\r
+#define BALLOON_DIALOG 0x0004 //Shown as a dialog instead of a tooltip\r
+#define BALLOON_DIALOG_DESTROY 0x0008 //delete the object after window is destroyed. Use carefully!\r
+\r
+//The masks\r
+#define BALLOON_MASK_STYLES 0x0001 //The styles for the tooltip gets from the structures\r
+#define BALLOON_MASK_EFFECT 0x0002 //The background's type for the tooltip gets from the structures\r
+#define BALLOON_MASK_COLORS 0x0004 //The background's colors for the tooltip gets from the structures\r
+#define BALLOON_MASK_DIRECTION 0x0008 //The align for the tooltip gets from the structures\r
+#define BALLOON_MASK_BEHAVIOUR 0x0010 //The behavior for the tooltip gets from the structures\r
+\r
+/**\r
+ * \ingroup Utils\r
+ * BALLOON_INFO structure.\r
+ */\r
+typedef struct tagBALLOON_INFO\r
+{\r
+ HICON hIcon; ///<The icon of the tooltip\r
+ CString sBalloonTip; ///<The string of the tooltip\r
+ UINT nMask; ///<The mask \r
+ UINT nStyles; ///<The tool tip's styles\r
+ UINT nDirection; ///<Direction display the tooltip relate cursor point\r
+ UINT nEffect; ///<The color's type or effects\r
+ UINT nBehaviour; ///<The tool tip's behavior\r
+ COLORREF crBegin; ///<Begin Color\r
+ COLORREF crMid; ///<Mid Color\r
+ COLORREF crEnd; ///<End Color\r
+\r
+ tagBALLOON_INFO(); ///<proper initialization of all members\r
+} BALLOON_INFO;\r
+\r
+/**\r
+ * \ingroup Utils\r
+ * This structure is sent to with the notify messages.\r
+ */\r
+typedef struct tagNM_BALLOON_DISPLAY {\r
+ NMHDR hdr;\r
+ CPoint * pt;\r
+ CWnd * pWnd;\r
+ BALLOON_INFO * bi;\r
+} NM_BALLOON_DISPLAY;\r
+\r
+#define BALLOON_CLASSNAME _T("CBalloon") // Window class name\r
+#define UDM_TOOLTIP_FIRST (WM_USER + 100)\r
+#define UDM_TOOLTIP_DISPLAY (UDM_TOOLTIP_FIRST) //User has changed the data\r
+\r
+/**\r
+ * \ingroup Utils\r
+ * Shows Balloons with info text in it. Either as Tooltips or as modeless dialog boxes.\r
+ * Several options are available to customize the look and behavior of the balloons.\r
+ * Since this class inherits CHTMLFormatter you can use all the tags CHTMLFormatter\r
+ * provides to format the text.\r
+ * Please refer to the documentation of the methods for details.\n\r
+ * \image html "balloon_box.jpg"\r
+ * \image html "balloon_tooltip.jpg"\r
+ * \r
+ * To use the dialog balloons just call the static methods:\r
+ * \code\r
+ * CWnd* ctrl = GetDlgItem(IDC_EDITBOX);\r
+ * CRect rt;\r
+ * ctrl->GetWindowRect(rt);\r
+ * CPoint point = CPoint((rt.left+rt.right)/2, (rt.top+rt.bottom)/2);\r
+ * CBalloon::ShowBalloon(NULL, point, \r
+ * "this is a <b>Message Balloon</b>\n<hr=100%>\n<ct=0x0000FF>Warning! Warning!</ct>\nSomething unexpected happened",\r
+ * TRUE, IDI_EXCLAMATION);\r
+ * \endcode\r
+ * \r
+ * To use the tooltips, declare an object of CBalloon as a member of your dialog class:\r
+ * \code\r
+ * CBalloon m_tooltips;\r
+ * \code\r
+ * In your OnInitDialog() method add the tooltips and modify them as you like:\r
+ * \code\r
+ * m_tooltips.Create(this); //initializes the tooltips\r
+ * m_tooltips.AddTool(IDC_BUTTON, "this button does nothing");\r
+ * m_tooltips.AddTool(IDC_EDITBOX, "enter a value here", IDI_ICON);\r
+ * m_tooltips.SetEffectBk(GetDlgItem(IDC_EDITBOX), CBalloon::BALLOON_EFFECT_HGRADIENT); //only affects the edit box tooltip\r
+ * m_tooltips.SetGradientColors(0x80ffff, 0x000000, 0xffff80);\r
+ * \endcode\r
+ * and last you have to override the PreTranslateMessage() method of your dialog box:\r
+ * \code\r
+ * BOOL CMyDialog::PreTranslateMessage(MSG* pMsg)\r
+ * {\r
+ * m_tooltips.RelayEvent(pMsg);\r
+ * return CDialog::PreTranslateMessage(pMsg);\r
+ * }\r
+ * \endcode\r
+ */\r
+class CBalloon : public CWnd, public CHTMLFormatter\r
+{\r
+// Construction\r
+public:\r
+ virtual BOOL Create(CWnd* pParentWnd);\r
+ CBalloon();\r
+ virtual ~CBalloon();\r
+\r
+// Attributes\r
+public:\r
+ enum { XBLSZ_ROUNDED_CX = 0,\r
+ XBLSZ_ROUNDED_CY,\r
+ XBLSZ_MARGIN_CX,\r
+ XBLSZ_MARGIN_CY,\r
+ XBLSZ_SHADOW_CX,\r
+ XBLSZ_SHADOW_CY,\r
+ XBLSZ_WIDTH_ANCHOR,\r
+ XBLSZ_HEIGHT_ANCHOR,\r
+ XBLSZ_MARGIN_ANCHOR,\r
+ XBLSZ_BORDER_CX,\r
+ XBLSZ_BORDER_CY,\r
+ XBLSZ_BUTTON_MARGIN_CX,\r
+ XBLSZ_BUTTON_MARGIN_CY,\r
+\r
+ XBLSZ_MAX_SIZES\r
+ };\r
+\r
+ enum { BALLOON_COLOR_FG = 0,\r
+ BALLOON_COLOR_BK_BEGIN,\r
+ BALLOON_COLOR_BK_MID,\r
+ BALLOON_COLOR_BK_END,\r
+ BALLOON_COLOR_SHADOW, // Color for the shadow\r
+ BALLOON_COLOR_BORDER, // Color for border of the tooltip\r
+\r
+ BALLOON_MAX_COLORS\r
+ };\r
+\r
+ enum { BALLOON_LEFT_TOP = 0,\r
+ BALLOON_RIGHT_TOP,\r
+ BALLOON_LEFT_BOTTOM,\r
+ BALLOON_RIGHT_BOTTOM,\r
+\r
+ BALLOON_MAX_DIRECTIONS\r
+ };\r
+\r
+ enum { BALLOON_EFFECT_SOLID = 0,\r
+ BALLOON_EFFECT_HGRADIENT,\r
+ BALLOON_EFFECT_VGRADIENT,\r
+ BALLOON_EFFECT_HCGRADIENT,\r
+ BALLOON_EFFECT_VCGRADIENT,\r
+ BALLOON_EFFECT_3HGRADIENT,\r
+ BALLOON_EFFECT_3VGRADIENT,\r
+\r
+ BALLOON_MAX_EFFECTS\r
+ };\r
+\r
+\r
+// Operations\r
+public:\r
+\r
+// Overrides\r
+ // ClassWizard generated virtual function overrides\r
+ //{{AFX_VIRTUAL(XToolTip)\r
+ public:\r
+ virtual BOOL PreTranslateMessage(MSG* pMsg);\r
+ //}}AFX_VIRTUAL\r
+\r
+// Implementation\r
+public:\r
+ /** \name Balloon Dialogs \r
+ * static methods to show a balloon like a modeless dialog\r
+ */\r
+ //@{\r
+ /**\r
+ * Pops up a balloon like a modeless dialog to inform the user in\r
+ * a non disturbing way like with a normal MessageBox().\r
+ * \image html "balloon_box.jpg"\r
+ * An example of when to use such balloons is in a dialog box where\r
+ * the user can enter values. If one or several values are outside\r
+ * of valid ranges then just pop up a balloon. That way the user \r
+ * knows exactly \b where the wrong value is (if the balloon is\r
+ * placed so that the anchor points to the edit box) and also\r
+ * doesn't have to press "OK" to close the box.\r
+ *\r
+ * \param pWnd the parent window. Or NULL if no parent window is available.\r
+ * \param pt the point where the anchor should point to. For example if you\r
+ * want to point to an edit box the point would be:\r
+ * \code\r
+ * CWnd* ctrl = GetDlgItem(IDC_EDITBOX);\r
+ * CRect rt;\r
+ * ctrl->GetWindowRect(rt);\r
+ * CPoint point = CPoint((rt.left+rt.right)/2, (rt.top+rt.bottom)/2);\r
+ * \endcode\r
+ * \param nIdText the string ID of the text to show. The ID has to be in your resources.\r
+ * \param sText the string to show.\r
+ * \param showCloseButton If TRUE, then the balloon has a close button in the upper right corner. That also\r
+ * makes the balloon to show up until the user presses the close button.\n\r
+ * If FALSE, then the balloon will be closed after a timeout of 5 seconds or as soon as the user clicks anywhere\r
+ * on the balloon.\r
+ * \param hIcon a handle of an icon.\r
+ * \param nIdIcon an ID of an icon which has to be in your resources.\r
+ * \param szIcon a name of an icon. Either a path to an icon file or one of\r
+ * the following system icons:\n\r
+ * - IDI_APPLICATION\r
+ * - IDI_ERROR\r
+ * - IDI_HAND\r
+ * - IDI_EXCLAMATION\r
+ * - IDI_WARNING\r
+ * - IDI_QUESTION\r
+ * - IDI_WINLOGO\r
+ * - IDI_INFORMATION\r
+ * - IDI_ASTERISK\r
+ * - IDI_QUESTION\r
+ * \r
+ * \param nDirection the direction to where the dialog should be drawn. Defaults to BALLOON_RIGHT_TOP.\r
+ * - BALLOON_LEFT_TOP\r
+ * - BALLOON_RIGHT_TOP\r
+ * - BALLOON_LEFT_BOTTOM\r
+ * - BALLOON_RIGHT_BOTTOM\r
+ *\r
+ * \param nEffect specifies how to draw the background. Defaults to BALLOON_EFFECT_SOLID.\r
+ * - BALLOON_EFFECT_SOLID one color for the background. The default is the standard windows color for tooltip backgrounds.\r
+ * - BALLOON_EFFECT_HGRADIENT draws a horizontal gradient from crStart to crEnd\r
+ * - BALLOON_EFFECT_VGRADIENT draws a vertical gradient from crStart to crEnd\r
+ * - BALLOON_EFFECT_HCGRADIENT draws a horizontal gradient from crStart to crEnd to crStart\r
+ * - BALLOON_EFFECT_VCGRADIENT draws a vertical gradient from crStart to crEnd to crStart\r
+ * - BALLOON_EFFECT_3HGRADIENT draws a horizontal gradient from crStart to crMid to crEnd\r
+ * - BALLOON_EFFECT_3VGRADIENT draws a vertical gradient from crStart to crMid to crEnd\r
+ *\r
+ * \param crStart the starting color for gradients\r
+ * \param crMid the middle color for three colored gradients\r
+ * \param crEnd the end color for gradients\r
+ */\r
+ /**\r
+ * \overload ShowBalloon(CWnd * pWnd, CPoint pt, UINT nIdText, BOOL showCloseButton, UINT nIdIcon, UINT nDirection = BALLOON_RIGHT_TOP, UINT nEffect = BALLOON_EFFECT_SOLID, COLORREF crStart = NULL, COLORREF crMid = NULL, COLORREF crEnd = NULL);\r
+ */\r
+ static void ShowBalloon(\r
+ CWnd * pWnd, CPoint pt, const CString& sText, BOOL showCloseButton, HICON hIcon,\r
+ UINT nDirection = BALLOON_RIGHT_TOP, UINT nEffect = BALLOON_EFFECT_SOLID,\r
+ COLORREF crStart = NULL, COLORREF crMid = NULL, COLORREF crEnd = NULL);\r
+ /**\r
+ * \overload ShowBalloon(CWnd * pWnd, CPoint pt, UINT nIdText, BOOL showCloseButton, LPCTSTR szIcon);\r
+ */\r
+ static void ShowBalloon(CWnd * pWnd, CPoint pt, UINT nIdText, BOOL showCloseButton, LPCTSTR szIcon);\r
+ //@}\r
+\r
+ /** \r
+ * Helper function to return the center point of a dialog control \r
+ * Useful for passing to ShowBalloon\r
+ */\r
+ static CPoint GetCtrlCentre(CWnd* pDlgWnd, UINT ctrlId);\r
+\r
+ /** \name ToolTips \r
+ * handling of tooltips.\r
+ */\r
+ //@{\r
+ //@{\r
+ /**\r
+ * Adds a tooltip for a windows element to the internal list.\r
+ * \param pWnd pointer to a windows element.\r
+ * \param nIdWnd an ID of a dialog resource.\r
+ * \param nIdText an ID of a string dialog resource to use as the tooltip text.\r
+ * \param sBalloontipText string for the tooltip.\r
+ * \param hIcon handle for an icon to show on the tooltip.\r
+ * \param nIdIcon a resource ID for an icon to show on the tooltip.\r
+ * \param bi pointer to a BALLOON_IFNO structure.\r
+ */\r
+ void AddTool(CWnd * pWnd, UINT nIdText, HICON hIcon = NULL); //Adds tool\r
+ void AddTool(CWnd * pWnd, UINT nIdText, UINT nIdIcon); //Adds tool\r
+ void AddTool(CWnd * pWnd, const CString& sBalloonTipText, HICON hIcon = NULL); //Adds tool\r
+ void AddTool(CWnd * pWnd, const CString& sBalloonTipText, UINT nIdIcon); //Adds tool\r
+ void AddTool(int nIdWnd, UINT nIdText, HICON hIcon = NULL); //Adds tool\r
+ void AddTool(int nIdWnd, UINT nIdText, UINT nIdIcon); //Adds tool\r
+ void AddTool(int nIdWnd, const CString& sBalloonTipText, HICON hIcon = NULL); //Adds tool\r
+ void AddTool(int nIdWnd, const CString& sBalloonTipText, UINT nIdIcon); //Adds tool\r
+ void AddTool(CWnd * pWnd, BALLOON_INFO & bi); //Adds tool\r
+ //@}\r
+\r
+ /**\r
+ * Gets the text and the icon handle of a specific tooltip.\r
+ * \param pWnd pointer to the tooltip window\r
+ * \param sBalloonTipText the returned tooltip text\r
+ * \param hIcon the returned icon handle\r
+ * \param bi pointer to the returned BALLOON_INFO structure.\r
+ * \return TRUE if the tooltip exists.\r
+ */\r
+ BOOL GetTool(CWnd * pWnd, CString & sBalloonTipText, HICON & hIcon) const; //Gets the tool tip's text\r
+ BOOL GetTool(CWnd * pWnd, BALLOON_INFO & bi) const; //Gets tool\r
+\r
+ /**\r
+ * Removes a specific tooltip from the internal list.\r
+ * \param pWnd pointer to the tooltip window\r
+ */\r
+ void RemoveTool(CWnd * pWnd); //Removes specified tool\r
+\r
+ /**\r
+ * Removes all tooltips from the internal list. \r
+ */\r
+ void RemoveAllTools(); // Removes all tools\r
+ //@}\r
+\r
+ /** \name Styles \r
+ * handling of tooltip appearance styles.\r
+ * The following styles are available:\r
+ * - BALLOON_ANCHOR the balloon is drawn with an anchor\r
+ * - BALLOON_SHADOW the balloon is drawn with a SE shadow\r
+ * - BALLOON_ROUNDED the balloon has round corners. For tooltips like the standard windows ones disable this style.\r
+ * - BALLOON_RSA combines BALLOON_ANCHOR, BALLOON_SHADOW and BALLOON_ROUNDED. This is the default.\r
+ * - BALLOON_VCENTER_ALIGN\r
+ * - BALLOON_BOTTOM_ALIGN\r
+ * - BALLOON_CLOSEBUTTON the balloon has a close button in the upper right corner.\r
+ */\r
+ //@{\r
+ /**\r
+ * sets styles for either all tooltips or specific ones.\r
+ * \param nStyles the styles to set.\r
+ * \param pWnd pointer to the tooltip window or NULL if the styles should affect all tooltips.\r
+ */\r
+ void SetStyles(DWORD nStyles, CWnd * pWnd = NULL); //Sets New Style\r
+ /**\r
+ * Modifies existing styles.\r
+ * \param nAddStyles the styles to add.\r
+ * \param nRemoveStyles the styles to remove\r
+ * \param pWnd pointer to the tooltip window or NULL if the styles should affect all tooltips.\r
+ */\r
+ void ModifyStyles(DWORD nAddStyles, DWORD nRemoveStyles, CWnd * pWnd = NULL); //Modifies styles\r
+ /**\r
+ * returns the current styles for the tooltip.\r
+ * \param pWnd pointer to the tooltip window or NULL if the global styles are needed.\r
+ */\r
+ DWORD GetStyles(CWnd * pWnd = NULL) const; //Gets current Styles\r
+ /**\r
+ * Resets the styles to the default values.\r
+ * \param pWnd pointer to the tooltip window or NULL if the styles should affect all tooltips.\r
+ */\r
+ void SetDefaultStyles(CWnd * pWnd = NULL); //Sets default styles\r
+ //@}\r
+\r
+ /** \name Colors\r
+ * different color settings. The following elements have colors:\r
+ * - BALLOON_COLOR_FG the foreground text color. Default is black.\r
+ * - BALLOON_COLOR_BK_BEGIN the background color and the first color in gradients.\r
+ * - BALLOON_COLOR_BK_MID the middle color for gradients.\r
+ * - BALLOON_COLOR_BK_END the end color for gradients.\r
+ * - BALLOON_COLOR_SHADOW the color of the shadow\r
+ * - BALLOON_COLOR_BORDER the color for the balloon border\r
+ */\r
+ //@{\r
+ /**\r
+ * Sets the color for a balloon element.\r
+ * \param nIndex the element to set the color.\r
+ * \param crColor the color.\r
+ */\r
+ void SetColor(int nIndex, COLORREF crColor); //Sets the color\r
+ /**\r
+ * Returns the color of a balloon element.\r
+ */\r
+ COLORREF GetColor(int nIndex) const; //Gets the color\r
+ /**\r
+ * Resets all colors to default values.\r
+ */\r
+ void SetDefaultColors(); //Sets default colors\r
+ /**\r
+ * Sets the colors used in the background gradients.\r
+ * \param crBegin first color\r
+ * \param crMid middle color\r
+ * \param crEnd end color\r
+ * \param pWnd pointer to the tooltip window or NULL if the settings are global.\r
+ */\r
+ void SetGradientColors(COLORREF crBegin, COLORREF crMid, COLORREF crEnd, CWnd * pWnd = NULL); //Sets the gradient's colors\r
+ /**\r
+ * Returns the colors used in the background gradients.\r
+ * \param pWnd pointer to the tooltip window or NULL if the global settings are needed.\r
+ */\r
+ void GetGradientColors(COLORREF & crBegin, COLORREF & crMid, COLORREF & crEnd, CWnd * pWnd = NULL) const; //Gets the gradient's colors\r
+ //@}\r
+\r
+\r
+ /** \name Masks \r
+ * Manipulate masks of tooltips. Masks are used to define styles, effects, colors and the like for single\r
+ * tooltips and not only for all tooltips.\r
+ * Whatever mask is set for a specific tooltip means that this tooltip has its own version of those settings\r
+ * and ignores the global settings.\n\r
+ * The following masks are available:\r
+ * - BALLOON_MASK_STYLES masks out the styles\r
+ * - BALLOON_MASK_EFFECT masks out the effects\r
+ * - BALLOON_MASK_COLORS masks out the colors\r
+ * - BALLOON_MASK_DIRECTION masks out the direction\r
+ * - BALLOON_MASK_BEHAVIOUR masks out the behavior\r
+ * \r
+ * The functions either set, modify or read out the masks for specific tooltip windows.\r
+ */\r
+ //@{\r
+ void SetMaskTool(CWnd * pWnd, UINT nMask = 0);\r
+ void ModifyMaskTool(CWnd * pWnd, UINT nAddMask, UINT nRemoveMask);\r
+ UINT GetMaskTool(CWnd * pWnd) const;\r
+ //@}\r
+\r
+ /** \name Effects\r
+ * Use these methods to manipulate background effects of the tooltip. The following\r
+ * effects are available.\r
+ * - BALLOON_EFFECT_SOLID one color for the background. The default is the standard windows color for tooltip backgrounds.\r
+ * - BALLOON_EFFECT_HGRADIENT draws a horizontal gradient from crStart to crEnd\r
+ * - BALLOON_EFFECT_VGRADIENT draws a vertical gradient from crStart to crEnd\r
+ * - BALLOON_EFFECT_HCGRADIENT draws a horizontal gradient from crStart to crEnd to crStart\r
+ * - BALLOON_EFFECT_VCGRADIENT draws a vertical gradient from crStart to crEnd to crStart\r
+ * - BALLOON_EFFECT_3HGRADIENT draws a horizontal gradient from crStart to crMid to crEnd\r
+ * - BALLOON_EFFECT_3VGRADIENT draws a vertical gradient from crStart to crMid to crEnd\r
+ */\r
+ //@{\r
+ void SetEffectBk(UINT nEffect, CWnd * pWnd = NULL);\r
+ UINT GetEffectBk(CWnd * pWnd = NULL) const;\r
+ //@}\r
+\r
+ /** \name Notification \r
+ * Gets or sets if the parent or any other window should get notification messages from\r
+ * the tooltips.\r
+ */\r
+ //@{\r
+ void SetNotify(HWND hWnd);\r
+ void SetNotify(BOOL bParentNotify = TRUE);\r
+ BOOL GetNotify() const; //Is enabled notification\r
+ //@}\r
+\r
+ /** \name Delaytimes\r
+ * Gets or sets the delay times for the tooltips.\r
+ * - TTDT_AUTOPOP time in milliseconds until the tooltip automatically closes.\r
+ * - TTDT_INITIAL time in milliseconds until the tooltip appears when the mouse pointer is over a control.\r
+ */\r
+ //@{\r
+ void SetDelayTime(DWORD dwDuration, UINT nTime);\r
+ UINT GetDelayTime(DWORD dwDuration) const;\r
+ //@}\r
+\r
+\r
+ /** \name Direction \r
+ * Gets or sets the direction of the balloons.\r
+ * - BALLOON_LEFT_TOP\r
+ * - BALLOON_RIGHT_TOP\r
+ * - BALLOON_LEFT_BOTTOM\r
+ * - BALLOON_RIGHT_BOTTOM\r
+ */\r
+ //@{\r
+ void SetDirection(UINT nDirection = BALLOON_RIGHT_TOP, CWnd * pWnd = NULL);\r
+ UINT GetDirection(CWnd * pWnd = NULL) const;\r
+ //@}\r
+\r
+ /** \name Behavior\r
+ * Gets or sets the behavior of the balloons.\r
+ * - BALLOON_MULTIPLE_SHOW if this is set then the tooltip will appear again if the mouse pointer is still over the same control.\r
+ * - BALLOON_TRACK_MOUSE if set then the tooltip will follow the mouse pointer\r
+ * - BALLOON_DIALOG the balloon is shown as a dialog instead of a tooltip, i.e. it won't close when the mouse pointer leaves the control.\r
+ * - BALLOON_DIALOG_DESTROY the object itself is destroyed when the balloon is closed. Use this \b very carefully!\r
+ */\r
+ //@{\r
+ void SetBehaviour(UINT nBehaviour = 0, CWnd * pWnd = NULL);\r
+ UINT GetBehaviour(CWnd * pWnd = NULL) const;\r
+ //@}\r
+\r
+ /** \name Fonts \r
+ * Font settings for the balloon text.\r
+ */\r
+ //@{\r
+ BOOL SetFont(CFont & font); //set font\r
+ BOOL SetFont(LPLOGFONT lf); //set font\r
+ BOOL SetFont(LPCTSTR lpszFaceName, int nSizePoints = 8,\r
+ BOOL bUnderline = FALSE, BOOL bBold = FALSE,\r
+ BOOL bStrikeOut = FALSE, BOOL bItalic = FALSE); //set font\r
+ void SetDefaultFont(); //set default fonts\r
+ void GetFont(CFont & font) const;\r
+ void GetFont(LPLOGFONT lf) const;\r
+ //@}\r
+\r
+ /**\r
+ * Call this method from CDialog::PreTranslateMessage(pMsg).\r
+ */\r
+ void RelayEvent(MSG* pMsg);\r
+ \r
+ /**\r
+ * Hide tooltip immediately.\r
+ */\r
+ void Pop();\r
+\r
+ /**\r
+ * Shows a tooltip immediately.\r
+ */\r
+ void DisplayToolTip(CPoint * pt = NULL);\r
+ void DisplayToolTip(CPoint * pt, CRect * rect);\r
+\r
+ // Generated message map functions\r
+protected:\r
+ void SetSize(int nSizeIndex, UINT nValue);\r
+ UINT GetSize(int nSizeIndex) const;\r
+ void SetDefaultSizes();\r
+\r
+ void Redraw(BOOL bRedraw = TRUE);\r
+ void KillTimers(UINT nIDTimer = NULL);\r
+ \r
+ void SetNewToolTip(CWnd * pWnd);\r
+ void GetMonitorWorkArea(const CPoint& sourcePoint, CRect& monitorRect) const;\r
+\r
+ /**\r
+ * Finds the child window to which the point belongs\r
+ * \param point the point to look for the child window\r
+ * \return the pointer to the child window, or NULL if there is now window\r
+ */\r
+ HWND GetChildWindowFromPoint(CPoint & point) const;\r
+ BOOL IsCursorInToolTip() const;\r
+ inline BOOL IsVisible() const { return ((GetStyle() & WS_VISIBLE) == WS_VISIBLE); }\r
+\r
+ CSize GetTooltipSize(const CString& str); //Gets max rectangle for display tooltip text\r
+ CSize GetSizeIcon(HICON hIcon) const;\r
+ void CalculateInfoBoxRect(CPoint * pt, CRect * rect);\r
+\r
+ LPLOGFONT GetSystemToolTipFont() const;\r
+\r
+ int GetNextHorizDirection(int nDirection) const;\r
+ int GetNextVertDirection(int nDirection) const;\r
+ BOOL TestHorizDirection(int x, int cx, const CRect& monitorRect, int nDirection, LPRECT rect);\r
+ BOOL TestVertDirection(int y, int cy, const CRect& monitorRect, int nDirection, LPRECT rect);\r
+\r
+ CRect GetWindowRegion(CRgn * rgn, CSize sz, CPoint pt) const;\r
+\r
+ LRESULT SendNotify(CWnd * pWnd, CPoint * pt, BALLOON_INFO & bi);\r
+\r
+ void OnDraw(CDC * pDC, CRect rect);\r
+ void OnDrawBackground(CDC * pDC, CRect * pRect);\r
+\r
+ virtual void PostNcDestroy();\r
+ afx_msg void OnPaint();\r
+ afx_msg void OnTimer(UINT_PTR nIDEvent);\r
+ afx_msg void OnDestroy();\r
+ afx_msg void OnKillFocus(CWnd* pNewWnd);\r
+ afx_msg void OnMouseMove(UINT nFlags, CPoint point);\r
+ afx_msg void OnLButtonDown(UINT nFlags, CPoint point);\r
+ afx_msg void OnLButtonUp(UINT nFlags, CPoint point);\r
+ DECLARE_MESSAGE_MAP()\r
+protected:\r
+ enum { BALLOON_SHOW = 0x100, //the identifier of the timer for show the tooltip\r
+ BALLOON_HIDE = 0x101 //the identifier of the timer for hide the tooltip\r
+ };\r
+\r
+ CMap<HWND, HWND, BALLOON_INFO, BALLOON_INFO> m_ToolMap; //Tool Maps\r
+\r
+ HWND m_hNotifyWnd; // Handle to window for notification about change data\r
+ CWnd * m_pParentWnd; // The pointer to the parent window\r
+ HWND m_hCurrentWnd;\r
+ HWND m_hDisplayedWnd;\r
+ UINT m_nLastDirection;\r
+ \r
+\r
+ LOGFONT m_LogFont; // Current font in use\r
+ \r
+ //Default setting\r
+ COLORREF m_crColor [BALLOON_MAX_COLORS]; //The indexing colors\r
+ UINT m_nSizes [XBLSZ_MAX_SIZES]; //All sizes \r
+ UINT m_nStyles;\r
+ UINT m_nDirection;\r
+ UINT m_nEffect;\r
+ UINT m_nBehaviour; //The tool tip's behavior \r
+\r
+ UINT m_nTimeAutoPop; \r
+ UINT m_nTimeInitial;\r
+\r
+ //The properties of the current tooltip\r
+ CPoint m_ptOriginal;\r
+\r
+ CRgn m_rgnBalloon;\r
+ CRgn m_rgnShadow;\r
+\r
+ CSize m_szBalloonIcon; //the size of the current icon\r
+ CSize m_szBalloonText; //the size of the tool tip's text\r
+ CSize m_szCloseButton;\r
+\r
+ CRect m_rtCloseButton; //the rect for the close button\r
+ BOOL m_bButtonPushed;\r
+\r
+ CCursor m_Cursor;\r
+\r
+ BALLOON_INFO m_pToolInfo; //info of the current tooltip\r
+\r
+\r
+};\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2007 - Stefan Kueng\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#include "stdafx.h"\r
+#include "BaseDialog.h"\r
+\r
+\r
+INT_PTR CDialog::DoModal(HINSTANCE hInstance, int resID, HWND hWndParent)\r
+{\r
+ hResource = hInstance;\r
+ return DialogBoxParam(hInstance, MAKEINTRESOURCE(resID), hWndParent, &CDialog::stDlgFunc, (LPARAM)this);\r
+}\r
+\r
+HWND CDialog::Create(HINSTANCE hInstance, int resID, HWND hWndParent)\r
+{\r
+ hResource = hInstance;\r
+ m_hwnd = CreateDialogParam(hInstance, MAKEINTRESOURCE(resID), hWndParent, &CDialog::stDlgFunc, (LPARAM)this);\r
+ return m_hwnd;\r
+}\r
+\r
+void CDialog::InitDialog(HWND hwndDlg, UINT iconID)\r
+{\r
+ HWND hwndOwner; \r
+ RECT rc, rcDlg, rcOwner;\r
+\r
+ hwndOwner = ::GetParent(hwndDlg);\r
+ if (hwndOwner == NULL)\r
+ hwndOwner = ::GetDesktopWindow();\r
+\r
+ GetWindowRect(hwndOwner, &rcOwner); \r
+ GetWindowRect(hwndDlg, &rcDlg); \r
+ CopyRect(&rc, &rcOwner); \r
+\r
+ OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top); \r
+ OffsetRect(&rc, -rc.left, -rc.top); \r
+ OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom); \r
+\r
+ SetWindowPos(hwndDlg, HWND_TOP, rcOwner.left + (rc.right / 2), rcOwner.top + (rc.bottom / 2), 0, 0, SWP_NOSIZE); \r
+ HICON hIcon = (HICON)::LoadImage(hResource, MAKEINTRESOURCE(iconID), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE|LR_SHARED);\r
+ ::SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);\r
+ ::SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);\r
+}\r
+\r
+INT_PTR CALLBACK CDialog::stDlgFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ CDialog* pWnd;\r
+ if (uMsg == WM_INITDIALOG)\r
+ {\r
+ // get the pointer to the window from lpCreateParams\r
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);\r
+ pWnd = (CDialog*)lParam;\r
+ pWnd->m_hwnd = hwndDlg;\r
+ }\r
+ // get the pointer to the window\r
+ pWnd = GetObjectFromWindow(hwndDlg);\r
+\r
+ // if we have the pointer, go to the message handler of the window\r
+ // else, use DefWindowProc\r
+ if (pWnd)\r
+ {\r
+ LRESULT lRes = pWnd->DlgFunc(hwndDlg, uMsg, wParam, lParam);\r
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, lRes);\r
+ return lRes;\r
+ }\r
+ else\r
+ return DefWindowProc(hwndDlg, uMsg, wParam, lParam);\r
+}\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2007 - Stefan Kueng\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#pragma once\r
+#include <string>\r
+\r
+\r
+/**\r
+ * \ingroup Utils\r
+ * A base window class.\r
+ * Provides separate window message handlers for every window object based on\r
+ * this class.\r
+ */\r
+class CDialog\r
+{\r
+public:\r
+ INT_PTR DoModal(HINSTANCE hInstance, int resID, HWND hWndParent);\r
+ HWND Create(HINSTANCE hInstance, int resID, HWND hWndParent);\r
+\r
+ virtual LRESULT CALLBACK DlgFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) = 0;\r
+\r
+ operator HWND() {return m_hwnd;}\r
+protected:\r
+ HINSTANCE hResource;\r
+ HWND m_hwnd;\r
+\r
+ void InitDialog(HWND hwndDlg, UINT iconID);\r
+\r
+ // the real message handler\r
+ static INT_PTR CALLBACK stDlgFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);\r
+\r
+ // returns a pointer the dialog (stored as the WindowLong)\r
+ inline static CDialog * GetObjectFromWindow(HWND hWnd)\r
+ {\r
+ return (CDialog *)GetWindowLongPtr(hWnd, GWLP_USERDATA);\r
+ }\r
+};\r
+\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2008 - TortoiseSVN\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#include "stdafx.h"\r
+#include "BaseWindow.h"\r
+\r
+\r
+ResString::ResString (HINSTANCE hInst, int resId)\r
+{\r
+ if (!::LoadString (hInst, resId, _buf, MAX_RESSTRING + 1))\r
+ {\r
+ SecureZeroMemory(_buf, sizeof(_buf));\r
+ }\r
+}\r
+\r
+\r
+bool CWindow::RegisterWindow(UINT style, HICON hIcon, HCURSOR hCursor, HBRUSH hbrBackground, \r
+ LPCTSTR lpszMenuName, LPCTSTR lpszClassName, HICON hIconSm)\r
+{\r
+ WNDCLASSEX wcx; \r
+ \r
+ // Fill in the window class structure with default parameters \r
+ \r
+ wcx.cbSize = sizeof(WNDCLASSEX); // size of structure \r
+ wcx.style = style; // redraw if size changes \r
+ wcx.lpfnWndProc = CWindow::stWinMsgHandler; // points to window procedure \r
+ wcx.cbClsExtra = 0; // no extra class memory \r
+ wcx.cbWndExtra = 0; // no extra window memory \r
+ wcx.hInstance = hResource; // handle to instance \r
+ wcx.hIcon = hIcon; // predefined app. icon \r
+ wcx.hCursor = hCursor; // predefined arrow \r
+ wcx.hbrBackground = hbrBackground; // white background brush \r
+ wcx.lpszMenuName = lpszMenuName; // name of menu resource \r
+ wcx.lpszClassName = lpszClassName; // name of window class \r
+ wcx.hIconSm = hIconSm; // small class icon \r
+ \r
+ // Register the window class. \r
+ return RegisterWindow(&wcx); \r
+}\r
+\r
+bool CWindow::RegisterWindow(CONST WNDCLASSEX* wcx)\r
+{\r
+ // Register the window class. \r
+ sClassName = std::wstring(wcx->lpszClassName);\r
+\r
+ if (RegisterClassEx(wcx) == 0)\r
+ return FALSE;\r
+ else\r
+ return TRUE;\r
+}\r
+\r
+LRESULT CALLBACK CWindow::stWinMsgHandler(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ CWindow* pWnd;\r
+\r
+ if (uMsg == WM_NCCREATE)\r
+ {\r
+ // get the pointer to the window from lpCreateParams which was set in CreateWindow\r
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (long)((LPCREATESTRUCT(lParam))->lpCreateParams));\r
+ }\r
+\r
+ // get the pointer to the window\r
+ pWnd = GetObjectFromWindow(hwnd);\r
+\r
+ // if we have the pointer, go to the message handler of the window\r
+ // else, use DefWindowProc\r
+ if (pWnd)\r
+ return pWnd->WinMsgHandler(hwnd, uMsg, wParam, lParam);\r
+ else\r
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
+}\r
+\r
+bool CWindow::Create()\r
+{ \r
+ // Create the window\r
+ RECT rect;\r
+\r
+ rect.top = 0;\r
+ rect.left = 0;\r
+ rect.right = 600;\r
+ rect.bottom = 400;\r
+\r
+ return Create(WS_OVERLAPPEDWINDOW | WS_VISIBLE, NULL, &rect);\r
+}\r
+\r
+bool CWindow::Create(DWORD dwStyles, HWND hParent /* = NULL */, RECT* rect /* = NULL */)\r
+{ \r
+ return CreateEx(0, dwStyles, hParent, rect); \r
+}\r
+\r
+bool CWindow::CreateEx(DWORD dwExStyles, DWORD dwStyles, HWND hParent /* = NULL */, RECT* rect /* = NULL */)\r
+{\r
+ // send the this pointer as the window creation parameter\r
+ if (rect == NULL)\r
+ m_hwnd = CreateWindowEx(dwExStyles, sClassName.c_str(), sWindowTitle.c_str(), dwStyles, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hParent, NULL, hResource, (void *)this);\r
+ else\r
+ {\r
+ m_hwnd = CreateWindowEx(dwExStyles, sClassName.c_str(), sWindowTitle.c_str(), dwStyles, rect->left, rect->top, \r
+ rect->right - rect->left, rect->bottom - rect->top, hParent, NULL, hResource, \r
+ (void *)this);\r
+ }\r
+ return (m_hwnd != NULL);\r
+}\r
+\r
+void CWindow::SetTransparency(BYTE alpha, COLORREF color /* = 0xFF000000 */)\r
+{\r
+ if (alpha == 255)\r
+ {\r
+ LONG_PTR exstyle = GetWindowLongPtr(*this, GWL_EXSTYLE);\r
+ exstyle &= ~WS_EX_LAYERED;\r
+ SetWindowLongPtr(*this, GWL_EXSTYLE, exstyle);\r
+ }\r
+ else\r
+ {\r
+ LONG_PTR exstyle = GetWindowLongPtr(*this, GWL_EXSTYLE);\r
+ exstyle |= WS_EX_LAYERED;\r
+ SetWindowLongPtr(*this, GWL_EXSTYLE, exstyle);\r
+ }\r
+ COLORREF col = color;\r
+ DWORD flags = LWA_ALPHA;\r
+ if (col & 0xFF000000)\r
+ {\r
+ col = RGB(255, 255, 255);\r
+ flags = LWA_ALPHA;\r
+ }\r
+ else\r
+ {\r
+ flags = LWA_COLORKEY;\r
+ }\r
+ SetLayeredWindowAttributes(*this, col, alpha, flags);\r
+}\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2007 - Stefan Kueng\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#pragma once\r
+#include <string>\r
+\r
+\r
+/**\r
+ * \ingroup Utils\r
+ * Loads a string from the application resources.\r
+ */\r
+class ResString\r
+{\r
+ enum { MAX_RESSTRING = 1024 };\r
+public:\r
+ ResString (HINSTANCE hInst, int resId);\r
+ operator TCHAR const * () const { return _buf; }\r
+private:\r
+ TCHAR _buf [MAX_RESSTRING + 1];\r
+};\r
+\r
+/**\r
+ * \ingroup Utils\r
+ * A base window class.\r
+ * Provides separate window message handlers for every window object based on\r
+ * this class.\r
+ */\r
+class CWindow\r
+{\r
+public:\r
+ virtual bool RegisterWindow(UINT style, HICON hIcon, HCURSOR hCursor, HBRUSH hbrBackground, \r
+ LPCTSTR lpszMenuName, LPCTSTR lpszClassName, HICON hIconSm);\r
+ virtual bool RegisterWindow(CONST WNDCLASSEX* wcx);\r
+\r
+ /// static message handler to put in WNDCLASSEX structure\r
+ static LRESULT CALLBACK stWinMsgHandler(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);\r
+\r
+ /**\r
+ * Sets the window title. \r
+ */\r
+ void SetWindowTitle(const std::wstring& sTitle) \r
+ {\r
+ sWindowTitle = sTitle;\r
+ };\r
+\r
+ /**\r
+ * Sets the transparency of the window.\r
+ * \remark note that this also sets the WS_EX_LAYERED style!\r
+ */\r
+ void SetTransparency(BYTE alpha, COLORREF color = 0xFF000000);\r
+\r
+ virtual bool Create();\r
+ virtual bool Create(DWORD dwStyles, HWND hParent = NULL, RECT* rect = NULL);\r
+ virtual bool CreateEx(DWORD dwExStyles, DWORD dwStyles, HWND hParent = NULL, RECT* rect = NULL);\r
+\r
+ //void MsgLoop();\r
+ bool IsWindowClosed() { return bWindowClosed; };\r
+\r
+ operator HWND() {return m_hwnd;}\r
+protected:\r
+ HINSTANCE hResource;\r
+ HWND m_hwnd;\r
+ bool bWindowClosed;\r
+ std::wstring sClassName;\r
+ std::wstring sWindowTitle;\r
+\r
+ //constructor \r
+ CWindow(HINSTANCE hInst, CONST WNDCLASSEX* wcx = NULL) : m_hwnd(NULL)\r
+ , hResource(NULL)\r
+ , bWindowClosed(FALSE)\r
+ {\r
+ hResource = hInst; \r
+ if (wcx != NULL)\r
+ RegisterWindow(wcx);\r
+ };\r
+\r
+ // the real message handler\r
+ virtual LRESULT CALLBACK WinMsgHandler(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) = 0;\r
+\r
+ // returns a pointer the window (stored as the WindowLong)\r
+ inline static CWindow * GetObjectFromWindow(HWND hWnd)\r
+ {\r
+ return (CWindow *)GetWindowLongPtr(hWnd, GWLP_USERDATA);\r
+ }\r
+};\r
+\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2008 - TortoiseSVN\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#include "StdAfx.h"\r
+#include <windowsx.h>\r
+#include "BrowseFolder.h"\r
+\r
+BOOL CBrowseFolder::m_bCheck = FALSE;\r
+BOOL CBrowseFolder::m_bCheck2 = FALSE;\r
+WNDPROC CBrowseFolder::CBProc = NULL;\r
+HWND CBrowseFolder::checkbox = NULL;\r
+HWND CBrowseFolder::checkbox2 = NULL;\r
+HWND CBrowseFolder::ListView = NULL;\r
+TCHAR CBrowseFolder::m_CheckText[200]; \r
+TCHAR CBrowseFolder::m_CheckText2[200]; \r
+CString CBrowseFolder::m_sDefaultPath;\r
+bool CBrowseFolder::m_DisableCheckbox2WhenCheckbox1IsChecked = false;\r
+\r
+\r
+CBrowseFolder::CBrowseFolder(void)\r
+: m_style(0),\r
+ m_root(NULL)\r
+{\r
+ memset(m_displayName, 0, sizeof(m_displayName));\r
+ memset(m_title, 0, sizeof(m_title));\r
+ memset(m_CheckText, 0, sizeof(m_CheckText));\r
+}\r
+\r
+CBrowseFolder::~CBrowseFolder(void)\r
+{\r
+}\r
+\r
+//show the dialog\r
+CBrowseFolder::retVal CBrowseFolder::Show(HWND parent, LPTSTR path, size_t pathlen, LPCTSTR szDefaultPath /* = NULL */)\r
+{\r
+ CString temp;\r
+ temp = path;\r
+ CString sDefault;\r
+ if (szDefaultPath)\r
+ sDefault = szDefaultPath;\r
+ CBrowseFolder::retVal ret = Show(parent, temp, sDefault);\r
+ _tcscpy_s(path, pathlen, temp);\r
+ return ret;\r
+}\r
+CBrowseFolder::retVal CBrowseFolder::Show(HWND parent, CString& path, const CString& sDefaultPath /* = CString() */)\r
+{\r
+ retVal ret = OK; //assume OK\r
+ m_sDefaultPath = sDefaultPath;\r
+ if (m_sDefaultPath.IsEmpty() && !path.IsEmpty())\r
+ {\r
+ // if the result path already contains a path, use that as the default path\r
+ m_sDefaultPath = path;\r
+ }\r
+ LPITEMIDLIST itemIDList;\r
+\r
+ BROWSEINFO browseInfo;\r
+\r
+ browseInfo.hwndOwner = parent;\r
+ browseInfo.pidlRoot = m_root;\r
+ browseInfo.pszDisplayName = m_displayName;\r
+ browseInfo.lpszTitle = m_title;\r
+ browseInfo.ulFlags = m_style;\r
+ browseInfo.lpfn = NULL;\r
+ browseInfo.lParam = (LPARAM)this;\r
+ \r
+ if ((_tcslen(m_CheckText) > 0)||(!m_sDefaultPath.IsEmpty()))\r
+ {\r
+ browseInfo.lpfn = BrowseCallBackProc;\r
+ }\r
+ \r
+ itemIDList = SHBrowseForFolder(&browseInfo);\r
+\r
+ //is the dialog canceled?\r
+ if (!itemIDList)\r
+ ret = CANCEL;\r
+\r
+ if (ret != CANCEL) \r
+ {\r
+ if (!SHGetPathFromIDList(itemIDList, path.GetBuffer(MAX_PATH))) // MAX_PATH ok. Explorer can't handle paths longer than MAX_PATH.\r
+ ret = NOPATH;\r
+\r
+ path.ReleaseBuffer();\r
+ \r
+ LPMALLOC shellMalloc;\r
+ HRESULT hr;\r
+\r
+ hr = SHGetMalloc(&shellMalloc);\r
+\r
+ if (SUCCEEDED(hr)) \r
+ {\r
+ //free memory\r
+ shellMalloc->Free(itemIDList);\r
+ //release interface\r
+ shellMalloc->Release();\r
+ }\r
+ }\r
+ return ret;\r
+}\r
+\r
+void CBrowseFolder::SetInfo(LPCTSTR title)\r
+{\r
+ ASSERT(title);\r
+ \r
+ if (title)\r
+ _tcscpy_s(m_title, 200, title);\r
+}\r
+\r
+void CBrowseFolder::SetCheckBoxText(LPCTSTR checktext)\r
+{\r
+ ASSERT(checktext);\r
+\r
+ if (checktext)\r
+ _tcscpy_s(m_CheckText, 200, checktext);\r
+}\r
+\r
+void CBrowseFolder::SetCheckBoxText2(LPCTSTR checktext)\r
+{\r
+ ASSERT(checktext);\r
+\r
+ if (checktext)\r
+ _tcscpy_s(m_CheckText2, 200, checktext);\r
+}\r
+\r
+void CBrowseFolder::SetFont(HWND hwnd,LPTSTR FontName,int FontSize)\r
+{\r
+\r
+ HFONT hf;\r
+ LOGFONT lf={0};\r
+ HDC hdc=GetDC(hwnd);\r
+\r
+ GetObject(GetWindowFont(hwnd),sizeof(lf),&lf);\r
+ lf.lfWeight = FW_REGULAR;\r
+ lf.lfHeight = (LONG)FontSize;\r
+ lstrcpy( lf.lfFaceName, FontName );\r
+ hf=CreateFontIndirect(&lf);\r
+ SetBkMode(hdc,OPAQUE);\r
+ SendMessage(hwnd,WM_SETFONT,(WPARAM)hf,TRUE);\r
+ ReleaseDC(hwnd,hdc);\r
+\r
+}\r
+\r
+int CBrowseFolder::BrowseCallBackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM /*lpData*/)\r
+{\r
+ RECT ListViewRect,Dialog;\r
+ //Initialization callback message\r
+ if (uMsg == BFFM_INITIALIZED)\r
+ {\r
+ if (_tcslen(m_CheckText) > 0)\r
+ {\r
+ bool bSecondCheckbox = (_tcslen(m_CheckText2)!=0);\r
+ //Rectangles for getting the positions\r
+ checkbox = CreateWindowEx( 0,\r
+ _T("BUTTON"),\r
+ m_CheckText,\r
+ WS_CHILD|WS_VISIBLE|WS_CLIPCHILDREN|BS_AUTOCHECKBOX,\r
+ 0,100,100,50,\r
+ hwnd,\r
+ 0,\r
+ NULL,\r
+ NULL);\r
+ if (checkbox == NULL)\r
+ return 0;\r
+\r
+ if (bSecondCheckbox)\r
+ {\r
+ //Rectangles for getting the positions\r
+ checkbox2 = CreateWindowEx( 0,\r
+ _T("BUTTON"),\r
+ m_CheckText2,\r
+ WS_CHILD|WS_VISIBLE|WS_CLIPCHILDREN|BS_AUTOCHECKBOX,\r
+ 0,100,100,50,\r
+ hwnd,\r
+ 0,\r
+ NULL,\r
+ NULL);\r
+ if (checkbox2 == NULL)\r
+ return 0;\r
+ }\r
+\r
+ ListView = FindWindowEx(hwnd,NULL,_T("SysTreeView32"),NULL);\r
+ if (ListView == NULL)\r
+ ListView = FindWindowEx(hwnd,NULL,_T("SHBrowseForFolder ShellNameSpace Control"),NULL);\r
+\r
+ if (ListView == NULL)\r
+ return 0;\r
+\r
+ //Gets the dimensions of the windows\r
+ GetWindowRect(hwnd,&Dialog);\r
+ GetWindowRect(ListView,&ListViewRect);\r
+ POINT pt;\r
+ pt.x = ListViewRect.left;\r
+ pt.y = ListViewRect.top;\r
+ ScreenToClient(hwnd, &pt);\r
+ ListViewRect.top = pt.y;\r
+ ListViewRect.left = pt.x;\r
+ pt.x = ListViewRect.right;\r
+ pt.y = ListViewRect.bottom;\r
+ ScreenToClient(hwnd, &pt);\r
+ ListViewRect.bottom = pt.y;\r
+ ListViewRect.right = pt.x;\r
+ //Sets the list view controls dimensions\r
+ SetWindowPos(ListView,0,ListViewRect.left,\r
+ bSecondCheckbox ? ListViewRect.top+40 : ListViewRect.top+20,\r
+ (ListViewRect.right-ListViewRect.left),\r
+ bSecondCheckbox ? (ListViewRect.bottom - ListViewRect.top)-40 : (ListViewRect.bottom - ListViewRect.top)-20,\r
+ SWP_NOZORDER);\r
+ //Sets the window positions of checkbox and dialog controls\r
+ SetWindowPos(checkbox,HWND_BOTTOM,ListViewRect.left,\r
+ ListViewRect.top,\r
+ (ListViewRect.right-ListViewRect.left),\r
+ 14,\r
+ SWP_NOZORDER);\r
+ if (bSecondCheckbox)\r
+ {\r
+ SetWindowPos(checkbox2,HWND_BOTTOM,ListViewRect.left,\r
+ ListViewRect.top+20,\r
+ (ListViewRect.right-ListViewRect.left),\r
+ 14,\r
+ SWP_NOZORDER);\r
+ }\r
+ HWND label = FindWindowEx(hwnd, NULL, _T("STATIC"), NULL);\r
+ if (label)\r
+ {\r
+ HFONT hFont = (HFONT)::SendMessage(label, WM_GETFONT, 0, 0);\r
+ LOGFONT lf = {0};\r
+ GetObject(hFont, sizeof(lf), &lf);\r
+ HFONT hf2 = CreateFontIndirect(&lf);\r
+ ::SendMessage(checkbox, WM_SETFONT, (WPARAM)hf2, TRUE);\r
+ if (bSecondCheckbox)\r
+ ::SendMessage(checkbox2, WM_SETFONT, (WPARAM)hf2, TRUE);\r
+ }\r
+ else\r
+ {\r
+ //Sets the fonts of static controls\r
+ SetFont(checkbox,_T("MS Sans Serif"),12);\r
+ if (bSecondCheckbox)\r
+ SetFont(checkbox2,_T("MS Sans Serif"),12);\r
+ }\r
+\r
+ // Subclass the checkbox control. \r
+ CBProc = (WNDPROC) SetWindowLongPtr(checkbox,GWLP_WNDPROC, (LONG_PTR) CheckBoxSubclassProc); \r
+ //Sets the checkbox to checked position\r
+ SendMessage(checkbox,BM_SETCHECK,(WPARAM)m_bCheck,0);\r
+ if (bSecondCheckbox)\r
+ {\r
+ CBProc = (WNDPROC) SetWindowLongPtr(checkbox2,GWLP_WNDPROC, (LONG_PTR) CheckBoxSubclassProc2); \r
+ SendMessage(checkbox2,BM_SETCHECK,(WPARAM)m_bCheck,0);\r
+ }\r
+ // send a resize message to the resized list view control. Otherwise it won't show\r
+ // up properly until the user resizes the window!\r
+ SendMessage(ListView, WM_SIZE, SIZE_RESTORED, MAKELONG(ListViewRect.right-ListViewRect.left, bSecondCheckbox ? (ListViewRect.bottom - ListViewRect.top)-40 : (ListViewRect.bottom - ListViewRect.top)-20));\r
+ }\r
+ \r
+ // now set the default directory\r
+ SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)(LPCTSTR)m_sDefaultPath);\r
+ }\r
+ if (uMsg == BFFM_SELCHANGED)\r
+ {\r
+ // Set the status window to the currently selected path.\r
+ TCHAR szDir[MAX_PATH];\r
+ if (SHGetPathFromIDList((LPITEMIDLIST)lParam, szDir))\r
+ {\r
+ SendMessage(hwnd,BFFM_SETSTATUSTEXT, 0, (LPARAM)szDir);\r
+ }\r
+ }\r
+ \r
+ return 0;\r
+}\r
+\r
+LRESULT CBrowseFolder::CheckBoxSubclassProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)\r
+{\r
+ if (uMsg == WM_LBUTTONUP)\r
+ {\r
+ m_bCheck = (SendMessage(hwnd,BM_GETCHECK,0,0)==BST_UNCHECKED);\r
+ if (m_bCheck && m_DisableCheckbox2WhenCheckbox1IsChecked)\r
+ {\r
+ ::EnableWindow(checkbox2, !m_bCheck);\r
+ }\r
+ else\r
+ ::EnableWindow(checkbox2, true);\r
+ }\r
+\r
+ return CallWindowProc(CBProc, hwnd, uMsg, \r
+ wParam, lParam); \r
+} \r
+\r
+LRESULT CBrowseFolder::CheckBoxSubclassProc2(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)\r
+{\r
+ if (uMsg == WM_LBUTTONUP)\r
+ {\r
+ m_bCheck2 = (SendMessage(hwnd,BM_GETCHECK,0,0)==BST_UNCHECKED);\r
+ }\r
+\r
+ return CallWindowProc(CBProc, hwnd, uMsg, \r
+ wParam, lParam); \r
+} \r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2008 - TortoiseSVN\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#pragma once\r
+\r
+/**\r
+ * \ingroup Utils\r
+ * A simple wrapper class for the SHBrowseForFolder API.\r
+ * Help-Link: ms-help://MS.VSCC/MS.MSDNVS/shellcc/platform/Shell/Functions/SHBrowseForFolder.htm\r
+ */\r
+class CBrowseFolder\r
+{\r
+public:\r
+ enum retVal\r
+ {\r
+ CANCEL = 0, ///< the user has pressed cancel\r
+ NOPATH, ///< no folder was selected\r
+ OK ///< everything went just fine\r
+ };\r
+public:\r
+ //constructor / deconstructor\r
+ CBrowseFolder(void);\r
+ ~CBrowseFolder(void);\r
+public:\r
+ DWORD m_style; ///< styles of the dialog.\r
+ /**\r
+ * Sets the info text of the dialog. Call this method before calling Show().\r
+ */\r
+ void SetInfo(LPCTSTR title);\r
+ /*\r
+ * Sets the text to show for the checkbox. If this method is not called,\r
+ * then no checkbox is added.\r
+ */\r
+ void SetCheckBoxText(LPCTSTR checktext);\r
+ void SetCheckBoxText2(LPCTSTR checktext);\r
+ /**\r
+ * Shows the Dialog. \r
+ * \param parent [in] window handle of the parent window.\r
+ * \param path [out] the path to the folder which the user has selected \r
+ * \return one of CANCEL, NOPATH or OK\r
+ */\r
+ CBrowseFolder::retVal Show(HWND parent, CString& path, const CString& sDefaultPath = CString());\r
+ CBrowseFolder::retVal Show(HWND parent, LPTSTR path, size_t pathlen, LPCTSTR szDefaultPath = NULL);\r
+\r
+ /**\r
+ * If this is set to true, then the second checkbox gets disabled as soon as the first\r
+ * checkbox is checked. If the first checkbox is unchecked, then the second checkbox is enabled\r
+ * again.\r
+ */\r
+ void DisableCheckBox2WhenCheckbox1IsEnabled(bool bSet = true) {m_DisableCheckbox2WhenCheckbox1IsChecked = bSet;}\r
+\r
+ static BOOL m_bCheck; ///< state of the checkbox on closing the dialog\r
+ static BOOL m_bCheck2;\r
+ TCHAR m_title[200];\r
+protected:\r
+ static void SetFont(HWND hwnd,LPTSTR FontName,int FontSize);\r
+\r
+ static int CALLBACK BrowseCallBackProc(HWND hwnd,UINT uMsg,LPARAM lParam,LPARAM lpData);\r
+ static LRESULT APIENTRY CheckBoxSubclassProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);\r
+ static LRESULT APIENTRY CheckBoxSubclassProc2(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);\r
+ \r
+ static WNDPROC CBProc;\r
+ static HWND checkbox;\r
+ static HWND checkbox2;\r
+ static HWND ListView;\r
+ static CString m_sDefaultPath;\r
+ TCHAR m_displayName[200];\r
+ LPITEMIDLIST m_root;\r
+ static TCHAR m_CheckText[200];\r
+ static TCHAR m_CheckText2[200];\r
+ static bool m_DisableCheckbox2WhenCheckbox1IsChecked;\r
+};\r
--- /dev/null
+#include "StdAfx.h"\r
+#include "BufferDC.h"\r
+\r
+IMPLEMENT_DYNAMIC(CBufferDC, CPaintDC)\r
+\r
+CBufferDC::CBufferDC(CWnd* pWnd) : CPaintDC(pWnd)\r
+{\r
+ if (pWnd != NULL && CPaintDC::m_hDC != NULL)\r
+ {\r
+ m_hOutputDC = CPaintDC::m_hDC;\r
+ m_hAttributeDC = CPaintDC::m_hAttribDC;\r
+\r
+ pWnd->GetClientRect(&m_ClientRect);\r
+\r
+ m_hMemoryDC = ::CreateCompatibleDC(m_hOutputDC);\r
+\r
+ m_hPaintBitmap =\r
+ ::CreateCompatibleBitmap(\r
+ m_hOutputDC,\r
+ m_ClientRect.right - m_ClientRect.left,\r
+ m_ClientRect.bottom - m_ClientRect.top);\r
+\r
+ m_hOldBitmap = (HBITMAP)::SelectObject(m_hMemoryDC, m_hPaintBitmap);\r
+\r
+ CPaintDC::m_hDC = m_hMemoryDC;\r
+ CPaintDC::m_hAttribDC = m_hMemoryDC;\r
+ }\r
+\r
+ m_bBoundsUpdated = FALSE;\r
+}\r
+\r
+CBufferDC::~CBufferDC(void)\r
+{\r
+ Flush();\r
+\r
+ ::SelectObject(m_hMemoryDC, m_hOldBitmap);\r
+ ::DeleteObject(m_hPaintBitmap);\r
+\r
+ CPaintDC::m_hDC = m_hOutputDC;\r
+ CPaintDC::m_hAttribDC = m_hAttributeDC;\r
+\r
+ ::DeleteDC(m_hMemoryDC);\r
+}\r
+\r
+void CBufferDC::Flush()\r
+{\r
+ ::BitBlt(\r
+ m_hOutputDC,\r
+ m_ClientRect.left, m_ClientRect.top,\r
+ m_ClientRect.right - m_ClientRect.left, \r
+ m_ClientRect.bottom - m_ClientRect.top,\r
+ m_hMemoryDC,\r
+ 0, 0,\r
+ SRCCOPY);\r
+}\r
+\r
+UINT CBufferDC::SetBoundsRect( LPCRECT lpRectBounds, UINT flags )\r
+{\r
+ if (lpRectBounds != NULL)\r
+ {\r
+ if (m_ClientRect.right - m_ClientRect.left > lpRectBounds->right - lpRectBounds->left ||\r
+ m_ClientRect.bottom - m_ClientRect.top > lpRectBounds->bottom - lpRectBounds->top)\r
+ {\r
+ lpRectBounds = &m_ClientRect;\r
+ }\r
+\r
+ HBITMAP bmp =\r
+ ::CreateCompatibleBitmap(\r
+ m_hOutputDC, \r
+ lpRectBounds->right - lpRectBounds->left, \r
+ lpRectBounds->bottom - lpRectBounds->top);\r
+\r
+ HDC tmpDC = ::CreateCompatibleDC(m_hOutputDC);\r
+ \r
+ HBITMAP oldBmp = (HBITMAP)::SelectObject(tmpDC, bmp);\r
+\r
+ ::BitBlt(\r
+ tmpDC,\r
+ m_ClientRect.left, m_ClientRect.top,\r
+ m_ClientRect.right - m_ClientRect.left, \r
+ m_ClientRect.bottom - m_ClientRect.top,\r
+ m_hMemoryDC,\r
+ 0, 0,\r
+ SRCCOPY);\r
+\r
+ ::SelectObject(tmpDC, oldBmp);\r
+ ::DeleteDC(tmpDC);\r
+\r
+ HBITMAP old = (HBITMAP)::SelectObject(m_hMemoryDC, bmp);\r
+\r
+ if (old != NULL && old != m_hPaintBitmap)\r
+ {\r
+ ::DeleteObject(old);\r
+ }\r
+\r
+ if (m_hPaintBitmap != NULL)\r
+ {\r
+ ::DeleteObject(m_hPaintBitmap);\r
+ }\r
+\r
+ m_hPaintBitmap = bmp;\r
+\r
+ m_ClientRect = *lpRectBounds;\r
+ m_bBoundsUpdated = TRUE;\r
+ }\r
+\r
+ return CPaintDC::SetBoundsRect(lpRectBounds, flags);\r
+}\r
+\r
+BOOL CBufferDC::RestoreDC( int nSavedDC )\r
+{\r
+ BOOL ret = CPaintDC::RestoreDC(nSavedDC);\r
+\r
+ if (m_bBoundsUpdated)\r
+ {\r
+ SelectObject(m_hPaintBitmap);\r
+ }\r
+\r
+ return ret;\r
+}
\ No newline at end of file
--- /dev/null
+#pragma once\r
+#include "afxwin.h"\r
+\r
+class CBufferDC :\r
+ public CPaintDC\r
+{\r
+ DECLARE_DYNAMIC(CBufferDC)\r
+\r
+private:\r
+ HDC m_hOutputDC;\r
+ HDC m_hAttributeDC;\r
+ HDC m_hMemoryDC;\r
+\r
+ HBITMAP m_hPaintBitmap;\r
+ HBITMAP m_hOldBitmap;\r
+\r
+ RECT m_ClientRect;\r
+\r
+ BOOL m_bBoundsUpdated;\r
+\r
+public:\r
+ CBufferDC(CWnd* pWnd);\r
+ ~CBufferDC(void);\r
+\r
+private:\r
+ void Flush();\r
+\r
+public:\r
+ UINT SetBoundsRect(LPCRECT lpRectBounds, UINT flags);\r
+ virtual BOOL RestoreDC(int nSavedDC);\r
+};\r
--- /dev/null
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2006 - Stefan Kueng\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#pragma once\r
+\r
+/**\r
+ * \ingroup Utils\r
+ * Helper class for setting mouse cursors.\n\r
+ * There are two ways of using this class:\r
+ * -# Just declare a CCursor object with the\r
+ * required cursor. As soon as the object\r
+ * goes out of scope the previous cursor\r
+ * is restored.\r
+ * \code\r
+ * someMethod()\r
+ * {\r
+ * CCursor(IDC_WAIT);\r
+ * //do something here\r
+ * }\r
+ * //now CCursor is out of scope and the default cursor is restored\r
+ * \endcode\r
+ * -# use the object the usual way. Declare a CCursor object\r
+ * and use the methods to set the cursors.\r
+ *\r
+ * \remark the class can be used on Win95 and NT4 too, but the\r
+ * hand cursor won't be available.\r
+ */\r
+class CCursor\r
+{\r
+public:\r
+ /**\r
+ * Constructs a CCursor object.\r
+ */\r
+ CCursor(LPCT