PageRenderTime 349ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/xbmc/interfaces/python/xbmcmodule/GUIPythonWindowXML.cpp

https://github.com/xbmc/xbmc-rbp
C++ | 457 lines | 344 code | 55 blank | 58 comment | 59 complexity | 6c8366b998f1e65ab369f0a7ad96730d MD5 | raw file
  1. /*
  2. * Copyright (C) 2005-2008 Team XBMC
  3. * http://www.xbmc.org
  4. *
  5. * This Program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2, or (at your option)
  8. * any later version.
  9. *
  10. * This Program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with XBMC; see the file COPYING. If not, write to
  17. * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  18. * http://www.gnu.org/copyleft/gpl.html
  19. *
  20. */
  21. #include "pyutil.h"
  22. #include "GUIPythonWindowXML.h"
  23. #include "window.h"
  24. #include "control.h"
  25. #include "action.h"
  26. #include "utils/URIUtils.h"
  27. #include "guilib/GUIWindowManager.h"
  28. #include "FileItem.h"
  29. #include "filesystem/File.h"
  30. #include "guilib/TextureManager.h"
  31. #include "../XBPython.h"
  32. #include "settings/GUISettings.h"
  33. #include "guilib/LocalizeStrings.h"
  34. #include "utils/log.h"
  35. #include "utils/XBMCTinyXML.h"
  36. using namespace std;
  37. #define CONTROL_BTNVIEWASICONS 2
  38. #define CONTROL_BTNSORTBY 3
  39. #define CONTROL_BTNSORTASC 4
  40. #define CONTROL_LABELFILES 12
  41. using namespace PYXBMC;
  42. CGUIPythonWindowXML::CGUIPythonWindowXML(int id, CStdString strXML, CStdString strFallBackPath)
  43. : CGUIMediaWindow(id, strXML), m_actionEvent(true)
  44. {
  45. pCallbackWindow = NULL;
  46. m_threadState = NULL;
  47. m_loadOnDemand = false;
  48. m_scriptPath = strFallBackPath;
  49. m_destroyAfterDeinit = false;
  50. }
  51. CGUIPythonWindowXML::~CGUIPythonWindowXML(void)
  52. {
  53. }
  54. bool CGUIPythonWindowXML::Update(const CStdString &strPath)
  55. {
  56. return true;
  57. }
  58. bool CGUIPythonWindowXML::OnAction(const CAction &action)
  59. {
  60. // call the base class first, then call python
  61. bool ret = CGUIWindow::OnAction(action);
  62. if(pCallbackWindow)
  63. {
  64. PyXBMCAction* inf = new PyXBMCAction(pCallbackWindow);
  65. inf->pObject = Action_FromAction(action);
  66. // aquire lock?
  67. PyXBMC_AddPendingCall((PyThreadState*)m_threadState, Py_XBMC_Event_OnAction, inf);
  68. PulseActionEvent();
  69. }
  70. return ret;
  71. }
  72. bool CGUIPythonWindowXML::OnBack(int actionID)
  73. {
  74. // if we have a callback window then python handles the closing
  75. if (!pCallbackWindow)
  76. return CGUIWindow::OnBack(actionID);
  77. return true;
  78. }
  79. bool CGUIPythonWindowXML::OnClick(int iItem) {
  80. // Hook Over calling CGUIMediaWindow::OnClick(iItem) results in it trying to PLAY the file item
  81. // which if its not media is BAD and 99 out of 100 times undesireable.
  82. return false;
  83. }
  84. // SetupShares();
  85. /*
  86. CGUIMediaWindow::OnWindowLoaded() calls SetupShares() so override it
  87. and just call UpdateButtons();
  88. */
  89. void CGUIPythonWindowXML::SetupShares()
  90. {
  91. UpdateButtons();
  92. }
  93. bool CGUIPythonWindowXML::OnMessage(CGUIMessage& message)
  94. {
  95. // TODO: We shouldn't be dropping down to CGUIWindow in any of this ideally.
  96. // We have to make up our minds about what python should be doing and
  97. // what this side of things should be doing
  98. switch (message.GetMessage())
  99. {
  100. case GUI_MSG_WINDOW_DEINIT:
  101. {
  102. return CGUIMediaWindow::OnMessage(message);
  103. }
  104. break;
  105. case GUI_MSG_WINDOW_INIT:
  106. {
  107. CGUIMediaWindow::OnMessage(message);
  108. if(pCallbackWindow)
  109. {
  110. PyXBMC_AddPendingCall((PyThreadState*)m_threadState, Py_XBMC_Event_OnInit, new PyXBMCAction(pCallbackWindow));
  111. PulseActionEvent();
  112. }
  113. return true;
  114. }
  115. break;
  116. case GUI_MSG_FOCUSED:
  117. {
  118. if (m_viewControl.HasControl(message.GetControlId()) && m_viewControl.GetCurrentControl() != (int)message.GetControlId())
  119. {
  120. m_viewControl.SetFocused();
  121. return true;
  122. }
  123. // check if our focused control is one of our category buttons
  124. int iControl=message.GetControlId();
  125. if(pCallbackWindow)
  126. {
  127. PyXBMCAction* inf = new PyXBMCAction(pCallbackWindow);
  128. inf->controlId = iControl;
  129. // aquire lock?
  130. PyXBMC_AddPendingCall((PyThreadState*)m_threadState, Py_XBMC_Event_OnFocus, inf);
  131. PulseActionEvent();
  132. }
  133. }
  134. break;
  135. case GUI_MSG_CLICKED:
  136. {
  137. int iControl=message.GetSenderId();
  138. // Handle Sort/View internally. Scripters shouldn't use ID 2, 3 or 4.
  139. if (iControl == CONTROL_BTNSORTASC) // sort asc
  140. {
  141. CLog::Log(LOGINFO, "WindowXML: Internal asc/dsc button not implemented");
  142. /*if (m_guiState.get())
  143. m_guiState->SetNextSortOrder();
  144. UpdateFileList();*/
  145. return true;
  146. }
  147. else if (iControl == CONTROL_BTNSORTBY) // sort by
  148. {
  149. CLog::Log(LOGINFO, "WindowXML: Internal sort button not implemented");
  150. /*if (m_guiState.get())
  151. m_guiState->SetNextSortMethod();
  152. UpdateFileList();*/
  153. return true;
  154. }
  155. else if (iControl == CONTROL_BTNVIEWASICONS)
  156. { // base class handles this one
  157. break;
  158. }
  159. if(pCallbackWindow && iControl && iControl != (int)this->GetID()) // pCallbackWindow && != this->GetID())
  160. {
  161. CGUIControl* controlClicked = (CGUIControl*)this->GetControl(iControl);
  162. // The old python way used to check list AND SELECITEM method or if its a button, checkmark.
  163. // Its done this way for now to allow other controls without a python version like togglebutton to still raise a onAction event
  164. if (controlClicked) // Will get problems if we the id is not on the window and we try to do GetControlType on it. So check to make sure it exists
  165. {
  166. if ((controlClicked->IsContainer() && (message.GetParam1() == ACTION_SELECT_ITEM || message.GetParam1() == ACTION_MOUSE_LEFT_CLICK)) || !controlClicked->IsContainer())
  167. {
  168. PyXBMCAction* inf = new PyXBMCAction(pCallbackWindow);
  169. inf->controlId = iControl;
  170. // aquire lock?
  171. PyXBMC_AddPendingCall((PyThreadState*)m_threadState, Py_XBMC_Event_OnClick, inf);
  172. PulseActionEvent();
  173. return true;
  174. }
  175. else if (controlClicked->IsContainer() && message.GetParam1() == ACTION_MOUSE_RIGHT_CLICK)
  176. {
  177. PyXBMCAction* inf = new PyXBMCAction(pCallbackWindow);
  178. inf->pObject = Action_FromAction(CAction(ACTION_CONTEXT_MENU));
  179. // aquire lock?
  180. PyXBMC_AddPendingCall((PyThreadState*)m_threadState, Py_XBMC_Event_OnAction, inf);
  181. PulseActionEvent();
  182. return true;
  183. }
  184. }
  185. }
  186. }
  187. break;
  188. }
  189. return CGUIMediaWindow::OnMessage(message);
  190. }
  191. void CGUIPythonWindowXML::OnDeinitWindow(int nextWindowID /*= 0*/)
  192. {
  193. CGUIMediaWindow::OnDeinitWindow(nextWindowID);
  194. if (m_destroyAfterDeinit)
  195. g_windowManager.Delete(GetID());
  196. }
  197. void CGUIPythonWindowXML::SetDestroyAfterDeinit(bool destroy /*= true*/)
  198. {
  199. m_destroyAfterDeinit = destroy;
  200. }
  201. void CGUIPythonWindowXML::AddItem(CFileItemPtr fileItem, int itemPosition)
  202. {
  203. if (itemPosition == INT_MAX || itemPosition > m_vecItems->Size())
  204. {
  205. m_vecItems->Add(fileItem);
  206. }
  207. else if (itemPosition < -1 && !(itemPosition*-1 < m_vecItems->Size()))
  208. {
  209. m_vecItems->AddFront(fileItem,0);
  210. }
  211. else
  212. {
  213. m_vecItems->AddFront(fileItem,itemPosition);
  214. }
  215. m_viewControl.SetItems(*m_vecItems);
  216. UpdateButtons();
  217. }
  218. void CGUIPythonWindowXML::RemoveItem(int itemPosition)
  219. {
  220. m_vecItems->Remove(itemPosition);
  221. m_viewControl.SetItems(*m_vecItems);
  222. UpdateButtons();
  223. }
  224. int CGUIPythonWindowXML::GetListSize()
  225. {
  226. return m_vecItems->Size();
  227. }
  228. int CGUIPythonWindowXML::GetCurrentListPosition()
  229. {
  230. return m_viewControl.GetSelectedItem();
  231. }
  232. void CGUIPythonWindowXML::SetCurrentListPosition(int item)
  233. {
  234. m_viewControl.SetSelectedItem(item);
  235. }
  236. void CGUIPythonWindowXML::SetProperty(const CStdString& key, const CStdString& value)
  237. {
  238. m_vecItems->SetProperty(key, value);
  239. }
  240. CFileItemPtr CGUIPythonWindowXML::GetListItem(int position)
  241. {
  242. if (position < 0 || position >= m_vecItems->Size()) return CFileItemPtr();
  243. return m_vecItems->Get(position);
  244. }
  245. void CGUIPythonWindowXML::ClearList()
  246. {
  247. ClearFileItems();
  248. m_viewControl.SetItems(*m_vecItems);
  249. UpdateButtons();
  250. }
  251. void CGUIPythonWindowXML::WaitForActionEvent()
  252. {
  253. g_pythonParser.WaitForEvent(m_actionEvent);
  254. m_actionEvent.Reset();
  255. }
  256. void CGUIPythonWindowXML::PulseActionEvent()
  257. {
  258. m_actionEvent.Set();
  259. }
  260. void CGUIPythonWindowXML::AllocResources(bool forceLoad /*= FALSE */)
  261. {
  262. CStdString tmpDir;
  263. URIUtils::GetDirectory(GetProperty("xmlfile").asString(), tmpDir);
  264. CStdString fallbackMediaPath;
  265. URIUtils::GetParentPath(tmpDir, fallbackMediaPath);
  266. URIUtils::RemoveSlashAtEnd(fallbackMediaPath);
  267. m_mediaDir = fallbackMediaPath;
  268. //CLog::Log(LOGDEBUG, "CGUIPythonWindowXML::AllocResources called: %s", fallbackMediaPath.c_str());
  269. g_TextureManager.AddTexturePath(m_mediaDir);
  270. CGUIMediaWindow::AllocResources(forceLoad);
  271. g_TextureManager.RemoveTexturePath(m_mediaDir);
  272. }
  273. bool CGUIPythonWindowXML::LoadXML(const CStdString &strPath, const CStdString &strLowerPath)
  274. {
  275. // load our window
  276. XFILE::CFile file;
  277. if (!file.Open(strPath) && !file.Open(CStdString(strPath).ToLower()) && !file.Open(strLowerPath))
  278. {
  279. // fail - can't load the file
  280. CLog::Log(LOGERROR, "%s: Unable to load skin file %s", __FUNCTION__, strPath.c_str());
  281. return false;
  282. }
  283. // load the strings in
  284. unsigned int offset = LoadScriptStrings();
  285. CStdString xml;
  286. char *buffer = new char[(unsigned int)file.GetLength()+1];
  287. if(buffer == NULL)
  288. return false;
  289. int size = file.Read(buffer, file.GetLength());
  290. if (size > 0)
  291. {
  292. buffer[size] = 0;
  293. xml = buffer;
  294. if (offset)
  295. {
  296. // replace the occurences of SCRIPT### with offset+###
  297. // not particularly efficient, but it works
  298. int pos = xml.Find("SCRIPT");
  299. while (pos != (int)CStdString::npos)
  300. {
  301. CStdString num = xml.Mid(pos + 6, 4);
  302. int number = atol(num.c_str());
  303. CStdString oldNumber, newNumber;
  304. oldNumber.Format("SCRIPT%d", number);
  305. newNumber.Format("%lu", offset + number);
  306. xml.Replace(oldNumber, newNumber);
  307. pos = xml.Find("SCRIPT", pos + 6);
  308. }
  309. }
  310. }
  311. delete[] buffer;
  312. CXBMCTinyXML xmlDoc;
  313. xmlDoc.Parse(xml.c_str());
  314. if (xmlDoc.Error())
  315. return false;
  316. return Load(xmlDoc);
  317. }
  318. void CGUIPythonWindowXML::FreeResources(bool forceUnLoad /*= FALSE */)
  319. {
  320. // Unload temporary language strings
  321. ClearScriptStrings();
  322. CGUIMediaWindow::FreeResources(forceUnLoad);
  323. }
  324. void CGUIPythonWindowXML::Process(unsigned int currentTime, CDirtyRegionList &regions)
  325. {
  326. g_TextureManager.AddTexturePath(m_mediaDir);
  327. CGUIMediaWindow::Process(currentTime, regions);
  328. g_TextureManager.RemoveTexturePath(m_mediaDir);
  329. }
  330. int Py_XBMC_Event_OnClick(void* arg)
  331. {
  332. if(!arg)
  333. return 0;
  334. PyXBMCAction* action = (PyXBMCAction*)arg;
  335. if (action->pCallbackWindow)
  336. {
  337. PyObject *ret = PyObject_CallMethod((PyObject*)action->pCallbackWindow, (char*)"onClick", (char*)"(i)", action->controlId);
  338. if (ret)
  339. {
  340. Py_DECREF(ret);
  341. }
  342. }
  343. delete action;
  344. return 0;
  345. }
  346. int Py_XBMC_Event_OnFocus(void* arg)
  347. {
  348. if(!arg)
  349. return 0;
  350. PyXBMCAction* action = (PyXBMCAction*)arg;
  351. if (action->pCallbackWindow)
  352. {
  353. PyObject *ret = PyObject_CallMethod((PyObject*)action->pCallbackWindow, (char*)"onFocus", (char*)"(i)", action->controlId);
  354. if (ret)
  355. {
  356. Py_DECREF(ret);
  357. }
  358. delete action;
  359. }
  360. return 0;
  361. }
  362. int Py_XBMC_Event_OnInit(void* arg)
  363. {
  364. if(!arg)
  365. return 0;
  366. PyXBMCAction* action = (PyXBMCAction*)arg;
  367. if (action->pCallbackWindow)
  368. {
  369. PyObject *ret = PyObject_CallMethod((PyObject*)action->pCallbackWindow, (char*)"onInit", (char*)"()"); //, (char*)"O", &self);
  370. if (ret)
  371. {
  372. Py_XDECREF(ret);
  373. }
  374. }
  375. delete action;
  376. return 0;
  377. }
  378. void CGUIPythonWindowXML::SetCallbackWindow(void *state, void *object)
  379. {
  380. pCallbackWindow = object;
  381. m_threadState = state;
  382. }
  383. void CGUIPythonWindowXML::GetContextButtons(int itemNumber, CContextButtons &buttons)
  384. {
  385. // maybe on day we can make an easy way to do this context menu
  386. // with out this method overriding the MediaWindow version, it will display 'Add to Favorites'
  387. }
  388. unsigned int CGUIPythonWindowXML::LoadScriptStrings()
  389. {
  390. // Path where the language strings reside
  391. CStdString pathToLanguageFile = m_scriptPath;
  392. URIUtils::AddFileToFolder(pathToLanguageFile, "resources", pathToLanguageFile);
  393. URIUtils::AddFileToFolder(pathToLanguageFile, "language", pathToLanguageFile);
  394. URIUtils::AddSlashAtEnd(pathToLanguageFile);
  395. // allocate a bunch of strings
  396. return g_localizeStrings.LoadBlock(m_scriptPath, pathToLanguageFile, g_guiSettings.GetString("locale.language"));
  397. }
  398. void CGUIPythonWindowXML::ClearScriptStrings()
  399. {
  400. // Unload temporary language strings
  401. g_localizeStrings.ClearBlock(m_scriptPath);
  402. }