2 * Copyright (C) 2005-2010 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 "GUIWindowAddonBrowser.h"
23 #include "addons/AddonManager.h"
24 #include "addons/Repository.h"
25 #include "dialogs/GUIDialogContextMenu.h"
26 #include "GUIDialogAddonInfo.h"
27 #include "GUIDialogAddonSettings.h"
28 #include "dialogs/GUIDialogKeyboard.h"
29 #include "dialogs/GUIDialogYesNo.h"
30 #include "dialogs/GUIDialogSelect.h"
31 #include "dialogs/GUIDialogFileBrowser.h"
32 #include "GUIUserMessages.h"
33 #include "guilib/GUIWindowManager.h"
34 #include "utils/URIUtils.h"
37 #include "filesystem/File.h"
38 #include "filesystem/Directory.h"
39 #include "filesystem/AddonsDirectory.h"
40 #include "addons/AddonInstaller.h"
41 #include "utils/JobManager.h"
42 #include "utils/log.h"
43 #include "threads/SingleLock.h"
44 #include "settings/Settings.h"
45 #include "utils/StringUtils.h"
46 #include "Application.h"
47 #include "AddonDatabase.h"
48 #include "settings/AdvancedSettings.h"
49 #include "storage/MediaManager.h"
50 #include "settings/GUISettings.h"
52 #define CONTROL_AUTOUPDATE 5
53 #define CONTROL_SHUTUP 6
55 using namespace ADDON;
56 using namespace XFILE;
59 CGUIWindowAddonBrowser::CGUIWindowAddonBrowser(void)
60 : CGUIMediaWindow(WINDOW_ADDON_BROWSER, "AddonBrowser.xml")
62 m_thumbLoader.SetNumOfWorkers(1);
65 CGUIWindowAddonBrowser::~CGUIWindowAddonBrowser()
69 bool CGUIWindowAddonBrowser::OnMessage(CGUIMessage& message)
71 switch ( message.GetMessage() )
73 case GUI_MSG_WINDOW_DEINIT:
75 if (m_thumbLoader.IsLoading())
76 m_thumbLoader.StopThread();
79 case GUI_MSG_WINDOW_INIT:
81 m_rootDir.AllowNonLocalSources(false);
83 // is this the first time the window is opened?
84 if (m_vecItems->GetPath() == "?" && message.GetStringParam().IsEmpty())
85 m_vecItems->SetPath("");
90 int iControl = message.GetSenderId();
91 if (iControl == CONTROL_AUTOUPDATE)
93 g_settings.m_bAddonAutoUpdate = !g_settings.m_bAddonAutoUpdate;
97 else if (iControl == CONTROL_SHUTUP)
99 g_settings.m_bAddonNotifications = !g_settings.m_bAddonNotifications;
103 else if (m_viewControl.HasControl(iControl)) // list/thumb control
106 int iItem = m_viewControl.GetSelectedItem();
107 int iAction = message.GetParam1();
109 // iItem is checked for validity inside these routines
110 if (iAction == ACTION_SHOW_INFO)
112 if (!m_vecItems->Get(iItem)->GetProperty("Addon.ID").empty())
113 return CGUIDialogAddonInfo::ShowForItem((*m_vecItems)[iItem]);
119 case GUI_MSG_NOTIFY_ALL:
121 if (message.GetParam1() == GUI_MSG_UPDATE_ITEM && IsActive() && message.GetNumStringParams() == 1)
122 { // update this item
123 for (int i = 0; i < m_vecItems->Size(); ++i)
125 CFileItemPtr item = m_vecItems->Get(i);
126 if (item->GetProperty("Addon.ID") == message.GetStringParam())
138 return CGUIMediaWindow::OnMessage(message);
141 void CGUIWindowAddonBrowser::GetContextButtons(int itemNumber,
142 CContextButtons& buttons)
144 CFileItemPtr pItem = m_vecItems->Get(itemNumber);
145 if (pItem->GetPath().Equals("addons://enabled/"))
146 buttons.Add(CONTEXT_BUTTON_SCAN,24034);
149 if (!CAddonMgr::Get().GetAddon(pItem->GetProperty("Addon.ID").asString(), addon, ADDON_UNKNOWN, false)) // allow disabled addons
152 if (addon->Type() == ADDON_REPOSITORY && pItem->m_bIsFolder)
154 buttons.Add(CONTEXT_BUTTON_SCAN,24034);
155 buttons.Add(CONTEXT_BUTTON_UPDATE_LIBRARY,24035);
158 buttons.Add(CONTEXT_BUTTON_INFO,24003);
160 if (addon->HasSettings())
161 buttons.Add(CONTEXT_BUTTON_SETTINGS,24020);
164 bool CGUIWindowAddonBrowser::OnContextButton(int itemNumber,
165 CONTEXT_BUTTON button)
167 CFileItemPtr pItem = m_vecItems->Get(itemNumber);
168 if (pItem->GetPath().Equals("addons://enabled/"))
170 if (button == CONTEXT_BUTTON_SCAN)
172 CAddonMgr::Get().FindAddons();
177 if (!CAddonMgr::Get().GetAddon(pItem->GetProperty("Addon.ID").asString(), addon, ADDON_UNKNOWN, false)) // allow disabled addons
180 if (button == CONTEXT_BUTTON_SETTINGS)
181 return CGUIDialogAddonSettings::ShowAndGetInput(addon);
183 if (button == CONTEXT_BUTTON_UPDATE_LIBRARY)
185 CAddonDatabase database;
187 database.DeleteRepository(addon->ID());
188 button = CONTEXT_BUTTON_SCAN;
191 if (button == CONTEXT_BUTTON_SCAN)
193 RepositoryPtr repo = boost::dynamic_pointer_cast<CRepository>(addon);
194 CAddonInstaller::Get().UpdateRepos(true);
198 if (button == CONTEXT_BUTTON_INFO)
200 CGUIDialogAddonInfo::ShowForItem(pItem);
204 return CGUIMediaWindow::OnContextButton(itemNumber, button);
207 bool CGUIWindowAddonBrowser::OnClick(int iItem)
209 CFileItemPtr item = m_vecItems->Get(iItem);
210 if (item->GetPath() == "addons://install/")
212 // pop up filebrowser to grab an installed folder
213 VECSOURCES shares = g_settings.m_fileSources;
214 g_mediaManager.GetLocalDrives(shares);
216 if (CGUIDialogFileBrowser::ShowAndGetFile(shares, "*.zip", g_localizeStrings.Get(24041), path))
217 CAddonInstaller::Get().InstallFromZip(path);
220 if (!item->m_bIsFolder)
222 // cancel a downloading job
223 if (item->HasProperty("Addon.Downloading"))
225 if (CGUIDialogYesNo::ShowAndGetInput(g_localizeStrings.Get(24000),
226 item->GetProperty("Addon.Name").asString(),
227 g_localizeStrings.Get(24066),""))
229 if (CAddonInstaller::Get().Cancel(item->GetProperty("Addon.ID").asString()))
230 Update(m_vecItems->GetPath());
235 CGUIDialogAddonInfo::ShowForItem(item);
238 if (item->GetPath().Equals("addons://search/"))
239 return Update(item->GetPath());
241 return CGUIMediaWindow::OnClick(iItem);
244 void CGUIWindowAddonBrowser::UpdateButtons()
246 SET_CONTROL_SELECTED(GetID(),CONTROL_AUTOUPDATE,g_settings.m_bAddonAutoUpdate);
247 SET_CONTROL_SELECTED(GetID(),CONTROL_SHUTUP,g_settings.m_bAddonNotifications);
248 CGUIMediaWindow::UpdateButtons();
251 bool CGUIWindowAddonBrowser::GetDirectory(const CStdString& strDirectory,
252 CFileItemList& items)
255 if (strDirectory.Equals("addons://downloading/"))
258 CAddonInstaller::Get().GetInstallList(addons);
260 CURL url(strDirectory);
261 CAddonsDirectory::GenerateListing(url,addons,items);
263 items.SetProperty("reponame",g_localizeStrings.Get(24067));
264 items.SetPath(strDirectory);
266 if (m_guiState.get() && !m_guiState->HideParentDirItems())
268 CFileItemPtr pItem(new CFileItem(".."));
269 pItem->SetPath(m_history.GetParentPath());
270 pItem->m_bIsFolder = true;
271 pItem->m_bIsShareOrDrive = false;
272 items.AddFront(pItem, 0);
277 result = CGUIMediaWindow::GetDirectory(strDirectory,items);
279 if (strDirectory.IsEmpty() && CAddonInstaller::Get().IsDownloading())
281 CFileItemPtr item(new CFileItem("addons://downloading/",true));
282 item->SetLabel(g_localizeStrings.Get(24067));
283 item->SetLabelPreformated(true);
284 item->SetIconImage("DefaultNetwork.png");
288 items.SetContent("addons");
290 for (int i=0;i<items.Size();++i)
291 SetItemLabel2(items[i]);
296 void CGUIWindowAddonBrowser::SetItemLabel2(CFileItemPtr item)
298 if (!item || item->m_bIsFolder) return;
299 unsigned int percent;
300 if (CAddonInstaller::Get().GetProgress(item->GetProperty("Addon.ID").asString(), percent))
303 progress.Format(g_localizeStrings.Get(24042).c_str(), percent);
304 item->SetProperty("Addon.Status", progress);
305 item->SetProperty("Addon.Downloading", true);
308 item->ClearProperty("Addon.Downloading");
309 item->SetLabel2(item->GetProperty("Addon.Status").asString());
310 // to avoid the view state overriding label 2
311 item->SetLabelPreformated(true);
314 bool CGUIWindowAddonBrowser::Update(const CStdString &strDirectory)
316 if (m_thumbLoader.IsLoading())
317 m_thumbLoader.StopThread();
319 if (!CGUIMediaWindow::Update(strDirectory))
322 m_thumbLoader.Load(*m_vecItems);
327 int CGUIWindowAddonBrowser::SelectAddonID(TYPE type, CStdString &addonID, bool showNone /*= false*/)
329 vector<ADDON::TYPE> types;
330 types.push_back(type);
331 return SelectAddonID(types, addonID, showNone);
334 int CGUIWindowAddonBrowser::SelectAddonID(ADDON::TYPE type, CStdStringArray &addonIDs, bool showNone /*= false*/, bool multipleSelection /*= true*/)
336 vector<ADDON::TYPE> types;
337 types.push_back(type);
338 return SelectAddonID(types, addonIDs, showNone, multipleSelection);
341 int CGUIWindowAddonBrowser::SelectAddonID(const vector<ADDON::TYPE> &types, CStdString &addonID, bool showNone /*= false*/)
343 CStdStringArray addonIDs;
344 if (!addonID.IsEmpty())
345 addonIDs.push_back(addonID);
346 int retval = SelectAddonID(types, addonIDs, showNone, false);
347 if (addonIDs.size() > 0)
348 addonID = addonIDs.at(0);
354 int CGUIWindowAddonBrowser::SelectAddonID(const vector<ADDON::TYPE> &types, CStdStringArray &addonIDs, bool showNone /*= false*/, bool multipleSelection /*= true*/)
356 CGUIDialogSelect *dialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
363 for (vector<ADDON::TYPE>::const_iterator it = types.begin(); it != types.end(); ++it)
365 if (*it == ADDON_UNKNOWN)
367 ADDON::VECADDONS addons;
369 if (*it == ADDON_AUDIO)
370 CAddonsDirectory::GetScriptsAndPlugins("audio",addons);
371 else if (*it == ADDON_EXECUTABLE)
372 CAddonsDirectory::GetScriptsAndPlugins("executable",addons);
373 else if (*it == ADDON_IMAGE)
374 CAddonsDirectory::GetScriptsAndPlugins("image",addons);
375 else if (*it == ADDON_VIDEO)
376 CAddonsDirectory::GetScriptsAndPlugins("video",addons);
378 CAddonMgr::Get().GetAddons(*it, addons);
379 for (ADDON::IVECADDONS it2 = addons.begin() ; it2 != addons.end() ; ++it2)
381 CFileItemPtr item(CAddonsDirectory::FileItemFromAddon(*it2, ""));
382 if (!items.Contains(item->GetPath()))
386 if (!heading.IsEmpty())
388 heading += TranslateType(*it, true);
394 dialog->SetHeading(heading);
396 dialog->SetUseDetails(true);
397 if (multipleSelection || iTypes > 1)
400 dialog->EnableButton(true, 186);
403 dialog->EnableButton(true, 21452);
406 CFileItemPtr item(new CFileItem("", false));
407 item->SetLabel(g_localizeStrings.Get(231));
408 item->SetLabel2(g_localizeStrings.Get(24040));
409 item->SetIconImage("DefaultAddonNone.png");
410 item->SetSpecialSort(SORT_ON_TOP);
413 items.Sort(SORT_METHOD_LABEL, SORT_ORDER_ASC);
415 if (addonIDs.size() > 0)
417 for (CStdStringArray::const_iterator it = addonIDs.begin(); it != addonIDs.end() ; it++)
419 CFileItemPtr item = items.Get(*it);
424 dialog->SetItems(&items);
425 dialog->SetMultiSelection(multipleSelection);
427 if (!multipleSelection && iTypes == 1 && dialog->IsButtonPressed())
428 { // switch to the addons browser.
429 vector<CStdString> params;
430 params.push_back("addons://all/"+TranslateType(types[0],false)+"/");
431 params.push_back("return");
432 g_windowManager.ActivateWindow(WINDOW_ADDON_BROWSER, params);
435 if (!multipleSelection && dialog->GetSelectedLabel() == -1)
438 const CFileItemList& list = dialog->GetSelectedItems();
439 for (int i = 0 ; i < list.Size() ; i++)
440 addonIDs.push_back(list.Get(i)->GetPath());
444 CStdString CGUIWindowAddonBrowser::GetStartFolder(const CStdString &dir)
446 if (dir.Left(9).Equals("addons://"))
448 return CGUIMediaWindow::GetStartFolder(dir);