From 171e81205e357e0d54283a63997ed58ff97d54a9 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Tue, 24 Jul 2012 11:48:31 +0000 Subject: UserInfoEx, Variables: changed folder structure git-svn-id: http://svn.miranda-ng.org/main/trunk@1160 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/UserInfoEx/src/classPsTreeItem.cpp | 697 +++++++++++++++++++++++++++++ 1 file changed, 697 insertions(+) create mode 100644 plugins/UserInfoEx/src/classPsTreeItem.cpp (limited to 'plugins/UserInfoEx/src/classPsTreeItem.cpp') diff --git a/plugins/UserInfoEx/src/classPsTreeItem.cpp b/plugins/UserInfoEx/src/classPsTreeItem.cpp new file mode 100644 index 0000000000..4f8b641691 --- /dev/null +++ b/plugins/UserInfoEx/src/classPsTreeItem.cpp @@ -0,0 +1,697 @@ +/* +UserinfoEx plugin for Miranda IM + +Copyright: +ฉ 2006-2010 DeathAxe, Yasnovidyashii, Merlin, K. Romanov, Kreol + +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. + +=============================================================================== + +File name : $HeadURL: https://userinfoex.googlecode.com/svn/trunk/classPsTreeItem.cpp $ +Revision : $Revision: 187 $ +Last change on : $Date: 2010-09-08 16:05:54 +0400 (ะกั€, 08 ัะตะฝ 2010) $ +Last change by : $Author: ing.u.horn $ + +=============================================================================== +*/ + +#include "commonheaders.h" +#include "dlg_propsheet.h" +#include "m_skin.h" + +/** + * name: BoldGroupTitlesEnumChildren() + * desc: set font of groupboxes to bold + * + * return: 0 + **/ +BOOL CALLBACK BoldGroupTitlesEnumChildren(HWND hWnd, LPARAM lParam) +{ + TCHAR szClass[64]; + GetClassName(hWnd, szClass, 64); + if (!mir_tcscmp(szClass, _T("Button")) && (GetWindowLongPtr(hWnd, GWL_STYLE) & 0x0F) == BS_GROUPBOX) + SendMessage(hWnd, WM_SETFONT, lParam, NULL); + return TRUE; +} + +/** + * name: CPsTreeItem + * class: CPsTreeItem + * desc: default constructor + * param: pPsh - propertysheet's init structure + * odp - optiondialogpage structure with the info about the item to add + * return: nothing + **/ +CPsTreeItem::CPsTreeItem() +{ + _idDlg = NULL; + _pTemplate = NULL; + _hInst = NULL; + _pfnDlgProc = NULL; + _hWnd = NULL; + _dwFlags = NULL; + _hItem = NULL; // handle to the treeview item + _iParent = -1; // index to the parent item + _iImage = -1; // index of treeview item's image + _bState = NULL; // initial state of this treeitem + _pszName = NULL; // original name, given by plugin (not customized) + _ptszLabel = NULL; + _pszProto = NULL; + _pszPrefix = NULL; + _hContact = NULL; +} + +/** + * name: ~CPsTreeItem + * class: CPsTreeItem + * desc: default destructor + * param: none + * return: nothing + **/ +CPsTreeItem::~CPsTreeItem() +{ + if (_hWnd) DestroyWindow(_hWnd); + if (_pszName) mir_free(_pszName); + if (_ptszLabel) mir_free(_ptszLabel); + if (_pszProto) mir_free((LPVOID)_pszProto); +} + +/** + * name: PropertyKey + * class: CPsTreeItem + * desc: merge the treeitem's unique name with a prefix to form a setting string + * param: pszProperty - the prefix to add + * return: pointer to the setting string + **/ +LPCSTR CPsTreeItem::PropertyKey(LPCSTR pszProperty) +{ + static CHAR pszSetting[MAXSETTING]; + mir_snprintf(pszSetting, SIZEOF(pszSetting), "{%s\\%s}_%s", _pszPrefix, _pszName, pszProperty); + return pszSetting; +} + +/** + * name: GlobalName + * class: CPsTreeItem + * desc: return item name without prepended protocol name + * param: nothing + * return: item name without protocol name + **/ +LPCSTR CPsTreeItem::GlobalName() +{ + LPSTR pgn = NULL; + + if (_dwFlags & PSPF_PROTOPREPENDED) + { + pgn = mir_strchr(_pszName, '\\'); + if (pgn && pgn[1]) pgn++; + } + return (!pgn || !*pgn) ?_pszName : pgn; +} + +/** + * name: GlobalPropertyKey + * class: CPsTreeItem + * desc: merge the treeitem's unique name with a prefix to form a setting string + * param: pszProperty - the prefix to add + * return: pointer to the setting string + **/ +LPCSTR CPsTreeItem::GlobalPropertyKey(LPCSTR pszProperty) +{ + static CHAR pszSetting[MAXSETTING]; + mir_snprintf(pszSetting, SIZEOF(pszSetting), "{Global\\%s}_%s", GlobalName(), pszProperty); + return pszSetting; +} + +/** + * name: IconKey + * class: CPsTreeItem + * desc: merge the treeitem's unique name with a prefix to form a setting string + * param: pszProperty - the prefix to add + * return: pointer to the setting string + **/ +LPCSTR CPsTreeItem::IconKey() +{ + LPCSTR pszIconName = GlobalName(); + if (pszIconName) + { + static CHAR pszSetting[MAXSETTING]; + mir_snprintf(pszSetting, SIZEOF(pszSetting), MODNAME"_{%s}", pszIconName); + return pszSetting; + } + return NULL; +} + +/** + * name: ParentItemName() + * class: CPsTreeItem + * desc: returns the unique name for the parent item + * param: nothing + * return: length of group name + **/ +LPSTR CPsTreeItem::ParentItemName() +{ + DBVARIANT dbv; + LPSTR result; + + // try to read the parent item from the database + if (!DB::Setting::GetAString(NULL, MODNAME, PropertyKey(SET_ITEM_GROUP), &dbv)) + { + result = dbv.pszVal; + } + else + { + const CHAR* p = mir_strrchr(_pszName, '\\'); + + if (p) + { + INT cchGroup = p - _pszName + 1; + result = mir_strncpy((LPSTR)mir_alloc(cchGroup), _pszName, cchGroup); + } + else + { + result = NULL; + } + } + return result; +} + +/** + * name: SetName + * class: CPsTreeItem + * desc: set the unique name for this item from a given title as it comes with OPTIONDIALOGPAGE + * param: ptszTitle - the title which is the base for the unique name + * bIsUnicode - if TRUE the title is unicode + * return: 0 on success, 1 to 4 indicating the failed operation + **/ +INT CPsTreeItem::Name(LPTSTR ptszTitle, const BOOLEAN bIsUnicode) +{ + // convert title to utf8 + _pszName = (bIsUnicode) ? mir_utf8encodeW((LPWSTR)ptszTitle) : mir_utf8encode((LPSTR)ptszTitle); + if (_pszName) + { + // convert disallowed characters + for (DWORD i = 0; _pszName[i] != 0; i++) + { + switch (_pszName[i]) + { + case '{': _pszName[i] = '('; break; + case '}': _pszName[i] = ')'; break; + } + } + } + return _pszName == NULL; +} + +/** + * name: HasName + * class: CPsTreeItem + * desc: returns true, if current item has the name provided by the parameter + * params: pszName - the name to match the item with + * return: nothing + **/ +BOOLEAN CPsTreeItem::HasName(const LPCSTR pszName) const +{ + return !mir_stricmp(_pszName, pszName); +}; + +/** + * name: Rename + * class: CPsTreeItem + * desc: Rename label for the treeitem + * params: pszLabel - the desired new label + * return: nothing + **/ +VOID CPsTreeItem::Rename(const LPTSTR pszLabel) +{ + if(pszLabel && *pszLabel) + { + LPTSTR pszDup = mir_tcsdup(pszLabel); + if(pszDup) + { + if(_ptszLabel) + { + mir_free(_ptszLabel); + } + _ptszLabel = pszDup; + // convert disallowed characters + while(*pszDup) + { + switch(*pszDup) + { + case '{': *pszDup = '('; break; + case '}': *pszDup = ')'; break; + } + pszDup++; + } + AddFlags(PSTVF_LABEL_CHANGED); + } + } +} + +/** + * name: ItemLabel + * class: CPsTreeItem + * desc: returns the label for a given item. The returned value must be freed after use! + * param: pszName - uniquely identifiing string for a propertypage encoded with utf8 (e.g.: {group\item}) + * return: Label in a newly allocated piece of memory + **/ +INT CPsTreeItem::ItemLabel(const BOOLEAN bReadDBValue) +{ + DBVARIANT dbv; + + // clear existing + if (_ptszLabel) + { + mir_free(_ptszLabel); + } + + // try to get custom label from database + if (!bReadDBValue || DB::Setting::GetTString(NULL, MODNAME, GlobalPropertyKey(SET_ITEM_LABEL), &dbv) || (_ptszLabel = dbv.ptszVal) == NULL) + { + // extract the name + LPSTR pszName = mir_strrchr(_pszName, '\\'); + if (pszName && pszName[1]) + { + pszName++; + } + else + { + pszName = _pszName; + } + + LPTSTR ptszLabel = mir_utf8decodeT(pszName); + if (ptszLabel) + { + _ptszLabel = mir_tcsdup(TranslateTS(ptszLabel)); + mir_free(ptszLabel); + } + } + // return nonezero if label is invalid + return _ptszLabel == NULL; +} + +/** + * name: ProtoIcon + * class: CPsTreeItem + * desc: check if current tree item name is a protocol name and return its icon if so + * params: none + * return: nothing + **/ +HICON CPsTreeItem::ProtoIcon() +{ + PROTOACCOUNT **pa; + INT ProtoCount, i; + + if (!CallService(MS_PROTO_ENUMACCOUNTS, (WPARAM)&ProtoCount, (LPARAM)&pa)) + { + if (_pszName) + { + for (i = 0; i < ProtoCount; i++) + { + if (pa[i]->type == PROTOTYPE_PROTOCOL) + { + TCHAR *ptszName = mir_a2t(_pszName); + if (!mir_tcsnicmp(pa[i]->tszAccountName, ptszName, mir_tcslen(pa[i]->tszAccountName))) + { + HICON hIco; + CHAR szIconID[MAX_PATH]; + + mir_snprintf(szIconID, SIZEOF(szIconID), "core_status_%s1", pa[i]->szModuleName); + hIco = IcoLib_GetIcon(szIconID); + if (!hIco) + { + hIco = (HICON)CallProtoService(pa[i]->szModuleName, PS_LOADICON, PLI_PROTOCOL, NULL); + } + MIR_FREE (ptszName); + return hIco; + } + MIR_FREE (ptszName); + } + } + } + } + return NULL; +} + +/** + * name: Icon + * class: CPsTreeItem + * desc: load the icon, add to icolib if required and add to imagelist of treeview + * params: hIml - treeview's imagelist to add the icon to + * odp - pointer to OPTIONSDIALOGPAGE providing the information about the icon to load + * hDefaultIcon - default icon to use + * return: nothing + **/ +INT CPsTreeItem::Icon(HIMAGELIST hIml, OPTIONSDIALOGPAGE *odp, BOOLEAN bInitIconsOnly) +{ + HICON hIcon; + + // check parameter + if (!_pszName || !odp) + return 1; + + // load the icon if no icolib is installed or creating the required settingname failed + LPCSTR pszIconName = IconKey(); + + // use icolib to handle icons + if (!(hIcon = IcoLib_GetIcon(pszIconName))) + { + SKINICONDESC sid; + + ZeroMemory(&sid, sizeof(sid)); + sid.cbSize = sizeof(sid); + sid.flags = SIDF_ALL_TCHAR; + sid.cx = GetSystemMetrics(SM_CXSMICON); + sid.cy = GetSystemMetrics(SM_CYSMICON); + sid.pszName = (LPSTR)pszIconName; + sid.ptszDescription = _ptszLabel; + sid.ptszSection = LPGENT(SECT_TREE); + + // the item to insert brings along an icon? + if (odp->flags & ODPF_ICON) { + // is it uinfoex item? + if (odp->hInstance == ghInst) { + + // the pszGroup holds the iconfile for items added by uinfoex + sid.ptszDefaultFile = odp->ptszGroup; + + // icon library exists? + if (sid.ptszDefaultFile) { + sid.iDefaultIndex = (INT_PTR)odp->hIcon; + } + // no valid icon library + else { + sid.hDefaultIcon = ImageList_GetIcon(hIml, 0, ILD_NORMAL);; + sid.iDefaultIndex = -1; + } + } + // default icon is delivered by the page to add + else { + sid.hDefaultIcon = (odp->hIcon) ? odp->hIcon : ImageList_GetIcon(hIml, 0, ILD_NORMAL); + sid.iDefaultIndex = -1; + } + } + // no icon to add, use default + else { + sid.iDefaultIndex = -1; + sid.hDefaultIcon = ProtoIcon(); + if (!sid.hDefaultIcon) sid.hDefaultIcon = ImageList_GetIcon(hIml, 0, ILD_NORMAL); + } + // add file to icolib + Skin_AddIcon(&sid); + + if (!bInitIconsOnly) + hIcon = IcoLib_GetIcon(pszIconName); + } + + if (!bInitIconsOnly && hIml) { + // set custom icon to image list + if (hIcon) return ((_iImage = ImageList_AddIcon(hIml, hIcon)) == -1); + _iImage = 0; + } + else + _iImage = -1; + return 0; +} + +/** + * name: OnAddPage + * class: CPsTreeItem + * desc: inits the treeitem's attributes + * params: pPsh - pointer to the property page's header structure + * odp - OPTIONSDIALOGPAGE structure with the information about the page to add + * return: 0 on success, 1 on failure + **/ +INT CPsTreeItem::Create(CPsHdr* pPsh, OPTIONSDIALOGPAGE *odp) +{ + INT err; + TCHAR szTitle[ MAXSETTING ]; + + // check parameter + if (pPsh && pPsh->_dwSize == sizeof(CPsHdr) && odp && PtrIsValid(odp->hInstance)) + { + // instance value + _hInst = odp->hInstance; + _dwFlags = odp->flags; + _initParam = odp->dwInitParam; + + // init page owning contact + _hContact = pPsh->_hContact; + _pszProto = mir_strdup(pPsh->_pszProto); + + // global settings prefix for current contact (is dialog owning contact's protocol by default) + _pszPrefix = (pPsh->_pszPrefix) ? pPsh->_pszPrefix : "Owner"; + + if (pPsh->_dwFlags & PSF_PROTOPAGESONLY) + { + if (_dwFlags & ODPF_USERINFOTAB) + { + mir_sntprintf(szTitle, SIZEOF(szTitle), _T("%s %d\\%s"), odp->ptszTitle, pPsh->_nSubContact+1, odp->ptszTab); + } + else + { + mir_sntprintf(szTitle, SIZEOF(szTitle), _T("%s %d"), odp->ptszTitle, pPsh->_nSubContact+1); + } + } + else + { + if (_dwFlags & ODPF_USERINFOTAB) + { + mir_sntprintf(szTitle, SIZEOF(szTitle), _T("%s\\%s"), odp->ptszTitle, odp->ptszTab); + } + else + { + mir_tcscpy(szTitle, odp->ptszTitle); + } + } + // set the unique utf8 encoded name for the item + if (err = Name(szTitle, (_dwFlags & ODPF_UNICODE) == ODPF_UNICODE)) + { + MsgErr(NULL, LPGENT("Creating unique name for a page failed with %d and error code %d"), err, GetLastError()); + } + // read label from database or create it + else if (err = ItemLabel(TRUE)) + { + MsgErr(NULL, LPGENT("Creating the label for a page failed with %d and error code %d"), err, GetLastError()); + } + else + { + // load icon for the item + Icon(pPsh->_hImages, odp, (pPsh->_dwFlags & PSTVF_INITICONS) == PSTVF_INITICONS); + + // the rest is not needed if only icons are loaded + if (pPsh->_dwFlags & PSTVF_INITICONS) + { + return 0; + } + + // load custom order + if (!(pPsh->_dwFlags & PSTVF_SORTTREE)) + { + _iPosition = (INT)DB::Setting::GetByte(PropertyKey(SET_ITEM_POS), odp->position); + if ((_iPosition < 0) && (_iPosition > 0x800000A)) + _iPosition = 0; + } + // read visibility state + _bState = DB::Setting::GetByte(PropertyKey(SET_ITEM_STATE), DBTVIS_EXPANDED); + + // error for no longer supported dialog template type + if (((UINT_PTR)odp->pszTemplate & 0xFFFF0000)) + { + MsgErr(NULL, LPGENT("The dialog template type is no longer supported")); + } + else + { + // fetch dialog resource id + _idDlg = (INT_PTR)odp->pszTemplate; + // dialog procedure + _pfnDlgProc = odp->pfnDlgProc; + + // is dummy item? + if (!_idDlg && !_pfnDlgProc) + return 0; + + if (_idDlg && _pfnDlgProc) + { + // lock the property pages dialog resource + _pTemplate = (DLGTEMPLATE*)LockResource(LoadResource(_hInst, FindResource(_hInst, (LPCTSTR)(UINT_PTR)_idDlg, RT_DIALOG))); + if (_pTemplate) + { + return 0; + } + } + } + } + } + return 1; +} + +/** + * name: DBSaveItemState + * class: CPsTreeItem + * desc: saves the current treeitem to database + * param: pszGroup - name of the parent item + * iItemPosition - iterated index to remember the order of the tree + * iState - expanded|collapsed|invisible + * dwFlags - tells what to save + * return: handle to new (moved) treeitem if successful or NULL otherwise + **/ +WORD CPsTreeItem::DBSaveItemState(LPCSTR pszGroup, INT iItemPosition, UINT iState, DWORD dwFlags) +{ + WORD numErrors = 0; + + // save group + if ((dwFlags & PSTVF_GROUPS) && (dwFlags & PSTVF_POS_CHANGED)) { + numErrors += DB::Setting::WriteUString(PropertyKey(SET_ITEM_GROUP), (LPSTR)pszGroup); + } + // save label + if ((dwFlags & PSTVF_LABEL_CHANGED) && (_dwFlags & PSTVF_LABEL_CHANGED)) { + numErrors += DB::Setting::WriteTString(GlobalPropertyKey(SET_ITEM_LABEL), Label()); + } + // save position + if ((dwFlags & PSTVF_POS_CHANGED) && !(dwFlags & PSTVF_SORTTREE)) { + numErrors += DB::Setting::WriteByte(PropertyKey(SET_ITEM_POS), iItemPosition); + } + // save state + if (dwFlags & PSTVF_STATE_CHANGED) { + numErrors += DB::Setting::WriteByte(PropertyKey(SET_ITEM_STATE), + _hItem ? ((iState & TVIS_EXPANDED) ? DBTVIS_EXPANDED : DBTVIS_NORMAL) : DBTVIS_INVISIBLE); + } + RemoveFlags(PSTVF_STATE_CHANGED|PSTVF_LABEL_CHANGED|PSTVF_POS_CHANGED); + return numErrors; +} + +/** + * name: CreateWnd + * class: CPsTreeItem + * desc: create the dialog for the propertysheet page + * params: pPs - propertysheet's datastructure + * hDlg - windowhandle of the propertysheet + * return: windowhandle of the dialog if successful + **/ +HWND CPsTreeItem::CreateWnd(LPPS pPs) +{ + if (pPs && !_hWnd && _pTemplate && _pfnDlgProc) + { + _hWnd = CreateDialogIndirectParam(_hInst, _pTemplate, pPs->hDlg, _pfnDlgProc, (LPARAM)_hContact); + if (_hWnd != NULL) + { + PSHNOTIFY pshn; + + pshn.hdr.code = PSN_PARAMCHANGED; + pshn.hdr.hwndFrom = _hWnd; + pshn.hdr.idFrom = 0; + pshn.lParam = (LPARAM)_initParam; + SendMessage(_hWnd, WM_NOTIFY, 0, (LPARAM)&pshn); + + // force child window (mainly for AIM property page) + SetWindowLongPtr(_hWnd, GWL_STYLE, (GetWindowLongPtr(_hWnd, GWL_STYLE) & ~(WS_POPUP|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME)) | WS_CHILD); + SetWindowLongPtr(_hWnd, GWL_EXSTYLE, GetWindowLongPtr(_hWnd, GWL_EXSTYLE) & ~(WS_EX_APPWINDOW|WS_EX_STATICEDGE|WS_EX_CLIENTEDGE)); + SetParent(_hWnd, pPs->hDlg); + + // move dialog into the display area + SetWindowPos(_hWnd, HWND_TOP, + pPs->rcDisplay.left, pPs->rcDisplay.top, + pPs->rcDisplay.right - pPs->rcDisplay.left, + pPs->rcDisplay.bottom - pPs->rcDisplay.top, FALSE); + // set bold titles + if (_dwFlags & ODPF_BOLDGROUPS) + { + EnumChildWindows(_hWnd, BoldGroupTitlesEnumChildren, (LPARAM)pPs->hBoldFont); + } + + // some initial notifications + OnInfoChanged(); + OnPageIconsChanged(); + return _hWnd; + } + } + return NULL; +} + +/*********************************************************************************************************** + * public event handlers + ***********************************************************************************************************/ + +/** + * name: OnInfoChanged + * class: CPsTreeItem + * desc: Notifies the propertypage of changed contact information + * params: none + * return: nothing + **/ +VOID CPsTreeItem::OnInfoChanged() +{ + if (_hWnd) { + PSHNOTIFY pshn; + + pshn.hdr.code = PSN_INFOCHANGED; + pshn.hdr.hwndFrom = _hWnd; + pshn.hdr.idFrom = 0; + pshn.lParam = (LPARAM)_hContact; + if (PSP_CHANGED != SendMessage(_hWnd, WM_NOTIFY, 0, (LPARAM)&pshn)) { + _dwFlags &= ~PSPF_CHANGED; + } + } +} + +/** + * name: OnPageIconsChanged + * class: CPsTreeItem + * desc: Notifies the propertypage of changed icons in icolib + * params: none + * return: nothing + **/ +VOID CPsTreeItem::OnPageIconsChanged() +{ + if (_hWnd) { + PSHNOTIFY pshn; + + pshn.hdr.code = PSN_ICONCHANGED; + pshn.hdr.hwndFrom = _hWnd; + pshn.hdr.idFrom = 0; + pshn.lParam = (LPARAM)_hContact; + SendMessage(_hWnd, WM_NOTIFY, 0, (LPARAM)&pshn); + } +} + +/** + * name: OnIconsChanged + * class: CPsTreeItem + * desc: Handles reloading icons if changed by icolib + * params: none + * return: nothing + **/ +VOID CPsTreeItem::OnIconsChanged(CPsTree *pTree) +{ + HICON hIcon; + RECT rc; + + // update tree item icons + if (pTree->ImageList() && (hIcon = IcoLib_GetIcon(IconKey())) != NULL) { + _iImage = (_iImage > 0) + ? ImageList_ReplaceIcon(pTree->ImageList(), _iImage, hIcon) + : ImageList_AddIcon(pTree->ImageList(), hIcon); + + if (_hItem && TreeView_GetItemRect(pTree->Window(), _hItem, &rc, 0)) { + InvalidateRect(pTree->Window(), &rc, TRUE); + } + } + // update pages icons + OnPageIconsChanged(); +} + -- cgit v1.2.3