diff options
Diffstat (limited to 'plugins')
| -rw-r--r-- | plugins/CSList/src/cslist.cpp | 2085 | 
1 files changed, 1042 insertions, 1043 deletions
| diff --git a/plugins/CSList/src/cslist.cpp b/plugins/CSList/src/cslist.cpp index 645850d5e6..de5baa57a5 100644 --- a/plugins/CSList/src/cslist.cpp +++ b/plugins/CSList/src/cslist.cpp @@ -1,1043 +1,1042 @@ -/* ========================================================================
 -
 -                              Custom Status List
 -                              __________________
 -
 -  Custom Status List plugin for Miranda-IM (www.miranda-im.org)
 -  Follower of Custom Status History List by HANAX
 -  Copyright © 2006-2008 HANAX
 -  Copyright © 2007-2009 jarvis
 -  Occasionally rewritten in 2012 by George Hazan
 -
 -  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 "cslist.h"
 -#include "strpos.h"
 -
 -CLIST_INTERFACE *pcli;
 -int hLangpack;
 -HINSTANCE g_hInst;
 -
 -static LIST<CSWindow> arWindows(3, HandleKeySortT);
 -
 -PLUGININFOEX pluginInfoEx =
 -{
 -	sizeof(PLUGININFOEX),
 -	__PLUGIN_NAME,
 -	PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
 -	__DESCRIPTION,
 -	__AUTHOR,
 -	__AUTHOREMAIL,
 -	__COPYRIGHT,
 -	__AUTHORWEB,
 -	UNICODE_AWARE,
 -	// {C8CC7414-6507-4AF6-925A-83C1D2F7BE8C}
 -	{0xc8cc7414, 0x6507, 0x4af6, {0x92, 0x5a, 0x83, 0xc1, 0xd2, 0xf7, 0xbe, 0x8c}}
 -};
 -
 -// ====[ MAIN ]===============================================================
 -
 -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 -{
 -	g_hInst = hinstDLL;
 -	return TRUE;
 -}
 -
 -// ====[ PLUGIN INFO ]========================================================
 -
 -extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD)
 -{
 -	return &pluginInfoEx;
 -}
 -
 -// ====[ LOADER ]=============================================================
 -
 -static int OnDbChanged(WPARAM hContact, LPARAM lparam)
 -{
 -	DBCONTACTWRITESETTING *cws = ( DBCONTACTWRITESETTING* )lparam;
 -
 -	// if user changes his UIN or JID on any account
 -	if (hContact == NULL) {
 -		INT_PTR szUniqueID = CallProtoService(cws->szModule, PS_GETCAPS, PFLAG_UNIQUEIDSETTING, 0);
 -		if (szUniqueID != CALLSERVICE_NOTFOUND && !lstrcmpA(cws->szSetting, (char*)szUniqueID))
 -			pcli->pfnReloadProtoMenus();
 -	}
 -	return 0;
 -}
 -
 -static int OnInitOptions(WPARAM wparam, LPARAM lparam)
 -{
 -	OPTIONSDIALOGPAGE odp = { sizeof(odp) };
 -	odp.position = 955000000;
 -	odp.hInstance = g_hInst;
 -	odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS);
 -	odp.pszTitle = MODULENAME;
 -	odp.pfnDlgProc = CSOptionsProc;
 -	odp.pszGroup = LPGEN("Status");
 -	odp.flags = ODPF_BOLDGROUPS;
 -	Options_AddPage(wparam, &odp);
 -	return 0;
 -}
 -
 -static int OnCreateMenuItems(WPARAM, LPARAM)
 -{
 -	int protoCount;
 -	PROTOACCOUNT** pdesc;
 -	ProtoEnumAccounts(&protoCount, &pdesc);
 -
 -	for (int i = 0; i < protoCount; i++)
 -		if ( ProtoServiceExists(pdesc[i]->szModuleName, PS_SETCUSTOMSTATUSEX))
 -			addProtoStatusMenuItem(pdesc[i]->szModuleName);
 -
 -	return 0;
 -}
 -
 -static int OnPreshutdown(WPARAM wparam, LPARAM lparam)
 -{
 -	for (int i=0; i < arWindows.getCount(); i++)
 -		DestroyWindow(arWindows[i]->m_handle);
 -	return 0;
 -}
 -
 -extern "C" __declspec(dllexport) int Load()
 -{
 -	mir_getLP(&pluginInfoEx);
 -	mir_getCLI();
 -	
 -	// support for ComboBoxEx
 -	INITCOMMONCONTROLSEX icc;
 -	icc.dwSize = sizeof(icc);
 -	icc.dwICC = ICC_USEREX_CLASSES;
 -	InitCommonControlsEx(&icc);
 -
 -	// init icons
 -	TCHAR tszFile[MAX_PATH];
 -	GetModuleFileName( g_hInst, tszFile, MAX_PATH );
 -
 -	SKINICONDESC sid = { sizeof(sid) };
 -	sid.ptszDefaultFile = tszFile;
 -	sid.flags = SIDF_ALL_TCHAR;
 -	sid.cx = sid.cy = 16;
 -	sid.ptszSection = _T(MODULENAME);
 -
 -	for (int i=0; i < SIZEOF(forms); i++) {
 -		char szSettingName[64];
 -		mir_snprintf(szSettingName, SIZEOF(szSettingName), "%s_%s", MODNAME, forms[i].pszIconIcoLib);
 -
 -		sid.pszName = szSettingName;
 -		sid.ptszDescription = forms[i].ptszDescr;
 -		sid.iDefaultIndex = -forms[i].iconNoIcoLib;
 -		forms[i].hIcoLibItem = Skin_AddIcon(&sid);
 -	}
 -
 -	HookEvent(ME_OPT_INITIALISE, OnInitOptions);
 -	HookEvent(ME_DB_CONTACT_SETTINGCHANGED, OnDbChanged);
 -	HookEvent(ME_CLIST_PREBUILDSTATUSMENU, OnCreateMenuItems);
 -	HookEvent(ME_SYSTEM_PRESHUTDOWN, OnPreshutdown);
 -
 -	// if we load a plugin dynamically, it will work, otherwise fail
 -	OnCreateMenuItems(0, 0);
 -	return 0;
 -}
 -
 -// ====[ UNLOADER ]===========================================================
 -
 -extern "C" __declspec(dllexport) int Unload()
 -{
 -	return 0;
 -}
 -
 -// ====[ FUN ]================================================================
 -
 -void RegisterHotkeys(char buf[200], TCHAR* accName, int Number)
 -{
 -	HOTKEYDESC hotkey = { sizeof(hotkey) };
 -	hotkey.dwFlags = HKD_TCHAR;
 -	hotkey.pszName = buf;
 -	hotkey.ptszDescription = accName;
 -	hotkey.ptszSection = LPGENT("Custom Status List");
 -	hotkey.pszService = buf;
 -	hotkey.DefHotKey = HOTKEYCODE( HOTKEYF_CONTROL | HOTKEYF_SHIFT, '0' + Number);
 -	Hotkey_Register(&hotkey);
 -}
 -
 -void SetStatus(WORD code, StatusItem* item,  char *szAccName)
 -{
 -	if ( code == IDCLOSE )
 -		return;
 -
 -	PROTOACCOUNT* pdescr = (PROTOACCOUNT*)CallService(MS_PROTO_GETACCOUNT, 0, (LPARAM)szAccName);
 -	if (pdescr == NULL)
 -		return;
 -
 -	if ( !ProtoServiceExists(szAccName, PS_SETCUSTOMSTATUSEX))
 -		return;
 -
 -	int statusToSet;
 -
 -	CUSTOM_STATUS ics = { sizeof(CUSTOM_STATUS) };
 -	ics.flags = CSSF_MASK_STATUS | CSSF_MASK_NAME | CSSF_MASK_MESSAGE | CSSF_TCHAR;
 -
 -	if (code == IDC_CANCEL) {
 -		statusToSet = 0;
 -		ics.ptszName = _T("");
 -		ics.ptszMessage = _T("");
 -	}
 -	else if (code == IDOK && item != NULL) {
 -		statusToSet = item->m_iIcon+1;
 -		ics.ptszName = variables_parsedup(item->m_tszTitle, NULL, NULL);
 -		ics.ptszMessage = variables_parsedup(item->m_tszMessage, NULL, NULL);
 -	}
 -	else return;
 -
 -	ics.status = &statusToSet;
 -	ProtoCallService(szAccName, PS_SETCUSTOMSTATUSEX, 0, (LPARAM)&ics);
 -}
 -
 -INT_PTR showList(WPARAM wparam, LPARAM lparam, LPARAM param)
 -{
 -	char* szProto = (char*)param;
 -	for (int i=0; i < arWindows.getCount(); i++) {
 -		CSWindow *p = arWindows[i];
 -		if ( !strcmp(szProto, p->m_protoName)) {
 -			ShowWindow(p->m_handle, SW_SHOW);
 -			SetForegroundWindow(p->m_handle);
 -			return 1;
 -		}
 -	}
 -
 -	CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_CSLIST), NULL, CSWindowProc, (LPARAM)new CSWindow(szProto));
 -	return 0;
 -}
 -
 -void addProtoStatusMenuItem(char *protoName)
 -{
 -	PROTOACCOUNT *pdescr = ProtoGetAccount(protoName);
 -	if (pdescr == NULL)
 -		return;
 -
 -	HGENMENU hRoot = MO_GetProtoRootMenu(pdescr->szModuleName);
 -	if (hRoot == NULL)
 -		return;
 -
 -	char buf[200];
 -	mir_snprintf(buf, SIZEOF(buf), "CSList/ShowList/%s", protoName);
 -	if ( !ServiceExists(buf))
 -		CreateServiceFunctionParam(buf, showList, (LPARAM)protoName);
 -
 -	CLISTMENUITEM mi = { sizeof(mi) };
 -	mi.flags = CMIF_CHILDPOPUP | CMIF_TCHAR;
 -	mi.icolibItem = forms[0].hIcoLibItem;
 -	mi.ptszName = _T(MODULENAME);
 -	mi.position = 2000040000;
 -	mi.pszService = buf;
 -	mi.hParentMenu = hRoot;
 -	Menu_AddStatusMenuItem(&mi);
 -
 -	RegisterHotkeys(buf, pdescr->tszAccountName, pdescr->iOrder);
 -}
 -
 -///////////////////////////////////////////////////////////////////////////////
 -
 -void importCustomStatuses(CSWindow* csw, int result)
 -{
 -	DBVARIANT dbv;
 -	char bufTitle[32], bufMessage[32], *protoName = csw->m_protoName;
 -
 -	for (int i = 0; i < csw->m_statusCount; i++) {
 -		StatusItem* si = new StatusItem();
 -		si->m_iIcon = i-1;
 -
 -		mir_snprintf(bufTitle, 32, "XStatus%dName", i);
 -		if ( !db_get_ts( NULL, protoName, bufTitle, &dbv )) {
 -			lstrcpy(si->m_tszTitle, dbv.ptszVal);
 -			db_free(&dbv);
 -		}
 -		else si->m_tszTitle[0] = 0;
 -
 -		mir_snprintf(bufMessage, 32, "XStatus%dMsg", i);
 -		if ( !db_get_ts( NULL, protoName, bufMessage, &dbv )) {
 -			lstrcpy(si->m_tszMessage, dbv.ptszVal);
 -			db_free(&dbv);
 -		}
 -		else si->m_tszMessage[0] = 0;
 -
 -		if (si->m_tszTitle[0] || si->m_tszMessage[0]) {
 -			csw->m_itemslist->m_list->add(si);
 -			csw->m_bSomethingChanged = TRUE;
 -		}
 -		else delete si;
 -
 -		if (result == IDYES) {
 -			db_unset(NULL, protoName, bufTitle);
 -			db_unset(NULL, protoName, bufMessage);
 -		}
 -	}
 -	csw->m_listview->reinitItems(csw->m_itemslist->m_list->getListHead());
 -}
 -
 -///////////////////////////////////////////////////////////////////////////////
 -// CSWindow class
 -
 -CSWindow::CSWindow(char *protoName)
 -{
 -	m_protoName = protoName;
 -	m_handle = NULL;
 -	m_bExtraIcons = getByte( "AllowExtraIcons", DEFAULT_ALLOW_EXTRA_ICONS );
 -	m_itemslist = new CSItemsList(m_protoName);
 -	m_listview = NULL;
 -	m_addModifyDlg = NULL;
 -	m_bSomethingChanged = FALSE;
 -	m_filterString = NULL;
 -}
 -
 -void __fastcall SAFE_FREE(void** p)
 -{
 -	if (*p)
 -	{
 -		free(*p);
 -		*p = NULL;
 -	}
 -}
 -
 -CSWindow::~CSWindow()
 -{
 -	delete m_itemslist;
 -	SAFE_FREE(( void** )&m_filterString );
 -}
 -
 -void CSWindow::initIcons()
 -{
 -	PROTOACCOUNT *pdescr = ProtoGetAccount(m_protoName);
 -	if (pdescr == NULL)
 -		return;
 -
 -	char *szUniqueID = (char*)CallProtoService(m_protoName, PS_GETCAPS, PFLAG_UNIQUEIDSETTING, 0);
 -	if (szUniqueID == NULL)
 -		return;
 -
 -	DBVARIANT dbv;
 -	if ( db_get(NULL, pdescr->szModuleName, szUniqueID, &dbv))
 -		return;
 -	db_free(&dbv);
 -
 -	WPARAM iNumStatuses = 0;
 -	CUSTOM_STATUS cs = { sizeof(cs) };
 -	cs.flags = CSSF_STATUSES_COUNT;
 -	cs.wParam = &iNumStatuses;
 -	if ( CallProtoService(pdescr->szModuleName, PS_GETCUSTOMSTATUSEX, 0, (LPARAM)&cs) != 0)
 -		return;
 -
 -	m_statusCount = (int)iNumStatuses;
 -	if (NULL == (m_icons = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, m_statusCount, 0)))
 -		return;
 -
 -	for (int i=1; i <= m_statusCount; i++) {
 -		HICON hIcon = (HICON)CallProtoService(pdescr->szModuleName, PS_GETCUSTOMSTATUSICON, i, 0);
 -		if (hIcon) {
 -			ImageList_AddIcon(m_icons, hIcon);
 -			DestroyIcon(hIcon);
 -		}
 -	}
 -}
 -
 -void CSWindow::deinitIcons()
 -{
 -	ImageList_Destroy( m_icons );
 -}
 -
 -void CSWindow::initButtons()
 -{
 -	for (int i = 0; i < SIZEOF(forms); i++) {
 -		if ( forms[i].idc < 0 )
 -			continue;
 -
 -		SendDlgItemMessage( m_handle, forms[i].idc, BM_SETIMAGE, IMAGE_ICON, (LPARAM)Skin_GetIconByHandle(forms[i].hIcoLibItem));
 -		SendDlgItemMessage( m_handle, forms[i].idc, BUTTONSETASFLATBTN, TRUE, 0 ); //maybe set as BUTTONSETDEFAULT?
 -		SendDlgItemMessage( m_handle, forms[i].idc, BUTTONADDTOOLTIP, (WPARAM )TranslateTS(forms[i].ptszTitle), BATF_TCHAR );
 -	}
 -}
 -
 -void CSWindow::loadWindowPosition()
 -{
 -	if (getByte("RememberWindowPosition", DEFAULT_REMEMBER_WINDOW_POSITION))
 -		Utils_RestoreWindowPosition(m_handle, NULL, MODNAME, "Position");
 -}
 -
 -void CSWindow::toggleEmptyListMessage()
 -{
 -	HWND hwnd = GetDlgItem( m_handle, IDC_NO_ITEMS );
 -	ShowWindow( hwnd, ( ListView_GetItemCount( m_listview->m_handle ) > 0 ) ? FALSE : TRUE );
 -	SetForegroundWindow( hwnd );
 -	hwnd = GetDlgItem( m_handle, IDC_ADD_SAMPLE );
 -	ShowWindow( hwnd, ( ListView_GetItemCount( m_listview->m_handle ) > 0 ) ? FALSE : TRUE );
 -	SetForegroundWindow( hwnd );
 -}
 -
 -BOOL CSWindow::itemPassedFilter( ListItem< StatusItem >* li )
 -{
 -	TCHAR filter[MAX_PATH];
 -	GetDlgItemText( m_handle, IDC_FILTER_FIELD, filter, MAX_PATH );
 -
 -	if ( lstrlen( filter ))
 -	{
 -		TCHAR title[EXTRASTATUS_TITLE_LIMIT], message[EXTRASTATUS_MESSAGE_LIMIT];
 -		lstrcpy( title, li->m_item->m_tszTitle ); lstrcpy( message, li->m_item->m_tszMessage );
 -		if ( strpos( _tcslwr( title ), _tcslwr( filter )) == -1 )
 -			if ( strpos( _tcslwr( message ), _tcslwr( filter )) == -1 )
 -				return FALSE;
 -	}
 -
 -	return TRUE;
 -}
 -
 -void CSWindow::toggleFilter()
 -{
 -	HWND hFilter = GetDlgItem( m_handle, IDC_FILTER_FIELD );
 -	BOOL isEnabled = !IsWindowEnabled( hFilter ) ? TRUE : FALSE; // ! = + isEnabled = !isEnabled in one
 -	EnableWindow( hFilter, isEnabled );
 -	ShowWindow( hFilter, isEnabled );
 -	CheckDlgButton( m_handle, IDC_FILTER, isEnabled );
 -	SetForegroundWindow( hFilter );
 -	if ( isEnabled )
 -		SetFocus( hFilter );
 -	else
 -	{
 -		TCHAR filterText[255];
 -		GetDlgItemText(m_handle, IDC_FILTER_FIELD, filterText, SIZEOF(filterText));
 -		if (filterText[0] != 0)
 -			SetDlgItemText( m_handle, IDC_FILTER_FIELD, TEXT( ""));
 -	}
 -}
 -
 -BOOL CSWindow::toggleButtons()
 -{
 -	int selection = ListView_GetSelectedItemMacro( m_listview->m_handle );
 -	BOOL validSelection = ( selection >= 0 && ( unsigned int )selection < m_itemslist->m_list->getCount()) ? TRUE : FALSE;
 -	BOOL filterEnabled = IsWindowVisible( GetDlgItem( m_handle, IDC_FILTER_FIELD ));
 -	BOOL somethingChanged = m_bSomethingChanged;
 -
 -	EnableWindow( GetDlgItem( m_handle, IDC_ADD       ), !filterEnabled );
 -	EnableWindow( GetDlgItem( m_handle, IDC_MODIFY    ), validSelection && !filterEnabled );
 -	EnableWindow( GetDlgItem( m_handle, IDC_REMOVE    ), validSelection && !filterEnabled );
 -	EnableWindow( GetDlgItem( m_handle, IDC_FAVOURITE ), validSelection && !filterEnabled );
 -	EnableWindow( GetDlgItem( m_handle, IDC_UNDO      ), somethingChanged && !filterEnabled );
 -	EnableWindow( GetDlgItem( m_handle, IDC_IMPORT    ), !filterEnabled );
 -	EnableWindow( GetDlgItem( m_handle, IDOK          ), validSelection );
 -
 -	return validSelection;
 -}
 -
 -///////////////////////////////////////////////////////////////////////////////
 -// CSAMWindow class - add form window
 -
 -CSAMWindow::CSAMWindow( WORD action, CSWindow* parent )
 -{
 -	m_action = action;
 -	m_parent = parent;
 -	m_bChanged = FALSE;
 -	m_hCombo = m_hMessage = NULL;
 -
 -	if ( m_action == IDC_ADD )
 -		m_item = new StatusItem();
 -	else
 -		m_item = new StatusItem( *m_parent->m_itemslist->m_list->get( m_parent->m_listview->getPositionInList()) );
 -}
 -
 -CSAMWindow::~CSAMWindow()
 -{
 -	if ( !m_bChanged )
 -		delete m_item;
 -}
 -
 -void CSAMWindow::exec()
 -{
 -	DialogBoxParam( g_hInst, MAKEINTRESOURCE( IDD_ADDMODIFY ), NULL, CSAMWindowProc, (LPARAM)this );
 -}
 -
 -
 -void CSAMWindow::setCombo()
 -{
 -	PROTOACCOUNT *pdescr = ProtoGetAccount(m_parent->m_protoName);
 -	if (pdescr == NULL)
 -		return;
 -
 -	char *szUniqueID = (char*)CallProtoService(pdescr->szModuleName, PS_GETCAPS, PFLAG_UNIQUEIDSETTING, 0);
 -	if (szUniqueID == NULL)
 -		return;
 -
 -	DBVARIANT dbv;
 -	if ( db_get(NULL, pdescr->szModuleName, szUniqueID, &dbv))
 -		return;
 -	db_free(&dbv);
 -
 -	WPARAM iStatus;
 -	TCHAR tszName[100];
 -	CUSTOM_STATUS cs = { sizeof(cs) };
 -	cs.flags = CSSF_MASK_NAME | CSSF_DEFAULT_NAME | CSSF_TCHAR;
 -	cs.ptszName = tszName;
 -	cs.wParam = &iStatus;
 -
 -	SendMessage( m_hCombo, CBEM_SETIMAGELIST, 0, (LPARAM)m_parent->m_icons);
 -	for (int i=1; i <= m_parent->m_statusCount; i++) {
 -		iStatus = i;
 -		if ( CallProtoService(pdescr->szModuleName, PS_GETCUSTOMSTATUSEX, 0, (LPARAM)&cs) != 0)
 -			continue;
 -
 -		COMBOBOXEXITEM cbi = { 0 };
 -		cbi.mask = CBEIF_TEXT | CBEIF_IMAGE | CBEIF_SELECTEDIMAGE;
 -		cbi.iItem = -1;
 -		cbi.iImage = cbi.iSelectedImage = i-1;
 -		cbi.pszText = TranslateTS(tszName);
 -		SendMessage( m_hCombo, CBEM_INSERTITEM, 0, (LPARAM)&cbi );
 -	}
 -	SendMessage( m_hCombo, CB_SETCURSEL, 0, 0 ); // first 0 sets selection to top
 -}
 -
 -void CSAMWindow::fillDialog()
 -{
 -	if (m_action == IDC_ADD) {
 -		SetWindowText(m_handle, TranslateT("Add new item"));
 -		SetDlgItemText(m_handle, IDOK, TranslateT("Add"));
 -	}
 -	else {
 -		SetWindowText(m_handle, TranslateT("Modify item"));
 -		SetDlgItemText(m_handle, IDOK, TranslateT("Modify"));
 -	}
 -
 -	SendMessage(m_hCombo, CB_SETCURSEL, m_item->m_iIcon, 0);
 -	SetDlgItemText(m_handle, IDC_MESSAGE, m_item->m_tszMessage);
 -}
 -
 -void CSAMWindow::checkFieldLimit( WORD action, WORD item )
 -{
 -	BOOL type = ( item == IDC_MESSAGE ) ? TRUE : FALSE;
 -	unsigned int limit = type ? EXTRASTATUS_MESSAGE_LIMIT : EXTRASTATUS_TITLE_LIMIT;
 -
 -	if ( action == EN_CHANGE )
 -	{
 -		TCHAR* ptszInputText = (TCHAR*)mir_alloc((limit + 8) * sizeof(TCHAR));
 -
 -		GetDlgItemText( m_handle, item, ptszInputText, limit + 8 );
 -
 -		if ( _tcslen( ptszInputText ) > limit )
 -		{
 -#if ( WINVER >= 0x501 )
 -			TCHAR tszPopupTip[MAX_PATH];
 -			EDITBALLOONTIP ebt = { 0 };
 -			ebt.cbStruct = sizeof(ebt);
 -			ebt.pszTitle = TranslateT("Warning");
 -			mir_sntprintf(tszPopupTip, SIZEOF(tszPopupTip), TranslateT("This field doesn't accept string longer than %d characters. The string will be truncated."), limit);
 -			ebt.pszText = tszPopupTip;
 -			ebt.ttiIcon = TTI_WARNING;
 -			SendMessage( GetDlgItem( m_handle, item ), EM_SHOWBALLOONTIP, 0, (LPARAM)&ebt );
 -#endif
 -			TCHAR* ptszOutputText = (TCHAR*)mir_alloc((limit + 1) * sizeof(TCHAR));
 -			GetDlgItemText( m_handle, item, ptszOutputText, limit + 1 );
 -			SetDlgItemText( m_handle, item, ptszOutputText );
 -			mir_free( ptszOutputText );
 -		}
 -		mir_free( ptszInputText );
 -	}
 -}
 -
 -void CSAMWindow::checkItemValidity()
 -{
 -	COMBOBOXEXITEM cbi = { 0 };
 -	cbi.mask = CBEIF_IMAGE;
 -	cbi.iItem = SendDlgItemMessage(m_handle, IDC_COMBO, CB_GETCURSEL, 0, 0);
 -	SendDlgItemMessage( m_handle, IDC_COMBO, CBEM_GETITEM, 0, (LPARAM)&cbi );
 -
 -	if (m_item->m_iIcon != cbi.iImage)
 -		m_item->m_iIcon = cbi.iImage, m_bChanged = TRUE;
 -
 -	TCHAR tszInputMessage[EXTRASTATUS_MESSAGE_LIMIT];
 -
 -	GetDlgItemText( m_handle, IDC_MESSAGE, tszInputMessage, EXTRASTATUS_MESSAGE_LIMIT );
 -
 -	PROTOACCOUNT* pdescr = (PROTOACCOUNT*)CallService(MS_PROTO_GETACCOUNT, 0, (LPARAM)m_parent->m_protoName);
 -	if (pdescr == NULL)
 -		return;
 -
 -	WPARAM i = SendMessage(m_hCombo, CB_GETCURSEL, 0, 0)+1;
 -	TCHAR tszTitle[100];
 -
 -	CUSTOM_STATUS cs = { sizeof(cs) };
 -	cs.flags = CSSF_MASK_NAME | CSSF_DEFAULT_NAME | CSSF_TCHAR;
 -	cs.ptszName = tszTitle;
 -	cs.wParam = &i;
 -	if ( CallProtoService(pdescr->szModuleName, PS_GETCUSTOMSTATUSEX, 0, (LPARAM)&cs) == 0)
 -		lstrcpyn(m_item->m_tszTitle, TranslateTS(tszTitle), SIZEOF(m_item->m_tszTitle));
 -
 -	if ( lstrcmp(m_item->m_tszMessage, tszInputMessage))
 -		lstrcpy( m_item->m_tszMessage, tszInputMessage), m_bChanged = true;
 -}
 -
 -CSListView::CSListView(HWND hwnd, CSWindow* parent)
 -{
 -	m_handle = hwnd;
 -	m_parent = parent;
 -
 -#if (_WIN32_WINNT >= 0x501)
 -	LVGROUP lg = { 0 };
 -	lg.cbSize = sizeof(LVGROUP);
 -	lg.mask = LVGF_HEADER | LVGF_GROUPID;
 -
 -	lg.pszHeader = TranslateT("Favorites");
 -	lg.iGroupId = 0;
 -	ListView_InsertGroup( m_handle, -1, &lg );
 -
 -	lg.pszHeader = TranslateT("Regular statuses");
 -	lg.iGroupId = 1;
 -	ListView_InsertGroup( m_handle, -1, &lg );
 -	ListView_EnableGroupView( m_handle, TRUE );
 -#endif
 -
 -	LVCOLUMN lvc = { 0 };
 -	lvc.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM;
 -	lvc.fmt = LVCFMT_LEFT;
 -	lvc.cx = 0x00;
 -	lvc.pszText = TEXT( "");
 -	lvc.cx = 0x16;
 -	SendMessage( m_handle, LVM_INSERTCOLUMN, 0, (LPARAM)&lvc );
 -	lvc.pszText = TranslateT("Title");
 -	lvc.cx = 0x64;
 -	SendMessage( m_handle, LVM_INSERTCOLUMN, 1, (LPARAM)&lvc );
 -	lvc.pszText = TranslateT("Message");
 -	lvc.cx = 0xa8;
 -	SendMessage( m_handle, LVM_INSERTCOLUMN, 2, (LPARAM)&lvc );
 -
 -#if (_WIN32_IE >= 0x0400)
 -	ListView_SetExtendedListViewStyleEx( m_handle, 0, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_HEADERDRAGDROP | LVS_EX_INFOTIP );
 -#endif
 -	ListView_SetImageList(m_handle, m_parent->m_icons, LVSIL_SMALL);
 -}
 -
 -void CSListView::addItem( StatusItem* item, int itemNumber )
 -{
 -	LVITEM lvi = { 0 };
 -	lvi.mask = LVIF_IMAGE | LVIF_GROUPID | LVIF_PARAM;
 -	lvi.cchTextMax = 256;
 -	lvi.iItem = ListView_GetItemCount( m_handle );
 -	lvi.lParam = itemNumber;
 -	lvi.iGroupId = item->m_bFavourite ? 0 : 1;
 -
 -	// first column
 -	lvi.iSubItem = 0;
 -	lvi.iImage = item->m_iIcon; // use selected xicon
 -	SendMessage( m_handle, LVM_INSERTITEM, 0, (LPARAM)&lvi );
 -
 -	// second column
 -	lvi.mask = LVIF_TEXT;
 -	lvi.iSubItem = 1;
 -	lvi.pszText = item->m_tszTitle;
 -	SendMessage( m_handle, LVM_SETITEM, 0, (LPARAM)&lvi );
 -
 -	// third column
 -	lvi.iSubItem = 2;
 -	lvi.pszText = item->m_tszMessage;
 -	SendMessage( m_handle, LVM_SETITEM, 0, (LPARAM)&lvi );
 -}
 -
 -void CSListView::initItems( ListItem< StatusItem >* items )
 -{
 -	ListItem< StatusItem >* help = items;
 -	for ( int i = 0; help != NULL; help = help->m_next, i++ )
 -		if (m_parent->itemPassedFilter( help ))
 -			addItem( help->m_item, i );
 -}
 -
 -void CSListView::reinitItems( ListItem< StatusItem >* items )
 -{
 -	EnableWindow(m_handle, FALSE);
 -	removeItems();
 -	initItems(items);
 -	EnableWindow(m_handle, TRUE);
 -}
 -
 -void CSListView::removeItems()
 -{
 -	ListView_DeleteAllItems( m_handle );
 -}
 -
 -int CSListView::getPositionInList()
 -{
 -	LVITEM lvi = { 0 };
 -	lvi.iItem = ListView_GetSelectedItemMacro(m_parent->m_listview->m_handle);
 -	lvi.iSubItem = 0;
 -	lvi.mask = LVIF_PARAM;
 -	ListView_GetItem(m_parent->m_listview->m_handle, &lvi);
 -	return lvi.lParam;
 -}
 -
 -void CSListView::setFullFocusedSelection( int selection )
 -{
 -	ListView_SetItemState(  m_handle, -1, 0,     LVIS_SELECTED );
 -	ListView_EnsureVisible( m_handle, selection, FALSE );
 -	ListView_SetItemState(  m_handle, selection, LVIS_SELECTED, LVIS_SELECTED );
 -	ListView_SetItemState(  m_handle, selection, LVIS_FOCUSED , LVIS_FOCUSED  );
 -	SetFocus( m_handle );
 -}
 -
 -// ====[ LIST MANAGEMENT ]====================================================
 -
 -CSItemsList::CSItemsList(char *protoName)
 -{
 -	m_list = new List< StatusItem >(compareItems);
 -	loadItems(protoName);
 -}
 -
 -CSItemsList::~CSItemsList()
 -{
 -	delete m_list;
 -}
 -
 -int CSItemsList::compareItems( const StatusItem* p1, const StatusItem* p2 )
 -{
 -	int favRes = 0, icoRes = 0, ttlRes = 0, msgRes = 0;
 -
 -	if ( p1->m_bFavourite < p2->m_bFavourite )
 -	    favRes = 1;
 -	else if ( p1->m_bFavourite > p2->m_bFavourite )
 -	    favRes = -1;
 -
 -	int result;
 -	if ( p1->m_iIcon > p2->m_iIcon )
 -		icoRes = 1;
 -	else if ( p1->m_iIcon < p2->m_iIcon )
 -		icoRes = -1;
 -
 -	result = lstrcmp(p1->m_tszTitle, p2->m_tszTitle);
 -	ttlRes = result;
 -
 -	result = lstrcmp(p1->m_tszMessage, p2->m_tszMessage);
 -	msgRes = result;
 -
 -	if ( !icoRes && !ttlRes && !msgRes)
 -		return 0;
 -
 -	if (favRes != 0)
 -		return favRes;
 -	if (icoRes != 0)
 -		return icoRes;
 -	if (ttlRes != 0)
 -		return ttlRes;
 -	if (msgRes != 0)
 -		return msgRes;
 -
 -	return 0;
 -}
 -
 -void CSItemsList::loadItems(char *protoName)
 -{
 -	char dbSetting[32];
 -	mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_ItemsCount", protoName);
 -	unsigned int itemsCount = getWord(dbSetting, DEFAULT_ITEMS_COUNT);
 -
 -	for (unsigned int i = 1; i <= itemsCount; i++) {
 -		StatusItem* item = new StatusItem();
 -		DBVARIANT dbv;
 -		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dIcon", protoName, i);
 -		item->m_iIcon = getByte(dbSetting, DEFAULT_ITEM_ICON);
 -
 -		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dTitle", protoName, i);
 -		if ( !getTString(dbSetting, &dbv)) {
 -			lstrcpy(item->m_tszTitle, dbv.ptszVal);
 -			db_free(&dbv);
 -		}
 -		else item->m_tszTitle[0] = 0;
 -
 -		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dMessage", protoName, i);
 -		if ( !getTString(dbSetting, &dbv)) {
 -			lstrcpy(item->m_tszMessage, dbv.ptszVal);
 -			db_free(&dbv);
 -		}
 -		else item->m_tszMessage[0] = 0;
 -
 -		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dFavourite", protoName, i);
 -		item->m_bFavourite = (BOOL)getByte(dbSetting, DEFAULT_ITEM_IS_FAVOURITE);
 -		
 -		m_list->add(item);
 -	}
 -}
 -
 -
 -void CSItemsList::saveItems(char *protoName)
 -{
 -	unsigned int i;
 -	char dbSetting[32];
 -	mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_ItemsCount", protoName);
 -	unsigned int oldItemsCount = getWord(dbSetting, DEFAULT_ITEMS_COUNT);
 -
 -	for (i = 1; i <= m_list->getCount(); i++)
 -	{
 -		StatusItem* item = m_list->get( i - 1 );
 -		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dIcon", protoName, i);
 -		setByte(dbSetting, item->m_iIcon);
 -		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dTitle", protoName, i);
 -		setTString(dbSetting, item->m_tszTitle);
 -		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dMessage", protoName, i);
 -		setTString(dbSetting, item->m_tszMessage);
 -		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dFavourite", protoName, i);
 -		setByte(dbSetting, item->m_bFavourite);
 -	}
 -
 -	mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_ItemsCount", protoName);
 -	setWord(dbSetting, m_list->getCount());
 -
 -	for ( ; i <= oldItemsCount; i++)
 -	{
 -		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dIcon", protoName, i);
 -		deleteSetting(dbSetting);
 -		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dTitle", protoName, i);
 -		deleteSetting(dbSetting);
 -		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dMessage", protoName, i);
 -		deleteSetting(dbSetting);
 -		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dFavourite", protoName, i);
 -		deleteSetting(dbSetting);
 -	}
 -}
 -
 -
 -// ====[ PROCEDURES ]=========================================================
 -
 -INT_PTR CALLBACK CSWindowProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam )
 -{
 -	CSWindow* csw = ( CSWindow* )GetWindowLongPtr( hwnd, GWLP_USERDATA );
 -
 -	switch ( message ) {
 -	case WM_INITDIALOG:
 -		TranslateDialogDefault(hwnd);
 -
 -		csw = (CSWindow*)lparam;
 -		arWindows.insert(csw);
 -		SetWindowLongPtr(hwnd, GWLP_USERDATA, lparam);
 -
 -		csw->m_handle = hwnd;
 -		csw->initIcons();
 -		csw->initButtons();
 -		csw->m_listview = new CSListView( GetDlgItem( hwnd, IDC_CSLIST ), csw);
 -		csw->m_listview->initItems(csw->m_itemslist->m_list->getListHead());
 -		csw->toggleButtons();
 -		csw->toggleEmptyListMessage();
 -		csw->loadWindowPosition();
 -		SetWindowText(hwnd, TranslateT(MODULENAME));
 -		return TRUE;
 -
 -	case WM_COMMAND:
 -		switch ( LOWORD( wparam )) {
 -		case IDC_MODIFY:
 -		case IDC_ADD:
 -			csw->m_addModifyDlg = new CSAMWindow( LOWORD( wparam ), csw );
 -			csw->m_addModifyDlg->exec();
 -			if ( csw->m_addModifyDlg->m_bChanged ) {
 -				if ( LOWORD( wparam ) == IDC_MODIFY )
 -					csw->m_itemslist->m_list->remove( csw->m_listview->getPositionInList());
 -
 -				int selection = csw->m_itemslist->m_list->add( csw->m_addModifyDlg->m_item );
 -				csw->m_bSomethingChanged = TRUE;
 -				csw->m_listview->reinitItems( csw->m_itemslist->m_list->getListHead());
 -				csw->m_listview->setFullFocusedSelection( selection );
 -				csw->toggleButtons();
 -				csw->toggleEmptyListMessage();
 -			}
 -			delete csw->m_addModifyDlg;
 -			break;
 -
 -		case IDC_REMOVE:
 -			if ( getByte( "ConfirmDeletion", DEFAULT_PLUGIN_CONFIRM_ITEMS_DELETION ))
 -				if ( MessageBox( hwnd, TranslateT("Do you really want to delete selected item?"), TranslateT(MODULENAME), MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION ) == IDNO )
 -					break;
 -
 -			csw->m_itemslist->m_list->remove( csw->m_listview->getPositionInList());
 -			csw->m_bSomethingChanged = TRUE;
 -			csw->m_listview->reinitItems( csw->m_itemslist->m_list->getListHead());
 -			csw->toggleButtons();
 -			csw->toggleEmptyListMessage();
 -			break;
 -
 -		case IDC_FAVOURITE:
 -			{
 -				int selection = csw->m_listview->getPositionInList();
 -				StatusItem* f = new StatusItem( *csw->m_itemslist->m_list->get( selection ));
 -				f->m_bFavourite = ! f->m_bFavourite;
 -				csw->m_itemslist->m_list->remove( selection );
 -				selection = csw->m_itemslist->m_list->add( f );
 -				csw->m_bSomethingChanged = TRUE;
 -				csw->m_listview->reinitItems( csw->m_itemslist->m_list->getListHead());
 -				csw->m_listview->setFullFocusedSelection( selection );
 -				csw->toggleButtons();
 -			}
 -			break;
 -
 -		case IDC_UNDO:
 -			csw->m_itemslist->m_list->destroy();
 -			csw->m_itemslist->loadItems(csw->m_protoName);
 -			csw->m_bSomethingChanged = FALSE;
 -			csw->m_listview->reinitItems( csw->m_itemslist->m_list->getListHead());
 -			csw->toggleButtons();
 -			csw->toggleEmptyListMessage();
 -			break;
 -
 -		case IDC_IMPORT:
 -			{
 -				int result = getByte( "DeleteAfterImport", DEFAULT_PLUGIN_DELETE_AFTER_IMPORT );
 -				if (result == TRUE)
 -					result = IDYES;
 -				else {
 -					result = MessageBox( hwnd, 
 -						TranslateT("Do you want old database entries to be deleted after Import?"),
 -					   TranslateT(MODULENAME), MB_YESNOCANCEL | MB_DEFBUTTON2 | MB_ICONQUESTION );
 -					if ( result == IDCANCEL )
 -						break;
 -				}
 -
 -				importCustomStatuses(csw, result);
 -				csw->m_bSomethingChanged = TRUE;
 -				csw->toggleButtons();
 -				csw->toggleEmptyListMessage();
 -			}
 -			break;
 -
 -		case IDC_FILTER:
 -			csw->toggleFilter();
 -			csw->toggleButtons();
 -			break;
 -
 -		case IDC_FILTER_FIELD:
 -			if ( HIWORD( wparam ) == EN_CHANGE )
 -				csw->m_listview->reinitItems( csw->m_itemslist->m_list->getListHead());
 -			break;
 -
 -		case IDCLOSE:    // close and save, no custom status
 -		case IDCANCEL:   // close and save, no custom status
 -		case IDC_CANCEL:   // close and save, cancel custom status
 -		case IDOK:       // close and save, set selected custom status
 -			if ( LOWORD( wparam ) == IDOK && csw->toggleButtons())
 -				SetStatus(IDOK, csw->m_itemslist->m_list->get(csw->m_listview->getPositionInList()), csw->m_protoName);
 -			if ( LOWORD( wparam ) == IDC_CANCEL )
 -				SetStatus(IDC_CANCEL, NULL, csw->m_protoName);
 -			if ( csw->m_bSomethingChanged )
 -				if (csw->m_itemslist!=NULL)
 -					csw->m_itemslist->saveItems(csw->m_protoName);
 -			csw->saveWindowPosition(csw->m_handle);
 -			EndDialog(hwnd, FALSE);
 -			break;
 -		}
 -		return FALSE;
 -
 -	case WM_NOTIFY:
 -		if ( wparam == IDC_CSLIST ) {
 -			NMHDR* pnmh = ( NMHDR* )lparam;
 -			switch ( pnmh->code ) {
 -			case NM_DBLCLK:
 -				PostMessage( hwnd, WM_COMMAND, IDOK, 0L );
 -				break;
 -
 -			case LVN_ITEMCHANGED:
 -			case NM_CLICK:
 -				csw->toggleButtons();
 -				break;
 -			}
 -		}
 -		return FALSE;
 -
 -	case WM_CTLCOLORSTATIC:
 -		SetTextColor(( HDC )wparam, RGB( 174, 174, 174 ));
 -		if (((HWND)lparam == GetDlgItem(hwnd, IDC_NO_ITEMS)) || ((HWND)lparam == GetDlgItem(hwnd, IDC_ADD_SAMPLE)))
 -			return ( BOOL )GetStockObject( WHITE_BRUSH );
 -		return FALSE;
 -
 -	case WM_DESTROY:
 -		SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
 -		arWindows.remove(csw);
 -		delete csw->m_listview;
 -		csw->deinitIcons();
 -		delete csw;
 -		break;
 -	}
 -	return FALSE;
 -}
 -
 -INT_PTR CALLBACK CSAMWindowProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam )
 -{
 -	CSAMWindow* csamw = ( CSAMWindow* )GetWindowLongPtr( hwnd, GWLP_USERDATA );
 -
 -	switch ( message ) {
 -	case WM_INITDIALOG:
 -		csamw = ( CSAMWindow* )lparam;
 -		SetWindowLongPtr( hwnd, GWLP_USERDATA, lparam );
 -		csamw->m_handle = hwnd;
 -		EnableWindow( csamw->m_parent->m_handle, FALSE );
 -		csamw->m_hCombo = GetDlgItem( hwnd, IDC_COMBO );
 -		csamw->m_hMessage = GetDlgItem( hwnd, IDC_MESSAGE );
 -		csamw->setCombo();
 -		csamw->fillDialog();
 -		TranslateDialogDefault(hwnd);
 -		break;
 -
 -	case WM_COMMAND:
 -		switch ( LOWORD( wparam )) {
 -		case IDC_MESSAGE:
 -			csamw->checkFieldLimit( HIWORD( wparam ), LOWORD( wparam ));
 -			break;
 -
 -		case IDOK:
 -			csamw->checkItemValidity();
 -
 -		case IDCANCEL:
 -			EnableWindow(csamw->m_parent->m_handle, TRUE);
 -			EndDialog(hwnd, LOWORD(wparam));
 -			break;
 -		}
 -		break;
 -	}
 -	return FALSE;
 -}
 -
 -
 -INT_PTR CALLBACK CSOptionsProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam )
 -{
 -	switch ( message ) {
 - 	case WM_INITDIALOG:
 -		TranslateDialogDefault(hwnd);
 -		CheckDlgButton( hwnd, IDC_CONFIRM_DELETION,
 -						getByte( "ConfirmDeletion", DEFAULT_PLUGIN_CONFIRM_ITEMS_DELETION ) ?
 -						BST_CHECKED : BST_UNCHECKED );
 -
 -		CheckDlgButton( hwnd, IDC_DELETE_AFTER_IMPORT,
 -						getByte( "DeleteAfterImport", DEFAULT_PLUGIN_DELETE_AFTER_IMPORT ) ?
 -						BST_CHECKED : BST_UNCHECKED );
 -
 -		CheckDlgButton( hwnd, IDC_REMEMBER_POSITION,
 -			               getByte( "RememberWindowPosition", DEFAULT_REMEMBER_WINDOW_POSITION ) ?
 -			               BST_CHECKED : BST_UNCHECKED );
 -		return TRUE;
 -
 -	case WM_NOTIFY:
 -		switch ((( LPNMHDR )lparam )->code ) {
 -		case PSN_APPLY:
 -			setByte( "ConfirmDeletion", IsDlgButtonChecked( hwnd, IDC_CONFIRM_DELETION ) ? 1 : 0 );
 -			setByte( "DeleteAfterImport", IsDlgButtonChecked( hwnd, IDC_DELETE_AFTER_IMPORT ) ? 1 : 0 );
 -			setByte( "RememberWindowPosition", IsDlgButtonChecked( hwnd, IDC_REMEMBER_POSITION ) ? 1 : 0 );
 -
 -			pcli->pfnReloadProtoMenus();
 -			break;
 -		}
 -		return TRUE;
 -	}
 -	return FALSE;
 -}
 +/* ======================================================================== + +                              Custom Status List +                              __________________ + +  Custom Status List plugin for Miranda-IM (www.miranda-im.org) +  Follower of Custom Status History List by HANAX +  Copyright © 2006-2008 HANAX +  Copyright © 2007-2009 jarvis +  Occasionally rewritten in 2012 by George Hazan + +  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 "cslist.h" +#include "strpos.h" + +CLIST_INTERFACE *pcli; +int hLangpack; +HINSTANCE g_hInst; + +static LIST<CSWindow> arWindows(3, HandleKeySortT); + +PLUGININFOEX pluginInfoEx = +{ +	sizeof(PLUGININFOEX), +	__PLUGIN_NAME, +	PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), +	__DESCRIPTION, +	__AUTHOR, +	__AUTHOREMAIL, +	__COPYRIGHT, +	__AUTHORWEB, +	UNICODE_AWARE, +	// {C8CC7414-6507-4AF6-925A-83C1D2F7BE8C} +	{0xc8cc7414, 0x6507, 0x4af6, {0x92, 0x5a, 0x83, 0xc1, 0xd2, 0xf7, 0xbe, 0x8c}} +}; + +// ====[ MAIN ]=============================================================== + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ +	g_hInst = hinstDLL; +	return TRUE; +} + +// ====[ PLUGIN INFO ]======================================================== + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD) +{ +	return &pluginInfoEx; +} + +// ====[ LOADER ]============================================================= + +static int OnDbChanged(WPARAM hContact, LPARAM lparam) +{ +	DBCONTACTWRITESETTING *cws = ( DBCONTACTWRITESETTING* )lparam; + +	// if user changes his UIN or JID on any account +	if (hContact == NULL) { +		INT_PTR szUniqueID = CallProtoService(cws->szModule, PS_GETCAPS, PFLAG_UNIQUEIDSETTING, 0); +		if (szUniqueID != CALLSERVICE_NOTFOUND && !lstrcmpA(cws->szSetting, (char*)szUniqueID)) +			pcli->pfnReloadProtoMenus(); +	} +	return 0; +} + +static int OnInitOptions(WPARAM wparam, LPARAM lparam) +{ +	OPTIONSDIALOGPAGE odp = { sizeof(odp) }; +	odp.position = 955000000; +	odp.hInstance = g_hInst; +	odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS); +	odp.pszTitle = MODULENAME; +	odp.pfnDlgProc = CSOptionsProc; +	odp.pszGroup = LPGEN("Status"); +	odp.flags = ODPF_BOLDGROUPS; +	Options_AddPage(wparam, &odp); +	return 0; +} + +static int OnCreateMenuItems(WPARAM, LPARAM) +{ +	int protoCount; +	PROTOACCOUNT** pdesc; +	ProtoEnumAccounts(&protoCount, &pdesc); + +	for (int i = 0; i < protoCount; i++) +		if ( ProtoServiceExists(pdesc[i]->szModuleName, PS_SETCUSTOMSTATUSEX)) +			addProtoStatusMenuItem(pdesc[i]->szModuleName); + +	return 0; +} + +static int OnPreshutdown(WPARAM wparam, LPARAM lparam) +{ +	for (int i=0; i < arWindows.getCount(); i++) +		DestroyWindow(arWindows[i]->m_handle); +	return 0; +} + +extern "C" __declspec(dllexport) int Load() +{ +	mir_getLP(&pluginInfoEx); +	mir_getCLI(); +	 +	// support for ComboBoxEx +	INITCOMMONCONTROLSEX icc; +	icc.dwSize = sizeof(icc); +	icc.dwICC = ICC_USEREX_CLASSES; +	InitCommonControlsEx(&icc); + +	// init icons +	TCHAR tszFile[MAX_PATH]; +	GetModuleFileName( g_hInst, tszFile, MAX_PATH ); + +	SKINICONDESC sid = { sizeof(sid) }; +	sid.ptszDefaultFile = tszFile; +	sid.flags = SIDF_ALL_TCHAR; +	sid.cx = sid.cy = 16; +	sid.ptszSection = _T(MODULENAME); + +	for (int i=0; i < SIZEOF(forms); i++) { +		char szSettingName[64]; +		mir_snprintf(szSettingName, SIZEOF(szSettingName), "%s_%s", MODNAME, forms[i].pszIconIcoLib); + +		sid.pszName = szSettingName; +		sid.ptszDescription = forms[i].ptszDescr; +		sid.iDefaultIndex = -forms[i].iconNoIcoLib; +		forms[i].hIcoLibItem = Skin_AddIcon(&sid); +	} + +	HookEvent(ME_OPT_INITIALISE, OnInitOptions); +	HookEvent(ME_DB_CONTACT_SETTINGCHANGED, OnDbChanged); +	HookEvent(ME_CLIST_PREBUILDSTATUSMENU, OnCreateMenuItems); +	HookEvent(ME_SYSTEM_PRESHUTDOWN, OnPreshutdown); + +	// if we load a plugin dynamically, it will work, otherwise fail +	OnCreateMenuItems(0, 0); +	return 0; +} + +// ====[ UNLOADER ]=========================================================== + +extern "C" __declspec(dllexport) int Unload() +{ +	return 0; +} + +// ====[ FUN ]================================================================ + +void RegisterHotkeys(char buf[200], TCHAR* accName, int Number) +{ +	HOTKEYDESC hotkey = { sizeof(hotkey) }; +	hotkey.dwFlags = HKD_TCHAR; +	hotkey.pszName = buf; +	hotkey.ptszDescription = accName; +	hotkey.ptszSection = LPGENT("Custom Status List"); +	hotkey.pszService = buf; +	hotkey.DefHotKey = HOTKEYCODE( HOTKEYF_CONTROL | HOTKEYF_SHIFT, '0' + Number); +	Hotkey_Register(&hotkey); +} + +void SetStatus(WORD code, StatusItem* item,  char *szAccName) +{ +	if ( code == IDCLOSE ) +		return; + +	PROTOACCOUNT* pdescr = (PROTOACCOUNT*)CallService(MS_PROTO_GETACCOUNT, 0, (LPARAM)szAccName); +	if (pdescr == NULL) +		return; + +	if ( !ProtoServiceExists(szAccName, PS_SETCUSTOMSTATUSEX)) +		return; + +	int statusToSet; + +	CUSTOM_STATUS ics = { sizeof(CUSTOM_STATUS) }; +	ics.flags = CSSF_MASK_STATUS | CSSF_MASK_NAME | CSSF_MASK_MESSAGE | CSSF_TCHAR; + +	if (code == IDC_CANCEL) { +		statusToSet = 0; +		ics.ptszName = _T(""); +		ics.ptszMessage = _T(""); +	} +	else if (code == IDOK && item != NULL) { +		statusToSet = item->m_iIcon+1; +		ics.ptszName = variables_parsedup(item->m_tszTitle, NULL, NULL); +		ics.ptszMessage = variables_parsedup(item->m_tszMessage, NULL, NULL); +	} +	else return; + +	ics.status = &statusToSet; +	ProtoCallService(szAccName, PS_SETCUSTOMSTATUSEX, 0, (LPARAM)&ics); +} + +INT_PTR showList(WPARAM wparam, LPARAM lparam, LPARAM param) +{ +	char* szProto = (char*)param; +	for (int i=0; i < arWindows.getCount(); i++) { +		CSWindow *p = arWindows[i]; +		if ( !strcmp(szProto, p->m_protoName)) { +			ShowWindow(p->m_handle, SW_SHOW); +			SetForegroundWindow(p->m_handle); +			return 1; +		} +	} + +	CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_CSLIST), NULL, CSWindowProc, (LPARAM)new CSWindow(szProto)); +	return 0; +} + +void addProtoStatusMenuItem(char *protoName) +{ +	PROTOACCOUNT *pdescr = ProtoGetAccount(protoName); +	if (pdescr == NULL) +		return; + +	HGENMENU hRoot = MO_GetProtoRootMenu(pdescr->szModuleName); +	if (hRoot == NULL) +		return; + +	char buf[200]; +	mir_snprintf(buf, SIZEOF(buf), "CSList/ShowList/%s", protoName); +	if ( !ServiceExists(buf)) +		CreateServiceFunctionParam(buf, showList, (LPARAM)protoName); + +	CLISTMENUITEM mi = { sizeof(mi) }; +	mi.flags = CMIF_CHILDPOPUP | CMIF_TCHAR; +	mi.icolibItem = forms[0].hIcoLibItem; +	mi.ptszName = _T(MODULENAME); +	mi.position = 2000040000; +	mi.pszService = buf; +	mi.hParentMenu = hRoot; +	Menu_AddStatusMenuItem(&mi); + +	RegisterHotkeys(buf, pdescr->tszAccountName, pdescr->iOrder); +} + +/////////////////////////////////////////////////////////////////////////////// + +void importCustomStatuses(CSWindow* csw, int result) +{ +	DBVARIANT dbv; +	char bufTitle[32], bufMessage[32], *protoName = csw->m_protoName; + +	for (int i = 0; i < csw->m_statusCount; i++) { +		StatusItem* si = new StatusItem(); +		si->m_iIcon = i-1; + +		mir_snprintf(bufTitle, 32, "XStatus%dName", i); +		if ( !db_get_ts( NULL, protoName, bufTitle, &dbv )) { +			lstrcpy(si->m_tszTitle, dbv.ptszVal); +			db_free(&dbv); +		} +		else si->m_tszTitle[0] = 0; + +		mir_snprintf(bufMessage, 32, "XStatus%dMsg", i); +		if ( !db_get_ts( NULL, protoName, bufMessage, &dbv )) { +			lstrcpy(si->m_tszMessage, dbv.ptszVal); +			db_free(&dbv); +		} +		else si->m_tszMessage[0] = 0; + +		if (si->m_tszTitle[0] || si->m_tszMessage[0]) { +			csw->m_itemslist->m_list->add(si); +			csw->m_bSomethingChanged = TRUE; +		} +		else delete si; + +		if (result == IDYES) { +			db_unset(NULL, protoName, bufTitle); +			db_unset(NULL, protoName, bufMessage); +		} +	} +	csw->m_listview->reinitItems(csw->m_itemslist->m_list->getListHead()); +} + +/////////////////////////////////////////////////////////////////////////////// +// CSWindow class + +CSWindow::CSWindow(char *protoName) +{ +	m_protoName = protoName; +	m_handle = NULL; +	m_bExtraIcons = getByte( "AllowExtraIcons", DEFAULT_ALLOW_EXTRA_ICONS ); +	m_itemslist = new CSItemsList(m_protoName); +	m_listview = NULL; +	m_addModifyDlg = NULL; +	m_bSomethingChanged = FALSE; +	m_filterString = NULL; +} + +void __fastcall SAFE_FREE(void** p) +{ +	if (*p) +	{ +		free(*p); +		*p = NULL; +	} +} + +CSWindow::~CSWindow() +{ +	delete m_itemslist; +	SAFE_FREE(( void** )&m_filterString ); +} + +void CSWindow::initIcons() +{ +	PROTOACCOUNT *pdescr = ProtoGetAccount(m_protoName); +	if (pdescr == NULL) +		return; + +	char *szUniqueID = (char*)CallProtoService(m_protoName, PS_GETCAPS, PFLAG_UNIQUEIDSETTING, 0); +	if (szUniqueID == NULL) +		return; + +	DBVARIANT dbv; +	if ( db_get(NULL, pdescr->szModuleName, szUniqueID, &dbv)) +		return; +	db_free(&dbv); + +	WPARAM iNumStatuses = 0; +	CUSTOM_STATUS cs = { sizeof(cs) }; +	cs.flags = CSSF_STATUSES_COUNT; +	cs.wParam = &iNumStatuses; +	if ( CallProtoService(pdescr->szModuleName, PS_GETCUSTOMSTATUSEX, 0, (LPARAM)&cs) != 0) +		return; + +	m_statusCount = (int)iNumStatuses; +	if (NULL == (m_icons = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, m_statusCount, 0))) +		return; + +	for (int i=1; i <= m_statusCount; i++) { +		HICON hIcon = (HICON)CallProtoService(pdescr->szModuleName, PS_GETCUSTOMSTATUSICON, i, 0); +		if (hIcon) { +			ImageList_AddIcon(m_icons, hIcon); +			DestroyIcon(hIcon); +		} +	} +} + +void CSWindow::deinitIcons() +{ +	ImageList_Destroy( m_icons ); +} + +void CSWindow::initButtons() +{ +	for (int i = 0; i < SIZEOF(forms); i++) { +		if ( forms[i].idc < 0 ) +			continue; + +		SendDlgItemMessage( m_handle, forms[i].idc, BM_SETIMAGE, IMAGE_ICON, (LPARAM)Skin_GetIconByHandle(forms[i].hIcoLibItem)); +		SendDlgItemMessage( m_handle, forms[i].idc, BUTTONSETASFLATBTN, TRUE, 0 ); //maybe set as BUTTONSETDEFAULT? +		SendDlgItemMessage( m_handle, forms[i].idc, BUTTONADDTOOLTIP, (WPARAM )TranslateTS(forms[i].ptszTitle), BATF_TCHAR ); +	} +} + +void CSWindow::loadWindowPosition() +{ +	if (getByte("RememberWindowPosition", DEFAULT_REMEMBER_WINDOW_POSITION)) +		Utils_RestoreWindowPosition(m_handle, NULL, MODNAME, "Position"); +} + +void CSWindow::toggleEmptyListMessage() +{ +	HWND hwnd = GetDlgItem( m_handle, IDC_NO_ITEMS ); +	ShowWindow( hwnd, ( ListView_GetItemCount( m_listview->m_handle ) > 0 ) ? FALSE : TRUE ); +	SetForegroundWindow( hwnd ); +	hwnd = GetDlgItem( m_handle, IDC_ADD_SAMPLE ); +	ShowWindow( hwnd, ( ListView_GetItemCount( m_listview->m_handle ) > 0 ) ? FALSE : TRUE ); +	SetForegroundWindow( hwnd ); +} + +BOOL CSWindow::itemPassedFilter( ListItem< StatusItem >* li ) +{ +	TCHAR filter[MAX_PATH]; +	GetDlgItemText( m_handle, IDC_FILTER_FIELD, filter, MAX_PATH ); + +	if ( lstrlen( filter )) +	{ +		TCHAR title[EXTRASTATUS_TITLE_LIMIT], message[EXTRASTATUS_MESSAGE_LIMIT]; +		lstrcpy( title, li->m_item->m_tszTitle ); lstrcpy( message, li->m_item->m_tszMessage ); +		if ( strpos( _tcslwr( title ), _tcslwr( filter )) == -1 ) +			if ( strpos( _tcslwr( message ), _tcslwr( filter )) == -1 ) +				return FALSE; +	} + +	return TRUE; +} + +void CSWindow::toggleFilter() +{ +	HWND hFilter = GetDlgItem( m_handle, IDC_FILTER_FIELD ); +	BOOL isEnabled = !IsWindowEnabled( hFilter ) ? TRUE : FALSE; // ! = + isEnabled = !isEnabled in one +	EnableWindow( hFilter, isEnabled ); +	ShowWindow( hFilter, isEnabled ); +	CheckDlgButton( m_handle, IDC_FILTER, isEnabled ); +	SetForegroundWindow( hFilter ); +	if ( isEnabled ) +		SetFocus( hFilter ); +	else +	{ +		TCHAR filterText[255]; +		GetDlgItemText(m_handle, IDC_FILTER_FIELD, filterText, SIZEOF(filterText)); +		if (filterText[0] != 0) +			SetDlgItemText( m_handle, IDC_FILTER_FIELD, TEXT( "")); +	} +} + +BOOL CSWindow::toggleButtons() +{ +	int selection = ListView_GetSelectedItemMacro( m_listview->m_handle ); +	BOOL validSelection = ( selection >= 0 && ( unsigned int )selection < m_itemslist->m_list->getCount()) ? TRUE : FALSE; +	BOOL filterEnabled = IsWindowVisible( GetDlgItem( m_handle, IDC_FILTER_FIELD )); +	BOOL somethingChanged = m_bSomethingChanged; + +	EnableWindow( GetDlgItem( m_handle, IDC_ADD       ), !filterEnabled ); +	EnableWindow( GetDlgItem( m_handle, IDC_MODIFY    ), validSelection && !filterEnabled ); +	EnableWindow( GetDlgItem( m_handle, IDC_REMOVE    ), validSelection && !filterEnabled ); +	EnableWindow( GetDlgItem( m_handle, IDC_FAVOURITE ), validSelection && !filterEnabled ); +	EnableWindow( GetDlgItem( m_handle, IDC_UNDO      ), somethingChanged && !filterEnabled ); +	EnableWindow( GetDlgItem( m_handle, IDC_IMPORT    ), !filterEnabled ); +	EnableWindow( GetDlgItem( m_handle, IDOK          ), validSelection ); + +	return validSelection; +} + +/////////////////////////////////////////////////////////////////////////////// +// CSAMWindow class - add form window + +CSAMWindow::CSAMWindow( WORD action, CSWindow* parent ) +{ +	m_action = action; +	m_parent = parent; +	m_bChanged = FALSE; +	m_hCombo = m_hMessage = NULL; + +	if ( m_action == IDC_ADD ) +		m_item = new StatusItem(); +	else +		m_item = new StatusItem( *m_parent->m_itemslist->m_list->get( m_parent->m_listview->getPositionInList()) ); +} + +CSAMWindow::~CSAMWindow() +{ +	if ( !m_bChanged ) +		delete m_item; +} + +void CSAMWindow::exec() +{ +	DialogBoxParam( g_hInst, MAKEINTRESOURCE( IDD_ADDMODIFY ), NULL, CSAMWindowProc, (LPARAM)this ); +} + + +void CSAMWindow::setCombo() +{ +	PROTOACCOUNT *pdescr = ProtoGetAccount(m_parent->m_protoName); +	if (pdescr == NULL) +		return; + +	char *szUniqueID = (char*)CallProtoService(pdescr->szModuleName, PS_GETCAPS, PFLAG_UNIQUEIDSETTING, 0); +	if (szUniqueID == NULL) +		return; + +	DBVARIANT dbv; +	if ( db_get(NULL, pdescr->szModuleName, szUniqueID, &dbv)) +		return; +	db_free(&dbv); + +	WPARAM iStatus; +	TCHAR tszName[100]; +	CUSTOM_STATUS cs = { sizeof(cs) }; +	cs.flags = CSSF_MASK_NAME | CSSF_DEFAULT_NAME | CSSF_TCHAR; +	cs.ptszName = tszName; +	cs.wParam = &iStatus; + +	SendMessage( m_hCombo, CBEM_SETIMAGELIST, 0, (LPARAM)m_parent->m_icons); +	for (int i=1; i <= m_parent->m_statusCount; i++) { +		iStatus = i; +		if ( CallProtoService(pdescr->szModuleName, PS_GETCUSTOMSTATUSEX, 0, (LPARAM)&cs) != 0) +			continue; + +		COMBOBOXEXITEM cbi = { 0 }; +		cbi.mask = CBEIF_TEXT | CBEIF_IMAGE | CBEIF_SELECTEDIMAGE; +		cbi.iItem = -1; +		cbi.iImage = cbi.iSelectedImage = i-1; +		cbi.pszText = TranslateTS(tszName); +		SendMessage( m_hCombo, CBEM_INSERTITEM, 0, (LPARAM)&cbi ); +	} +	SendMessage( m_hCombo, CB_SETCURSEL, 0, 0 ); // first 0 sets selection to top +} + +void CSAMWindow::fillDialog() +{ +	if (m_action == IDC_ADD) { +		SetWindowText(m_handle, TranslateT("Add new item")); +		SetDlgItemText(m_handle, IDOK, TranslateT("Add")); +	} +	else { +		SetWindowText(m_handle, TranslateT("Modify item")); +		SetDlgItemText(m_handle, IDOK, TranslateT("Modify")); +	} + +	SendMessage(m_hCombo, CB_SETCURSEL, m_item->m_iIcon, 0); +	SetDlgItemText(m_handle, IDC_MESSAGE, m_item->m_tszMessage); +} + +void CSAMWindow::checkFieldLimit( WORD action, WORD item ) +{ +	BOOL type = ( item == IDC_MESSAGE ) ? TRUE : FALSE; +	unsigned int limit = type ? EXTRASTATUS_MESSAGE_LIMIT : EXTRASTATUS_TITLE_LIMIT; + +	if ( action == EN_CHANGE ) +	{ +		TCHAR* ptszInputText = (TCHAR*)mir_alloc((limit + 8) * sizeof(TCHAR)); + +		GetDlgItemText( m_handle, item, ptszInputText, limit + 8 ); + +		if ( _tcslen( ptszInputText ) > limit ) +		{ +#if ( WINVER >= 0x501 ) +			TCHAR tszPopupTip[MAX_PATH]; +			EDITBALLOONTIP ebt = { 0 }; +			ebt.cbStruct = sizeof(ebt); +			ebt.pszTitle = TranslateT("Warning"); +			mir_sntprintf(tszPopupTip, SIZEOF(tszPopupTip), TranslateT("This field doesn't accept string longer than %d characters. The string will be truncated."), limit); +			ebt.pszText = tszPopupTip; +			ebt.ttiIcon = TTI_WARNING; +			SendMessage( GetDlgItem( m_handle, item ), EM_SHOWBALLOONTIP, 0, (LPARAM)&ebt ); +#endif +			TCHAR* ptszOutputText = (TCHAR*)mir_alloc((limit + 1) * sizeof(TCHAR)); +			GetDlgItemText( m_handle, item, ptszOutputText, limit + 1 ); +			SetDlgItemText( m_handle, item, ptszOutputText ); +			mir_free( ptszOutputText ); +		} +		mir_free( ptszInputText ); +	} +} + +void CSAMWindow::checkItemValidity() +{ +	COMBOBOXEXITEM cbi = { 0 }; +	cbi.mask = CBEIF_IMAGE; +	cbi.iItem = SendDlgItemMessage(m_handle, IDC_COMBO, CB_GETCURSEL, 0, 0); +	SendDlgItemMessage( m_handle, IDC_COMBO, CBEM_GETITEM, 0, (LPARAM)&cbi ); + +	if (m_item->m_iIcon != cbi.iImage) +		m_item->m_iIcon = cbi.iImage, m_bChanged = TRUE; + +	TCHAR tszInputMessage[EXTRASTATUS_MESSAGE_LIMIT]; + +	GetDlgItemText( m_handle, IDC_MESSAGE, tszInputMessage, EXTRASTATUS_MESSAGE_LIMIT ); + +	PROTOACCOUNT* pdescr = (PROTOACCOUNT*)CallService(MS_PROTO_GETACCOUNT, 0, (LPARAM)m_parent->m_protoName); +	if (pdescr == NULL) +		return; + +	WPARAM i = SendMessage(m_hCombo, CB_GETCURSEL, 0, 0)+1; +	TCHAR tszTitle[100]; + +	CUSTOM_STATUS cs = { sizeof(cs) }; +	cs.flags = CSSF_MASK_NAME | CSSF_DEFAULT_NAME | CSSF_TCHAR; +	cs.ptszName = tszTitle; +	cs.wParam = &i; +	if ( CallProtoService(pdescr->szModuleName, PS_GETCUSTOMSTATUSEX, 0, (LPARAM)&cs) == 0) +		lstrcpyn(m_item->m_tszTitle, TranslateTS(tszTitle), SIZEOF(m_item->m_tszTitle)); + +	if ( lstrcmp(m_item->m_tszMessage, tszInputMessage)) +		lstrcpy( m_item->m_tszMessage, tszInputMessage), m_bChanged = true; +} + +CSListView::CSListView(HWND hwnd, CSWindow* parent) +{ +	m_handle = hwnd; +	m_parent = parent; + +#if (_WIN32_WINNT >= 0x501) +	LVGROUP lg = { 0 }; +	lg.cbSize = sizeof(LVGROUP); +	lg.mask = LVGF_HEADER | LVGF_GROUPID; + +	lg.pszHeader = TranslateT("Favorites"); +	lg.iGroupId = 0; +	ListView_InsertGroup( m_handle, -1, &lg ); + +	lg.pszHeader = TranslateT("Regular statuses"); +	lg.iGroupId = 1; +	ListView_InsertGroup( m_handle, -1, &lg ); +	ListView_EnableGroupView( m_handle, TRUE ); +#endif + +	LVCOLUMN lvc = { 0 }; +	lvc.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM; +	lvc.fmt = LVCFMT_LEFT; +	lvc.cx = 0x00; +	lvc.pszText = TEXT( ""); +	lvc.cx = 0x16; +	SendMessage( m_handle, LVM_INSERTCOLUMN, 0, (LPARAM)&lvc ); +	lvc.pszText = TranslateT("Title"); +	lvc.cx = 0x64; +	SendMessage( m_handle, LVM_INSERTCOLUMN, 1, (LPARAM)&lvc ); +	lvc.pszText = TranslateT("Message"); +	lvc.cx = 0xa8; +	SendMessage( m_handle, LVM_INSERTCOLUMN, 2, (LPARAM)&lvc ); + +#if (_WIN32_IE >= 0x0400) +	ListView_SetExtendedListViewStyleEx( m_handle, 0, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_HEADERDRAGDROP | LVS_EX_INFOTIP ); +#endif +	ListView_SetImageList(m_handle, m_parent->m_icons, LVSIL_SMALL); +} + +void CSListView::addItem( StatusItem* item, int itemNumber ) +{ +	LVITEM lvi = { 0 }; +	lvi.mask = LVIF_IMAGE | LVIF_GROUPID | LVIF_PARAM; +	lvi.cchTextMax = 256; +	lvi.iItem = ListView_GetItemCount( m_handle ); +	lvi.lParam = itemNumber; +	lvi.iGroupId = item->m_bFavourite ? 0 : 1; + +	// first column +	lvi.iSubItem = 0; +	lvi.iImage = item->m_iIcon; // use selected xicon +	SendMessage( m_handle, LVM_INSERTITEM, 0, (LPARAM)&lvi ); + +	// second column +	lvi.mask = LVIF_TEXT; +	lvi.iSubItem = 1; +	lvi.pszText = item->m_tszTitle; +	SendMessage( m_handle, LVM_SETITEM, 0, (LPARAM)&lvi ); + +	// third column +	lvi.iSubItem = 2; +	lvi.pszText = item->m_tszMessage; +	SendMessage( m_handle, LVM_SETITEM, 0, (LPARAM)&lvi ); +} + +void CSListView::initItems( ListItem< StatusItem >* items ) +{ +	ListItem< StatusItem >* help = items; +	for ( int i = 0; help != NULL; help = help->m_next, i++ ) +		if (m_parent->itemPassedFilter( help )) +			addItem( help->m_item, i ); +} + +void CSListView::reinitItems( ListItem< StatusItem >* items ) +{ +	EnableWindow(m_handle, FALSE); +	removeItems(); +	initItems(items); +	EnableWindow(m_handle, TRUE); +} + +void CSListView::removeItems() +{ +	ListView_DeleteAllItems( m_handle ); +} + +int CSListView::getPositionInList() +{ +	LVITEM lvi = { 0 }; +	lvi.iItem = ListView_GetSelectedItemMacro(m_parent->m_listview->m_handle); +	lvi.iSubItem = 0; +	lvi.mask = LVIF_PARAM; +	ListView_GetItem(m_parent->m_listview->m_handle, &lvi); +	return lvi.lParam; +} + +void CSListView::setFullFocusedSelection( int selection ) +{ +	ListView_SetItemState(  m_handle, -1, 0,     LVIS_SELECTED ); +	ListView_EnsureVisible( m_handle, selection, FALSE ); +	ListView_SetItemState(  m_handle, selection, LVIS_SELECTED, LVIS_SELECTED ); +	ListView_SetItemState(  m_handle, selection, LVIS_FOCUSED , LVIS_FOCUSED  ); +	SetFocus( m_handle ); +} + +// ====[ LIST MANAGEMENT ]==================================================== + +CSItemsList::CSItemsList(char *protoName) +{ +	m_list = new List< StatusItem >(compareItems); +	loadItems(protoName); +} + +CSItemsList::~CSItemsList() +{ +	delete m_list; +} + +int CSItemsList::compareItems( const StatusItem* p1, const StatusItem* p2 ) +{ +	int favRes = 0, icoRes = 0, ttlRes = 0, msgRes = 0; + +	if ( p1->m_bFavourite < p2->m_bFavourite ) +	    favRes = 1; +	else if ( p1->m_bFavourite > p2->m_bFavourite ) +	    favRes = -1; + +	int result; +	if ( p1->m_iIcon > p2->m_iIcon ) +		icoRes = 1; +	else if ( p1->m_iIcon < p2->m_iIcon ) +		icoRes = -1; + +	result = lstrcmp(p1->m_tszTitle, p2->m_tszTitle); +	ttlRes = result; + +	result = lstrcmp(p1->m_tszMessage, p2->m_tszMessage); +	msgRes = result; + +	if ( !icoRes && !ttlRes && !msgRes) +		return 0; + +	if (favRes != 0) +		return favRes; +	if (icoRes != 0) +		return icoRes; +	if (ttlRes != 0) +		return ttlRes; +	if (msgRes != 0) +		return msgRes; + +	return 0; +} + +void CSItemsList::loadItems(char *protoName) +{ +	char dbSetting[32]; +	mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_ItemsCount", protoName); +	unsigned int itemsCount = getWord(dbSetting, DEFAULT_ITEMS_COUNT); + +	for (unsigned int i = 1; i <= itemsCount; i++) { +		StatusItem* item = new StatusItem(); +		DBVARIANT dbv; +		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dIcon", protoName, i); +		item->m_iIcon = getByte(dbSetting, DEFAULT_ITEM_ICON); + +		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dTitle", protoName, i); +		if ( !getTString(dbSetting, &dbv)) { +			lstrcpy(item->m_tszTitle, dbv.ptszVal); +			db_free(&dbv); +		} +		else item->m_tszTitle[0] = 0; + +		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dMessage", protoName, i); +		if ( !getTString(dbSetting, &dbv)) { +			lstrcpy(item->m_tszMessage, dbv.ptszVal); +			db_free(&dbv); +		} +		else item->m_tszMessage[0] = 0; + +		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dFavourite", protoName, i); +		item->m_bFavourite = (BOOL)getByte(dbSetting, DEFAULT_ITEM_IS_FAVOURITE); +		 +		m_list->add(item); +	} +} + + +void CSItemsList::saveItems(char *protoName) +{ +	unsigned int i; +	char dbSetting[32]; +	mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_ItemsCount", protoName); +	unsigned int oldItemsCount = getWord(dbSetting, DEFAULT_ITEMS_COUNT); + +	for (i = 1; i <= m_list->getCount(); i++) +	{ +		StatusItem* item = m_list->get( i - 1 ); +		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dIcon", protoName, i); +		setByte(dbSetting, item->m_iIcon); +		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dTitle", protoName, i); +		setTString(dbSetting, item->m_tszTitle); +		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dMessage", protoName, i); +		setTString(dbSetting, item->m_tszMessage); +		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dFavourite", protoName, i); +		setByte(dbSetting, item->m_bFavourite); +	} + +	mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_ItemsCount", protoName); +	setWord(dbSetting, m_list->getCount()); + +	for ( ; i <= oldItemsCount; i++) +	{ +		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dIcon", protoName, i); +		deleteSetting(dbSetting); +		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dTitle", protoName, i); +		deleteSetting(dbSetting); +		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dMessage", protoName, i); +		deleteSetting(dbSetting); +		mir_snprintf(dbSetting, SIZEOF(dbSetting), "%s_Item%dFavourite", protoName, i); +		deleteSetting(dbSetting); +	} +} + + +// ====[ PROCEDURES ]========================================================= + +INT_PTR CALLBACK CSWindowProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam ) +{ +	CSWindow* csw = ( CSWindow* )GetWindowLongPtr( hwnd, GWLP_USERDATA ); + +	switch ( message ) { +	case WM_INITDIALOG: +		TranslateDialogDefault(hwnd); + +		csw = (CSWindow*)lparam; +		arWindows.insert(csw); +		SetWindowLongPtr(hwnd, GWLP_USERDATA, lparam); + +		csw->m_handle = hwnd; +		csw->initIcons(); +		csw->initButtons(); +		csw->m_listview = new CSListView( GetDlgItem( hwnd, IDC_CSLIST ), csw); +		csw->m_listview->initItems(csw->m_itemslist->m_list->getListHead()); +		csw->toggleButtons(); +		csw->toggleEmptyListMessage(); +		csw->loadWindowPosition(); +		SetWindowText(hwnd, TranslateT(MODULENAME)); +		return TRUE; + +	case WM_COMMAND: +		switch ( LOWORD( wparam )) { +		case IDC_MODIFY: +		case IDC_ADD: +			csw->m_addModifyDlg = new CSAMWindow( LOWORD( wparam ), csw ); +			csw->m_addModifyDlg->exec(); +			if ( csw->m_addModifyDlg->m_bChanged ) { +				if ( LOWORD( wparam ) == IDC_MODIFY ) +					csw->m_itemslist->m_list->remove( csw->m_listview->getPositionInList()); + +				int selection = csw->m_itemslist->m_list->add( csw->m_addModifyDlg->m_item ); +				csw->m_bSomethingChanged = TRUE; +				csw->m_listview->reinitItems( csw->m_itemslist->m_list->getListHead()); +				csw->m_listview->setFullFocusedSelection( selection ); +				csw->toggleButtons(); +				csw->toggleEmptyListMessage(); +			} +			delete csw->m_addModifyDlg; +			break; + +		case IDC_REMOVE: +			if ( getByte( "ConfirmDeletion", DEFAULT_PLUGIN_CONFIRM_ITEMS_DELETION )) +				if ( MessageBox( hwnd, TranslateT("Do you really want to delete selected item?"), TranslateT(MODULENAME), MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION ) == IDNO ) +					break; + +			csw->m_itemslist->m_list->remove( csw->m_listview->getPositionInList()); +			csw->m_bSomethingChanged = TRUE; +			csw->m_listview->reinitItems( csw->m_itemslist->m_list->getListHead()); +			csw->toggleButtons(); +			csw->toggleEmptyListMessage(); +			break; + +		case IDC_FAVOURITE: +			{ +				int selection = csw->m_listview->getPositionInList(); +				StatusItem* f = new StatusItem( *csw->m_itemslist->m_list->get( selection )); +				f->m_bFavourite = ! f->m_bFavourite; +				csw->m_itemslist->m_list->remove( selection ); +				selection = csw->m_itemslist->m_list->add( f ); +				csw->m_bSomethingChanged = TRUE; +				csw->m_listview->reinitItems( csw->m_itemslist->m_list->getListHead()); +				csw->m_listview->setFullFocusedSelection( selection ); +				csw->toggleButtons(); +			} +			break; + +		case IDC_UNDO: +			csw->m_itemslist->m_list->destroy(); +			csw->m_itemslist->loadItems(csw->m_protoName); +			csw->m_bSomethingChanged = FALSE; +			csw->m_listview->reinitItems( csw->m_itemslist->m_list->getListHead()); +			csw->toggleButtons(); +			csw->toggleEmptyListMessage(); +			break; + +		case IDC_IMPORT: +			{ +				int result = getByte( "DeleteAfterImport", DEFAULT_PLUGIN_DELETE_AFTER_IMPORT ); +				if (result == TRUE) +					result = IDYES; +				else { +					result = MessageBox( hwnd,  +						TranslateT("Do you want old database entries to be deleted after Import?"), +					   TranslateT(MODULENAME), MB_YESNOCANCEL | MB_DEFBUTTON2 | MB_ICONQUESTION ); +					if ( result == IDCANCEL ) +						break; +				} + +				importCustomStatuses(csw, result); +				csw->m_bSomethingChanged = TRUE; +				csw->toggleButtons(); +				csw->toggleEmptyListMessage(); +			} +			break; + +		case IDC_FILTER: +			csw->toggleFilter(); +			csw->toggleButtons(); +			break; + +		case IDC_FILTER_FIELD: +			if ( HIWORD( wparam ) == EN_CHANGE ) +				csw->m_listview->reinitItems( csw->m_itemslist->m_list->getListHead()); +			break; + +		case IDCLOSE:    // close and save, no custom status +		case IDCANCEL:   // close and save, no custom status +		case IDC_CANCEL:   // close and save, cancel custom status +		case IDOK:       // close and save, set selected custom status +			if ( LOWORD( wparam ) == IDOK && csw->toggleButtons()) +				SetStatus(IDOK, csw->m_itemslist->m_list->get(csw->m_listview->getPositionInList()), csw->m_protoName); +			if ( LOWORD( wparam ) == IDC_CANCEL ) +				SetStatus(IDC_CANCEL, NULL, csw->m_protoName); +			if ( csw->m_bSomethingChanged ) +				csw->m_itemslist->saveItems(csw->m_protoName); +			csw->saveWindowPosition(csw->m_handle); +			EndDialog(hwnd, FALSE); +			break; +		} +		return FALSE; + +	case WM_NOTIFY: +		if ( wparam == IDC_CSLIST ) { +			NMHDR* pnmh = ( NMHDR* )lparam; +			switch ( pnmh->code ) { +			case NM_DBLCLK: +				PostMessage( hwnd, WM_COMMAND, IDOK, 0L ); +				break; + +			case LVN_ITEMCHANGED: +			case NM_CLICK: +				csw->toggleButtons(); +				break; +			} +		} +		return FALSE; + +	case WM_CTLCOLORSTATIC: +		SetTextColor(( HDC )wparam, RGB( 174, 174, 174 )); +		if (((HWND)lparam == GetDlgItem(hwnd, IDC_NO_ITEMS)) || ((HWND)lparam == GetDlgItem(hwnd, IDC_ADD_SAMPLE))) +			return ( BOOL )GetStockObject( WHITE_BRUSH ); +		return FALSE; + +	case WM_DESTROY: +		SetWindowLongPtr(hwnd, GWLP_USERDATA, 0); +		arWindows.remove(csw); +		delete csw->m_listview; +		csw->deinitIcons(); +		delete csw; +		break; +	} +	return FALSE; +} + +INT_PTR CALLBACK CSAMWindowProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam ) +{ +	CSAMWindow* csamw = ( CSAMWindow* )GetWindowLongPtr( hwnd, GWLP_USERDATA ); + +	switch ( message ) { +	case WM_INITDIALOG: +		csamw = ( CSAMWindow* )lparam; +		SetWindowLongPtr( hwnd, GWLP_USERDATA, lparam ); +		csamw->m_handle = hwnd; +		EnableWindow( csamw->m_parent->m_handle, FALSE ); +		csamw->m_hCombo = GetDlgItem( hwnd, IDC_COMBO ); +		csamw->m_hMessage = GetDlgItem( hwnd, IDC_MESSAGE ); +		csamw->setCombo(); +		csamw->fillDialog(); +		TranslateDialogDefault(hwnd); +		break; + +	case WM_COMMAND: +		switch ( LOWORD( wparam )) { +		case IDC_MESSAGE: +			csamw->checkFieldLimit( HIWORD( wparam ), LOWORD( wparam )); +			break; + +		case IDOK: +			csamw->checkItemValidity(); + +		case IDCANCEL: +			EnableWindow(csamw->m_parent->m_handle, TRUE); +			EndDialog(hwnd, LOWORD(wparam)); +			break; +		} +		break; +	} +	return FALSE; +} + + +INT_PTR CALLBACK CSOptionsProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam ) +{ +	switch ( message ) { + 	case WM_INITDIALOG: +		TranslateDialogDefault(hwnd); +		CheckDlgButton( hwnd, IDC_CONFIRM_DELETION, +						getByte( "ConfirmDeletion", DEFAULT_PLUGIN_CONFIRM_ITEMS_DELETION ) ? +						BST_CHECKED : BST_UNCHECKED ); + +		CheckDlgButton( hwnd, IDC_DELETE_AFTER_IMPORT, +						getByte( "DeleteAfterImport", DEFAULT_PLUGIN_DELETE_AFTER_IMPORT ) ? +						BST_CHECKED : BST_UNCHECKED ); + +		CheckDlgButton( hwnd, IDC_REMEMBER_POSITION, +			               getByte( "RememberWindowPosition", DEFAULT_REMEMBER_WINDOW_POSITION ) ? +			               BST_CHECKED : BST_UNCHECKED ); +		return TRUE; + +	case WM_NOTIFY: +		switch ((( LPNMHDR )lparam )->code ) { +		case PSN_APPLY: +			setByte( "ConfirmDeletion", IsDlgButtonChecked( hwnd, IDC_CONFIRM_DELETION ) ? 1 : 0 ); +			setByte( "DeleteAfterImport", IsDlgButtonChecked( hwnd, IDC_DELETE_AFTER_IMPORT ) ? 1 : 0 ); +			setByte( "RememberWindowPosition", IsDlgButtonChecked( hwnd, IDC_REMEMBER_POSITION ) ? 1 : 0 ); + +			pcli->pfnReloadProtoMenus(); +			break; +		} +		return TRUE; +	} +	return FALSE; +} | 
