From 49f4cab93b2f50a8132c6b8c26f1535f4f9ebb63 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Mon, 21 May 2012 15:17:41 +0000 Subject: - added ChangeClientNotify - CommonLibs finally became common ;) git-svn-id: http://svn.miranda-ng.org/main/trunk@118 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/CommonLibs/CString.cpp | 382 +++++++++++ plugins/CommonLibs/CString.h | 347 ++++++++++ plugins/CommonLibs/GroupCheckbox.cpp | 408 ++++++++++++ plugins/CommonLibs/GroupCheckbox.h | 26 + plugins/CommonLibs/Options.cpp | 985 +++++++++++++++++++++++++++++ plugins/CommonLibs/Options.h | 483 ++++++++++++++ plugins/CommonLibs/TMyArray.h | 353 +++++++++++ plugins/CommonLibs/ThemedImageCheckbox.cpp | 382 +++++++++++ plugins/CommonLibs/ThemedImageCheckbox.h | 26 + plugins/CommonLibs/Themes.cpp | 50 ++ plugins/CommonLibs/Themes.h | 51 ++ plugins/CommonLibs/pcre.cpp | 278 ++++++++ plugins/CommonLibs/pcre.h | 30 + plugins/CommonLibs/pcre_main.h | 298 +++++++++ 14 files changed, 4099 insertions(+) create mode 100644 plugins/CommonLibs/CString.cpp create mode 100644 plugins/CommonLibs/CString.h create mode 100644 plugins/CommonLibs/GroupCheckbox.cpp create mode 100644 plugins/CommonLibs/GroupCheckbox.h create mode 100644 plugins/CommonLibs/Options.cpp create mode 100644 plugins/CommonLibs/Options.h create mode 100644 plugins/CommonLibs/TMyArray.h create mode 100644 plugins/CommonLibs/ThemedImageCheckbox.cpp create mode 100644 plugins/CommonLibs/ThemedImageCheckbox.h create mode 100644 plugins/CommonLibs/Themes.cpp create mode 100644 plugins/CommonLibs/Themes.h create mode 100644 plugins/CommonLibs/pcre.cpp create mode 100644 plugins/CommonLibs/pcre.h create mode 100644 plugins/CommonLibs/pcre_main.h (limited to 'plugins/CommonLibs') diff --git a/plugins/CommonLibs/CString.cpp b/plugins/CommonLibs/CString.cpp new file mode 100644 index 0000000000..87266513d0 --- /dev/null +++ b/plugins/CommonLibs/CString.cpp @@ -0,0 +1,382 @@ +/* + TCString.cpp - TCString class + Copyright (c) 2005-2008 Chervov Dmitry + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "Common.h" +#include "CString.h" + +#define STR_GROWBY 64 + +#define min(a,b) (((a) < (b)) ? (a) : (b)) + + +template +void TString::Empty() +{ + nBufSize = 1; + SetAllocSize(STR_GROWBY); + pBuf[0] = 0; +} + + +template +void TString::Free() +{ +// HeapFree(GetProcessHeap(), 0, pBuf); + free(pBuf); + pBuf = NULL; + nBufSize = 0; + nAllocSize = 0; +} + + +template +T *TString::GetBuffer(int nNewLen) +{ + if (nNewLen != -1) + { + SetBufSize(nNewLen + 1); + } + _ASSERT(pBuf); + return pBuf; +} + + +template +void TString::ReleaseBuffer(int nNewLen) +{ + if (nNewLen == -1) + { + nBufSize = My_lstrlen(pBuf) + 1; + } else + { + nBufSize = nNewLen + 1; + pBuf[nNewLen] = 0; + _ASSERT(My_lstrlen(pBuf) == nNewLen); + } + _ASSERT(nBufSize <= nAllocSize); // prevent buffer overruns +} + + +template +void TString::SetAllocSize(int nNewAllocSize) +{ + _ASSERT(nNewAllocSize > 0); + T *pNewBuf = /*(char *)HeapAlloc(GetProcessHeap(), 0, sizeof(char) * nNewAllocSize);*/ +(T *)malloc(sizeof(T) * nNewAllocSize); + if (pBuf) + { + memcpy(pNewBuf, pBuf, sizeof(T) * min(nBufSize, nNewAllocSize)); + //HeapFree(GetProcessHeap(), 0, pBuf); + free(pBuf); + } + pBuf = pNewBuf; + nAllocSize = nNewAllocSize; +} + + +template +void TString::SetBufSize(int nNewBufSize) +{ + _ASSERT(nNewBufSize >= 0); + if (nNewBufSize < nBufSize) + { + _ASSERT(pBuf); + pBuf[nNewBufSize - 1] = 0; + } + if ((unsigned)(nAllocSize - nNewBufSize) / STR_GROWBY) + { + SetAllocSize((nNewBufSize + STR_GROWBY - 1) - (nNewBufSize + STR_GROWBY - 1) % STR_GROWBY); + } + nBufSize = nNewBufSize; +} + + +template +TString& TString::Cat(const T *pStr) +{ + _ASSERT(pBuf && pStr); + int StrLen = My_lstrlen(pStr); + SetAllocSize(nBufSize + StrLen); + My_lstrcpy(GetBuffer() + GetLen(), pStr); + ReleaseBuffer(nBufSize + StrLen - 1); + return *this; +} + + +template +TString& TString::Cat(const T c) +{ + _ASSERT(pBuf); + SetAllocSize(nBufSize + 1); + int CurLen = GetLen(); + T *p = GetBuffer(); + p[CurLen] = c; + p[CurLen + 1] = '\0'; + ReleaseBuffer(nBufSize); + return *this; +} + + +template +TString& TString::DiffCat(const T *pStart, const T *pEnd) +{ + _ASSERT(pBuf && pStart && pEnd); + int StrLen = pEnd - pStart; + SetAllocSize(nBufSize + StrLen); + My_strncpy(GetBuffer() + GetLen(), pStart, StrLen); + ReleaseBuffer(nBufSize + StrLen - 1); + return *this; +} + + +template +TString& TString::Replace(const T *szFind, const T *szReplaceBy) +{ + if (!pBuf) + { + return *this; + } + T *pCurPos = pBuf; + int FindLen = My_lstrlen(szFind); + T *p; + TString Result; + Result.GetBuffer(1)[0] = '\0'; + Result.ReleaseBuffer(0); // set the string to ""; we can't do it in a usual way (using a constructor or an assignment) because we don't know whether "" needs to be unicode or ansi + while (p = ( T* )My_strstr(pCurPos, szFind)) + { + Result.DiffCat(pCurPos, p); + Result += szReplaceBy; + pCurPos = p + FindLen; + } + Result += pCurPos; + *this = Result; + return *this; +} + + +template +TString& TString::Replace(int nIndex, int nCount, const T *szReplaceBy) +{ + if (!pBuf || !szReplaceBy || nIndex < 0 || nCount < 0) + { + return *this; + } + + TString Result; + Result.GetBuffer(1)[0] = '\0'; + Result.ReleaseBuffer(0); // set the string to ""; we can't do it in a usual way (using a constructor or an assignment) because we don't know whether "" needs to be unicode or ansi + if (nIndex > GetLen()) + { + nIndex = GetLen(); + } + if (nIndex + nCount > GetLen()) + { + nCount = GetLen() - nIndex; + } + Result.DiffCat(pBuf, pBuf + nIndex); + Result += szReplaceBy; + Result += pBuf + nIndex + nCount; + *this = Result; + return *this; +} + + +template +TString TString::Left(int nCount) const +{ + _ASSERT(nCount >= 0); + TString Result(*this); + Result.SetBufSize(nCount + 1); + return Result; +} + + +template +TString TString::Right(int nCount) const +{ + _ASSERT(nCount >= 0); + if (nCount < GetLen()) + { + return &pBuf[GetLen() - nCount]; + } else + { + return *this; + } +} + + +template +TString TString::SubStr(int nIndex, int nCount) const +{ + _ASSERT(nIndex >= 0 && nCount >= 0); + TString Result; + if (nIndex < GetLen()) + { + My_strncpy(Result.GetBuffer(nCount), &pBuf[nIndex], nCount); + Result.ReleaseBuffer(); + } else + { + Result.GetBuffer(1)[0] = '\0'; + Result.ReleaseBuffer(0); + } + return Result; +} + + +template +TString TString::ToLower() const +{ + TString Result(*this); + if (!pBuf) + { + return Result; // return NULL string + } + My_strlwr((T*)Result); + return Result; +} + + +template +TString& TString::operator = (const T *pStr) +{ + if (pStr) + { + int StrLen = My_lstrlen(pStr); + SetBufSize(StrLen + 1); + My_lstrcpy(GetBuffer(), pStr); + ReleaseBuffer(StrLen); + } else + { + Free(); + } + return *this; +} + + +/*TCString& TCString::Format(char *pszFormat, ...) +{ + va_list argList; + va_start(argList, pszFormat); + int StrLen = _vscprintf(pszFormat, argList); // it's stupidity. in some versions of msvcrt.dll there's no _vscprintf function, so there's no any way to determine needed string length. so actually I can't use _vsnprintf too. + _vsnprintf(GetBuffer(StrLen), StrLen, pszFormat, argList); + ReleaseBuffer(StrLen); + va_end(argList); + return *this; +} +*/ + +template class TString; +template class TString; +template class TString; + + +CString DBGetContactSettingString(HANDLE hContact, const char *szModule, const char *szSetting, const char *szDefaultValue) +{ + DBVARIANT dbv = {0}; + DBCONTACTGETSETTING dbcgs; + dbcgs.szModule = szModule; + dbcgs.pValue = &dbv; + dbcgs.szSetting = szSetting; + int iRes = CallService(MS_DB_CONTACT_GETSETTING, (WPARAM)hContact, (LPARAM)&dbcgs); + CString Result; + if (!iRes && dbv.type == DBVT_ASCIIZ) + { + Result = dbv.pszVal; + } else + { + Result = szDefaultValue; + } + if (!iRes) + { + CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv); + } + return Result; +} + + +#ifdef _UNICODE +TCString DBGetContactSettingString(HANDLE hContact, const char *szModule, const char *szSetting, const TCHAR *szDefaultValue) +{ + DBVARIANT dbv = {0}; + DBCONTACTGETSETTING dbcgs; + dbcgs.szModule = szModule; + dbcgs.pValue = &dbv; + dbcgs.szSetting = szSetting; + dbv.type = DBVT_WCHAR; + int iRes = CallService(MS_DB_CONTACT_GETSETTING_STR, (WPARAM)hContact, (LPARAM)&dbcgs); + TCString Result; + if (!iRes && dbv.type == DBVT_WCHAR) + { + Result = dbv.ptszVal; + } else + { + Result = szDefaultValue; + } + if (!iRes) + { + CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv); + } + return Result; +} +#endif + + +int DBGetContactSettingString(HANDLE hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv) +{ +#ifdef _DEBUG + return DBGetContactSettingString_Helper(hContact, szModule, szSetting, dbv, __FILE__, __LINE__, DBVT_ASCIIZ); +#else + return DBGetContactSettingString_Helper(hContact, szModule, szSetting, dbv, DBVT_ASCIIZ); +#endif +} + + + +TCString DBGetContactSettingAsString(HANDLE hContact, const char *szModule, const char *szSetting, const TCHAR *szDefaultValue) +{ // also converts numeric values to a string + DBVARIANT dbv = {0}; + DBCONTACTGETSETTING dbcgs; + dbcgs.szModule = szModule; + dbcgs.pValue = &dbv; + dbcgs.szSetting = szSetting; +#ifdef _UNICODE + dbv.type = DBVT_WCHAR; + int iRes = CallService(MS_DB_CONTACT_GETSETTING_STR, (WPARAM)hContact, (LPARAM)&dbcgs); +#else + int iRes = CallService(MS_DB_CONTACT_GETSETTING, (WPARAM)hContact, (LPARAM)&dbcgs); +#endif + TCString Result; + if (!iRes && (dbv.type == DBVT_ASCIIZ || dbv.type == DBVT_WCHAR)) + { + Result = dbv.ptszVal; + } else if (dbv.type == DBVT_BYTE || dbv.type == DBVT_WORD || dbv.type == DBVT_DWORD) + { + long value = (dbv.type == DBVT_DWORD) ? dbv.dVal : (dbv.type == DBVT_WORD ? dbv.wVal : dbv.bVal); + _ultot(value, Result.GetBuffer(64), 10); + Result.ReleaseBuffer(); + } else + { + Result = szDefaultValue; + } + if (!iRes) + { + CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv); + } + return Result; +} diff --git a/plugins/CommonLibs/CString.h b/plugins/CommonLibs/CString.h new file mode 100644 index 0000000000..ed2540c511 --- /dev/null +++ b/plugins/CommonLibs/CString.h @@ -0,0 +1,347 @@ +/* + TCString.h - TCString class + Copyright (c) 2005-2008 Chervov Dmitry + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#pragma once + +#include +#include +#include +#ifdef CHARARRAY_CONVERT +#include "TMyArray.h" +#endif +#include "newpluginapi.h" +#include "m_system.h" +#include "m_database.h" + +__inline int My_lstrlen(LPCSTR lpString) {return lstrlenA(lpString);} +__inline int My_lstrlen(LPCWSTR lpString) {return lstrlenW(lpString);} +__inline int My_lstrcmp(LPCSTR lpString1, LPCSTR lpString2) {return lstrcmpA(lpString1, lpString2);} +__inline int My_lstrcmp(LPCWSTR lpString1, LPCWSTR lpString2) {return lstrcmpW(lpString1, lpString2);} +__inline LPCSTR My_strstr(LPCSTR lpString1, LPCSTR lpString2) {return strstr(lpString1, lpString2);} +__inline LPWSTR My_strstr(LPCWSTR lpString1, LPCWSTR lpString2) {return (LPWSTR)wcsstr(lpString1, lpString2);} +__inline LPSTR My_lstrcpy(LPSTR lpString1, LPCSTR lpString2) {return lstrcpyA(lpString1, lpString2);} +__inline LPWSTR My_lstrcpy(LPWSTR lpString1, LPCWSTR lpString2) {return lstrcpyW(lpString1, lpString2);} +__inline LPSTR My_strncpy(LPSTR lpString1, LPCSTR lpString2, int Len) {return strncpy(lpString1, lpString2, Len);} +__inline LPWSTR My_strncpy(LPWSTR lpString1, LPCWSTR lpString2, int Len) {return wcsncpy(lpString1, lpString2, Len);} +__inline LPSTR My_strlwr(LPSTR lpString) {return _strlwr(lpString);} +__inline LPWSTR My_strlwr(LPWSTR lpString) {return _wcslwr(lpString);} + +template +class TString +{ +public: + TString(): pBuf(NULL), nBufSize(0), nAllocSize(0) {} + TString(const T *pStr): pBuf(NULL), nBufSize(0), nAllocSize(0) {*this = pStr;} + TString(const TString &Str): pBuf(NULL), nBufSize(0), nAllocSize(0) {*this = Str.pBuf;} + ~TString() {Free();} + + int GetLen() const {return (nBufSize) ? (nBufSize - 1) : 0;}; + int IsEmpty() const {return (!GetLen());}; + T *GetBuffer(int nNewLen = -1); + void ReleaseBuffer(int nNewLen = -1); + TString& Cat(const T *pStr); + TString& Cat(const T c); + TString& DiffCat(const T *pStart, const T *pEnd); + TString& Replace(const T *szFind, const T *szReplaceBy); + TString& Replace(int nIndex, int nCount, const T *szReplaceBy); + TString Left(int nCount) const; + TString Right(int nCount) const; + TString SubStr(int nIndex, int nCount) const; + TString ToLower() const; + void Empty(); + void Free(); + T& operator [] (int nIndex) {_ASSERT(nIndex >= 0 && nIndex <= GetLen()); return pBuf[nIndex];} + operator const T*() const {return pBuf;} + operator T*() {return pBuf;} + TString& operator = (const T *pStr); + TString& operator = (const TString &Str) {return *this = Str.pBuf;} +// TCString& operator + (const char *pStr) +// {_ASSERT(pBuf && pStr); TCString Result(*this); return Result.Cat(pStr);} + friend TString operator + (const TString &Str1, const T *Str2) + {_ASSERT(Str1.pBuf && Str2); TString Result(Str1); return Result.Cat(Str2);} +/* friend TCString operator + (const char *Str1, const TCString &Str2) + {_ASSERT(Str1 && Str2.pBuf); TCString Result(Str1); return Result.Cat(Str2);}*/ + TString& operator += (const T *pStr) {_ASSERT(pBuf && pStr); return this->Cat(pStr);} + TString& operator += (const T c) {_ASSERT(pBuf); return this->Cat(c);} + int operator == (const T *pStr) const {return (!pBuf || !pStr) ? (pBuf == pStr) : !My_lstrcmp(pBuf, pStr);} + int operator != (const T *pStr) const {return (!pBuf || !pStr) ? (pBuf != pStr) : My_lstrcmp(pBuf, pStr);} + int operator < (const T *pStr) const {_ASSERT(pBuf && pStr); return My_lstrcmp(pBuf, pStr) > 0;} + int operator > (const T *pStr) const {_ASSERT(pBuf && pStr); return My_lstrcmp(pBuf, pStr) < 0;} + int operator <= (const T *pStr) const {_ASSERT(pBuf && pStr); return My_lstrcmp(pBuf, pStr) >= 0;} + int operator >= (const T *pStr) const {_ASSERT(pBuf && pStr); return My_lstrcmp(pBuf, pStr) <= 0;} +// TCString& Format(char *pszFormat, ...); + +private: + void SetBufSize(int nNewBufSize); + void SetAllocSize(int nNewAllocSize); + + T *pBuf; + int nBufSize; // current string length + 1 (including 0 at the end) + int nAllocSize; // allocated memory size +}; + + +typedef TString TCString; +typedef TString CString; +typedef TString WCString; + + +/*#define TCString TString +#define CString TString +#define WCString TString*/ + + +__inline CString TCHAR2ANSI(TCString Str) +{ +#ifdef _UNICODE + if (Str == NULL) + { + return CString(); + } + CString AStr; + if (!WideCharToMultiByte(CP_ACP, 0, Str, -1, AStr.GetBuffer(Str.GetLen() + 1), Str.GetLen() + 1, NULL, NULL)) + { + AStr.ReleaseBuffer(0); + } else + { + AStr.ReleaseBuffer(Str.GetLen()); + } + return AStr; +#else + return Str; +#endif +} + + +__inline TCString ANSI2TCHAR(CString Str) +{ +#ifdef _UNICODE + if (Str == NULL) + { + return TCString(); + } + TCString TStr; + int Len = MultiByteToWideChar(CP_ACP, 0, Str, -1, NULL, 0); + if (!MultiByteToWideChar(CP_ACP, 0, Str, -1, TStr.GetBuffer(Len), Len)) + { + TStr.ReleaseBuffer(0); + } else + { + TStr.ReleaseBuffer(Len - 1); + } + return TStr; +#else + return Str; +#endif +} + + +__inline WCString TCHAR2WCHAR(TCString Str) +{ +#ifdef _UNICODE + return Str; +#else + if (Str == NULL) + { + return WCString(); + } + WCString WStr; + int Len = MultiByteToWideChar(CP_ACP, 0, Str, -1, NULL, 0); + if (!MultiByteToWideChar(CP_ACP, 0, Str, -1, WStr.GetBuffer(Len), Len)) + { + WStr.ReleaseBuffer(0); + } else + { + WStr.ReleaseBuffer(Len - 1); + } + return WStr; +#endif +} + + +__inline TCString WCHAR2TCHAR(WCString Str) +{ +#ifdef _UNICODE + return Str; +#else + if (Str == NULL) + { + return TCString(); + } + CString AStr; + if (!WideCharToMultiByte(CP_ACP, 0, Str, -1, AStr.GetBuffer(Str.GetLen() + 1), Str.GetLen() + 1, NULL, NULL)) + { + AStr.ReleaseBuffer(0); + } else + { + AStr.ReleaseBuffer(Str.GetLen()); + } + return AStr; +#endif +} + + +#ifdef _UNICODE +#define WCHAR2ANSI TCHAR2ANSI +#define ANSI2WCHAR ANSI2TCHAR +#else +#define WCHAR2ANSI WCHAR2TCHAR +#define ANSI2WCHAR TCHAR2WCHAR +#endif + + +#ifdef CHARARRAY_CONVERT + +__inline CHARARRAY WCHAR2ANSI_ARRAY(CHARARRAY &c) +{ + CHARARRAY Result; + int Len = WideCharToMultiByte(CP_ACP, 0, (WCHAR*)c.GetData(), c.GetSize() / sizeof(WCHAR), NULL, 0, NULL, NULL); + if (Len) + { + Result.SetAtGrow(Len - 1); + if (!WideCharToMultiByte(CP_ACP, 0, (WCHAR*)c.GetData(), c.GetSize() / sizeof(WCHAR), Result.GetData(), Len, NULL, NULL)) + { + Result.RemoveAll(); + } + if (Result.GetSize()) + { + Result.RemoveElem(Result.GetSize() - 1); // remove the null terminator + } + } + return Result; +} + +__inline CHARARRAY ANSI2WCHAR_ARRAY(CHARARRAY &c) +{ + CHARARRAY Result; + int Len = MultiByteToWideChar(CP_ACP, 0, c.GetData(), c.GetSize(), NULL, 0); + if (Len) + { + Result.SetAtGrow(Len * sizeof(WCHAR) - 1); + if (!MultiByteToWideChar(CP_ACP, 0, c.GetData(), c.GetSize(), (WCHAR*)Result.GetData(), Len)) + { + Result.RemoveAll(); + } + if (Result.GetSize()) + { + Result.RemoveElem(Result.GetSize() - 1); + Result.RemoveElem(Result.GetSize() - 1); // remove the null terminator + } + } + return Result; +} + +#ifdef _UNICODE // utf8 conversion doesn't work on win95 +__inline CHARARRAY WCHAR2UTF8(WCString Str) +{ + CHARARRAY Result; + int Len = WideCharToMultiByte(CP_UTF8, 0, Str, -1, NULL, 0, NULL, NULL); + if (Len) + { + Result.SetAtGrow(Len - 1); + if (!WideCharToMultiByte(CP_UTF8, 0, Str, -1, Result.GetData(), Len, NULL, NULL)) + { + Result.RemoveAll(); + } + } + return Result; +} +#endif + +#endif // CHARARRAY_CONVERT + + +#undef DBGetContactSettingString +CString DBGetContactSettingString(HANDLE hContact, const char *szModule, const char *szSetting, const char *szDefaultValue); +TCString DBGetContactSettingString(HANDLE hContact, const char *szModule, const char *szSetting, const TCHAR *szDefaultValue); +int DBGetContactSettingString(HANDLE hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv); +TCString DBGetContactSettingAsString(HANDLE hContact, const char *szModule, const char *szSetting, const TCHAR *szDefaultValue); // also converts numeric values to a string + +// various string helpers. their return values are valid only while the class is visible +class UTF8Encode +{ +public: + UTF8Encode(const char *str) { p = mir_utf8encode(str); } + UTF8Encode(const wchar_t *str) { p = mir_utf8encodeW(str); } + ~UTF8Encode() { mir_free(p); } + operator char*() { return p; } + +private: + char *p; +}; + +class UTF8DecodeA +{ +public: + UTF8DecodeA(const char *str) { p = mir_strdup(str); mir_utf8decode(p, NULL); } + ~UTF8DecodeA() { mir_free(p); } + operator char*() { return p; } + +private: + char *p; +}; + +class UTF8DecodeW +{ +public: + UTF8DecodeW(const char *str) { p = mir_utf8decodeW(str); } + ~UTF8DecodeW() { mir_free(p); } + operator wchar_t*() { return p; } + +private: + wchar_t *p; +}; + +#ifdef _UNICODE +#define UTF8Decode UTF8DecodeW +#else +#define UTF8Decode UTF8DecodeA +#endif + + +/*class mallocStrA +{ +public: + mallocStrA(int n) { p = (char*)malloc((n + 1) * sizeof(char)); } + mallocStrA(const char *str) { p = str ? strdup(str) : NULL; } + ~mallocStrA() { if (p) free(p); } + operator char*() { return p; } + +private: + char *p; +}; + +class mallocStrW +{ +public: + mallocStrW(int n) { p = (wchar_t*)malloc((n + 1) * sizeof(wchar_t)); } + mallocStrW(const wchar_t *str) { p = str ? _wcsdup(str) : NULL; } + ~mallocStrW() { if (p) free(p); } + operator wchar_t*() { return p; } + +private: + wchar_t *p; +}; + +#ifdef _UNICODE +#define mallocStr mallocStrW +#else +#define mallocStr mallocStrA +#endif +*/ \ No newline at end of file diff --git a/plugins/CommonLibs/GroupCheckbox.cpp b/plugins/CommonLibs/GroupCheckbox.cpp new file mode 100644 index 0000000000..20276fcbf3 --- /dev/null +++ b/plugins/CommonLibs/GroupCheckbox.cpp @@ -0,0 +1,408 @@ +/* + GroupCheckbox.cpp + Copyright (c) 2007 Chervov Dmitry + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "Common.h" +#include "GroupCheckbox.h" +#include "Themes.h" + +#define WM_THEMECHANGED 0x031A + +#define UM_INITCHECKBOX (WM_USER + 123) +#define UM_AUTOSIZE (WM_USER + 124) + +#define CG_CHECKBOX_VERTINDENT 0 +#define CG_CHECKBOX_INDENT 1 +#define CG_CHECKBOX_WIDTH 16 +#define CG_TEXT_INDENT 2 +#define CG_ADDITIONAL_WIDTH 3 + +// states +#define CGS_UNCHECKED BST_UNCHECKED +#define CGS_CHECKED BST_CHECKED +#define CGS_INDETERMINATE BST_INDETERMINATE +#define CGS_PRESSED BST_PUSHED // values above and including CGS_PRESSED must coincide with BST_ constants for BM_GETSTATE to work properly +#define CGS_HOVERED 8 + +// state masks +#define CGSM_ISCHECKED 3 // mask for BM_GETCHECK +#define CGSM_GETSTATE 7 // mask to get only valid values for BM_GETSTATE + +#ifndef lengthof +#define lengthof(s) (sizeof(s) / sizeof(*s)) +#endif + +class CCheckboxData +{ +public: + CCheckboxData(): OldWndProc(NULL), Style(0), State(0), hFont(NULL) {}; + + WNDPROC OldWndProc; + int Style; // BS_CHECKBOX, BS_AUTOCHECKBOX, BS_3STATE or BS_AUTO3STATE + int State; + HFONT hFont; +}; + +static int CALLBACK CheckboxWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + CCheckboxData *dat = (CCheckboxData*)GetWindowLong(hWnd, GWL_USERDATA); + if (!dat) + { + return 0; + } + switch (Msg) + { + case UM_INITCHECKBOX: + { + LOGFONT lf; + HFONT hFont = (HFONT)SendMessage(hWnd, WM_GETFONT, 0, 0); + if (!hFont) + { + hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); + } + GetObject(hFont, sizeof(lf), &lf); + lf.lfWeight = FW_BOLD; + dat->hFont = CreateFontIndirect(&lf); + SendMessage(hWnd, UM_AUTOSIZE, 0, 0); + return 0; + } break; + case UM_AUTOSIZE: + { + HTHEME hTheme = pOpenThemeData ? pOpenThemeData(hWnd, L"BUTTON") : NULL; + int Len = GetWindowTextLength(hWnd) + 1; + HDC hdc = GetDC(hWnd); + HFONT hOldFont = (HFONT)SelectObject(hdc, dat->hFont); + RECT rcText = {0}; + if (hTheme && pGetThemeTextExtent) + { + WCHAR *szText = (WCHAR*)malloc(Len * sizeof(WCHAR)); + GetWindowTextW(hWnd, szText, Len); + pGetThemeTextExtent(hTheme, hdc, BP_GROUPBOX, IsWindowEnabled(hWnd) ? GBS_NORMAL : GBS_DISABLED, szText, -1, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_SINGLELINE, 0, &rcText); + free(szText); + } else + { + SIZE size; + TCHAR *szText = (TCHAR*)malloc(Len * sizeof(TCHAR)); + GetWindowText(hWnd, szText, Len); + GetTextExtentPoint32(hdc, szText, lstrlen(szText), &size); + free(szText); + rcText.right = size.cx; + rcText.bottom = size.cy; + } + + SelectObject(hdc, hOldFont); + ReleaseDC(hWnd, hdc); + if (hTheme && pCloseThemeData) + { + pCloseThemeData(hTheme); + } + OffsetRect(&rcText, CG_CHECKBOX_INDENT + CG_CHECKBOX_WIDTH + CG_TEXT_INDENT, 0); + RECT rc; + GetClientRect(hWnd, &rc); + SetWindowPos(hWnd, 0, 0, 0, rcText.right + CG_ADDITIONAL_WIDTH, rc.bottom, SWP_NOMOVE | SWP_NOZORDER); + } break; + case BM_CLICK: + { + SendMessage(hWnd, WM_LBUTTONDOWN, 0, 0); + SendMessage(hWnd, WM_LBUTTONUP, 0, 0); + return 0; + } break; + case BM_GETCHECK: + { + return dat->State & CGSM_ISCHECKED; + } break; + case BM_SETCHECK: + { + if ((wParam != BST_UNCHECKED && wParam != BST_CHECKED && wParam != BST_INDETERMINATE) || (wParam == BST_INDETERMINATE && dat->Style != BS_3STATE && dat->Style != BS_AUTO3STATE)) + { // invalid value + wParam = BST_CHECKED; + } + dat->State &= ~CGSM_ISCHECKED; + dat->State |= wParam; + InvalidateRect(hWnd, NULL, false); + SendMessage(GetParent(hWnd), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hWnd), BN_CLICKED), (LPARAM)hWnd); + return 0; + } break; + case BM_SETSTATE: + { + if (wParam) + { + dat->State |= CGS_PRESSED; + } else + { + dat->State &= ~CGS_PRESSED; + } + InvalidateRect(hWnd, NULL, false); + return 0; + } break; + case BM_GETSTATE: + { + return (dat->State & CGSM_GETSTATE) | ((GetFocus() == hWnd) ? BST_FOCUS : 0); + } break; + case WM_GETDLGCODE: + { + return DLGC_BUTTON; + } break; + case WM_THEMECHANGED: + case WM_ENABLE: + { + InvalidateRect(hWnd, NULL, false); + return 0; + } break; + case WM_SETTEXT: + { + if (CallWindowProc(dat->OldWndProc, hWnd, Msg, wParam, lParam)) + { + SendMessage(hWnd, UM_AUTOSIZE, 0, 0); + } + return 0; + } break; + case WM_KEYDOWN: + { + if (wParam == VK_SPACE) + { + SendMessage(hWnd, BM_SETSTATE, true, 0); + } + return 0; + } break; + case WM_KEYUP: + { + if (wParam == VK_SPACE) + { + SendMessage(hWnd, BM_SETCHECK, (SendMessage(hWnd, BM_GETCHECK, 0, 0) + 1) % ((dat->Style == BS_AUTO3STATE) ? 3 : 2), 0); + SendMessage(hWnd, BM_SETSTATE, false, 0); + } + return 0; + } break; + case WM_CAPTURECHANGED: + { + SendMessage(hWnd, BM_SETSTATE, false, 0); + return 0; + } break; + case WM_ERASEBKGND: + { + return true; + } break; + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + { + SetFocus(hWnd); + SendMessage(hWnd, BM_SETSTATE, true, 0); + SetCapture(hWnd); + return 0; + } break; + case WM_LBUTTONUP: + { + if (GetCapture() == hWnd) + { + ReleaseCapture(); + } + SendMessage(hWnd, BM_SETSTATE, false, 0); + if (dat->State & CGS_HOVERED && (dat->Style == BS_AUTOCHECKBOX || dat->Style == BS_AUTO3STATE)) + { + SendMessage(hWnd, BM_SETCHECK, (SendMessage(hWnd, BM_GETCHECK, 0, 0) + 1) % ((dat->Style == BS_AUTO3STATE) ? 3 : 2), 0); + } + return 0; + } break; + case WM_MOUSEMOVE: + { + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_LEAVE; + tme.dwHoverTime = HOVER_DEFAULT; + tme.hwndTrack = hWnd; + _TrackMouseEvent(&tme); + + POINT pt; + GetCursorPos(&pt); + if ((WindowFromPoint(pt) == hWnd) ^ ((dat->State & CGS_HOVERED) != 0)) + { + dat->State ^= CGS_HOVERED; + InvalidateRect(hWnd, NULL, false); + } + return 0; + } break; + case WM_MOUSELEAVE: + { + if (dat->State & CGS_HOVERED) + { + dat->State &= ~CGS_HOVERED; + InvalidateRect(hWnd, NULL, false); + } + return 0; + } break; + case WM_SETFOCUS: + case WM_KILLFOCUS: + case WM_SYSCOLORCHANGE: + { + InvalidateRect(hWnd, NULL, false); + return 0; + } break; + case WM_PAINT: + { + HDC hdc; + PAINTSTRUCT ps; + hdc = BeginPaint(hWnd, &ps); + RECT rc; + GetClientRect(hWnd, &rc); + HDC hdcMem = CreateCompatibleDC(hdc); + HBITMAP hbmMem = CreateCompatibleBitmap(hdc, rc.right, rc.bottom); + HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hbmMem); + HTHEME hTheme = pOpenThemeData ? pOpenThemeData(hWnd, L"BUTTON") : NULL; + if (hTheme && pDrawThemeParentBackground) + { + pDrawThemeParentBackground(hWnd, hdcMem, NULL); + } else + { + FillRect(hdcMem, &rc, GetSysColorBrush(COLOR_3DFACE)); + } + int StateID = 0; +#define CBSCHECK_UNCHECKED 1 +#define CBSCHECK_CHECKED 5 +#define CBSCHECK_MIXED 9 +#define CBSSTATE_NORMAL 0 +#define CBSSTATE_HOT 1 +#define CBSSTATE_PRESSED 2 +#define CBSSTATE_DISABLED 3 + switch (SendMessage(hWnd, BM_GETCHECK, 0, 0)) + { + case BST_CHECKED: + { + StateID += CBSCHECK_CHECKED; + } break; + case BST_UNCHECKED: + { + StateID += CBSCHECK_UNCHECKED; + } break; + case BST_INDETERMINATE: + { + StateID += CBSCHECK_MIXED; + } break; + } + if (!IsWindowEnabled(hWnd)) + { + StateID += CBSSTATE_DISABLED; + } else if (dat->State & CGS_PRESSED && (GetCapture() != hWnd || dat->State & CGS_HOVERED)) + { + StateID += CBSSTATE_PRESSED; + } else if (dat->State & CGS_PRESSED || dat->State & CGS_HOVERED) + { + StateID += CBSSTATE_HOT; + } + rc.left += CG_CHECKBOX_INDENT; + rc.right = rc.left + CG_CHECKBOX_WIDTH; // left-align the image in the client area + rc.top += CG_CHECKBOX_VERTINDENT; + rc.bottom = rc.top + CG_CHECKBOX_WIDTH; // exact rc dimensions are necessary for DrawFrameControl to draw correctly + if (hTheme && pDrawThemeBackground) + { + pDrawThemeBackground(hTheme, hdcMem, BP_CHECKBOX, StateID, &rc, &rc); + } else + { + int dfcStates[] = + {0, 0, DFCS_PUSHED, DFCS_INACTIVE, + DFCS_CHECKED, DFCS_CHECKED, DFCS_CHECKED | DFCS_PUSHED, DFCS_CHECKED | DFCS_INACTIVE, + DFCS_BUTTON3STATE | DFCS_CHECKED, DFCS_BUTTON3STATE | DFCS_CHECKED, DFCS_BUTTON3STATE | DFCS_INACTIVE | DFCS_CHECKED | DFCS_PUSHED, DFCS_BUTTON3STATE | DFCS_INACTIVE | DFCS_CHECKED | DFCS_PUSHED}; + _ASSERT(StateID >= 1 && StateID <= lengthof(dfcStates)); + DrawFrameControl(hdcMem, &rc, DFC_BUTTON, dfcStates[StateID - 1]); + } + + GetClientRect(hWnd, &rc); + rc.left += CG_CHECKBOX_INDENT + CG_CHECKBOX_WIDTH + CG_TEXT_INDENT; + int Len = GetWindowTextLength(hWnd) + 1; + WCHAR *szTextW = NULL; + TCHAR *szTextT = NULL; + if (hTheme && pDrawThemeText && pGetThemeTextExtent) + { + szTextW = (WCHAR*)malloc(Len * sizeof(WCHAR)); + GetWindowTextW(hWnd, szTextW, Len); + } else + { + szTextT = (TCHAR*)malloc(Len * sizeof(TCHAR)); + GetWindowText(hWnd, szTextT, Len); + } + HFONT hOldFont = (HFONT)SelectObject(hdcMem, dat->hFont); + SetBkMode(hdcMem, TRANSPARENT); + if (hTheme && pDrawThemeText && pGetThemeTextExtent) + { + pDrawThemeText(hTheme, hdcMem, BP_GROUPBOX, IsWindowEnabled(hWnd) ? GBS_NORMAL : GBS_DISABLED, szTextW, -1, DT_LEFT | DT_VCENTER | DT_SINGLELINE, 0, &rc); + } else + { + DrawText(hdcMem, szTextT, -1, &rc, DT_LEFT | DT_VCENTER | DT_SINGLELINE); + } + if (GetFocus() == hWnd) + { + RECT rcText = {0}; + if (hTheme && pDrawThemeText && pGetThemeTextExtent) + { + pGetThemeTextExtent(hTheme, hdcMem, BP_GROUPBOX, IsWindowEnabled(hWnd) ? GBS_NORMAL : GBS_DISABLED, szTextW, -1, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_SINGLELINE, 0, &rcText); + } else + { + SIZE size; + GetTextExtentPoint32(hdcMem, szTextT, lstrlen(szTextT), &size); + rcText.right = size.cx; + rcText.bottom = size.cy; + } + rcText.bottom = rc.bottom; + OffsetRect(&rcText, rc.left, 0); + InflateRect(&rcText, 1, -1); + DrawFocusRect(hdcMem, &rcText); + } + free((hTheme && pDrawThemeText && pGetThemeTextExtent) ? (TCHAR*)szTextW : szTextT); + SelectObject(hdcMem, hOldFont); + if (hTheme && pCloseThemeData) + { + pCloseThemeData(hTheme); + } + BitBlt(hdc, 0, 0, rc.right, rc.bottom, hdcMem, 0, 0, SRCCOPY); + SelectObject(hdcMem, hbmOld); + DeleteObject(hbmMem); + DeleteDC(hdcMem); + EndPaint(hWnd, &ps); + return 0; + } break; + case WM_DESTROY: + { + if (dat->hFont) + { + DeleteObject(dat->hFont); + } + SetWindowLong(hWnd, GWL_USERDATA, NULL); + CallWindowProc(dat->OldWndProc, hWnd, Msg, wParam, lParam); + delete dat; + return 0; + } break; + } + return CallWindowProc(dat->OldWndProc, hWnd, Msg, wParam, lParam); +} + +int MakeGroupCheckbox(HWND hWndCheckbox) +{ // workaround to make SetTextColor work in WM_CTLCOLORSTATIC with windows themes enabled + CCheckboxData *dat = new CCheckboxData(); + dat->OldWndProc = (WNDPROC)GetWindowLong(hWndCheckbox, GWL_WNDPROC); + dat->State = SendMessage(hWndCheckbox, BM_GETSTATE, 0, 0); + long Style = GetWindowLong(hWndCheckbox, GWL_STYLE); + dat->Style = Style & (BS_CHECKBOX | BS_AUTOCHECKBOX | BS_3STATE | BS_AUTO3STATE); + _ASSERT(dat->Style == BS_CHECKBOX || dat->Style == BS_AUTOCHECKBOX || dat->Style == BS_3STATE || dat->Style == BS_AUTO3STATE); + Style &= ~(BS_CHECKBOX | BS_AUTOCHECKBOX | BS_3STATE | BS_AUTO3STATE); + Style |= BS_OWNERDRAW; + SetWindowLong(hWndCheckbox, GWL_STYLE, Style); + SetWindowLong(hWndCheckbox, GWL_USERDATA, (LONG)dat); + SetWindowLong(hWndCheckbox, GWL_WNDPROC, (LONG)CheckboxWndProc); + SendMessage(hWndCheckbox, UM_INITCHECKBOX, 0, 0); + return 0; +} diff --git a/plugins/CommonLibs/GroupCheckbox.h b/plugins/CommonLibs/GroupCheckbox.h new file mode 100644 index 0000000000..3aa121f869 --- /dev/null +++ b/plugins/CommonLibs/GroupCheckbox.h @@ -0,0 +1,26 @@ +/* + GroupCheckbox.h + Copyright (c) 2007 Chervov Dmitry + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#pragma once + +#include +#include +#include + +int MakeGroupCheckbox(HWND hWndCheckbox); diff --git a/plugins/CommonLibs/Options.cpp b/plugins/CommonLibs/Options.cpp new file mode 100644 index 0000000000..7e7f9a23e1 --- /dev/null +++ b/plugins/CommonLibs/Options.cpp @@ -0,0 +1,985 @@ +/* + Options.cpp + Copyright (c) 2005-2008 Chervov Dmitry + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "Common.h" +#include "Options.h" + +static CString sEmptyString(""); + + +COptPage::COptPage(const COptPage &Item) +{ + *this = Item; +} + +COptPage::~COptPage() +{ + int I; + for (I = 0; I < Items.GetSize(); I++) + { + delete Items[I]; + } + Items.RemoveAll(); +} + +void COptPage::MemToPage(int OnlyEnable) +{ + int I; + _ASSERT(hWnd); + for (I = 0; I < Items.GetSize(); I++) + { + if (OnlyEnable) + { + Items[I]->COptItem::MemToWnd(hWnd); + } else + { + Items[I]->MemToWnd(hWnd); + } + } +} + +void COptPage::PageToMem() +{ + int I; + _ASSERT(hWnd); + for (I = 0; I < Items.GetSize(); I++) + { + Items[I]->WndToMem(hWnd); + } +} + +void COptPage::DBToMem() +{ + int I; + _ASSERT(sModule != ""); + for (I = 0; I < Items.GetSize(); I++) + { + Items[I]->DBToMem(sModule, &sDBSettingPrefix); + } +} + +void COptPage::MemToDB() +{ + int I; + _ASSERT(sModule != ""); + for (I = 0; I < Items.GetSize(); I++) + { + Items[I]->MemToDB(sModule, &sDBSettingPrefix); + } +} + +void COptPage::CleanDBSettings() +{ + int I; + _ASSERT(sModule != ""); + for (I = 0; I < Items.GetSize(); I++) + { + Items[I]->CleanDBSettings(sModule, &sDBSettingPrefix); + } +} + +bool COptPage::GetModified() +{ + int I; + _ASSERT(sModule != ""); + for (I = 0; I < Items.GetSize(); I++) + { + if (Items[I]->GetModified()) + { + return true; + } + } + return false; +} + +void COptPage::SetModified(bool Modified) +{ + int I; + _ASSERT(sModule != ""); + for (I = 0; I < Items.GetSize(); I++) + { + Items[I]->SetModified(Modified); + } +} + +COptItem *COptPage::Find(int DlgItemID) +{ + int I; + for (I = 0; I < Items.GetSize(); I++) + { + if (Items[I]->GetID() == DlgItemID) + { + return Items[I]; + } + } + _ASSERT(0); + return 0; +} + +COptPage& COptPage::operator = (const COptPage& Page) +{ + int I; + hWnd = Page.hWnd; + sModule = Page.sModule; + sDBSettingPrefix = Page.sDBSettingPrefix; + Items.RemoveAll(); + for (I = 0; I < Page.Items.GetSize(); I++) + { + Items.AddElem(Page.Items[I]->Copy()); + } + return *this; +} + + +int COptItem::GetIntDBVal(CString &sModule, int bSigned, CString *sDBSettingPrefix) +{ // default procedure for reading value from DB; used only for integral types + if (sDBSetting != NULL) + { + _ASSERT(nValueSize == DBVT_BYTE || nValueSize == DBVT_WORD || nValueSize == DBVT_DWORD); + DBVARIANT dbv; + DBCONTACTGETSETTING cgs; + cgs.szModule = sModule; + //NightFox: WTF is this shit + //cgs.szSetting = sDBSettingPrefix ? (*sDBSettingPrefix + sDBSetting) : sDBSetting; + cgs.szSetting = sDBSetting; + cgs.pValue = &dbv; + if (CallService(MS_DB_CONTACT_GETSETTING, NULL, (LPARAM)&cgs)) + { + return GetDefValue(); + } + return (nValueSize == DBVT_BYTE) ? (bSigned ? (signed char)dbv.bVal : (unsigned char)dbv.bVal) : ((nValueSize == DBVT_WORD) ? (bSigned ? (signed short)dbv.wVal : (unsigned short)dbv.wVal) : dbv.dVal); + } + return GetDefValue(); +} + +void COptItem::SetIntDBVal(CString &sModule, int Value, CString *sDBSettingPrefix) +{ // default procedure for writing value to the DB; used only for integral types + if (sDBSetting != NULL && !ReadOnly) + { + _ASSERT(nValueSize == DBVT_BYTE || nValueSize == DBVT_WORD || nValueSize == DBVT_DWORD); + DBCONTACTWRITESETTING cws; + cws.szModule = sModule; + //NightFox: WTF is this shit + //cws.szSetting = sDBSettingPrefix ? (*sDBSettingPrefix + sDBSetting) : sDBSetting; + cws.szSetting = sDBSetting; + + cws.value.type = nValueSize; + cws.value.dVal = Value; + +// DBWriteContactSettingByte(NULL, sModule, *sDBSettingPrefix + sDBSetting + TREEITEM_DBSTR_FLAGS + StrID, Value[I].Flags); + + //itoa(Value[I].ID, StrID.GetBuffer(64), 10); + //StrID.ReleaseBuffer(); + + CallService(MS_DB_CONTACT_WRITESETTING, NULL, (LPARAM)&cws); + + } +} + +TCString COptItem::GetStrDBVal(CString &sModule, CString *sDBSettingPrefix) +{ + if (sDBSetting != NULL) + { + _ASSERT(GetDefValue()); + return DBGetContactSettingString(NULL, sModule, sDBSettingPrefix ? (*sDBSettingPrefix + sDBSetting) : sDBSetting, *(TCString*)GetDefValue()); + } + return *(TCString*)GetDefValue(); +} + +void COptItem::SetStrDBVal(CString &sModule, TCString &Str, CString *sDBSettingPrefix) +{ + if (sDBSetting != NULL && !ReadOnly) + { + DBWriteContactSettingTString(NULL, sModule, sDBSettingPrefix ? (*sDBSettingPrefix + sDBSetting) : sDBSetting, Str); + } +} + + + +void COptItem_Checkbox::DBToMem(CString &sModule, CString *sDBSettingPrefix) +{ + if (ValueMask) + { + Value = (GetIntDBVal(sModule, false, sDBSettingPrefix) & ValueMask) ? BST_CHECKED : BST_UNCHECKED; + } else + { + Value = GetIntDBVal(sModule, false, sDBSettingPrefix); + } + COptItem::DBToMem(sModule, sDBSettingPrefix); +} + +void COptItem_Checkbox::MemToDB(CString &sModule, CString *sDBSettingPrefix) +{ + if (ValueMask) + { + if (Value == BST_CHECKED) + { + SetIntDBVal(sModule, GetIntDBVal(sModule, false, sDBSettingPrefix) | ValueMask, sDBSettingPrefix); + } else + { + SetIntDBVal(sModule, GetIntDBVal(sModule, false, sDBSettingPrefix) & ~ValueMask, sDBSettingPrefix); + } + } else + { + SetIntDBVal(sModule, Value, sDBSettingPrefix); + } + COptItem::MemToDB(sModule, sDBSettingPrefix); +} + +void COptItem_Checkbox::WndToMem(HWND hWnd) +{ + Value = IsDlgButtonChecked(hWnd, DlgItemID); +// tri-state checkboxes in combination with ValueMask != 0 are not supported ;) + _ASSERT(!ValueMask || Value != BST_INDETERMINATE); + COptItem::WndToMem(hWnd); +} + +void COptItem_Checkbox::MemToWnd(HWND hWnd) +{ + CheckDlgButton(hWnd, DlgItemID, Value); + COptItem::MemToWnd(hWnd); +} + + + +void COptItem_BitDBSetting::DBToMem(CString &sModule, CString *sDBSettingPrefix) +{ + if (ValueMask) + { + Value = (GetIntDBVal(sModule, false, sDBSettingPrefix) & ValueMask) != 0; + } else + { + Value = GetIntDBVal(sModule, false, sDBSettingPrefix); + } + COptItem::DBToMem(sModule, sDBSettingPrefix); +} + +void COptItem_BitDBSetting::MemToDB(CString &sModule, CString *sDBSettingPrefix) +{ + if (ValueMask) + { + if (Value) + { + SetIntDBVal(sModule, GetIntDBVal(sModule, false, sDBSettingPrefix) | ValueMask, sDBSettingPrefix); + } else + { + SetIntDBVal(sModule, GetIntDBVal(sModule, false, sDBSettingPrefix) & ~ValueMask, sDBSettingPrefix); + } + } else + { + SetIntDBVal(sModule, Value, sDBSettingPrefix); + } + COptItem::MemToDB(sModule, sDBSettingPrefix); +} + + +// ================================================ COptItem_TreeCtrl ================================================ + +int COptItem_TreeCtrl::IDToOrder(int ID) +{ + int I; + for (I = 0; I < RootItems.GetSize(); I++) + { + if (RootItems[I].ID == ID) + { + return ROOT_INDEX_TO_ORDER(I); + } + } + for (I = 0; I < Value.GetSize(); I++) + { + if (Value[I].ID == ID) + { + return I; + } + } + return -1; +} + +int COptItem_TreeCtrl::hItemToOrder(HTREEITEM hItem) +{ + int I; + for (I = 0; I < RootItems.GetSize(); I++) + { + if (RootItems[I].hItem == hItem) + { + return ROOT_INDEX_TO_ORDER(I); + } + } + for (I = 0; I < Value.GetSize(); I++) + { + if (Value[I].hItem == hItem) + { + return I; + } + } + return -1; +} + +int COptItem_TreeCtrl::GenerateID() +{ + int ID = 0; + while (IDToOrder(ID) != -1) + { + ID++; + } + return ID; +} + +typedef struct +{ + COptItem_TreeCtrl *TreeCtrl; + CString *sModule; + CString *sDBSettingPrefix; +} sTreeReadEnumData; + +int TreeReadEnum(const char *szSetting, LPARAM lParam) +{ + sTreeReadEnumData *TreeReadEnumData = (sTreeReadEnumData*)lParam; + int Len = TreeReadEnumData->TreeCtrl->sDBSetting.GetLen() + lengthof(TREEITEM_DBSTR_TITLE) - 1; + if (!strncmp(szSetting, TreeReadEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_TITLE, Len) && isdigit(szSetting[Len])) + { + int ID = atol(szSetting + Len); + short ParentID = (TreeReadEnumData->TreeCtrl->TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL) ? 0 : DBGetContactSettingWord(NULL, *TreeReadEnumData->sModule, + *TreeReadEnumData->sDBSettingPrefix + TreeReadEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_PARENT + (szSetting + Len), -1); + short Order = DBGetContactSettingWord(NULL, *TreeReadEnumData->sModule, + *TreeReadEnumData->sDBSettingPrefix + TreeReadEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_ORDER + (szSetting + Len), -1); + char Flags = (TreeReadEnumData->TreeCtrl->TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL && !(TreeReadEnumData->TreeCtrl->TreeFlags & TREECTRL_FLAG_HAS_CHECKBOXES)) ? 0 : DBGetContactSettingByte(NULL, *TreeReadEnumData->sModule, + *TreeReadEnumData->sDBSettingPrefix + TreeReadEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_FLAGS + (szSetting + Len), 0); + if (ParentID >= 0 && Order >= 0) + { + TreeReadEnumData->TreeCtrl->Value.SetAtGrow(Order).ID = ID; + TreeReadEnumData->TreeCtrl->Value.SetAtGrow(Order).ParentID = ParentID; + TreeReadEnumData->TreeCtrl->Value.SetAtGrow(Order).Flags = Flags; + TreeReadEnumData->TreeCtrl->Value.SetAtGrow(Order).hItem = NULL; + TreeReadEnumData->TreeCtrl->Value.SetAtGrow(Order).Title = DBGetContactSettingString(NULL, *TreeReadEnumData->sModule, *TreeReadEnumData->sDBSettingPrefix + szSetting, _T("")); + TreeReadEnumData->TreeCtrl->Value.SetAtGrow(Order).User_Str1 = (TreeReadEnumData->TreeCtrl->User_Str1_DBName == NULL) ? NULL : + DBGetContactSettingString(NULL, *TreeReadEnumData->sModule, + *TreeReadEnumData->sDBSettingPrefix + TreeReadEnumData->TreeCtrl->sDBSetting + TreeReadEnumData->TreeCtrl->User_Str1_DBName + (szSetting + Len), (TCHAR*)NULL); + } + } + return 0; +} + +void COptItem_TreeCtrl::DBToMem(CString &sModule, CString *sDBSettingPrefix) +{ + if (!sDBSettingPrefix) + { + sDBSettingPrefix = &sEmptyString; + } + Value.RemoveAll(); + sTreeReadEnumData TreeReadEnumData; + TreeReadEnumData.TreeCtrl = this; + TreeReadEnumData.sModule = &sModule; + TreeReadEnumData.sDBSettingPrefix = sDBSettingPrefix; + DBCONTACTENUMSETTINGS dbEnum; + dbEnum.lParam = (LPARAM)&TreeReadEnumData; + dbEnum.ofsSettings = 0; + dbEnum.pfnEnumProc = TreeReadEnum; + dbEnum.szModule = sModule; + CallService(MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbEnum); + if (!Value.GetSize()) + { + Value = DefValue; + } else + { + int I; + for (I = 0; I < Value.GetSize(); I++) + { + if (Value[I].Title == NULL) + { + Value.RemoveElem(I); + I--; + } + } + } + COptItem::DBToMem(sModule, sDBSettingPrefix); +} + +void COptItem_TreeCtrl::MemToDB(CString &sModule, CString *sDBSettingPrefix) +{ + if (!ReadOnly && Modified) + { + if (!sDBSettingPrefix) + { + sDBSettingPrefix = &sEmptyString; + } + CleanDBSettings(sModule, sDBSettingPrefix); + int I; + for (I = 0; I < Value.GetSize(); I++) + { + CString StrID; + _itoa(Value[I].ID, StrID.GetBuffer(64), 10); + StrID.ReleaseBuffer(); + DBWriteContactSettingTString(NULL, sModule, *sDBSettingPrefix + sDBSetting + TREEITEM_DBSTR_TITLE + StrID, Value[I].Title); + if (!(TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL)) + { + DBWriteContactSettingWord(NULL, sModule, *sDBSettingPrefix + sDBSetting + TREEITEM_DBSTR_PARENT + StrID, Value[I].ParentID); + } + DBWriteContactSettingWord(NULL, sModule, *sDBSettingPrefix + sDBSetting + TREEITEM_DBSTR_ORDER + StrID, I); + if (!(TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL) || TreeFlags & TREECTRL_FLAG_HAS_CHECKBOXES) + { + DBWriteContactSettingByte(NULL, sModule, *sDBSettingPrefix + sDBSetting + TREEITEM_DBSTR_FLAGS + StrID, Value[I].Flags); + } + if (User_Str1_DBName != NULL && Value[I].User_Str1 != NULL) + { + DBWriteContactSettingTString(NULL, sModule, *sDBSettingPrefix + sDBSetting + User_Str1_DBName + StrID, Value[I].User_Str1); + } + } + COptItem::MemToDB(sModule, sDBSettingPrefix); + } +} + +void COptItem_TreeCtrl::WndToMem(HWND hWnd) +{ // only need to gather info of items state (expanded/collapsed, checked/unchecked) + HWND hTreeView = GetDlgItem(hWnd, DlgItemID); + int I; + for (I = 0; I < Value.GetSize(); I++) + { + DWORD State = TreeView_GetItemState(hTreeView, Value[I].hItem, TVIS_EXPANDED | TVIS_STATEIMAGEMASK); + int OldFlags = Value[I].Flags; + if (State & TVIS_EXPANDED) + { + Value[I].Flags |= TIF_EXPANDED; + } else + { + Value[I].Flags &= ~TIF_EXPANDED; + } + if (TreeFlags & TREECTRL_FLAG_HAS_CHECKBOXES && (State >> 12) - 1) + { + Value[I].Flags |= TIF_ENABLED; + } else + { + Value[I].Flags &= ~TIF_ENABLED; + } + if (Value[I].Flags != OldFlags) + { + Modified = true; + } + } + COptItem::WndToMem(hWnd); +} + +void COptItem_TreeCtrl::MemToWnd(HWND hWnd) +{ + HWND hTreeView = GetDlgItem(hWnd, DlgItemID); + if (TreeFlags & TREECTRL_FLAG_HAS_CHECKBOXES) + { // have to set this in run-time as it's specified in MSDN + LONG Style = GetWindowLong(hTreeView, GWL_STYLE); + SetWindowLong(hTreeView, GWL_STYLE, Style & ~TVS_CHECKBOXES); + SetWindowLong(hTreeView, GWL_STYLE, Style | TVS_CHECKBOXES); + } + TVINSERTSTRUCT tvIn = {0}; + int ScrollPos = GetScrollPos(hTreeView, SB_VERT); + int SelectOrder = IDToOrder(GetSelectedItemID(hWnd)); + SendMessage(hTreeView, WM_SETREDRAW, false, 0); + TreeView_DeleteAllItems(hTreeView); + _ASSERT(RootItems.GetSize()); + int I; + if (!(TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL)) + { + for (I = 0; I < RootItems.GetSize(); I++) + { + tvIn.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM; + RootItems[I].Flags |= TIF_GROUP; + tvIn.item.state = tvIn.item.stateMask = TVIS_BOLD | ((RootItems[I].Flags & TIF_EXPANDED) ? TVIS_EXPANDED : 0); + tvIn.item.pszText = RootItems[I].Title; + tvIn.hParent = TVI_ROOT; + tvIn.hInsertAfter = TVI_LAST; + tvIn.item.lParam = RootItems[I].ID; + RootItems[I].hItem = TreeView_InsertItem(hTreeView, &tvIn); + } + } + for (I = 0; I < Value.GetSize(); I++) + { + Value[I].hItem = RootItems[0].hItem; // put an item to first group in case of some strange error + } + for (I = 0; I < Value.GetSize(); I++) + { + tvIn.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM; + tvIn.item.state = tvIn.item.stateMask = (Value[I].Flags & TIF_GROUP) ? (TVIS_BOLD | ((Value[I].Flags & TIF_EXPANDED) ? TVIS_EXPANDED : 0)) : 0; + if (TreeFlags & TREECTRL_FLAG_HAS_CHECKBOXES) + { + tvIn.item.stateMask |= TVIS_STATEIMAGEMASK; + tvIn.item.state |= INDEXTOSTATEIMAGEMASK((Value[I].Flags & TIF_ENABLED) ? 2 : 1); + } + tvIn.item.pszText = Value[I].Title; + int Order = IDToOrder(Value[I].ParentID); + if (Order != -1) + { + tvIn.hParent = (Order <= TREECTRL_ROOTORDEROFFS) ? RootItems[ROOT_ORDER_TO_INDEX(Order)].hItem : Value[Order].hItem; + tvIn.hInsertAfter = TVI_LAST; + tvIn.item.lParam = Value[I].ID; + Value[I].hItem = TreeView_InsertItem(hTreeView, &tvIn); + } else + { // found an orphan item; probably it's better just to delete it + Value.RemoveElem(I); + I--; + } + } + TreeView_SelectItem(hTreeView, (SelectOrder >= 0) ? Value[SelectOrder].hItem : ((SelectOrder <= TREECTRL_ROOTORDEROFFS) ? RootItems[ROOT_ORDER_TO_INDEX(SelectOrder)].hItem : NULL)); + SendMessage(hTreeView, WM_SETREDRAW, true, 0); + SCROLLBARINFO sbi; + sbi.cbSize = sizeof(sbi); + GetScrollBarInfo(hTreeView, OBJID_VSCROLL, &sbi); + if (!(sbi.rgstate[0] & STATE_SYSTEM_INVISIBLE)) + { + int MinPos, MaxPos; + GetScrollRange(hTreeView, SB_VERT, &MinPos, &MaxPos); + if (ScrollPos < MinPos) + { + ScrollPos = MinPos; + } else if (ScrollPos > MaxPos) + { + ScrollPos = MaxPos; + } + SetScrollPos(hTreeView, SB_VERT, ScrollPos, true); + } + COptItem::MemToWnd(hWnd); +} + + +typedef struct +{ + TMyArray TreeSettings; + COptItem_TreeCtrl *TreeCtrl; + CString *sDBSettingPrefix; +} sTreeDeleteEnumData; + +int TreeDeleteEnum(const char *szSetting, LPARAM lParam) +{ + sTreeDeleteEnumData *TreeDeleteEnumData = (sTreeDeleteEnumData*)lParam; + CString CurSetting; + CurSetting = *TreeDeleteEnumData->sDBSettingPrefix + TreeDeleteEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_TITLE; + if (!strncmp(szSetting, CurSetting, CurSetting.GetLen())) + { + TreeDeleteEnumData->TreeSettings.AddElem(szSetting); + } + CurSetting = *TreeDeleteEnumData->sDBSettingPrefix + TreeDeleteEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_PARENT; + if (!strncmp(szSetting, CurSetting, CurSetting.GetLen())) + { + TreeDeleteEnumData->TreeSettings.AddElem(szSetting); + } + CurSetting = *TreeDeleteEnumData->sDBSettingPrefix + TreeDeleteEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_ORDER; + if (!strncmp(szSetting, CurSetting, CurSetting.GetLen())) + { + TreeDeleteEnumData->TreeSettings.AddElem(szSetting); + } + CurSetting = *TreeDeleteEnumData->sDBSettingPrefix + TreeDeleteEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_FLAGS; + if (!strncmp(szSetting, CurSetting, CurSetting.GetLen())) + { + TreeDeleteEnumData->TreeSettings.AddElem(szSetting); + } + if (TreeDeleteEnumData->TreeCtrl->User_Str1_DBName != NULL) + { + CurSetting = *TreeDeleteEnumData->sDBSettingPrefix + TreeDeleteEnumData->TreeCtrl->sDBSetting + TreeDeleteEnumData->TreeCtrl->User_Str1_DBName; + if (!strncmp(szSetting, CurSetting, CurSetting.GetLen())) + { + TreeDeleteEnumData->TreeSettings.AddElem(szSetting); + } + } + return 0; +} + +void COptItem_TreeCtrl::CleanDBSettings(CString &sModule, CString *sDBSettingPrefix) +{ + if (!sDBSettingPrefix) + { + sDBSettingPrefix = &sEmptyString; + } + sTreeDeleteEnumData TreeDeleteEnumData; + TreeDeleteEnumData.TreeCtrl = this; + TreeDeleteEnumData.sDBSettingPrefix = sDBSettingPrefix; + DBCONTACTENUMSETTINGS dbEnum; + dbEnum.lParam = (LPARAM)&TreeDeleteEnumData; + dbEnum.ofsSettings = 0; + dbEnum.pfnEnumProc = TreeDeleteEnum; + dbEnum.szModule = sModule; + CallService(MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbEnum); + int I; + for (I = 0; I < TreeDeleteEnumData.TreeSettings.GetSize(); I++) + { + DBDeleteContactSetting(NULL, sModule, TreeDeleteEnumData.TreeSettings[I]); + } +} + + +int COptItem_TreeCtrl::GetSelectedItemID(HWND hWnd) +{ + HWND hTreeView = GetDlgItem(hWnd, DlgItemID); + TVITEM tvi = {0}; + tvi.hItem = TreeView_GetSelection(hTreeView); + if (!tvi.hItem) + { + return -1; + } + tvi.mask = TVIF_HANDLE | TVIF_PARAM; + TreeView_GetItem(hTreeView, &tvi); + return tvi.lParam; +} + +void COptItem_TreeCtrl::Delete(HWND hWnd, int ID) +{ + int SelectedOrder = IDToOrder(ID); + _ASSERT(SelectedOrder >= 0); + RecursiveDelete(hWnd, SelectedOrder); + Modified = true; +} + +void COptItem_TreeCtrl::RecursiveDelete(HWND hWnd, int I) +{ + if (Value[I].Flags & TIF_GROUP) + { + int J; + for (J = I + 1; J < Value.GetSize(); J++) + { + if (Value[J].ParentID == Value[I].ID) + { + RecursiveDelete(hWnd, J--); + } + } + } + HWND hTreeView = GetDlgItem(hWnd, DlgItemID); + TreeView_DeleteItem(hTreeView, Value[I].hItem); + Value.RemoveElem(I); +} + +CTreeItem* COptItem_TreeCtrl::InsertItem(HWND hWnd, CTreeItem &Item) +// Item's ID and ParentID are not used (the new item position is determined by current selection in the tree) +// returns a pointer to the newly inserted item info +{ + _ASSERT(!(TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL) || !(Item.Flags & TIF_GROUP)); + HWND hTreeView = GetDlgItem(hWnd, DlgItemID); + TVITEM tvi; + int SelOrder = -1; + Item.ParentID = RootItems[0].ID; + TVINSERTSTRUCT tvIn = {0}; + tvIn.hParent = RootItems[0].hItem; + tvIn.hInsertAfter = TVI_FIRST; + if (tvi.hItem = TreeView_GetSelection(hTreeView)) + { + tvi.mask = TVIF_HANDLE | TVIF_PARAM; + TreeView_GetItem(hTreeView, &tvi); + SelOrder = IDToOrder(tvi.lParam); + if (SelOrder <= TREECTRL_ROOTORDEROFFS) + { + Item.ParentID = RootItems[ROOT_ORDER_TO_INDEX(SelOrder)].ID; + tvIn.hParent = RootItems[ROOT_ORDER_TO_INDEX(SelOrder)].hItem; + SelOrder = -1; + } else + { + if (Value[SelOrder].Flags & TIF_GROUP) + { + Item.ParentID = Value[SelOrder].ID; + tvIn.hParent = Value[SelOrder].hItem; + } else + { + Item.ParentID = Value[SelOrder].ParentID; + int Order = IDToOrder(Value[SelOrder].ParentID); + tvIn.hParent = (Order <= TREECTRL_ROOTORDEROFFS) ? RootItems[ROOT_ORDER_TO_INDEX(Order)].hItem : Value[Order].hItem; + tvIn.hInsertAfter = Value[SelOrder].hItem; + } + } + } + tvIn.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM; + tvIn.item.state = tvIn.item.stateMask = (Item.Flags & TIF_GROUP) ? (TVIS_BOLD | + ((Item.Flags & TIF_EXPANDED) ? TVIS_EXPANDED : 0)) : 0; + if (TreeFlags & TREECTRL_FLAG_HAS_CHECKBOXES) + { + tvIn.item.stateMask |= TVIS_STATEIMAGEMASK; + tvIn.item.state |= INDEXTOSTATEIMAGEMASK((Item.Flags & TIF_ENABLED) ? 2 : 1); + } + tvIn.item.pszText = Item.Title; + tvIn.item.lParam = Item.ID = GenerateID(); + Value.InsertElem(Item, SelOrder + 1); + Value[SelOrder + 1].hItem = TreeView_InsertItem(hTreeView, &tvIn); + TreeView_SelectItem(hTreeView, Value[SelOrder + 1].hItem); + Modified = true; + return &Value[SelOrder + 1]; +} + +int COptItem_TreeCtrl::RecursiveMove(int ItemOrder, int ParentID, int InsertAtOrder) +// ItemOrder must be a movable item (i.e. ItemOrder >= 0) +// InsertAtOrder must be >= 0 too. +{ + int ItemsMoved = 1; + Value.MoveElem(ItemOrder, InsertAtOrder); + Value[InsertAtOrder].ParentID = ParentID; + if (Value[InsertAtOrder].Flags & TIF_GROUP) // need to ensure that no items were left before their group by an order. + { + int GroupID = Value[InsertAtOrder].ID; + int I; + for (I = ItemOrder; I < InsertAtOrder; I++) // if ItemOrder > InsertAtOrder then there is simply nothing to do + { + if (Value[I].ParentID == GroupID) + { + int CurrentItemsMoved = RecursiveMove(I, GroupID, InsertAtOrder); + ItemsMoved += CurrentItemsMoved; + InsertAtOrder -= CurrentItemsMoved; + I--; + } + } + } + return ItemsMoved; +} + +void COptItem_TreeCtrl::MoveItem(HWND hWnd, HTREEITEM hItem, HTREEITEM hMoveTo) +{ // hMoveTo can be NULL and it means that we must move hItem to the beginning of the list + _ASSERT(hItem && (hMoveTo || TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL)); + if (hItem == hMoveTo) + { + return; + } + HWND hTreeView = GetDlgItem(hWnd, DlgItemID); + TVITEM tvi; + tvi.mask = TVIF_HANDLE | TVIF_PARAM; + tvi.hItem = hItem; + TreeView_GetItem(hTreeView, &tvi); + int ItemOrder = IDToOrder(tvi.lParam); + _ASSERT(ItemOrder != -1); + int MoveToOrder; + if (hMoveTo) + { + tvi.hItem = hMoveTo; + TreeView_GetItem(hTreeView, &tvi); + MoveToOrder = IDToOrder(tvi.lParam); + _ASSERT(MoveToOrder != -1); + } else + { + MoveToOrder = -1; + } + if (ItemOrder <= TREECTRL_ROOTORDEROFFS) + { + return; // can't move root items + } + if (Value[ItemOrder].Flags & TIF_GROUP) + { // need to check for a case when trying to move a group to its own subgroup. + int Order = MoveToOrder; + while (Order >= 0) + { + Order = IDToOrder(Value[Order].ParentID); + if (Order == ItemOrder) + { + return; + } + } + } +// well, everything is ok, we really can move that item. + WndToMem(hWnd); // save groups state (expanded/collapsed) + if (MoveToOrder != -1 && ((MoveToOrder <= TREECTRL_ROOTORDEROFFS) ? RootItems[ROOT_ORDER_TO_INDEX(MoveToOrder)].Flags : Value[MoveToOrder].Flags) & TIF_GROUP) + { // if the destination is a group, then move the item to that group + RecursiveMove(ItemOrder, (MoveToOrder <= TREECTRL_ROOTORDEROFFS) ? RootItems[ROOT_ORDER_TO_INDEX(MoveToOrder)].ID : Value[MoveToOrder].ID, (MoveToOrder >= 0) ? ((ItemOrder < MoveToOrder) ? MoveToOrder : (MoveToOrder + 1)) : 0); + } else + { // else place the item after the destination item + RecursiveMove(ItemOrder, (MoveToOrder == -1) ? 0 : Value[MoveToOrder].ParentID, (ItemOrder < MoveToOrder) ? MoveToOrder : (MoveToOrder + 1)); // when TREECTRL_FLAG_IS_SINGLE_LEVEL, we always have a root item with ID = 0. + } + MemToWnd(hWnd); // update the tree + Modified = true; +} + + +// ================================================ COptItem_ListCtrl ================================================ + +typedef struct +{ + COptItem_ListCtrl *ListCtrl; + CString *sModule; + CString *sDBSettingPrefix; +} sListReadEnumData; + +int ListReadEnum(const char *szSetting, LPARAM lParam) +{ + sListReadEnumData *ListReadEnumData = (sListReadEnumData*)lParam; + int Len = ListReadEnumData->sDBSettingPrefix->GetLen() + ListReadEnumData->ListCtrl->sDBSetting.GetLen() + lengthof(LISTITEM_DBSTR_TEXT) - 1; + if (!strncmp(szSetting, *ListReadEnumData->sDBSettingPrefix + ListReadEnumData->ListCtrl->sDBSetting + LISTITEM_DBSTR_TEXT, Len) && isdigit(szSetting[Len])) + { + int ID = atol(szSetting + Len); + ListReadEnumData->ListCtrl->Value.SetAtGrow(ID).Text = DBGetContactSettingString(NULL, *ListReadEnumData->sModule, *ListReadEnumData->sDBSettingPrefix + szSetting, _T("")); + } + return 0; +} + +void COptItem_ListCtrl::DBToMem(CString &sModule, CString *sDBSettingPrefix) +{ + if (!sDBSettingPrefix) + { + sDBSettingPrefix = &sEmptyString; + } + Value.RemoveAll(); + sListReadEnumData ListReadEnumData; + ListReadEnumData.ListCtrl = this; + ListReadEnumData.sModule = &sModule; + ListReadEnumData.sDBSettingPrefix = sDBSettingPrefix; + DBCONTACTENUMSETTINGS dbEnum; + dbEnum.lParam = (LPARAM)&ListReadEnumData; + dbEnum.ofsSettings = 0; + dbEnum.pfnEnumProc = ListReadEnum; + dbEnum.szModule = sModule; + CallService(MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbEnum); + if (!Value.GetSize()) + { + Value = DefValue; + } else + { + int I; + for (I = 0; I < Value.GetSize(); I++) + { + if (Value[I].Text == NULL) // NULL is not ""! + { + Value.RemoveElem(I); + I--; + } + } + } + COptItem::DBToMem(sModule, sDBSettingPrefix); +} + +void COptItem_ListCtrl::MemToDB(CString &sModule, CString *sDBSettingPrefix) +{ + if (!ReadOnly && Modified) + { + if (!sDBSettingPrefix) + { + sDBSettingPrefix = &sEmptyString; + } + CleanDBSettings(sModule, sDBSettingPrefix); + int I; + for (I = 0; I < Value.GetSize(); I++) + { + CString StrID; + _itoa(I, StrID.GetBuffer(64), 10); + StrID.ReleaseBuffer(); + DBWriteContactSettingTString(NULL, sModule, *sDBSettingPrefix + sDBSetting + LISTITEM_DBSTR_TEXT + StrID, Value[I].Text); + } + COptItem::MemToDB(sModule, sDBSettingPrefix); + } +} + +void COptItem_ListCtrl::WndToMem(HWND hWnd) +{ +// nothing to do + COptItem::WndToMem(hWnd); +} + +void COptItem_ListCtrl::MemToWnd(HWND hWnd) +{ + HWND hListView = GetDlgItem(hWnd, DlgItemID); + SendMessage(hListView, WM_SETREDRAW, false, 0); + SendMessage(hListView, LB_RESETCONTENT, 0, 0); + int I; + for (I = 0; I < Value.GetSize(); I++) + { + SendMessage(hListView, LB_INSERTSTRING, -1, (LPARAM)(TCHAR*)Value[I].Text); + } + SendMessage(hListView, WM_SETREDRAW, true, 0); + COptItem::MemToWnd(hWnd); +} + + +typedef struct +{ + TMyArray ListSettings; + COptItem_ListCtrl *ListCtrl; + CString *sDBSettingPrefix; +} sListDeleteEnumData; + +int ListDeleteEnum(const char *szSetting, LPARAM lParam) +{ + sListDeleteEnumData *ListDeleteEnumData = (sListDeleteEnumData*)lParam; + CString CurSetting = *ListDeleteEnumData->sDBSettingPrefix + ListDeleteEnumData->ListCtrl->sDBSetting + LISTITEM_DBSTR_TEXT; + if (!strncmp(szSetting, CurSetting, CurSetting.GetLen())) + { + ListDeleteEnumData->ListSettings.AddElem(szSetting); + } + return 0; +} + +void COptItem_ListCtrl::CleanDBSettings(CString &sModule, CString *sDBSettingPrefix) +{ + if (!sDBSettingPrefix) + { + sDBSettingPrefix = &sEmptyString; + } + sListDeleteEnumData ListDeleteEnumData; + ListDeleteEnumData.ListCtrl = this; + ListDeleteEnumData.sDBSettingPrefix = sDBSettingPrefix; + DBCONTACTENUMSETTINGS dbEnum; + dbEnum.lParam = (LPARAM)&ListDeleteEnumData; + dbEnum.ofsSettings = 0; + dbEnum.pfnEnumProc = ListDeleteEnum; + dbEnum.szModule = sModule; + CallService(MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbEnum); + int I; + for (I = 0; I < ListDeleteEnumData.ListSettings.GetSize(); I++) + { + DBDeleteContactSetting(NULL, sModule, ListDeleteEnumData.ListSettings[I]); + } +} + + +int COptItem_ListCtrl::GetSelectedItemID(HWND hWnd) +{ + int Res = SendDlgItemMessage(hWnd, DlgItemID, LB_GETCURSEL, 0, 0); + return (Res == LB_ERR) ? -1 : Res; // I know that LB_ERR = -1 ;) +} + +int COptItem_ListCtrl::SetSelectedItemID(HWND hWnd, int ID) +{ + int Res = SendDlgItemMessage(hWnd, DlgItemID, LB_SETCURSEL, ID, 0); + return (Res == LB_ERR) ? -1 : Res; +} + +void COptItem_ListCtrl::Delete(HWND hWnd, int ID) +{ + _ASSERT(ID >= 0); + HWND hListView = GetDlgItem(hWnd, DlgItemID); + int Res = SendMessage(hListView, LB_DELETESTRING, ID, 0); + _ASSERT(Res != LB_ERR); + Value.RemoveElem(ID); + Modified = true; +} + +void COptItem_ListCtrl::ModifyItem(HWND hWnd, int ID, CListItem &Item) +{ // changes the text of item with the specified ID + _ASSERT(ID >= 0); + HWND hListView = GetDlgItem(hWnd, DlgItemID); + SendMessage(hListView, WM_SETREDRAW, false, 0); + int CurSel = SendMessage(hListView, LB_GETCURSEL, 0, 0); + int TopIndex = SendMessage(hListView, LB_GETTOPINDEX, 0, 0); + int Res = SendMessage(hListView, LB_DELETESTRING, ID, 0); + _ASSERT(Res != LB_ERR); + Res = SendMessage(hListView, LB_INSERTSTRING, ID, (LPARAM)(TCHAR*)(Item.Text)); + _ASSERT(Res != LB_ERR && Res != LB_ERRSPACE); + SendMessage(hListView, LB_SETCURSEL, CurSel, 0); + SendMessage(hListView, LB_SETTOPINDEX, TopIndex, 0); + SendMessage(hListView, WM_SETREDRAW, true, 0); + Value[ID].Text = Item.Text; + Modified = true; +} + +CListItem* COptItem_ListCtrl::InsertItem(HWND hWnd, int ID, CListItem &Item) +// returns a pointer to the newly inserted item info +// ID is position at which to insert the item; -1 = add to the end of the list +{ + HWND hListView = GetDlgItem(hWnd, DlgItemID); + int Res = SendMessage(hListView, LB_INSERTSTRING, ID, (LPARAM)(TCHAR*)(Item.Text)); // LB_INSERTSTRING doesn't sort the lists even with LBS_SORT style + _ASSERT(Res != LB_ERR && Res != LB_ERRSPACE); + int I = Value.AddElem(Item); + Modified = true; + return &Value[I]; +} diff --git a/plugins/CommonLibs/Options.h b/plugins/CommonLibs/Options.h new file mode 100644 index 0000000000..1b3bb0a284 --- /dev/null +++ b/plugins/CommonLibs/Options.h @@ -0,0 +1,483 @@ +/* + Options.h + Copyright (c) 2005-2008 Chervov Dmitry + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#pragma once + +#include "CString.h" +#include "TMyArray.h" + +#ifndef lengthof +#define lengthof(s) (sizeof(s) / sizeof(*s)) +#endif + + +class COptItem +{ +public: + COptItem() {} + COptItem(int DlgItemID, char *szDBSetting, int nValueSize, int lParam = 0, bool ReadOnly = false): + DlgItemID(DlgItemID), nValueSize(nValueSize), sDBSetting(szDBSetting), lParam(lParam), Enabled(true), ReadOnly(ReadOnly), Modified(false) {} +/* COptItem(const COptItem &Item): DlgItemID(Item.DlgItemID), nValueSize(Item.nValueSize), + sDBSetting(Item.szDBSetting), lParam(Item.lParam), Enabled(Item.Enabled) {};*/ + virtual ~COptItem() {} + + virtual void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Modified = false;} + virtual void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {Modified = false;} + virtual void WndToMem(HWND hWnd) {} + virtual void MemToWnd(HWND hWnd) {EnableWindow(GetDlgItem(hWnd, DlgItemID), Enabled);} + void DBToMemToWnd(CString &sModule, HWND hWnd, CString *sDBSettingPrefix = NULL) {DBToMem(sModule, sDBSettingPrefix); MemToWnd(hWnd);} + void WndToMemToDB(HWND hWnd, CString &sModule, CString *sDBSettingPrefix = NULL) {WndToMem(hWnd); MemToDB(sModule, sDBSettingPrefix);} + virtual void CleanDBSettings(CString &sModule, CString *sDBSettingPrefix = NULL) {DBDeleteContactSetting(NULL, sModule, sDBSettingPrefix ? (*sDBSettingPrefix + sDBSetting) : sDBSetting);}; // TODO: also set Value to DefValue? + + virtual void SetValue(int Value) {Modified = true;} + virtual void SetDefValue(int DefValue) {} + virtual int GetValue() {return 0;} + virtual int GetDefValue() {return 0;} + int GetDBValue(CString &sModule, CString *sDBSettingPrefix = NULL) {DBToMem(sModule, sDBSettingPrefix); return GetValue();} + void SetDBValue(CString &sModule, int Value, CString *sDBSettingPrefix = NULL) {SetValue(Value); MemToDB(sModule, sDBSettingPrefix);} + int GetDBValueCopy(CString &sModule, CString *sDBSettingPrefix = NULL) {COptItem* Item = Copy(); Item->DBToMem(sModule, sDBSettingPrefix); int Value = Item->GetValue(); delete Item; return Value;} // retrieves DB value, but doesn't affect current page/item state; beware! it doesn't work with string values / other dynamic pointers + void SetDBValueCopy(CString &sModule, int Value, CString *sDBSettingPrefix = NULL) {COptItem* Item = Copy(); Item->SetValue(Value); Item->MemToDB(sModule, sDBSettingPrefix); delete Item;} + int GetWndValue(HWND hWnd) {WndToMem(hWnd); return GetValue();} + void SetWndValue(HWND hWnd, int Value) {SetValue(Value); MemToWnd(hWnd);} + void SetDlgItemID(int DlgItemID) {this->DlgItemID = DlgItemID;} + bool GetModified() {return Modified;} + void SetModified(bool Modified) {this->Modified = Modified;} + + void Enable(int Enabled) {this->Enabled = Enabled;} + int GetParam() {return lParam;} + int GetID() {return DlgItemID;} + +// virtual COptItem& operator = (const COptItem& Item) {return *this;}; + virtual COptItem* Copy() {_ASSERT(0); return NULL;} // Attention! Free Copy() result when it's not needed anymore! + + CString sDBSetting; + +protected: + int GetIntDBVal(CString &sModule, int bSigned = false, CString *sDBSettingPrefix = NULL); + void SetIntDBVal(CString &sModule, int Value, CString *sDBSettingPrefix = NULL); + TCString GetStrDBVal(CString &sModule, CString *sDBSettingPrefix = NULL); + void SetStrDBVal(CString &sModule, TCString &Str, CString *sDBSettingPrefix = NULL); + + int DlgItemID; + int Enabled; + bool ReadOnly; + bool Modified; + int nValueSize; // maximum pValue size in bytes + int lParam; +}; + + +class COptItem_Generic : public COptItem +{ +public: + COptItem_Generic() {} + COptItem_Generic(int DlgItemID, int lParam = 0): COptItem(DlgItemID, NULL, 0, lParam) {} + virtual COptItem* Copy() {return new COptItem_Generic(*this);} +}; + + +class COptItem_Edit : public COptItem +{ +public: + COptItem_Edit() {} + COptItem_Edit(int DlgItemID, char *szDBSetting, int nMaxLen, TCHAR *szDefValue, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nMaxLen, lParam, ReadOnly), sDefValue(szDefValue) {} +// COptItem_Edit(const COptItem_Edit &Item): sDefValue(Item.sDefValue), sValue(Item.sValue) {} + void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {sValue = GetStrDBVal(sModule, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);} + void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetStrDBVal(sModule, sValue, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);} + void WndToMem(HWND hWnd) {GetDlgItemText(hWnd, DlgItemID, sValue.GetBuffer(nValueSize), nValueSize); sValue.ReleaseBuffer(); COptItem::MemToWnd(hWnd);} + void MemToWnd(HWND hWnd) {SetDlgItemText(hWnd, DlgItemID, sValue); COptItem::MemToWnd(hWnd);} + void SetValue(int Value) {sValue = *(TCString*)Value; COptItem::SetValue(Value);} + void SetDefValue(int DefValue) {sDefValue = *(TCString*)DefValue; COptItem::SetDefValue(DefValue);} + int GetValue() {return (int)&sValue;} + int GetDefValue() {return (int)&sDefValue;} + +// COptItem_Edit& operator = (const COptItem_Edit& Item) {return *this;}; + virtual COptItem* Copy() {return new COptItem_Edit(*this);} + + TCString sDefValue; + TCString sValue; +}; + + +class COptItem_IntEdit : public COptItem +{ +public: + COptItem_IntEdit() {} + COptItem_IntEdit(int DlgItemID, char *szDBSetting, int nValueSize = DBVT_BYTE, int bSigned = true, int DefValue = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0), bSigned(bSigned) {} + void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Value = GetIntDBVal(sModule, bSigned, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);} + void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetIntDBVal(sModule, Value, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);} + void WndToMem(HWND hWnd) {Value = GetDlgItemInt(hWnd, DlgItemID, NULL, bSigned); COptItem::WndToMem(hWnd);} + void MemToWnd(HWND hWnd) {SetDlgItemInt(hWnd, DlgItemID, Value, bSigned); COptItem::MemToWnd(hWnd);} + void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);} + void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);} + int GetValue() {return Value;} + int GetDefValue() {return DefValue;} + virtual COptItem* Copy() {return new COptItem_IntEdit(*this);} + + int DefValue; + int Value; + int bSigned; +}; + + +class COptItem_Checkbox : public COptItem +{ +public: + COptItem_Checkbox() {} + COptItem_Checkbox(int DlgItemID, char *szDBSetting, int nValueSize = DBVT_BYTE, int DefValue = 0, int ValueMask = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0), ValueMask(ValueMask) {} + + void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL); + void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL); + void WndToMem(HWND hWnd); + void MemToWnd(HWND hWnd); + + void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);} + void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);} + int GetValue() {return Value;} + int GetDefValue() {return DefValue;} + virtual COptItem* Copy() {return new COptItem_Checkbox(*this);} + + int Value; + int DefValue; + int ValueMask; +}; + + +class COptItem_Radiobutton : public COptItem +{ +public: + COptItem_Radiobutton() {} + COptItem_Radiobutton(int DlgItemID, char *szDBSetting, int nValueSize, int DefValue, int ValueMask, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0), ValueMask(ValueMask) {} + + void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Value = (GetIntDBVal(sModule, false, sDBSettingPrefix) == ValueMask) ? BST_CHECKED : BST_UNCHECKED; COptItem::DBToMem(sModule, sDBSettingPrefix);} + void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {if ((Value == BST_CHECKED)) SetIntDBVal(sModule, ValueMask, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);} + void WndToMem(HWND hWnd) {Value = IsDlgButtonChecked(hWnd, DlgItemID); COptItem::WndToMem(hWnd);} + void MemToWnd(HWND hWnd) {CheckDlgButton(hWnd, DlgItemID, Value); COptItem::MemToWnd(hWnd);} + + void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);} + void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);} + int GetValue() {return Value;} + int GetDefValue() {return DefValue;} + virtual COptItem* Copy() {return new COptItem_Radiobutton(*this);} + + int Value; + int DefValue; + int ValueMask; +}; + + +class COptItem_Combobox : public COptItem +{ +public: + COptItem_Combobox() {} + COptItem_Combobox(int DlgItemID, char *szDBSetting, int nValueSize = DBVT_BYTE, int DefValue = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0) {} + void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Value = GetIntDBVal(sModule, false, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);} + void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetIntDBVal(sModule, Value, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);} + void WndToMem(HWND hWnd) {Value = SendDlgItemMessage(hWnd, DlgItemID, CB_GETITEMDATA, (WPARAM)SendDlgItemMessage(hWnd, DlgItemID, CB_GETCURSEL, 0, 0), 0); COptItem::WndToMem(hWnd);} + void MemToWnd(HWND hWnd) {SendDlgItemMessage(hWnd, DlgItemID, CB_SETCURSEL, Value, 0); COptItem::MemToWnd(hWnd);} + void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);} + void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);} + int GetValue() {return Value;} + int GetDefValue() {return DefValue;} + virtual COptItem* Copy() {return new COptItem_Combobox(*this);} + + int DefValue; + int Value; +}; + + +class COptItem_Colourpicker : public COptItem +{ +public: + COptItem_Colourpicker() {} + COptItem_Colourpicker(int DlgItemID, char *szDBSetting, int DefValue = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, DBVT_DWORD, lParam, ReadOnly), DefValue(DefValue), Value(0) {} + void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Value = GetIntDBVal(sModule, false, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);} + void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetIntDBVal(sModule, Value, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);} + void WndToMem(HWND hWnd) {Value = SendDlgItemMessage(hWnd, DlgItemID, CPM_GETCOLOUR, 0, 0); COptItem::WndToMem(hWnd);} + void MemToWnd(HWND hWnd) {SendDlgItemMessage(hWnd, DlgItemID, CPM_SETCOLOUR, 0, Value); COptItem::MemToWnd(hWnd);} + void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);} + void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);} + int GetValue() {return Value;} + int GetDefValue() {return DefValue;} + virtual COptItem* Copy() {return new COptItem_Colourpicker(*this);} + + DWORD DefValue; + DWORD Value; +}; + + +class COptItem_Slider : public COptItem +{ +public: + COptItem_Slider() {} + COptItem_Slider(int DlgItemID, char *szDBSetting, int nValueSize = DBVT_BYTE, int DefValue = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0) {} + void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Value = GetIntDBVal(sModule, false, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);} + void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetIntDBVal(sModule, Value, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);} + void WndToMem(HWND hWnd) {Value = SendDlgItemMessage(hWnd, DlgItemID, TBM_GETPOS, 0, 0); COptItem::WndToMem(hWnd);} + void MemToWnd(HWND hWnd) {SendDlgItemMessage(hWnd, DlgItemID, TBM_SETPOS, true, Value); COptItem::MemToWnd(hWnd);} + void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);} + void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);} + int GetValue() {return Value;} + int GetDefValue() {return DefValue;} + virtual COptItem* Copy() {return new COptItem_Slider(*this);} + + int DefValue; + int Value; +}; + + +class COptItem_IntDBSetting : public COptItem +{ +public: + COptItem_IntDBSetting() {} + COptItem_IntDBSetting(int DlgItemID, char *szDBSetting, int nValueSize = DBVT_BYTE, int bSigned = true, int DefValue = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0), bSigned(bSigned) {} + void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Value = GetIntDBVal(sModule, bSigned, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);} + void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetIntDBVal(sModule, Value, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);} + void WndToMem(HWND hWnd) {COptItem::WndToMem(hWnd);} + void MemToWnd(HWND hWnd) {COptItem::MemToWnd(hWnd);} + void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);} + void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);} + int GetValue() {return Value;} + int GetDefValue() {return DefValue;} + virtual COptItem* Copy() {return new COptItem_IntDBSetting(*this);} + + int Value; + int DefValue; + int bSigned; +}; + + +class COptItem_BitDBSetting : public COptItem +{ +public: + COptItem_BitDBSetting() {} + COptItem_BitDBSetting(int DlgItemID, char *szDBSetting, int nValueSize = DBVT_BYTE, int DefValue = 0, int ValueMask = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0), ValueMask(ValueMask) {} + + void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL); + void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL); + void WndToMem(HWND hWnd) {COptItem::WndToMem(hWnd);} + void MemToWnd(HWND hWnd) {COptItem::MemToWnd(hWnd);} + + void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);} + void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);} + int GetValue() {return Value;} + int GetDefValue() {return DefValue;} + virtual COptItem* Copy() {return new COptItem_BitDBSetting(*this);} + + int Value; + int DefValue; + int ValueMask; +}; + + +class COptItem_StrDBSetting : public COptItem +{ +public: + COptItem_StrDBSetting() {} + COptItem_StrDBSetting(int DlgItemID, char *szDBSetting, int nMaxLen, TCHAR *szDefValue, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nMaxLen, lParam, ReadOnly), sDefValue(szDefValue) {} + void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {sValue = GetStrDBVal(sModule, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);} + void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetStrDBVal(sModule, sValue, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);} + void WndToMem(HWND hWnd) {COptItem::WndToMem(hWnd);} + void MemToWnd(HWND hWnd) {COptItem::MemToWnd(hWnd);} + void SetValue(int Value) {sValue = *(TCString*)Value; COptItem::SetValue(Value);} + void SetDefValue(int DefValue) {sDefValue = *(TCString*)DefValue; COptItem::SetDefValue(DefValue);} + int GetValue() {return (int)&sValue;} + int GetDefValue() {return (int)&sDefValue;} + virtual COptItem* Copy() {return new COptItem_StrDBSetting(*this);} + + TCString sDefValue; + TCString sValue; +}; + + +// Tree item flags +#define TIF_GROUP 1 // is a group +#define TIF_EXPANDED 2 // item is expanded +#define TIF_ENABLED 4 // item is checked (has sense when the tree has checkboxes) +#define TIF_ROOTITEM 0x80 // item is a root item + +class CBaseTreeItem +{ +public: + CBaseTreeItem(); + CBaseTreeItem(TCString Title, int ID, int Flags): Title(Title), ID(ID), Flags(Flags), hItem(NULL) {} + + TCString Title; + int ID; + int Flags; + HTREEITEM hItem; +}; + +class CTreeItem : public CBaseTreeItem +{ +public: + CTreeItem(); + CTreeItem(TCString Title, int ParentID, int ID, int Flags = 0, TCString User_Str1 = NULL): + CBaseTreeItem(Title, ID, Flags & ~TIF_ROOTITEM), ParentID(ParentID), User_Str1(User_Str1) {} + + int ParentID; + TCString User_Str1; +}; + +class CTreeRootItem : public CBaseTreeItem +{ +public: + CTreeRootItem(); + CTreeRootItem(TCString Title, int ID, int Flags): CBaseTreeItem(Title, ID, Flags | TIF_ROOTITEM) {} +}; + +typedef TMyArray TreeItemArray; +typedef TMyArray TreeRootItemArray; + +#define TREECTRL_ROOTORDEROFFS -2 +#define ROOT_INDEX_TO_ORDER(i) (TREECTRL_ROOTORDEROFFS - (i)) +#define ROOT_ORDER_TO_INDEX(i) (TREECTRL_ROOTORDEROFFS - (i)) + +#define TREEITEMTITLE_MAXLEN 128 +#define TREEITEM_DBSTR_TITLE "Title" +#define TREEITEM_DBSTR_PARENT "Parent" +#define TREEITEM_DBSTR_ORDER "Order" +#define TREEITEM_DBSTR_FLAGS "Flags" + +// Tree control flags +#define TREECTRL_FLAG_IS_SINGLE_LEVEL 1 // means that the tree items can't have children, i.e. the tree is a plain list of items +#define TREECTRL_FLAG_HAS_CHECKBOXES 2 +//#define TREECTRL_FLAG_UNORDERED 4 TODO? + +class COptItem_TreeCtrl : public COptItem +{ +public: + COptItem_TreeCtrl() {} + COptItem_TreeCtrl(int DlgItemID, char *szDBSetting, TreeItemArray &DefValue, TreeRootItemArray RootItems, int lParam = 0, CString User_Str1_DBName = NULL, bool ReadOnly = false, int TreeFlags = 0): COptItem(DlgItemID, szDBSetting, DBVT_DWORD, lParam, ReadOnly), DefValue(DefValue), RootItems(RootItems), User_Str1_DBName(User_Str1_DBName), TreeFlags(TreeFlags) + { + if (TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL) + { + _ASSERT(!RootItems.GetSize()); // there can't be any root items when the tree is a plain list + this->RootItems.AddElem(CTreeRootItem(_T(""), 0, TIF_EXPANDED)); // TODO?? + this->RootItems[0].hItem = TVI_ROOT; + } + } + ~COptItem_TreeCtrl() {} + void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL); + void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL); + void WndToMem(HWND hWnd); + void MemToWnd(HWND hWnd); + void CleanDBSettings(CString &sModule, CString *sDBSettingPrefix = NULL); + void SetValue(int Value) {this->Value = *(TreeItemArray*)Value; COptItem::SetValue(Value);} + void SetDefValue(int DefValue) {this->DefValue = *(TreeItemArray*)DefValue; COptItem::SetDefValue(DefValue);} + int GetValue() {return (int)&Value;} + int GetDefValue() {return (int)&DefValue;} + virtual COptItem* Copy() {return new COptItem_TreeCtrl(*this);} + + int IDToOrder(int ID); + int hItemToOrder(HTREEITEM hItem); + int GenerateID(); + int GetSelectedItemID(HWND hWnd); + void Delete(HWND hWnd, int ID); + CTreeItem* InsertItem(HWND hWnd, CTreeItem &Item); + void MoveItem(HWND hWnd, HTREEITEM hItem, HTREEITEM hMoveTo); + + TreeItemArray DefValue, Value; + TreeRootItemArray RootItems; + CString User_Str1_DBName; + int TreeFlags; + +protected: + void RecursiveDelete(HWND hWnd, int I); + int RecursiveMove(int ItemOrder, int ParentID, int InsertAtOrder); +}; + + +class CListItem +{ +public: + CListItem(); + CListItem(TCString Text): Text(Text) {} + + TCString Text; +}; + +typedef TMyArray ListItemArray; + +#define LISTITEM_DBSTR_TEXT "Text" + +class COptItem_ListCtrl : public COptItem +{ +public: + COptItem_ListCtrl() {} + COptItem_ListCtrl(int DlgItemID, char *szDBSetting, ListItemArray &DefValue, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, DBVT_DWORD, lParam, ReadOnly), DefValue(DefValue) {} + ~COptItem_ListCtrl() {} + void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL); + void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL); + void WndToMem(HWND hWnd); + void MemToWnd(HWND hWnd); + void CleanDBSettings(CString &sModule, CString *sDBSettingPrefix = NULL); + void SetValue(int Value) {this->Value = *(ListItemArray*)Value; COptItem::SetValue(Value);} + void SetDefValue(int DefValue) {this->DefValue = *(ListItemArray*)DefValue; COptItem::SetDefValue(DefValue);} + int GetValue() {return (int)&Value;} + int GetDefValue() {return (int)&DefValue;} + virtual COptItem* Copy() {return new COptItem_ListCtrl(*this);} + + int GetSelectedItemID(HWND hWnd); // returns -1 if there's no selection + int SetSelectedItemID(HWND hWnd, int ID); + void Delete(HWND hWnd, int ID); + CListItem* InsertItem(HWND hWnd, int ID, CListItem &Item); + void ModifyItem(HWND hWnd, int ID, CListItem &Item); + + ListItemArray DefValue, Value; +}; + + +class COptPage +{ +public: + COptPage(): hWnd(NULL), sDBSettingPrefix("") {} + COptPage(char *szModule, HWND hWnd, CString sDBSettingPrefix = ""): sModule(szModule), hWnd(hWnd), sDBSettingPrefix(sDBSettingPrefix) {} + COptPage(const COptPage &Item); + ~COptPage(); + + void DBToMem(); + void MemToDB(); + void MemToPage(int OnlyEnable = 0); + void PageToMem(); + void DBToMemToPage() {DBToMem(); MemToPage();} + void PageToMemToDB() {PageToMem(); MemToDB();} + void CleanDBSettings(); + + COptItem *Find(int DlgItemID); + int GetValue(int DlgItemID) {return Find(DlgItemID)->GetValue();} + void SetValue(int DlgItemID, int Value) {Find(DlgItemID)->SetValue(Value);} + int GetDBValue(int DlgItemID) {return Find(DlgItemID)->GetDBValue(sModule, &sDBSettingPrefix);} + void SetDBValue(int DlgItemID, int Value) {Find(DlgItemID)->SetDBValue(sModule, Value, &sDBSettingPrefix);} + int GetDBValueCopy(int DlgItemID) {return Find(DlgItemID)->GetDBValueCopy(sModule, &sDBSettingPrefix);} + void SetDBValueCopy(int DlgItemID, int Value) {Find(DlgItemID)->SetDBValueCopy(sModule, Value, &sDBSettingPrefix);} + int GetWndValue(int DlgItemID) {return Find(DlgItemID)->GetWndValue(hWnd);} + void SetWndValue(int DlgItemID, int Value) {Find(DlgItemID)->SetWndValue(hWnd, Value);} + HWND GetWnd() {return hWnd;} + void SetWnd(HWND hWnd) {_ASSERT(!this->hWnd || !hWnd); this->hWnd = hWnd;} + void Enable(int DlgItemID, int Enabled) {Find(DlgItemID)->Enable(Enabled);} + bool GetModified(); + void SetModified(bool Modified); + + COptPage& operator = (const COptPage& Page); + + HWND hWnd; + CString sModule, sDBSettingPrefix; + TMyArray Items; +}; diff --git a/plugins/CommonLibs/TMyArray.h b/plugins/CommonLibs/TMyArray.h new file mode 100644 index 0000000000..68ca908fe1 --- /dev/null +++ b/plugins/CommonLibs/TMyArray.h @@ -0,0 +1,353 @@ +/* + TMyArray.h - TMyArray template + Copyright (c) 2005-2008 Chervov Dmitry + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#pragma once + +#include + +#define ARRAY_GROWBY 4 +// if there is more than ARRAY_FREETHRESHOLD free array elements, then we're reallocating the array +#define ARRAY_FREETHRESHOLD 16 + +template +class TMyArray +{ +public: + TMyArray(); + TMyArray(const TMyArray &A); + ~TMyArray(); + + int GetSize() const; + T* GetData() const; + int AddElem(ARG_T pElem); + int Add(const T *pItems, int nItems); + void InsertElem(ARG_T pElem, int nInsertAt); + void MoveElem(int nIndex, int nMoveTo); + T& SetAtGrow(int nIndex); + int Find(ARG_T pElem); // returns an index of the specified item, or -1 if the array doesn't contain the item + int BinarySearch(int (*CmpFunc)(ARG_T pItem, LPARAM lParam), LPARAM lParam, int *pIndex = NULL); // returns an index of the specified item, or -1 if the array doesn't contain the item; + // also it's possible to specify pIndex so that even if the array doesn't contain the item, the function will set *pIndex to a position where the item can be inserted; + // CmpFunc must return -1, 0 and 1 depending whether pItem is lesser, equal or greater than needed; + // BinarySearch() requires the array to be sorted in an ascending order + void RemoveElem(int nIndex, int nItems = 1); + void RemoveAll(); + const T& operator[](int nIndex) const; + T& operator[](int nIndex); + TMyArray& operator = (const TMyArray &A); + TMyArray& operator += (const TMyArray &A); + +private: + int SetAllocNum(int nNewAllocNum); + + T* pData; + int nElemNum; + int nAllocNum; +}; + +template +TMyArray::TMyArray() +{ + nElemNum = 0; + nAllocNum = 0; + pData = NULL; +} + +template +TMyArray::TMyArray(const TMyArray &A)//: TMyArray() +{ + nElemNum = 0; + nAllocNum = 0; + pData = NULL; + *this = A; +} + +template +TMyArray::~TMyArray() +{ + RemoveAll(); +} + +template +__forceinline int TMyArray::GetSize() const +{ + return nElemNum; +} + +template +__forceinline T* TMyArray::GetData() const +{ + return pData; +} + +template +__forceinline int TMyArray::SetAllocNum(int nNewAllocNum) +{ + _ASSERT(nNewAllocNum >= nElemNum); + T*pNewData = (nNewAllocNum) ? (T*)malloc(sizeof(T) * nNewAllocNum) : NULL; + if (pData) + { + if (pNewData) + { + memcpy(pNewData, pData, sizeof(T) * nElemNum); + } + free(pData); + } + pData = pNewData; + if (!pNewData) + { + nAllocNum = 0; + return -1; // not enough memory? + } else + { + nAllocNum = nNewAllocNum; + return 0; // everything's ok + } +} + +template +__forceinline int TMyArray::AddElem(ARG_T pElem) +{ + if (nElemNum >= nAllocNum) + { // reallocate memory to fit new element + SetAllocNum(nAllocNum + GrowBy); + } + memset(pData + nElemNum, 0, sizeof(T)); + pData[nElemNum] = pElem; + return nElemNum++; +} + +template +__forceinline int TMyArray::Add(const T *pItems, int nItems) +{ + if (nElemNum + nItems > nAllocNum) + { // reallocate memory to fit new items + SetAllocNum(nAllocNum + nElemNum + nItems - 1 - ((nElemNum + nItems - 1) % GrowBy) + GrowBy); + } + memset(pData + nElemNum, 0, sizeof(T) * nItems); + int I; + for (I = 0; I < nItems; I++) + { + pData[nElemNum++] = pItems[I]; + } + return nElemNum - nItems; // returns an index of the first item added +} + +template +__forceinline void TMyArray::InsertElem(ARG_T pElem, int nInsertAt) +{ + _ASSERT(nInsertAt >= 0 && nInsertAt <= nElemNum); + if (nElemNum >= nAllocNum) + { // reallocate memory to fit new items + SetAllocNum(nAllocNum + GrowBy); + } + memmove(pData + nInsertAt + 1, pData + nInsertAt, sizeof(T) * (nElemNum - nInsertAt)); + memset(pData + nInsertAt, 0, sizeof(T)); + pData[nInsertAt] = pElem; + nElemNum++; +} + +template +__forceinline void TMyArray::MoveElem(int nIndex, int nMoveTo) +{ + _ASSERT(nIndex >= 0 && nIndex < nElemNum && nMoveTo >= 0 && nMoveTo < nElemNum); + if (nIndex == nMoveTo) + { + return; // nothing to do + } + char Elem[sizeof(T)]; + memmove(Elem, pData + nIndex, sizeof(T)); + if (nIndex < nMoveTo) + { + memmove(pData + nIndex, pData + nIndex + 1, sizeof(T) * (nMoveTo - nIndex)); + } else + { + memmove(pData + nMoveTo + 1, pData + nMoveTo, sizeof(T) * (nIndex - nMoveTo)); + } + memmove(pData + nMoveTo, Elem, sizeof(T)); +} + +template +__forceinline T& TMyArray::SetAtGrow(int nIndex) +{ + _ASSERT(nIndex >= 0); + if (nIndex < nElemNum) + { + return pData[nIndex]; + } + if (nIndex >= nAllocNum) + { + if (SetAllocNum(nIndex - (nIndex % GrowBy) + GrowBy)) + { // if there was an error + nElemNum = 0; + return *pData; + } + } + memset(pData + nElemNum, 0, sizeof(T) * (nIndex - nElemNum + 1)); + nElemNum = nIndex + 1; + return pData[nIndex]; +} + +template +__forceinline int TMyArray::Find(ARG_T pElem) +{ + int I; + for (I = 0; I < nElemNum; I++) + { + if (pData[I] == pElem) + { + return I; + } + } + return -1; +} + +template +__forceinline int TMyArray::BinarySearch(int (*CmpFunc)(ARG_T pItem, LPARAM lParam), LPARAM lParam, int *pIndex) +{ + int L, R; + int CmpResult; + if (!nElemNum) + { + if (pIndex) + { + *pIndex = -1; + } + return -1; + } + for (L = 0, R = nElemNum; R - L > 1;) + { + int C = (L + R) >> 1; // rounds always to a lesser index if L + R is odd + CmpResult = CmpFunc(pData[C], lParam); // usually, CmpFunc = pData[C] - lParam; i.e. CmpFunc > 0 when pData[C] is greater than necessary, < 0 when pData[C] is less, and = 0 when pData[C] is the item we search for + if (CmpResult < 0) + { + L = C; + } else if (CmpResult > 0) + { + R = C; + } else + { // CmpResult == 0 + if (pIndex) + { + *pIndex = C; + } + return C; + } + } + if (pIndex) + { + *pIndex = L; + } + CmpResult = CmpFunc(pData[L], lParam); + if (!CmpResult) + { + return L; + } + if (CmpResult > 0) + { // we don't need to check pData[R], as pData[R] > pData[L] > lParam, i.e. there are no suitable item in the array + return -1; + } +// CmpResult < 0, we have to check pData[R] too + if (pIndex) + { + *pIndex = R; + } + if (R >= nElemNum) + { + return -1; + } + return CmpFunc(pData[R], lParam) ? -1 : R; +} + +template +__forceinline void TMyArray::RemoveElem(int nIndex, int nItems) +{ + _ASSERT(nIndex >= 0 && nIndex + nItems <= nElemNum); + if (!nItems) + { + return; + } +// delete pData[nIndex]; +// ~pData[nIndex]; + int I; + for (I = nIndex; I < nIndex + nItems; I++) + { + (pData + I)->~T(); + } + memmove(pData + nIndex, pData + nIndex + nItems, sizeof(T) * (nElemNum - nIndex - nItems)); + nElemNum -= nItems; + if (nAllocNum - nElemNum >= FreeThreshold) + { + SetAllocNum(nAllocNum - FreeThreshold); + }/* else + { + memset(pData + nElemNum, 0, sizeof(T)); + }*/ +} + +template +__forceinline void TMyArray::RemoveAll() +{ + int I; + for (I = 0; I < nElemNum; I++) + { + //delete pData[I]; + (pData + I)->~T(); + } + nElemNum = 0; + SetAllocNum(0); +} + +template +__forceinline const T& TMyArray::operator[](int nIndex) const +{ + _ASSERT(nIndex >= 0 && nIndex < nElemNum); + return pData[nIndex]; +} + +template +__forceinline T& TMyArray::operator[](int nIndex) +{ + _ASSERT(nIndex >= 0 && nIndex < nElemNum); + return pData[nIndex]; +} + +template +__forceinline TMyArray& TMyArray::operator = (const TMyArray &A) +{ + RemoveAll(); + int I; + for (I = 0; I < A.GetSize(); I++) + { + AddElem(A[I]); + } + return *this; +} + +template +__forceinline TMyArray& TMyArray::operator += (const TMyArray &A) +{ + int I; + for (I = 0; I < A.GetSize(); I++) + { + AddElem(A[I]); + } + return *this; +} + +typedef TMyArray CHARARRAY; diff --git a/plugins/CommonLibs/ThemedImageCheckbox.cpp b/plugins/CommonLibs/ThemedImageCheckbox.cpp new file mode 100644 index 0000000000..ea0fbcea0a --- /dev/null +++ b/plugins/CommonLibs/ThemedImageCheckbox.cpp @@ -0,0 +1,382 @@ +/* + ThemedImageCheckbox.cpp + Copyright (c) 2007 Chervov Dmitry + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "Common.h" +#include "ThemedImageCheckbox.h" +#include "Themes.h" +#include "win2k.h" + +#define WM_THEMECHANGED 0x031A + +#define CG_CHECKBOX_VERTINDENT 2 +#define CG_CHECKBOX_INDENT 1 +#define CG_CHECKBOX_WIDTH 16 +#define CG_IMAGE_INDENT 7 +#define CG_ADDITIONAL_WIDTH 3 + +// states +#define CGS_UNCHECKED BST_UNCHECKED +#define CGS_CHECKED BST_CHECKED +#define CGS_INDETERMINATE BST_INDETERMINATE +#define CGS_PRESSED BST_PUSHED // values above and including CGS_PRESSED must coincide with BST_ constants for BM_GETSTATE to work properly +#define CGS_HOVERED 8 + +// state masks +#define CGSM_ISCHECKED 3 // mask for BM_GETCHECK +#define CGSM_GETSTATE 7 // mask to get only valid values for BM_GETSTATE + +#ifndef lengthof +#define lengthof(s) (sizeof(s) / sizeof(*s)) +#endif + +class CCheckboxData +{ +public: + CCheckboxData(): OldWndProc(NULL), Style(0), State(0), hBitmap(NULL), hIcon(NULL) {}; + + WNDPROC OldWndProc; + int Style; // BS_CHECKBOX, BS_AUTOCHECKBOX, BS_3STATE or BS_AUTO3STATE + int State; + HBITMAP hBitmap; + HICON hIcon; +}; + +static int CALLBACK CheckboxWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + CCheckboxData *dat = (CCheckboxData*)GetWindowLong(hWnd, GWL_USERDATA); + if (!dat) + { + return 0; + } + switch (Msg) + { + case BM_CLICK: + { + SendMessage(hWnd, WM_LBUTTONDOWN, 0, 0); + SendMessage(hWnd, WM_LBUTTONUP, 0, 0); + return 0; + } break; + case BM_GETCHECK: + { + return dat->State & CGSM_ISCHECKED; + } break; + case BM_SETCHECK: + { + if ((wParam != BST_UNCHECKED && wParam != BST_CHECKED && wParam != BST_INDETERMINATE) || (wParam == BST_INDETERMINATE && dat->Style != BS_3STATE && dat->Style != BS_AUTO3STATE)) + { // invalid value + wParam = BST_CHECKED; + } + dat->State &= ~CGSM_ISCHECKED; + dat->State |= wParam; + InvalidateRect(hWnd, NULL, false); + SendMessage(GetParent(hWnd), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hWnd), BN_CLICKED), (LPARAM)hWnd); + return 0; + } break; + case BM_SETSTATE: + { + if (wParam) + { + dat->State |= CGS_PRESSED; + } else + { + dat->State &= ~CGS_PRESSED; + } + InvalidateRect(hWnd, NULL, false); + return 0; + } break; + case BM_GETSTATE: + { + return (dat->State & CGSM_GETSTATE) | ((GetFocus() == hWnd) ? BST_FOCUS : 0); + } break; + case BM_SETIMAGE: + { + int PrevHandle = 0; + switch (wParam) + { + case IMAGE_BITMAP: + { + PrevHandle = (int)dat->hBitmap; + dat->hBitmap = (HBITMAP)lParam; + } break; + case IMAGE_ICON: + { + PrevHandle = (int)dat->hIcon; + dat->hIcon = (HICON)lParam; + } break; + default: + { + return 0; + } + } + InvalidateRect(hWnd, NULL, false); + return PrevHandle; + } break; + case BM_GETIMAGE: + { + switch (wParam) + { + case IMAGE_BITMAP: + { + return (int)dat->hBitmap; + } break; + case IMAGE_ICON: + { + return (int)dat->hIcon; + } break; + } + return 0; + } break; + case WM_GETDLGCODE: + { + return DLGC_BUTTON; + } break; + case WM_THEMECHANGED: + case WM_ENABLE: + { + InvalidateRect(hWnd, NULL, false); + return 0; + } break; + case WM_KEYDOWN: + { + if (wParam == VK_SPACE) + { + SendMessage(hWnd, BM_SETSTATE, true, 0); + } + return 0; + } break; + case WM_KEYUP: + { + if (wParam == VK_SPACE) + { + SendMessage(hWnd, BM_SETCHECK, (SendMessage(hWnd, BM_GETCHECK, 0, 0) + 1) % ((dat->Style == BS_AUTO3STATE) ? 3 : 2), 0); + SendMessage(hWnd, BM_SETSTATE, false, 0); + } + return 0; + } break; + case WM_CAPTURECHANGED: + { + SendMessage(hWnd, BM_SETSTATE, false, 0); + return 0; + } break; + case WM_ERASEBKGND: + { + return true; + } break; + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + { + SetFocus(hWnd); + SendMessage(hWnd, BM_SETSTATE, true, 0); + SetCapture(hWnd); + return 0; + } break; + case WM_LBUTTONUP: + { + if (GetCapture() == hWnd) + { + ReleaseCapture(); + } + SendMessage(hWnd, BM_SETSTATE, false, 0); + if (dat->State & CGS_HOVERED && (dat->Style == BS_AUTOCHECKBOX || dat->Style == BS_AUTO3STATE)) + { + SendMessage(hWnd, BM_SETCHECK, (SendMessage(hWnd, BM_GETCHECK, 0, 0) + 1) % ((dat->Style == BS_AUTO3STATE) ? 3 : 2), 0); + } + return 0; + } break; + case WM_MOUSEMOVE: + { + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_LEAVE; + tme.dwHoverTime = HOVER_DEFAULT; + tme.hwndTrack = hWnd; + _TrackMouseEvent(&tme); + + POINT pt; + GetCursorPos(&pt); + if ((WindowFromPoint(pt) == hWnd) ^ ((dat->State & CGS_HOVERED) != 0)) + { + dat->State ^= CGS_HOVERED; + InvalidateRect(hWnd, NULL, false); + } + return 0; + } break; + case WM_MOUSELEAVE: + { + if (dat->State & CGS_HOVERED) + { + dat->State &= ~CGS_HOVERED; + InvalidateRect(hWnd, NULL, false); + } + return 0; + } break; + case WM_SETFOCUS: + case WM_KILLFOCUS: + case WM_SYSCOLORCHANGE: + { + InvalidateRect(hWnd, NULL, false); + return 0; + } break; + case WM_PAINT: + { + HDC hdc; + PAINTSTRUCT ps; + hdc = BeginPaint(hWnd, &ps); + RECT rc; + GetClientRect(hWnd, &rc); + HDC hdcMem = CreateCompatibleDC(hdc); + HBITMAP hbmMem = CreateCompatibleBitmap(hdc, rc.right, rc.bottom); + HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hbmMem); + HTHEME hTheme = pOpenThemeData ? pOpenThemeData(hWnd, L"BUTTON") : NULL; + if (hTheme && pDrawThemeParentBackground) + { + pDrawThemeParentBackground(hWnd, hdcMem, NULL); + } else + { + FillRect(hdcMem, &rc, GetSysColorBrush(COLOR_3DFACE)); + } + int StateID = 0; +#define CBSCHECK_UNCHECKED 1 +#define CBSCHECK_CHECKED 5 +#define CBSCHECK_MIXED 9 +#define CBSSTATE_NORMAL 0 +#define CBSSTATE_HOT 1 +#define CBSSTATE_PRESSED 2 +#define CBSSTATE_DISABLED 3 + switch (SendMessage(hWnd, BM_GETCHECK, 0, 0)) + { + case BST_CHECKED: + { + StateID += CBSCHECK_CHECKED; + } break; + case BST_UNCHECKED: + { + StateID += CBSCHECK_UNCHECKED; + } break; + case BST_INDETERMINATE: + { + StateID += CBSCHECK_MIXED; + } break; + } + if (!IsWindowEnabled(hWnd)) + { + StateID += CBSSTATE_DISABLED; + } else if (dat->State & CGS_PRESSED && (GetCapture() != hWnd || dat->State & CGS_HOVERED)) + { + StateID += CBSSTATE_PRESSED; + } else if (dat->State & CGS_PRESSED || dat->State & CGS_HOVERED) + { + StateID += CBSSTATE_HOT; + } + rc.left += CG_CHECKBOX_INDENT; + rc.right = rc.left + CG_CHECKBOX_WIDTH; // left-align the image in the client area + rc.top += CG_CHECKBOX_VERTINDENT; + rc.bottom = rc.top + CG_CHECKBOX_WIDTH; // exact rc dimensions are necessary for DrawFrameControl to draw correctly + if (hTheme && pDrawThemeBackground) + { + pDrawThemeBackground(hTheme, hdcMem, BP_CHECKBOX, StateID, &rc, &rc); + } else + { + int dfcStates[] = + {0, 0, DFCS_PUSHED, DFCS_INACTIVE, + DFCS_CHECKED, DFCS_CHECKED, DFCS_CHECKED | DFCS_PUSHED, DFCS_CHECKED | DFCS_INACTIVE, + DFCS_BUTTON3STATE | DFCS_CHECKED, DFCS_BUTTON3STATE | DFCS_CHECKED, DFCS_BUTTON3STATE | DFCS_INACTIVE | DFCS_CHECKED | DFCS_PUSHED, DFCS_BUTTON3STATE | DFCS_INACTIVE | DFCS_CHECKED | DFCS_PUSHED}; + _ASSERT(StateID >= 1 && StateID <= lengthof(dfcStates)); + DrawFrameControl(hdcMem, &rc, DFC_BUTTON, dfcStates[StateID - 1]); + } + + GetClientRect(hWnd, &rc); + RECT rcImage = rc; + LPARAM hImage = NULL; + DWORD DSFlags; + HIMAGELIST hImageList = NULL; + if (dat->hBitmap) + { + BITMAP bminfo; + GetObject(dat->hBitmap, sizeof(bminfo), &bminfo); + rcImage.right = bminfo.bmWidth; + rcImage.bottom = bminfo.bmHeight; + DSFlags = DST_BITMAP; + hImage = (LPARAM)dat->hBitmap; + } else + { + rcImage.right = GetSystemMetrics(SM_CXSMICON); + rcImage.bottom = GetSystemMetrics(SM_CYSMICON); + DSFlags = DST_ICON; + if (dat->hIcon) + { + hImageList = ImageList_Create(rcImage.right, rcImage.bottom, IsWinVerXPPlus() ? ILC_COLOR32 | ILC_MASK : ILC_COLOR16 | ILC_MASK, 1, 0); + ImageList_AddIcon(hImageList, dat->hIcon); + hImage = (LPARAM)ImageList_GetIcon(hImageList, 0, ILD_NORMAL); + } + } // rcImage.right and rcImage.bottom are width and height, not absolute coordinates + rcImage.left += CG_CHECKBOX_INDENT + CG_CHECKBOX_WIDTH + CG_IMAGE_INDENT; + rcImage.top += (rc.bottom - rcImage.bottom) / 2; + DrawState(hdcMem, NULL, NULL, hImage, 0, rcImage.left, rcImage.top, rcImage.right, rcImage.bottom, DSFlags | (IsWindowEnabled(hWnd) ? DSS_NORMAL : DSS_DISABLED)); + if (hImageList) + { + ImageList_RemoveAll(hImageList); + ImageList_Destroy(hImageList); + DestroyIcon((HICON)hImage); + } + if (GetFocus() == hWnd) + { + rcImage.right += rcImage.left; + rcImage.bottom += rcImage.top; + InflateRect(&rcImage, 1, 1); + DrawFocusRect(hdcMem, &rcImage); + } + if (hTheme && pCloseThemeData) + { + pCloseThemeData(hTheme); + } + BitBlt(hdc, 0, 0, rc.right, rc.bottom, hdcMem, 0, 0, SRCCOPY); + SelectObject(hdcMem, hbmOld); + DeleteObject(hbmMem); + DeleteDC(hdcMem); + EndPaint(hWnd, &ps); + return 0; + } break; + case WM_DESTROY: + { + SetWindowLong(hWnd, GWL_USERDATA, NULL); + CallWindowProc(dat->OldWndProc, hWnd, Msg, wParam, lParam); + delete dat; + return 0; + } break; + } + return CallWindowProc(dat->OldWndProc, hWnd, Msg, wParam, lParam); +} + +int MakeThemedImageCheckbox(HWND hWndCheckbox) +{ // workaround to make checkbox with BS_ICON or BS_BITMAP work with windows themes enabled + CCheckboxData *dat = new CCheckboxData(); + dat->OldWndProc = (WNDPROC)GetWindowLong(hWndCheckbox, GWL_WNDPROC); + dat->State = SendMessage(hWndCheckbox, BM_GETSTATE, 0, 0); + long Style = GetWindowLong(hWndCheckbox, GWL_STYLE); + _ASSERT(Style & BS_ICON || Style & BS_BITMAP); + dat->Style = Style & (BS_CHECKBOX | BS_AUTOCHECKBOX | BS_3STATE | BS_AUTO3STATE); + _ASSERT(dat->Style == BS_CHECKBOX || dat->Style == BS_AUTOCHECKBOX || dat->Style == BS_3STATE || dat->Style == BS_AUTO3STATE); + Style &= ~(BS_CHECKBOX | BS_AUTOCHECKBOX | BS_3STATE | BS_AUTO3STATE); + Style |= BS_OWNERDRAW; + SetWindowLong(hWndCheckbox, GWL_STYLE, Style); + SetWindowLong(hWndCheckbox, GWL_USERDATA, (LONG)dat); + SetWindowLong(hWndCheckbox, GWL_WNDPROC, (LONG)CheckboxWndProc); + return 0; +} diff --git a/plugins/CommonLibs/ThemedImageCheckbox.h b/plugins/CommonLibs/ThemedImageCheckbox.h new file mode 100644 index 0000000000..f3449ec8fc --- /dev/null +++ b/plugins/CommonLibs/ThemedImageCheckbox.h @@ -0,0 +1,26 @@ +/* + ThemedImageCheckbox.h + Copyright (c) 2007 Chervov Dmitry + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#pragma once + +#include +#include +#include + +int MakeThemedImageCheckbox(HWND hWndCheckbox); diff --git a/plugins/CommonLibs/Themes.cpp b/plugins/CommonLibs/Themes.cpp new file mode 100644 index 0000000000..359d226b13 --- /dev/null +++ b/plugins/CommonLibs/Themes.cpp @@ -0,0 +1,50 @@ +/* + Themes.cpp + Copyright (c) 2005-2007 Chervov Dmitry + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "Common.h" +#include "Themes.h" +#include + +tOpenThemeData pOpenThemeData = NULL; +tCloseThemeData pCloseThemeData = NULL; +tDrawThemeBackground pDrawThemeBackground = NULL; +tDrawThemeParentBackground pDrawThemeParentBackground = NULL; +tDrawThemeText pDrawThemeText = NULL; +tGetThemeTextExtent pGetThemeTextExtent = NULL; +tEnableThemeDialogTexture pEnableThemeDialogTexture = NULL; +tSetWindowTheme pSetWindowTheme = NULL; + +void InitThemes() +{ + if (IsWinVerXPPlus()) + { + HMODULE hThemeAPI = GetModuleHandle(_T("uxtheme")); + if (hThemeAPI) + { + pOpenThemeData = (tOpenThemeData)GetProcAddress(hThemeAPI, "OpenThemeData"); + pCloseThemeData = (tCloseThemeData)GetProcAddress(hThemeAPI, "CloseThemeData"); + pDrawThemeBackground = (tDrawThemeBackground)GetProcAddress(hThemeAPI, "DrawThemeBackground"); + pDrawThemeParentBackground = (tDrawThemeParentBackground)GetProcAddress(hThemeAPI, "DrawThemeParentBackground"); + pDrawThemeText = (tDrawThemeText)GetProcAddress(hThemeAPI, "DrawThemeText"); + pGetThemeTextExtent = (tGetThemeTextExtent)GetProcAddress(hThemeAPI, "GetThemeTextExtent"); + pEnableThemeDialogTexture = (tEnableThemeDialogTexture)GetProcAddress(hThemeAPI, "EnableThemeDialogTexture"); + pSetWindowTheme = (tSetWindowTheme)GetProcAddress(hThemeAPI, "SetWindowTheme"); + } + } +} diff --git a/plugins/CommonLibs/Themes.h b/plugins/CommonLibs/Themes.h new file mode 100644 index 0000000000..524c7514a5 --- /dev/null +++ b/plugins/CommonLibs/Themes.h @@ -0,0 +1,51 @@ +/* + Themes.h + Copyright (c) 2007 Chervov Dmitry + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#pragma once + +#include +#include + +typedef HANDLE HTHEME; + +// EnableThemeDialogTexture() flags +#define ETDT_DISABLE 0x00000001 +#define ETDT_ENABLE 0x00000002 +#define ETDT_USETABTEXTURE 0x00000004 +#define ETDT_ENABLETAB (ETDT_ENABLE | ETDT_USETABTEXTURE) + +typedef HANDLE (WINAPI *tOpenThemeData)(HWND, LPCWSTR); +typedef HRESULT (WINAPI *tCloseThemeData)(HANDLE); +typedef HRESULT (WINAPI *tDrawThemeBackground)(HANDLE, HDC, int, int, const RECT*, const RECT*); +typedef HRESULT (WINAPI *tDrawThemeParentBackground)(HWND, HDC, RECT*); +typedef HRESULT (WINAPI *tDrawThemeText)(HANDLE, HDC, int, int, LPCWSTR, int, DWORD, DWORD, const RECT*); +typedef HRESULT (WINAPI *tGetThemeTextExtent)(HANDLE, HDC, int, int, LPCWSTR, int, DWORD, const RECT*, RECT*); +typedef HRESULT (WINAPI *tEnableThemeDialogTexture)(HWND, DWORD); +typedef HRESULT (WINAPI *tSetWindowTheme)(HWND, LPCWSTR, LPCWSTR); + +extern tOpenThemeData pOpenThemeData; +extern tCloseThemeData pCloseThemeData; +extern tDrawThemeBackground pDrawThemeBackground; +extern tDrawThemeParentBackground pDrawThemeParentBackground; +extern tDrawThemeText pDrawThemeText; +extern tGetThemeTextExtent pGetThemeTextExtent; +extern tEnableThemeDialogTexture pEnableThemeDialogTexture; +extern tSetWindowTheme pSetWindowTheme; + +void InitThemes(); diff --git a/plugins/CommonLibs/pcre.cpp b/plugins/CommonLibs/pcre.cpp new file mode 100644 index 0000000000..5bd85833d9 --- /dev/null +++ b/plugins/CommonLibs/pcre.cpp @@ -0,0 +1,278 @@ +/* + Pcre.cpp + Copyright (c) 2007-2008 Chervov Dmitry + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "common.h" +#include +#include +#include +#include "newpluginapi.h" +#include "m_utils.h" +#include "TMyArray.h" +#include "CString.h" +#include "pcre.h" + + +HMODULE hPcreDLL = NULL; + +static pcre* (*pcre_compile)(const char*, int, const char**, int*, const unsigned char*); +static int (*pcre_config)(int, void*); +static int (*pcre_exec)(const pcre*, const pcre_extra*, const char*, int, int, int, int*, int); +static void (*pcre_free)(void*); +static pcre_extra* (*pcre_study)(const pcre*, int, const char **); + + +typedef struct +{ + pcre *pPcre; + pcre_extra *pExtra; + TCString Pattern; // used when it's not a valid regexp + int ID; // user-defined ID of the pattern; returned by PcreCheck on a match +} sPcreCompileData; + +TMyArray PcreCompileData; + + +void FreePcreCompileData() +{ + int I; + for (I = 0; I < PcreCompileData.GetSize(); I++) + { + if (PcreCompileData[I].pPcre) + { + pcre_free(PcreCompileData[I].pPcre); + if (PcreCompileData[I].pExtra) + { + pcre_free(PcreCompileData[I].pExtra); + } + } + } + PcreCompileData.RemoveAll(); +} + + +TCString CompileRegexp(TCString Regexp, int bAddAsUsualSubstring, int ID) +{ + TCString Result(_T("")); + sPcreCompileData s = {0}; + int NewID = PcreCompileData.AddElem(s); + PcreCompileData[NewID].ID = ID; + if (hPcreDLL && !bAddAsUsualSubstring) + { + const char *Err; + int ErrOffs; + int Flags = PCRE_CASELESS; + if (Regexp[0] == '/') + { + TCString OrigRegexp = Regexp; + Regexp = Regexp.Right(Regexp.GetLen() - 1); + TCHAR *pRegexpEnd = (TCHAR*)Regexp + Regexp.GetLen(); + TCHAR *p = _tcsrchr(Regexp.GetBuffer(), '/'); + if (!p) + { + Regexp = OrigRegexp; + } else + { + *p = 0; + Flags = 0; + while (++p < pRegexpEnd) + { + switch (*p) { + case 'i': + Flags |= PCRE_CASELESS; + break; + case 'm': + Flags |= PCRE_MULTILINE; + break; + case 's': + Flags |= PCRE_DOTALL; + break; + case 'x': + Flags |= PCRE_EXTENDED; + break; + case 'A': + Flags |= PCRE_ANCHORED; + break; + case 'f': + Flags |= PCRE_FIRSTLINE; + break; + case 'D': + Flags |= PCRE_DOLLAR_ENDONLY; + break; + case 'U': + Flags |= PCRE_UNGREEDY; + break; + case 'X': + Flags |= PCRE_EXTRA; + break; + default: + // Result += LogMessage(Translate("Warning, unknown pattern modifier '%c':\n"), *p ); + break; + } + } + } + Regexp.ReleaseBuffer(); + } +#ifdef _UNICODE + PcreCompileData[NewID].pPcre = pcre_compile(WCHAR2UTF8(Regexp).GetData(), PCRE_UTF8 | PCRE_NO_UTF8_CHECK | Flags, &Err, &ErrOffs, NULL); +#else + PcreCompileData[NewID].pPcre = pcre_compile(Regexp, Flags, &Err, &ErrOffs, NULL); +#endif + if (PcreCompileData[NewID].pPcre) { + PcreCompileData[NewID].pExtra = NULL; + if (pcre_study) + PcreCompileData[NewID].pExtra = pcre_study(PcreCompileData[NewID].pPcre, 0, &Err); + } + else { + // Result += LogMessage(TranslateT("Syntax error in regexp\n%s\nat offset %d: %s."), (TCHAR*)Regexp, ErrOffs, (TCHAR*)ANSI2TCHAR(Err)) + _T("\n\n"); + PcreCompileData[NewID].Pattern = Regexp; + } + } + else PcreCompileData[NewID].Pattern = Regexp; + + return Result; +} + + +HMODULE LoadPcreLibrary(const char *szPath) +{ + _ASSERT(szPath); + HMODULE hModule = LoadLibraryA(szPath); + if (!hModule) + { + return NULL; + } + *(FARPROC*)&pcre_config = GetProcAddress(hModule, "pcre_config"); + *(FARPROC*)&pcre_compile = GetProcAddress(hModule, "pcre_compile"); + *(FARPROC*)&pcre_exec = GetProcAddress(hModule, "pcre_exec"); + *(FARPROC*)&pcre_study = GetProcAddress(hModule, "pcre_study"); + *(FARPROC*)&pcre_free = *(FARPROC*)GetProcAddress(hModule, "pcre_free"); // pcre_free is a pointer to a variable containing pointer to the function %) + if (pcre_compile && pcre_exec && pcre_free) + { +#ifdef _UNICODE + int Utf8Supported = 0; + if (pcre_config) + { + pcre_config(PCRE_CONFIG_UTF8, &Utf8Supported); + } + if (Utf8Supported) + { + return hModule; + } +#else + return hModule; +#endif + } + FreeLibrary(hModule); + return NULL; +} + + +void InitPcre() +{ + _ASSERT(!hPcreDLL); + hPcreDLL = LoadPcreLibrary("pcre.dll"); + if (!hPcreDLL) + { + hPcreDLL = LoadPcreLibrary("pcre3.dll"); + } + if (!hPcreDLL) + { + char path[MAX_PATH]; + GetModuleFileNameA(NULL, path, sizeof(path)); + char *p = strrchr(path, '\\'); + if (p) + { + strcpy(p + 1, "pcre.dll"); + } else + { + strcpy(path, "pcre.dll"); + } + hPcreDLL = LoadPcreLibrary(path); + if (!hPcreDLL) + { + if (p) + { + strcpy(p + 1, "pcre3.dll"); + } else + { + strcpy(path, "pcre3.dll"); + } + hPcreDLL = LoadPcreLibrary(path); + } + } +} + + +void UninitPcre() +{ + if (hPcreDLL) + { + FreePcreCompileData(); + FreeLibrary(hPcreDLL); + } +} + + +int PcreEnabled() +{ + return (int)hPcreDLL; +} + + +int PcreCheck(TCString Str, int StartingID) +{ // StartingID specifies the pattern from which to start checking, i.e. the check starts from the next pattern after the one that has ID == StartingID + int I; + if (StartingID == -1) + { + I = 0; + } else + { + for (I = 0; I < PcreCompileData.GetSize(); I++) + { + if (PcreCompileData[I].ID == StartingID) + { + I++; + break; + } + } + } + for (; I < PcreCompileData.GetSize(); I++) + { + if (hPcreDLL && PcreCompileData[I].pPcre) + { +#ifdef _UNICODE + CHARARRAY Utf8Str = WCHAR2UTF8(Str); + int Res = pcre_exec(PcreCompileData[I].pPcre, PcreCompileData[I].pExtra, Utf8Str.GetData(), Utf8Str.GetSize() - 1, 0, PCRE_NOTEMPTY | PCRE_NO_UTF8_CHECK, NULL, 0); +#else + int Res = pcre_exec(PcreCompileData[I].pPcre, PcreCompileData[I].pExtra, Str, Str.GetLen(), 0, PCRE_NOTEMPTY, NULL, 0); +#endif + if (Res >= 0) + { + return PcreCompileData[I].ID; + } + } else + { + if (_tcsstr(Str.ToLower(), PcreCompileData[I].Pattern.ToLower())) + { + return PcreCompileData[I].ID; + } + } + } + return -1; +} diff --git a/plugins/CommonLibs/pcre.h b/plugins/CommonLibs/pcre.h new file mode 100644 index 0000000000..2663870f85 --- /dev/null +++ b/plugins/CommonLibs/pcre.h @@ -0,0 +1,30 @@ +/* + Pcre.h + Copyright (c) 2007-2008 Chervov Dmitry + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "CString.h" +#include "pcre_main.h" + +#pragma once + +void InitPcre(); +void UninitPcre(); +int PcreEnabled(); +int PcreCheck(TCString Str, int StartingID = -1); +void FreePcreCompileData(); +TCString CompileRegexp(TCString Regexp, int bAddAsUsualSubstring = 0, int ID = 0); diff --git a/plugins/CommonLibs/pcre_main.h b/plugins/CommonLibs/pcre_main.h new file mode 100644 index 0000000000..ca6e7449df --- /dev/null +++ b/plugins/CommonLibs/pcre_main.h @@ -0,0 +1,298 @@ +/************************************************* +* Perl-Compatible Regular Expressions * +*************************************************/ + +/* This is the public header file for the PCRE library, to be #included by +applications that call the PCRE functions. + + Copyright (c) 1997-2006 University of Cambridge + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#ifndef _PCRE_H +#define _PCRE_H + +/* The current PCRE version information. */ + +/* NOTES FOR FUTURE MAINTAINERS: Do not use numbers with leading zeros, because +they may be treated as octal constants. The PCRE_PRERELEASE feature is for +identifying release candidates. It might be defined as -RC2, for example. In +real releases, it should be defined empty. Do not change the alignment of these +statments. The code in ./configure greps out the version numbers by using "cut" +to get values from column 29 onwards. These are substituted into pcre-config +and libpcre.pc. The values are not put into configure.ac and substituted here +(which would simplify this issue) because that makes life harder for those who +cannot run ./configure. As it now stands, this file need not be edited in that +circumstance. */ + +#define PCRE_MAJOR 7 +#define PCRE_MINOR 0 +#define PCRE_PRERELEASE +#define PCRE_DATE 18-Dec-2006 + +/* Win32 uses DLL by default; it needs special stuff for exported functions +when building PCRE. */ + +#ifdef _WIN32 +# ifdef PCRE_DEFINITION +# ifdef DLL_EXPORT +# define PCRE_DATA_SCOPE __declspec(dllexport) +# endif +# else +# ifndef PCRE_STATIC +# define PCRE_DATA_SCOPE extern __declspec(dllimport) +# endif +# endif +#endif + +/* Otherwise, we use the standard "extern". */ + +#ifndef PCRE_DATA_SCOPE +# ifdef __cplusplus +# define PCRE_DATA_SCOPE extern "C" +# else +# define PCRE_DATA_SCOPE extern +# endif +#endif + +/* Have to include stdlib.h in order to ensure that size_t is defined; +it is needed here for malloc. */ + +#include + +/* Allow for C++ users */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Options */ + +#define PCRE_CASELESS 0x00000001 +#define PCRE_MULTILINE 0x00000002 +#define PCRE_DOTALL 0x00000004 +#define PCRE_EXTENDED 0x00000008 +#define PCRE_ANCHORED 0x00000010 +#define PCRE_DOLLAR_ENDONLY 0x00000020 +#define PCRE_EXTRA 0x00000040 +#define PCRE_NOTBOL 0x00000080 +#define PCRE_NOTEOL 0x00000100 +#define PCRE_UNGREEDY 0x00000200 +#define PCRE_NOTEMPTY 0x00000400 +#define PCRE_UTF8 0x00000800 +#define PCRE_NO_AUTO_CAPTURE 0x00001000 +#define PCRE_NO_UTF8_CHECK 0x00002000 +#define PCRE_AUTO_CALLOUT 0x00004000 +#define PCRE_PARTIAL 0x00008000 +#define PCRE_DFA_SHORTEST 0x00010000 +#define PCRE_DFA_RESTART 0x00020000 +#define PCRE_FIRSTLINE 0x00040000 +#define PCRE_DUPNAMES 0x00080000 +#define PCRE_NEWLINE_CR 0x00100000 +#define PCRE_NEWLINE_LF 0x00200000 +#define PCRE_NEWLINE_CRLF 0x00300000 +#define PCRE_NEWLINE_ANY 0x00400000 + +/* Exec-time and get/set-time error codes */ + +#define PCRE_ERROR_NOMATCH (-1) +#define PCRE_ERROR_NULL (-2) +#define PCRE_ERROR_BADOPTION (-3) +#define PCRE_ERROR_BADMAGIC (-4) +#define PCRE_ERROR_UNKNOWN_OPCODE (-5) +#define PCRE_ERROR_UNKNOWN_NODE (-5) /* For backward compatibility */ +#define PCRE_ERROR_NOMEMORY (-6) +#define PCRE_ERROR_NOSUBSTRING (-7) +#define PCRE_ERROR_MATCHLIMIT (-8) +#define PCRE_ERROR_CALLOUT (-9) /* Never used by PCRE itself */ +#define PCRE_ERROR_BADUTF8 (-10) +#define PCRE_ERROR_BADUTF8_OFFSET (-11) +#define PCRE_ERROR_PARTIAL (-12) +#define PCRE_ERROR_BADPARTIAL (-13) +#define PCRE_ERROR_INTERNAL (-14) +#define PCRE_ERROR_BADCOUNT (-15) +#define PCRE_ERROR_DFA_UITEM (-16) +#define PCRE_ERROR_DFA_UCOND (-17) +#define PCRE_ERROR_DFA_UMLIMIT (-18) +#define PCRE_ERROR_DFA_WSSIZE (-19) +#define PCRE_ERROR_DFA_RECURSE (-20) +#define PCRE_ERROR_RECURSIONLIMIT (-21) +#define PCRE_ERROR_NULLWSLIMIT (-22) +#define PCRE_ERROR_BADNEWLINE (-23) + +/* Request types for pcre_fullinfo() */ + +#define PCRE_INFO_OPTIONS 0 +#define PCRE_INFO_SIZE 1 +#define PCRE_INFO_CAPTURECOUNT 2 +#define PCRE_INFO_BACKREFMAX 3 +#define PCRE_INFO_FIRSTBYTE 4 +#define PCRE_INFO_FIRSTCHAR 4 /* For backwards compatibility */ +#define PCRE_INFO_FIRSTTABLE 5 +#define PCRE_INFO_LASTLITERAL 6 +#define PCRE_INFO_NAMEENTRYSIZE 7 +#define PCRE_INFO_NAMECOUNT 8 +#define PCRE_INFO_NAMETABLE 9 +#define PCRE_INFO_STUDYSIZE 10 +#define PCRE_INFO_DEFAULT_TABLES 11 + +/* Request types for pcre_config(). Do not re-arrange, in order to remain +compatible. */ + +#define PCRE_CONFIG_UTF8 0 +#define PCRE_CONFIG_NEWLINE 1 +#define PCRE_CONFIG_LINK_SIZE 2 +#define PCRE_CONFIG_POSIX_MALLOC_THRESHOLD 3 +#define PCRE_CONFIG_MATCH_LIMIT 4 +#define PCRE_CONFIG_STACKRECURSE 5 +#define PCRE_CONFIG_UNICODE_PROPERTIES 6 +#define PCRE_CONFIG_MATCH_LIMIT_RECURSION 7 + +/* Bit flags for the pcre_extra structure. Do not re-arrange or redefine +these bits, just add new ones on the end, in order to remain compatible. */ + +#define PCRE_EXTRA_STUDY_DATA 0x0001 +#define PCRE_EXTRA_MATCH_LIMIT 0x0002 +#define PCRE_EXTRA_CALLOUT_DATA 0x0004 +#define PCRE_EXTRA_TABLES 0x0008 +#define PCRE_EXTRA_MATCH_LIMIT_RECURSION 0x0010 + +/* Types */ + +struct real_pcre; /* declaration; the definition is private */ +typedef struct real_pcre pcre; + +/* When PCRE is compiled as a C++ library, the subject pointer type can be +replaced with a custom type. For conventional use, the public interface is a +const char *. */ + +#ifndef PCRE_SPTR +#define PCRE_SPTR const char * +#endif + +/* The structure for passing additional data to pcre_exec(). This is defined in +such as way as to be extensible. Always add new fields at the end, in order to +remain compatible. */ + +typedef struct pcre_extra { + unsigned long int flags; /* Bits for which fields are set */ + void *study_data; /* Opaque data from pcre_study() */ + unsigned long int match_limit; /* Maximum number of calls to match() */ + void *callout_data; /* Data passed back in callouts */ + const unsigned char *tables; /* Pointer to character tables */ + unsigned long int match_limit_recursion; /* Max recursive calls to match() */ +} pcre_extra; + +/* The structure for passing out data via the pcre_callout_function. We use a +structure so that new fields can be added on the end in future versions, +without changing the API of the function, thereby allowing old clients to work +without modification. */ + +typedef struct pcre_callout_block { + int version; /* Identifies version of block */ + /* ------------------------ Version 0 ------------------------------- */ + int callout_number; /* Number compiled into pattern */ + int *offset_vector; /* The offset vector */ + PCRE_SPTR subject; /* The subject being matched */ + int subject_length; /* The length of the subject */ + int start_match; /* Offset to start of this match attempt */ + int current_position; /* Where we currently are in the subject */ + int capture_top; /* Max current capture */ + int capture_last; /* Most recently closed capture */ + void *callout_data; /* Data passed in with the call */ + /* ------------------- Added for Version 1 -------------------------- */ + int pattern_position; /* Offset to next item in the pattern */ + int next_item_length; /* Length of next item in the pattern */ + /* ------------------------------------------------------------------ */ +} pcre_callout_block; + +/* Indirection for store get and free functions. These can be set to +alternative malloc/free functions if required. Special ones are used in the +non-recursive case for "frames". There is also an optional callout function +that is triggered by the (?) regex item. For Virtual Pascal, these definitions +have to take another form. */ + +#ifdef PCRE_EXPORTS + +#ifndef VPCOMPAT +PCRE_DATA_SCOPE void *(*pcre_malloc)(size_t); +PCRE_DATA_SCOPE void (*pcre_free)(void *); +PCRE_DATA_SCOPE void *(*pcre_stack_malloc)(size_t); +PCRE_DATA_SCOPE void (*pcre_stack_free)(void *); +PCRE_DATA_SCOPE int (*pcre_callout)(pcre_callout_block *); +#else /* VPCOMPAT */ +PCRE_DATA_SCOPE void *pcre_malloc(size_t); +PCRE_DATA_SCOPE void pcre_free(void *); +PCRE_DATA_SCOPE void *pcre_stack_malloc(size_t); +PCRE_DATA_SCOPE void pcre_stack_free(void *); +PCRE_DATA_SCOPE int pcre_callout(pcre_callout_block *); +#endif /* VPCOMPAT */ + +/* Exported PCRE functions */ + +PCRE_DATA_SCOPE pcre *pcre_compile(const char *, int, const char **, int *, + const unsigned char *); +PCRE_DATA_SCOPE pcre *pcre_compile2(const char *, int, int *, const char **, + int *, const unsigned char *); +PCRE_DATA_SCOPE int pcre_config(int, void *); +PCRE_DATA_SCOPE int pcre_copy_named_substring(const pcre *, const char *, + int *, int, const char *, char *, int); +PCRE_DATA_SCOPE int pcre_copy_substring(const char *, int *, int, int, char *, + int); +PCRE_DATA_SCOPE int pcre_dfa_exec(const pcre *, const pcre_extra *, + const char *, int, int, int, int *, int , int *, int); +PCRE_DATA_SCOPE int pcre_exec(const pcre *, const pcre_extra *, PCRE_SPTR, + int, int, int, int *, int); +PCRE_DATA_SCOPE void pcre_free_substring(const char *); +PCRE_DATA_SCOPE void pcre_free_substring_list(const char **); +PCRE_DATA_SCOPE int pcre_fullinfo(const pcre *, const pcre_extra *, int, + void *); +PCRE_DATA_SCOPE int pcre_get_named_substring(const pcre *, const char *, + int *, int, const char *, const char **); +PCRE_DATA_SCOPE int pcre_get_stringnumber(const pcre *, const char *); +PCRE_DATA_SCOPE int pcre_get_stringtable_entries(const pcre *, const char *, + char **, char **); +PCRE_DATA_SCOPE int pcre_get_substring(const char *, int *, int, int, + const char **); +PCRE_DATA_SCOPE int pcre_get_substring_list(const char *, int *, int, + const char ***); +PCRE_DATA_SCOPE int pcre_info(const pcre *, int *, int *); +PCRE_DATA_SCOPE const unsigned char *pcre_maketables(void); +PCRE_DATA_SCOPE int pcre_refcount(pcre *, int); +PCRE_DATA_SCOPE pcre_extra *pcre_study(const pcre *, int, const char **); +PCRE_DATA_SCOPE const char *pcre_version(void); + +#endif /* PCRE_EXPORTS */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* End of pcre.h */ -- cgit v1.2.3