[osx/ios] remove unused function
[vuplus_xbmc] / xbmc / interfaces / python / xbmcmodule / GUIPythonWindowXML.cpp
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
22 #include "GUIPythonWindowXML.h"
23 #include "pyutil.h"
24 #include "window.h"
25 #include "control.h"
26 #include "action.h"
27 #include "utils/URIUtils.h"
28 #include "guilib/GUIWindowManager.h"
29 #include "FileItem.h"
30 #include "filesystem/File.h"
31 #include "guilib/TextureManager.h"
32 #include "../XBPython.h"
33 #include "settings/GUISettings.h"
34 #include "guilib/LocalizeStrings.h"
35 #include "utils/log.h"
36 #include "tinyXML/tinyxml.h"
37
38 using namespace std;
39
40 #define CONTROL_BTNVIEWASICONS  2
41 #define CONTROL_BTNSORTBY       3
42 #define CONTROL_BTNSORTASC      4
43 #define CONTROL_LABELFILES      12
44
45 using namespace PYXBMC;
46
47 CGUIPythonWindowXML::CGUIPythonWindowXML(int id, CStdString strXML, CStdString strFallBackPath)
48 : CGUIMediaWindow(id, strXML)
49 {
50   pCallbackWindow = NULL;
51   m_threadState = NULL;
52   m_actionEvent = CreateEvent(NULL, true, false, NULL);
53   m_loadOnDemand = false;
54   m_coordsRes = RES_PAL_4x3;
55   m_scriptPath = strFallBackPath;
56 }
57
58 CGUIPythonWindowXML::~CGUIPythonWindowXML(void)
59 {
60   CloseHandle(m_actionEvent);
61 }
62
63 bool CGUIPythonWindowXML::Update(const CStdString &strPath)
64 {
65   return true;
66 }
67
68 bool CGUIPythonWindowXML::OnAction(const CAction &action)
69 {
70   // do the base class window first, and the call to python after this
71   bool ret = CGUIWindow::OnAction(action);  // we don't currently want the mediawindow actions here
72   if(pCallbackWindow)
73   {
74     PyXBMCAction* inf = new PyXBMCAction(pCallbackWindow);
75     inf->pObject = Action_FromAction(action);
76
77     // aquire lock?
78     PyXBMC_AddPendingCall(m_threadState, Py_XBMC_Event_OnAction, inf);
79     PulseActionEvent();
80   }
81   return ret;
82 }
83
84 bool CGUIPythonWindowXML::OnClick(int iItem) {
85   // Hook Over calling  CGUIMediaWindow::OnClick(iItem) results in it trying to PLAY the file item
86   // which if its not media is BAD and 99 out of 100 times undesireable.
87   return false;
88 }
89
90 // SetupShares();
91 /*
92  CGUIMediaWindow::OnWindowLoaded() calls SetupShares() so override it
93 and just call UpdateButtons();
94 */
95 void CGUIPythonWindowXML::SetupShares()
96 {
97   UpdateButtons();
98 }
99
100 bool CGUIPythonWindowXML::OnMessage(CGUIMessage& message)
101 {
102   // TODO: We shouldn't be dropping down to CGUIWindow in any of this ideally.
103   //       We have to make up our minds about what python should be doing and
104   //       what this side of things should be doing
105   switch (message.GetMessage())
106   {
107     case GUI_MSG_WINDOW_DEINIT:
108     {
109       return CGUIMediaWindow::OnMessage(message);
110     }
111     break;
112
113     case GUI_MSG_WINDOW_INIT:
114     {
115       CGUIMediaWindow::OnMessage(message);
116       if(pCallbackWindow)
117       {
118         PyXBMC_AddPendingCall(m_threadState, Py_XBMC_Event_OnInit, new PyXBMCAction(pCallbackWindow));
119         PulseActionEvent();
120       }
121       return true;
122     }
123     break;
124
125     case GUI_MSG_FOCUSED:
126     {
127       if (m_viewControl.HasControl(message.GetControlId()) && m_viewControl.GetCurrentControl() != (int)message.GetControlId())
128       {
129         m_viewControl.SetFocused();
130         return true;
131       }
132         // check if our focused control is one of our category buttons
133         int iControl=message.GetControlId();
134         if(pCallbackWindow)
135         {
136           PyXBMCAction* inf = new PyXBMCAction(pCallbackWindow);
137           inf->controlId = iControl;
138           // aquire lock?
139           PyXBMC_AddPendingCall(m_threadState, Py_XBMC_Event_OnFocus, inf);
140           PulseActionEvent();
141         }
142     }
143     break;
144
145     case GUI_MSG_CLICKED:
146     {
147       int iControl=message.GetSenderId();
148       // Handle Sort/View internally. Scripters shouldn't use ID 2, 3 or 4.
149       if (iControl == CONTROL_BTNSORTASC) // sort asc
150       {
151         CLog::Log(LOGINFO, "WindowXML: Internal asc/dsc button not implemented");
152         /*if (m_guiState.get())
153           m_guiState->SetNextSortOrder();
154         UpdateFileList();*/
155         return true;
156       }
157       else if (iControl == CONTROL_BTNSORTBY) // sort by
158       {
159         CLog::Log(LOGINFO, "WindowXML: Internal sort button not implemented");
160         /*if (m_guiState.get())
161           m_guiState->SetNextSortMethod();
162         UpdateFileList();*/
163         return true;
164       }
165       else if (iControl == CONTROL_BTNVIEWASICONS)
166       { // base class handles this one
167         break;
168       }
169       if(pCallbackWindow && iControl && iControl != (int)this->GetID()) // pCallbackWindow &&  != this->GetID())
170       {
171         CGUIControl* controlClicked = (CGUIControl*)this->GetControl(iControl);
172
173         // The old python way used to check list AND SELECITEM method or if its a button, checkmark.
174         // Its done this way for now to allow other controls without a python version like togglebutton to still raise a onAction event
175         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
176         {
177           if ((controlClicked->IsContainer() && (message.GetParam1() == ACTION_SELECT_ITEM || message.GetParam1() == ACTION_MOUSE_LEFT_CLICK)) || !controlClicked->IsContainer())
178           {
179             PyXBMCAction* inf = new PyXBMCAction(pCallbackWindow);
180             inf->controlId = iControl;
181             // aquire lock?
182             PyXBMC_AddPendingCall(m_threadState, Py_XBMC_Event_OnClick, inf);
183             PulseActionEvent();
184             return true;
185           }
186           else if (controlClicked->IsContainer() && message.GetParam1() == ACTION_MOUSE_RIGHT_CLICK)
187           {
188             PyXBMCAction* inf = new PyXBMCAction(pCallbackWindow);
189             inf->pObject = Action_FromAction(CAction(ACTION_CONTEXT_MENU));
190
191             // aquire lock?
192             PyXBMC_AddPendingCall(m_threadState, Py_XBMC_Event_OnAction, inf);
193             PulseActionEvent();
194             return true;
195           }
196         }
197       }
198     }
199     break;
200   }
201
202   return CGUIMediaWindow::OnMessage(message);
203 }
204
205 void CGUIPythonWindowXML::AddItem(CFileItemPtr fileItem, int itemPosition)
206 {
207   if (itemPosition == INT_MAX || itemPosition > m_vecItems->Size())
208   {
209     m_vecItems->Add(fileItem);
210   }
211   else if (itemPosition <  -1 &&  !(itemPosition*-1 < m_vecItems->Size()))
212   {
213     m_vecItems->AddFront(fileItem,0);
214   }
215   else
216   {
217     m_vecItems->AddFront(fileItem,itemPosition);
218   }
219   m_viewControl.SetItems(*m_vecItems);
220   UpdateButtons();
221 }
222
223 void CGUIPythonWindowXML::RemoveItem(int itemPosition)
224 {
225   m_vecItems->Remove(itemPosition);
226   m_viewControl.SetItems(*m_vecItems);
227   UpdateButtons();
228 }
229
230 int CGUIPythonWindowXML::GetListSize()
231 {
232   return m_vecItems->Size();
233 }
234
235 int CGUIPythonWindowXML::GetCurrentListPosition()
236 {
237   return m_viewControl.GetSelectedItem();
238 }
239
240 void CGUIPythonWindowXML::SetCurrentListPosition(int item)
241 {
242   m_viewControl.SetSelectedItem(item);
243 }
244
245 void CGUIPythonWindowXML::SetProperty(const CStdString& key, const CStdString& value)
246 {
247   m_vecItems->SetProperty(key, value);
248 }
249
250 CFileItemPtr CGUIPythonWindowXML::GetListItem(int position)
251 {
252   if (position < 0 || position >= m_vecItems->Size()) return CFileItemPtr();
253   return m_vecItems->Get(position);
254 }
255
256 void CGUIPythonWindowXML::ClearList()
257 {
258   ClearFileItems();
259
260   m_viewControl.SetItems(*m_vecItems);
261   UpdateButtons();
262 }
263
264 void CGUIPythonWindowXML::WaitForActionEvent(unsigned int timeout)
265 {
266   g_pythonParser.WaitForEvent(m_actionEvent, timeout);
267   ResetEvent(m_actionEvent);
268 }
269
270 void CGUIPythonWindowXML::PulseActionEvent()
271 {
272   SetEvent(m_actionEvent);
273 }
274
275 void CGUIPythonWindowXML::AllocResources(bool forceLoad /*= FALSE */)
276 {
277   CStdString tmpDir;
278   URIUtils::GetDirectory(GetProperty("xmlfile"), tmpDir);
279   CStdString fallbackMediaPath;
280   URIUtils::GetParentPath(tmpDir, fallbackMediaPath);
281   URIUtils::RemoveSlashAtEnd(fallbackMediaPath);
282   m_mediaDir = fallbackMediaPath;
283
284   //CLog::Log(LOGDEBUG, "CGUIPythonWindowXML::AllocResources called: %s", fallbackMediaPath.c_str());
285   g_TextureManager.AddTexturePath(m_mediaDir);
286   CGUIMediaWindow::AllocResources(forceLoad);
287   g_TextureManager.RemoveTexturePath(m_mediaDir);
288 }
289
290 bool CGUIPythonWindowXML::LoadXML(const CStdString &strPath, const CStdString &strLowerPath)
291 {
292   // load our window
293   XFILE::CFile file;
294   if (!file.Open(strPath) && !file.Open(CStdString(strPath).ToLower()) && !file.Open(strLowerPath))
295   {
296     // fail - can't load the file
297     CLog::Log(LOGERROR, "%s: Unable to load skin file %s", __FUNCTION__, strPath.c_str());
298     return false;
299   }
300   // load the strings in
301   unsigned int offset = LoadScriptStrings();
302
303   CStdString xml;
304   char *buffer = new char[(unsigned int)file.GetLength()+1];
305   if(buffer == NULL)
306     return false;
307   int size = file.Read(buffer, file.GetLength());
308   if (size > 0)
309   {
310     buffer[size] = 0;
311     xml = buffer;
312     if (offset)
313     {
314       // replace the occurences of SCRIPT### with offset+###
315       // not particularly efficient, but it works
316       int pos = xml.Find("SCRIPT");
317       while (pos != (int)CStdString::npos)
318       {
319         CStdString num = xml.Mid(pos + 6, 4);
320         int number = atol(num.c_str());
321         CStdString oldNumber, newNumber;
322         oldNumber.Format("SCRIPT%d", number);
323         newNumber.Format("%lu", offset + number);
324         xml.Replace(oldNumber, newNumber);
325         pos = xml.Find("SCRIPT", pos + 6);
326       }
327     }
328   }
329   delete[] buffer;
330
331   TiXmlDocument xmlDoc;
332   xmlDoc.Parse(xml.c_str());
333
334   if (xmlDoc.Error())
335     return false;
336
337   return Load(xmlDoc);
338 }
339
340 void CGUIPythonWindowXML::FreeResources(bool forceUnLoad /*= FALSE */)
341 {
342   // Unload temporary language strings
343   ClearScriptStrings();
344
345   CGUIMediaWindow::FreeResources(forceUnLoad);
346 }
347
348 void CGUIPythonWindowXML::Render()
349 {
350   g_TextureManager.AddTexturePath(m_mediaDir);
351   CGUIMediaWindow::Render();
352   g_TextureManager.RemoveTexturePath(m_mediaDir);
353 }
354
355 int Py_XBMC_Event_OnClick(void* arg)
356 {
357   if(!arg)
358     return 0;
359
360   PyXBMCAction* action = (PyXBMCAction*)arg;
361   if (action->pCallbackWindow)
362   {
363     PyObject *ret = PyObject_CallMethod(action->pCallbackWindow, (char*)"onClick", (char*)"(i)", action->controlId);
364     if (ret)
365     {
366       Py_DECREF(ret);
367     }
368   }
369   delete action;
370   return 0;
371 }
372
373 int Py_XBMC_Event_OnFocus(void* arg)
374 {
375   if(!arg)
376     return 0;
377
378   PyXBMCAction* action = (PyXBMCAction*)arg;
379   if (action->pCallbackWindow)
380   {
381     PyObject *ret = PyObject_CallMethod(action->pCallbackWindow, (char*)"onFocus", (char*)"(i)", action->controlId);
382     if (ret)
383     {
384       Py_DECREF(ret);
385     }
386     delete action;
387   }
388   return 0;
389 }
390
391 int Py_XBMC_Event_OnInit(void* arg)
392 {
393   if(!arg)
394     return 0;
395
396   PyXBMCAction* action = (PyXBMCAction*)arg;
397   if (action->pCallbackWindow)
398   {
399     PyObject *ret = PyObject_CallMethod(action->pCallbackWindow, (char*)"onInit", (char*)"()"); //, (char*)"O", &self);
400     if (ret)
401     {
402       Py_XDECREF(ret);
403     }
404   }
405   delete action;
406   return 0;
407 }
408
409 void CGUIPythonWindowXML::SetCallbackWindow(PyThreadState *state, PyObject *object)
410 {
411   pCallbackWindow = object;
412   m_threadState   = state;
413 }
414
415 void CGUIPythonWindowXML::GetContextButtons(int itemNumber, CContextButtons &buttons)
416 {
417   // maybe on day we can make an easy way to do this context menu
418   // with out this method overriding the MediaWindow version, it will display 'Add to Favorites'
419 }
420
421 unsigned int CGUIPythonWindowXML::LoadScriptStrings()
422 {
423   // Path where the language strings reside
424   CStdString pathToLanguageFile = m_scriptPath;
425   CStdString pathToFallbackLanguageFile = m_scriptPath;
426   URIUtils::AddFileToFolder(pathToLanguageFile, "resources", pathToLanguageFile);
427   URIUtils::AddFileToFolder(pathToFallbackLanguageFile, "resources", pathToFallbackLanguageFile);
428   URIUtils::AddFileToFolder(pathToLanguageFile, "language", pathToLanguageFile);
429   URIUtils::AddFileToFolder(pathToFallbackLanguageFile, "language", pathToFallbackLanguageFile);
430   URIUtils::AddFileToFolder(pathToLanguageFile, g_guiSettings.GetString("locale.language"), pathToLanguageFile);
431   URIUtils::AddFileToFolder(pathToFallbackLanguageFile, "english", pathToFallbackLanguageFile);
432   URIUtils::AddFileToFolder(pathToLanguageFile, "strings.xml", pathToLanguageFile);
433   URIUtils::AddFileToFolder(pathToFallbackLanguageFile, "strings.xml", pathToFallbackLanguageFile);
434
435   // allocate a bunch of strings
436   return g_localizeStrings.LoadBlock(m_scriptPath, pathToLanguageFile, pathToFallbackLanguageFile);
437 }
438
439 void CGUIPythonWindowXML::ClearScriptStrings()
440 {
441   // Unload temporary language strings
442   g_localizeStrings.ClearBlock(m_scriptPath);
443 }
444
445