xmlview.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. #include "main.h"
  2. #include <bfc/dispatch.h>
  3. #include <windowsx.h>
  4. #include "shlobj.h"
  5. #include "..\..\General\gen_ml\ml_ipc_0313.h"
  6. #include "..\..\General\gen_ml\childwnd.h"
  7. #include "../Winamp/wa_dlg.h"
  8. #include "../xml/ifc_xmlreadercallback.h"
  9. #include "../xml/obj_xml.h"
  10. #include <api/service/waServiceFactory.h>
  11. #include "resource.h"
  12. #include "api.h"
  13. typedef void (*ChildResizeFunc)(HWND, ChildWndResizeItem*, int);
  14. static ChildResizeFunc ml_childresize_init=0, ml_childresize_resize=0;
  15. typedef int (*HookDialogFunc)(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  16. static HookDialogFunc ml_hook_dialog_msg = 0;
  17. typedef void (*DrawFunc)(HWND hwndDlg, int *tab, int tabsize);
  18. static DrawFunc ml_draw = 0;
  19. LRESULT CALLBACK view_xmlexDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
  20. static HWND m_hwnd;
  21. static ChildWndResizeItem xmlwnd_rlist[]={
  22. {IDC_LIST,0x0011},
  23. {IDC_LOAD,0x0101},
  24. };
  25. //--------------------------
  26. class ListXMLLoader : public ifc_xmlreadercallback
  27. {
  28. public:
  29. ListXMLLoader(HWND _hwndList) : hwndList(_hwndList), index(0) {}
  30. void loadSongFromXml(const wchar_t* filename, const wchar_t* artist, const wchar_t* title)
  31. {
  32. LVITEM lvi = {0, };
  33. lvi.mask = LVIF_TEXT;
  34. lvi.iItem = index;
  35. lvi.pszText = (LPTSTR)filename;
  36. lvi.cchTextMax = lstrlenW(filename);
  37. SendMessage(hwndList, LVM_INSERTITEMW, 0, (LPARAM)&lvi);
  38. lvi.iSubItem = 1;
  39. lvi.pszText = (LPTSTR)artist;
  40. lvi.cchTextMax = lstrlenW(artist);
  41. SendMessageW(hwndList, LVM_SETITEMW, 0, (LPARAM)&lvi);
  42. lvi.iSubItem = 2;
  43. lvi.pszText = (LPTSTR)title;
  44. lvi.cchTextMax = lstrlenW(title);
  45. SendMessageW(hwndList, LVM_SETITEMW, 0, (LPARAM)&lvi);
  46. index++;
  47. }
  48. void reset()
  49. {
  50. ListView_DeleteAllItems(hwndList);
  51. index = 0;
  52. }
  53. void loadXML(wchar_t []);
  54. /* XML loader callback */
  55. void StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params)
  56. {
  57. //read subtags of LIBRARY
  58. if(!wcsicmp(xmlpath, L"LIBRARY\fSONG"))
  59. {
  60. //getItemValue() will return the value for an attribute
  61. loadSongFromXml(params->getItemValue(L"FILENAME"), params->getItemValue(L"ARTIST"),params->getItemValue(L"TITLE"));
  62. }
  63. }
  64. private:
  65. HWND hwndList;
  66. int index;
  67. protected: // this is a Wasabi object, so we need to declare a dispatch table
  68. RECVS_DISPATCH;
  69. };
  70. /* Dispatch table for a Wasabi object */
  71. #define CBCLASS ListXMLLoader
  72. START_DISPATCH;
  73. VCB(ONSTARTELEMENT, StartTag)
  74. END_DISPATCH;
  75. #undef CBCLASS
  76. /* helper function for ListXMLLoader::loadXML */
  77. static bool LoadFile(obj_xml *parser, const wchar_t *filename)
  78. {
  79. HANDLE file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
  80. if (file == INVALID_HANDLE_VALUE)
  81. return false;
  82. char data[1024];
  83. DWORD bytesRead;
  84. while (true)
  85. {
  86. if (ReadFile(file, data, 1024, &bytesRead, NULL) && bytesRead)
  87. {
  88. parser->xmlreader_feed(data, bytesRead);
  89. }
  90. else
  91. break;
  92. }
  93. CloseHandle(file);
  94. parser->xmlreader_feed(0, 0);
  95. return true;
  96. }
  97. void ListXMLLoader::loadXML(wchar_t xmlfile[MAX_PATH] = L"xmltest.xml")
  98. {
  99. // reset the listview state
  100. reset();
  101. // get an XML parser object from the service manager
  102. obj_xml *parser=0;
  103. waServiceFactory *parserFactory = WASABI_API_SVC->service_getServiceByGuid(obj_xmlGUID);
  104. if (parserFactory)
  105. parser = (obj_xml *)parserFactory->getInterface();
  106. if (parser)
  107. {
  108. //set up a tag that we can read
  109. //within StartTag(), we can read all subtags of this tag
  110. parser->xmlreader_registerCallback(L"LIBRARY\f*", this);
  111. parser->xmlreader_open();
  112. LoadFile(parser, xmlfile);
  113. parser->xmlreader_unregisterCallback(this);
  114. parser->xmlreader_close();
  115. parserFactory->releaseInterface(parser);
  116. }
  117. }
  118. //--------------------------
  119. /* This function gets called directly from gen_ml when it wants our plugin to do something
  120. we're only handling dialog creation, but there are lots of other messages a full-featured
  121. plugin would deal with */
  122. INT_PTR xmlex_pluginMessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3)
  123. {
  124. if (message_type == ML_MSG_TREE_ONCREATEVIEW && param1 == xmlex_treeItem)
  125. {
  126. return (INT_PTR)CreateDialog(plugin.hDllInstance, MAKEINTRESOURCE(IDD_VIEW_XMLEX), (HWND)(LONG_PTR)param2, (DLGPROC)view_xmlexDialogProc);
  127. }
  128. return 0;
  129. }
  130. static BOOL xmlex_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  131. {
  132. /* gen_ml has some helper functions to deal with skinned dialogs,
  133. we're going to grab their function pointers.
  134. for definition of magic numbers, see gen_ml/ml.h */
  135. if (!ml_childresize_init)
  136. {
  137. /* skinning helper functions */
  138. ml_hook_dialog_msg = (HookDialogFunc)SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)2, ML_IPC_SKIN_WADLG_GETFUNC);
  139. ml_draw = (DrawFunc)SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)3, ML_IPC_SKIN_WADLG_GETFUNC);
  140. /* resizing helper functions */
  141. ml_childresize_init = (ChildResizeFunc)SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)32, ML_IPC_SKIN_WADLG_GETFUNC);
  142. ml_childresize_resize = (ChildResizeFunc)SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)33, ML_IPC_SKIN_WADLG_GETFUNC);
  143. }
  144. m_hwnd=hwnd;
  145. HWND listWnd = GetDlgItem(hwnd,IDC_LIST);
  146. /* add listview columns */
  147. LVCOLUMN lvc = {0, };
  148. lvc.mask = LVCF_TEXT | LVCF_WIDTH;
  149. lvc.pszText = (LPTSTR)L"Filename";
  150. lvc.cx = 250;
  151. SendMessageW(listWnd, LVM_INSERTCOLUMNW, (WPARAM)0, (LPARAM)&lvc);
  152. lvc.pszText = (LPTSTR)L"Artist";
  153. lvc.cx = 150;
  154. SendMessageW(listWnd, LVM_INSERTCOLUMNW, (WPARAM)1, (LPARAM)&lvc);
  155. lvc.pszText = (LPTSTR)L"Title";
  156. lvc.cx = 150;
  157. SendMessageW(listWnd, LVM_INSERTCOLUMNW, (WPARAM)2, (LPARAM)&lvc);
  158. /* skin dialog */
  159. MLSKINWINDOW sw;
  160. sw.skinType = SKINNEDWND_TYPE_DIALOG;
  161. sw.style = SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWS_USESKINFONT;
  162. sw.hwndToSkin = hwnd;
  163. MLSkinWindow(plugin.hwndLibraryParent, &sw);
  164. /* skin listview */
  165. sw.hwndToSkin = listWnd;
  166. sw.skinType = SKINNEDWND_TYPE_LISTVIEW;
  167. sw.style = SWLVS_FULLROWSELECT | SWLVS_DOUBLEBUFFER | SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS;
  168. MLSkinWindow(plugin.hwndLibraryParent, &sw);
  169. /* skin button */
  170. sw.skinType = SKINNEDWND_TYPE_BUTTON;
  171. sw.style = SWS_USESKINCOLORS | SWS_USESKINCURSORS | SWS_USESKINFONT;
  172. sw.hwndToSkin = GetDlgItem(hwnd, IDC_LOAD);
  173. MLSkinWindow(plugin.hwndLibraryParent, &sw);
  174. ml_childresize_init(hwnd, xmlwnd_rlist, sizeof(xmlwnd_rlist) / sizeof(xmlwnd_rlist[0]));
  175. //all other initialization is done. lets wait 20ms before we actually do anything with this plugin
  176. //this way other (more important) things finish before this does
  177. SetTimer(hwnd,101,20,NULL);
  178. return FALSE;
  179. }
  180. static BOOL xmlex_OnSize(HWND hwnd, UINT state, int cx, int cy)
  181. {
  182. if (state != SIZE_MINIMIZED)
  183. ml_childresize_resize(hwnd, xmlwnd_rlist, sizeof(xmlwnd_rlist) / sizeof(xmlwnd_rlist[0]));
  184. return FALSE;
  185. }
  186. static BOOL xmlex_OnDestroy(HWND hwnd)
  187. {
  188. m_hwnd=0;
  189. return FALSE;
  190. }
  191. static void xmlex_OnTimer(HWND hwnd, UINT id)
  192. {
  193. if (id == 101)
  194. {
  195. KillTimer(hwnd,101);
  196. // 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)
  197. ListXMLLoader loader(GetDlgItem(hwnd, IDC_LIST));
  198. loader.loadXML();
  199. }
  200. }
  201. static BOOL xmlex_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  202. {
  203. switch(id) {
  204. case IDC_LOAD:
  205. {
  206. wchar_t filename[256] = L"";
  207. //browse box supported in windows 2000+
  208. //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
  209. OPENFILENAME ofn = {0};
  210. ofn.lStructSize = sizeof (OPENFILENAME);
  211. ofn.hwndOwner=hwnd;
  212. ofn.lpstrFilter=L"XML Files (*.xml)\0*.XML\0\0";
  213. ofn.lpstrCustomFilter=NULL;
  214. ofn.nFilterIndex=1;
  215. ofn.lpstrFile=filename; //contains file name after user has selected it
  216. ofn.nMaxFile=MAX_PATH;
  217. ofn.lpstrFileTitle=NULL;
  218. ofn.lpstrInitialDir=NULL;
  219. ofn.Flags=OFN_PATHMUSTEXIST;
  220. GetOpenFileName(&ofn);
  221. if(*filename) //do not load on browse -> cancel
  222. {
  223. ListXMLLoader loader(GetDlgItem(hwnd, IDC_LIST));
  224. loader.loadXML(filename);
  225. }
  226. }
  227. break;
  228. }
  229. return 0;
  230. }
  231. LRESULT CALLBACK view_xmlexDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
  232. {
  233. /* first, ask the dialog skinning system if it wants to do anything with the message
  234. the function pointer gets set during WM_INITDIALOG so might be NULL for the first few messages
  235. in theory we could grab it right here if we don't have it, but it's not necessary
  236. and I wanted to put all the function pointer gathering code in the same place for this example */
  237. if (ml_hook_dialog_msg)
  238. {
  239. INT_PTR a = ml_hook_dialog_msg(hwndDlg, uMsg, wParam, lParam);
  240. if (a)
  241. return a;
  242. }
  243. switch(uMsg) {
  244. HANDLE_MSG(hwndDlg, WM_INITDIALOG, xmlex_OnInitDialog);
  245. HANDLE_MSG(hwndDlg, WM_TIMER, xmlex_OnTimer);
  246. HANDLE_MSG(hwndDlg, WM_COMMAND, xmlex_OnCommand);
  247. HANDLE_MSG(hwndDlg, WM_SIZE, xmlex_OnSize);
  248. case WM_PAINT:
  249. {
  250. int tab[] = { IDC_LIST|DCW_SUNKENBORDER};
  251. ml_draw(hwndDlg, tab, sizeof(tab) / sizeof(tab[0]));
  252. }
  253. return 0;
  254. HANDLE_MSG(hwndDlg, WM_DESTROY, xmlex_OnDestroy);
  255. }
  256. return FALSE;
  257. }