#include "main.h" #include #include #include "shlobj.h" #include "..\..\General\gen_ml\ml_ipc_0313.h" #include "..\..\General\gen_ml\childwnd.h" #include "../Winamp/wa_dlg.h" #include "../xml/ifc_xmlreadercallback.h" #include "../xml/obj_xml.h" #include #include "resource.h" #include "api.h" typedef void (*ChildResizeFunc)(HWND, ChildWndResizeItem*, int); static ChildResizeFunc ml_childresize_init=0, ml_childresize_resize=0; typedef int (*HookDialogFunc)(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); static HookDialogFunc ml_hook_dialog_msg = 0; typedef void (*DrawFunc)(HWND hwndDlg, int *tab, int tabsize); static DrawFunc ml_draw = 0; LRESULT CALLBACK view_xmlexDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam); static HWND m_hwnd; static ChildWndResizeItem xmlwnd_rlist[]={ {IDC_LIST,0x0011}, {IDC_LOAD,0x0101}, }; //-------------------------- class ListXMLLoader : public ifc_xmlreadercallback { public: ListXMLLoader(HWND _hwndList) : hwndList(_hwndList), index(0) {} void loadSongFromXml(const wchar_t* filename, const wchar_t* artist, const wchar_t* title) { LVITEM lvi = {0, }; lvi.mask = LVIF_TEXT; lvi.iItem = index; lvi.pszText = (LPTSTR)filename; lvi.cchTextMax = lstrlenW(filename); SendMessage(hwndList, LVM_INSERTITEMW, 0, (LPARAM)&lvi); lvi.iSubItem = 1; lvi.pszText = (LPTSTR)artist; lvi.cchTextMax = lstrlenW(artist); SendMessageW(hwndList, LVM_SETITEMW, 0, (LPARAM)&lvi); lvi.iSubItem = 2; lvi.pszText = (LPTSTR)title; lvi.cchTextMax = lstrlenW(title); SendMessageW(hwndList, LVM_SETITEMW, 0, (LPARAM)&lvi); index++; } void reset() { ListView_DeleteAllItems(hwndList); index = 0; } void loadXML(wchar_t []); /* XML loader callback */ void StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params) { //read subtags of LIBRARY if(!wcsicmp(xmlpath, L"LIBRARY\fSONG")) { //getItemValue() will return the value for an attribute loadSongFromXml(params->getItemValue(L"FILENAME"), params->getItemValue(L"ARTIST"),params->getItemValue(L"TITLE")); } } private: HWND hwndList; int index; protected: // this is a Wasabi object, so we need to declare a dispatch table RECVS_DISPATCH; }; /* Dispatch table for a Wasabi object */ #define CBCLASS ListXMLLoader START_DISPATCH; VCB(ONSTARTELEMENT, StartTag) END_DISPATCH; #undef CBCLASS /* helper function for ListXMLLoader::loadXML */ static bool LoadFile(obj_xml *parser, const wchar_t *filename) { HANDLE file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); if (file == INVALID_HANDLE_VALUE) return false; char data[1024]; DWORD bytesRead; while (true) { if (ReadFile(file, data, 1024, &bytesRead, NULL) && bytesRead) { parser->xmlreader_feed(data, bytesRead); } else break; } CloseHandle(file); parser->xmlreader_feed(0, 0); return true; } void ListXMLLoader::loadXML(wchar_t xmlfile[MAX_PATH] = L"xmltest.xml") { // reset the listview state reset(); // get an XML parser object from the service manager obj_xml *parser=0; waServiceFactory *parserFactory = WASABI_API_SVC->service_getServiceByGuid(obj_xmlGUID); if (parserFactory) parser = (obj_xml *)parserFactory->getInterface(); if (parser) { //set up a tag that we can read //within StartTag(), we can read all subtags of this tag parser->xmlreader_registerCallback(L"LIBRARY\f*", this); parser->xmlreader_open(); LoadFile(parser, xmlfile); parser->xmlreader_unregisterCallback(this); parser->xmlreader_close(); parserFactory->releaseInterface(parser); } } //-------------------------- /* This function gets called directly from gen_ml when it wants our plugin to do something we're only handling dialog creation, but there are lots of other messages a full-featured plugin would deal with */ INT_PTR xmlex_pluginMessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3) { if (message_type == ML_MSG_TREE_ONCREATEVIEW && param1 == xmlex_treeItem) { return (INT_PTR)CreateDialog(plugin.hDllInstance, MAKEINTRESOURCE(IDD_VIEW_XMLEX), (HWND)(LONG_PTR)param2, (DLGPROC)view_xmlexDialogProc); } return 0; } static BOOL xmlex_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) { /* gen_ml has some helper functions to deal with skinned dialogs, we're going to grab their function pointers. for definition of magic numbers, see gen_ml/ml.h */ if (!ml_childresize_init) { /* skinning helper functions */ ml_hook_dialog_msg = (HookDialogFunc)SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)2, ML_IPC_SKIN_WADLG_GETFUNC); ml_draw = (DrawFunc)SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)3, ML_IPC_SKIN_WADLG_GETFUNC); /* resizing helper functions */ ml_childresize_init = (ChildResizeFunc)SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)32, ML_IPC_SKIN_WADLG_GETFUNC); ml_childresize_resize = (ChildResizeFunc)SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)33, ML_IPC_SKIN_WADLG_GETFUNC); } m_hwnd=hwnd; HWND listWnd = GetDlgItem(hwnd,IDC_LIST); /* add listview columns */ LVCOLUMN lvc = {0, }; lvc.mask = LVCF_TEXT | LVCF_WIDTH; lvc.pszText = (LPTSTR)L"Filename"; lvc.cx = 250; SendMessageW(listWnd, LVM_INSERTCOLUMNW, (WPARAM)0, (LPARAM)&lvc); lvc.pszText = (LPTSTR)L"Artist"; lvc.cx = 150; SendMessageW(listWnd, LVM_INSERTCOLUMNW, (WPARAM)1, (LPARAM)&lvc); lvc.pszText = (LPTSTR)L"Title"; lvc.cx = 150; SendMessageW(listWnd, LVM_INSERTCOLUMNW, (WPARAM)2, (LPARAM)&lvc); /* skin dialog */ MLSKINWINDOW sw; sw.skinType = SKINNEDWND_TYPE_DIALOG; sw.style = SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWS_USESKINFONT; sw.hwndToSkin = hwnd; MLSkinWindow(plugin.hwndLibraryParent, &sw); /* skin listview */ sw.hwndToSkin = listWnd; sw.skinType = SKINNEDWND_TYPE_LISTVIEW; sw.style = SWLVS_FULLROWSELECT | SWLVS_DOUBLEBUFFER | SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS; MLSkinWindow(plugin.hwndLibraryParent, &sw); /* skin button */ sw.skinType = SKINNEDWND_TYPE_BUTTON; sw.style = SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWS_USESKINFONT; sw.hwndToSkin = GetDlgItem(hwnd, IDC_LOAD); MLSkinWindow(plugin.hwndLibraryParent, &sw); ml_childresize_init(hwnd, xmlwnd_rlist, sizeof(xmlwnd_rlist) / sizeof(xmlwnd_rlist[0])); //all other initialization is done. lets wait 20ms before we actually do anything with this plugin //this way other (more important) things finish before this does SetTimer(hwnd,101,20,NULL); return FALSE; } static BOOL xmlex_OnSize(HWND hwnd, UINT state, int cx, int cy) { if (state != SIZE_MINIMIZED) ml_childresize_resize(hwnd, xmlwnd_rlist, sizeof(xmlwnd_rlist) / sizeof(xmlwnd_rlist[0])); return FALSE; } static BOOL xmlex_OnDestroy(HWND hwnd) { m_hwnd=0; return FALSE; } static void xmlex_OnTimer(HWND hwnd, UINT id) { if (id == 101) { KillTimer(hwnd,101); // populate list with default local file, no pre-loaded xml file if not in working dir (really will only pre-load something in debug mode) ListXMLLoader loader(GetDlgItem(hwnd, IDC_LIST)); loader.loadXML(); } } static BOOL xmlex_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) { switch(id) { case IDC_LOAD: { wchar_t filename[256] = L""; //browse box supported in windows 2000+ //if this doesnt work for you (old versions of windows) just know that the file name is set in ofn.lpstrFile which is then moved to filename variable OPENFILENAME ofn = {0}; ofn.lStructSize = sizeof (OPENFILENAME); ofn.hwndOwner=hwnd; ofn.lpstrFilter=L"XML Files (*.xml)\0*.XML\0\0"; ofn.lpstrCustomFilter=NULL; ofn.nFilterIndex=1; ofn.lpstrFile=filename; //contains file name after user has selected it ofn.nMaxFile=MAX_PATH; ofn.lpstrFileTitle=NULL; ofn.lpstrInitialDir=NULL; ofn.Flags=OFN_PATHMUSTEXIST; GetOpenFileName(&ofn); if(*filename) //do not load on browse -> cancel { ListXMLLoader loader(GetDlgItem(hwnd, IDC_LIST)); loader.loadXML(filename); } } break; } return 0; } LRESULT CALLBACK view_xmlexDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) { /* first, ask the dialog skinning system if it wants to do anything with the message the function pointer gets set during WM_INITDIALOG so might be NULL for the first few messages in theory we could grab it right here if we don't have it, but it's not necessary and I wanted to put all the function pointer gathering code in the same place for this example */ if (ml_hook_dialog_msg) { INT_PTR a = ml_hook_dialog_msg(hwndDlg, uMsg, wParam, lParam); if (a) return a; } switch(uMsg) { HANDLE_MSG(hwndDlg, WM_INITDIALOG, xmlex_OnInitDialog); HANDLE_MSG(hwndDlg, WM_TIMER, xmlex_OnTimer); HANDLE_MSG(hwndDlg, WM_COMMAND, xmlex_OnCommand); HANDLE_MSG(hwndDlg, WM_SIZE, xmlex_OnSize); case WM_PAINT: { int tab[] = { IDC_LIST|DCW_SUNKENBORDER}; ml_draw(hwndDlg, tab, sizeof(tab) / sizeof(tab[0])); } return 0; HANDLE_MSG(hwndDlg, WM_DESTROY, xmlex_OnDestroy); } return FALSE; }