2 * Copyright (C) 2005-2008 Team XBMC
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)
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.
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
22 #include "GUIPythonWindowXML.h"
27 #include "utils/URIUtils.h"
28 #include "guilib/GUIWindowManager.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"
40 #define CONTROL_BTNVIEWASICONS 2
41 #define CONTROL_BTNSORTBY 3
42 #define CONTROL_BTNSORTASC 4
43 #define CONTROL_LABELFILES 12
45 using namespace PYXBMC;
47 CGUIPythonWindowXML::CGUIPythonWindowXML(int id, CStdString strXML, CStdString strFallBackPath)
48 : CGUIMediaWindow(id, strXML)
50 pCallbackWindow = NULL;
52 m_actionEvent = CreateEvent(NULL, true, false, NULL);
53 m_loadOnDemand = false;
54 m_coordsRes = RES_PAL_4x3;
55 m_scriptPath = strFallBackPath;
58 CGUIPythonWindowXML::~CGUIPythonWindowXML(void)
60 CloseHandle(m_actionEvent);
63 bool CGUIPythonWindowXML::Update(const CStdString &strPath)
68 bool CGUIPythonWindowXML::OnAction(const CAction &action)
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
74 PyXBMCAction* inf = new PyXBMCAction(pCallbackWindow);
75 inf->pObject = Action_FromAction(action);
78 PyXBMC_AddPendingCall(m_threadState, Py_XBMC_Event_OnAction, inf);
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.
92 CGUIMediaWindow::OnWindowLoaded() calls SetupShares() so override it
93 and just call UpdateButtons();
95 void CGUIPythonWindowXML::SetupShares()
100 bool CGUIPythonWindowXML::OnMessage(CGUIMessage& message)
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())
107 case GUI_MSG_WINDOW_DEINIT:
109 return CGUIMediaWindow::OnMessage(message);
113 case GUI_MSG_WINDOW_INIT:
115 CGUIMediaWindow::OnMessage(message);
118 PyXBMC_AddPendingCall(m_threadState, Py_XBMC_Event_OnInit, new PyXBMCAction(pCallbackWindow));
125 case GUI_MSG_FOCUSED:
127 if (m_viewControl.HasControl(message.GetControlId()) && m_viewControl.GetCurrentControl() != (int)message.GetControlId())
129 m_viewControl.SetFocused();
132 // check if our focused control is one of our category buttons
133 int iControl=message.GetControlId();
136 PyXBMCAction* inf = new PyXBMCAction(pCallbackWindow);
137 inf->controlId = iControl;
139 PyXBMC_AddPendingCall(m_threadState, Py_XBMC_Event_OnFocus, inf);
145 case GUI_MSG_CLICKED:
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
151 CLog::Log(LOGINFO, "WindowXML: Internal asc/dsc button not implemented");
152 /*if (m_guiState.get())
153 m_guiState->SetNextSortOrder();
157 else if (iControl == CONTROL_BTNSORTBY) // sort by
159 CLog::Log(LOGINFO, "WindowXML: Internal sort button not implemented");
160 /*if (m_guiState.get())
161 m_guiState->SetNextSortMethod();
165 else if (iControl == CONTROL_BTNVIEWASICONS)
166 { // base class handles this one
169 if(pCallbackWindow && iControl && iControl != (int)this->GetID()) // pCallbackWindow && != this->GetID())
171 CGUIControl* controlClicked = (CGUIControl*)this->GetControl(iControl);
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
177 if ((controlClicked->IsContainer() && (message.GetParam1() == ACTION_SELECT_ITEM || message.GetParam1() == ACTION_MOUSE_LEFT_CLICK)) || !controlClicked->IsContainer())
179 PyXBMCAction* inf = new PyXBMCAction(pCallbackWindow);
180 inf->controlId = iControl;
182 PyXBMC_AddPendingCall(m_threadState, Py_XBMC_Event_OnClick, inf);
186 else if (controlClicked->IsContainer() && message.GetParam1() == ACTION_MOUSE_RIGHT_CLICK)
188 PyXBMCAction* inf = new PyXBMCAction(pCallbackWindow);
189 inf->pObject = Action_FromAction(CAction(ACTION_CONTEXT_MENU));
192 PyXBMC_AddPendingCall(m_threadState, Py_XBMC_Event_OnAction, inf);
202 return CGUIMediaWindow::OnMessage(message);
205 void CGUIPythonWindowXML::AddItem(CFileItemPtr fileItem, int itemPosition)
207 if (itemPosition == INT_MAX || itemPosition > m_vecItems->Size())
209 m_vecItems->Add(fileItem);
211 else if (itemPosition < -1 && !(itemPosition*-1 < m_vecItems->Size()))
213 m_vecItems->AddFront(fileItem,0);
217 m_vecItems->AddFront(fileItem,itemPosition);
219 m_viewControl.SetItems(*m_vecItems);
223 void CGUIPythonWindowXML::RemoveItem(int itemPosition)
225 m_vecItems->Remove(itemPosition);
226 m_viewControl.SetItems(*m_vecItems);
230 int CGUIPythonWindowXML::GetListSize()
232 return m_vecItems->Size();
235 int CGUIPythonWindowXML::GetCurrentListPosition()
237 return m_viewControl.GetSelectedItem();
240 void CGUIPythonWindowXML::SetCurrentListPosition(int item)
242 m_viewControl.SetSelectedItem(item);
245 void CGUIPythonWindowXML::SetProperty(const CStdString& key, const CStdString& value)
247 m_vecItems->SetProperty(key, value);
250 CFileItemPtr CGUIPythonWindowXML::GetListItem(int position)
252 if (position < 0 || position >= m_vecItems->Size()) return CFileItemPtr();
253 return m_vecItems->Get(position);
256 void CGUIPythonWindowXML::ClearList()
260 m_viewControl.SetItems(*m_vecItems);
264 void CGUIPythonWindowXML::WaitForActionEvent(unsigned int timeout)
266 g_pythonParser.WaitForEvent(m_actionEvent, timeout);
267 ResetEvent(m_actionEvent);
270 void CGUIPythonWindowXML::PulseActionEvent()
272 SetEvent(m_actionEvent);
275 void CGUIPythonWindowXML::AllocResources(bool forceLoad /*= FALSE */)
278 URIUtils::GetDirectory(GetProperty("xmlfile"), tmpDir);
279 CStdString fallbackMediaPath;
280 URIUtils::GetParentPath(tmpDir, fallbackMediaPath);
281 URIUtils::RemoveSlashAtEnd(fallbackMediaPath);
282 m_mediaDir = fallbackMediaPath;
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);
290 bool CGUIPythonWindowXML::LoadXML(const CStdString &strPath, const CStdString &strLowerPath)
294 if (!file.Open(strPath) && !file.Open(CStdString(strPath).ToLower()) && !file.Open(strLowerPath))
296 // fail - can't load the file
297 CLog::Log(LOGERROR, "%s: Unable to load skin file %s", __FUNCTION__, strPath.c_str());
300 // load the strings in
301 unsigned int offset = LoadScriptStrings();
304 char *buffer = new char[(unsigned int)file.GetLength()+1];
307 int size = file.Read(buffer, file.GetLength());
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)
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);
331 TiXmlDocument xmlDoc;
332 xmlDoc.Parse(xml.c_str());
340 void CGUIPythonWindowXML::FreeResources(bool forceUnLoad /*= FALSE */)
342 // Unload temporary language strings
343 ClearScriptStrings();
345 CGUIMediaWindow::FreeResources(forceUnLoad);
348 void CGUIPythonWindowXML::Render()
350 g_TextureManager.AddTexturePath(m_mediaDir);
351 CGUIMediaWindow::Render();
352 g_TextureManager.RemoveTexturePath(m_mediaDir);
355 int Py_XBMC_Event_OnClick(void* arg)
360 PyXBMCAction* action = (PyXBMCAction*)arg;
361 if (action->pCallbackWindow)
363 PyObject *ret = PyObject_CallMethod(action->pCallbackWindow, (char*)"onClick", (char*)"(i)", action->controlId);
373 int Py_XBMC_Event_OnFocus(void* arg)
378 PyXBMCAction* action = (PyXBMCAction*)arg;
379 if (action->pCallbackWindow)
381 PyObject *ret = PyObject_CallMethod(action->pCallbackWindow, (char*)"onFocus", (char*)"(i)", action->controlId);
391 int Py_XBMC_Event_OnInit(void* arg)
396 PyXBMCAction* action = (PyXBMCAction*)arg;
397 if (action->pCallbackWindow)
399 PyObject *ret = PyObject_CallMethod(action->pCallbackWindow, (char*)"onInit", (char*)"()"); //, (char*)"O", &self);
409 void CGUIPythonWindowXML::SetCallbackWindow(PyThreadState *state, PyObject *object)
411 pCallbackWindow = object;
412 m_threadState = state;
415 void CGUIPythonWindowXML::GetContextButtons(int itemNumber, CContextButtons &buttons)
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'
421 unsigned int CGUIPythonWindowXML::LoadScriptStrings()
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);
435 // allocate a bunch of strings
436 return g_localizeStrings.LoadBlock(m_scriptPath, pathToLanguageFile, pathToFallbackLanguageFile);
439 void CGUIPythonWindowXML::ClearScriptStrings()
441 // Unload temporary language strings
442 g_localizeStrings.ClearBlock(m_scriptPath);