2 * Copyright (C) 2005-2013 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, see
17 * <http://www.gnu.org/licenses/>.
21 #include "GUIWindowAddonBrowser.h"
22 #include "addons/AddonManager.h"
23 #include "addons/Repository.h"
24 #include "GUIDialogAddonInfo.h"
25 #include "GUIDialogAddonSettings.h"
26 #include "dialogs/GUIDialogYesNo.h"
27 #include "dialogs/GUIDialogSelect.h"
28 #include "dialogs/GUIDialogFileBrowser.h"
29 #include "GUIUserMessages.h"
30 #include "guilib/GUIWindowManager.h"
31 #include "utils/URIUtils.h"
34 #include "filesystem/File.h"
35 #include "filesystem/Directory.h"
36 #include "filesystem/AddonsDirectory.h"
37 #include "addons/AddonInstaller.h"
38 #include "utils/JobManager.h"
39 #include "utils/log.h"
40 #include "threads/SingleLock.h"
41 #include "settings/Settings.h"
42 #include "settings/MediaSourceSettings.h"
43 #include "utils/StringUtils.h"
44 #include "AddonDatabase.h"
45 #include "settings/AdvancedSettings.h"
46 #include "storage/MediaManager.h"
48 #include "guilib/Key.h"
50 #define CONTROL_AUTOUPDATE 5
51 #define CONTROL_SHUTUP 6
52 #define CONTROL_FOREIGNFILTER 7
54 using namespace ADDON;
55 using namespace XFILE;
58 CGUIWindowAddonBrowser::CGUIWindowAddonBrowser(void)
59 : CGUIMediaWindow(WINDOW_ADDON_BROWSER, "AddonBrowser.xml")
63 CGUIWindowAddonBrowser::~CGUIWindowAddonBrowser()
67 bool CGUIWindowAddonBrowser::OnMessage(CGUIMessage& message)
69 switch ( message.GetMessage() )
71 case GUI_MSG_WINDOW_DEINIT:
73 if (m_thumbLoader.IsLoading())
74 m_thumbLoader.StopThread();
77 case GUI_MSG_WINDOW_INIT:
79 m_rootDir.AllowNonLocalSources(false);
81 // is this the first time the window is opened?
82 if (m_vecItems->GetPath() == "?" && message.GetStringParam().IsEmpty())
83 m_vecItems->SetPath("");
88 int iControl = message.GetSenderId();
89 if (iControl == CONTROL_AUTOUPDATE)
91 CSettings::Get().ToggleBool("general.addonautoupdate");
94 else if (iControl == CONTROL_SHUTUP)
96 CSettings::Get().ToggleBool("general.addonnotifications");
97 CSettings::Get().Save();
100 else if (iControl == CONTROL_FOREIGNFILTER)
102 CSettings::Get().ToggleBool("general.addonforeignfilter");
103 CSettings::Get().Save();
107 else if (m_viewControl.HasControl(iControl)) // list/thumb control
110 int iItem = m_viewControl.GetSelectedItem();
111 int iAction = message.GetParam1();
113 // iItem is checked for validity inside these routines
114 if (iAction == ACTION_SHOW_INFO)
116 if (!m_vecItems->Get(iItem)->GetProperty("Addon.ID").empty())
117 return CGUIDialogAddonInfo::ShowForItem((*m_vecItems)[iItem]);
123 case GUI_MSG_NOTIFY_ALL:
125 if (message.GetParam1() == GUI_MSG_UPDATE_ITEM && IsActive() && message.GetNumStringParams() == 1)
126 { // update this item
127 for (int i = 0; i < m_vecItems->Size(); ++i)
129 CFileItemPtr item = m_vecItems->Get(i);
130 if (item->GetProperty("Addon.ID") == message.GetStringParam())
142 return CGUIMediaWindow::OnMessage(message);
145 void CGUIWindowAddonBrowser::GetContextButtons(int itemNumber,
146 CContextButtons& buttons)
148 CFileItemPtr pItem = m_vecItems->Get(itemNumber);
149 if (pItem->GetPath().Equals("addons://enabled/"))
150 buttons.Add(CONTEXT_BUTTON_SCAN,24034);
153 if (!CAddonMgr::Get().GetAddon(pItem->GetProperty("Addon.ID").asString(), addon, ADDON_UNKNOWN, false)) // allow disabled addons
156 if (addon->Type() == ADDON_REPOSITORY && pItem->m_bIsFolder)
158 buttons.Add(CONTEXT_BUTTON_SCAN,24034);
159 buttons.Add(CONTEXT_BUTTON_REFRESH,24035);
162 buttons.Add(CONTEXT_BUTTON_INFO,24003);
164 if (addon->HasSettings())
165 buttons.Add(CONTEXT_BUTTON_SETTINGS,24020);
168 bool CGUIWindowAddonBrowser::OnContextButton(int itemNumber,
169 CONTEXT_BUTTON button)
171 CFileItemPtr pItem = m_vecItems->Get(itemNumber);
172 if (pItem->GetPath().Equals("addons://enabled/"))
174 if (button == CONTEXT_BUTTON_SCAN)
176 CAddonMgr::Get().FindAddons();
181 if (!CAddonMgr::Get().GetAddon(pItem->GetProperty("Addon.ID").asString(), addon, ADDON_UNKNOWN, false)) // allow disabled addons
184 if (button == CONTEXT_BUTTON_SETTINGS)
185 return CGUIDialogAddonSettings::ShowAndGetInput(addon);
187 if (button == CONTEXT_BUTTON_REFRESH)
189 CAddonDatabase database;
191 database.DeleteRepository(addon->ID());
192 button = CONTEXT_BUTTON_SCAN;
195 if (button == CONTEXT_BUTTON_SCAN)
197 RepositoryPtr repo = boost::dynamic_pointer_cast<CRepository>(addon);
198 CAddonInstaller::Get().UpdateRepos(true);
202 if (button == CONTEXT_BUTTON_INFO)
204 CGUIDialogAddonInfo::ShowForItem(pItem);
208 return CGUIMediaWindow::OnContextButton(itemNumber, button);
211 bool CGUIWindowAddonBrowser::OnClick(int iItem)
213 CFileItemPtr item = m_vecItems->Get(iItem);
214 if (item->GetPath() == "addons://install/")
216 // pop up filebrowser to grab an installed folder
217 VECSOURCES shares = *CMediaSourceSettings::Get().GetSources("files");
218 g_mediaManager.GetLocalDrives(shares);
219 g_mediaManager.GetNetworkLocations(shares);
221 if (CGUIDialogFileBrowser::ShowAndGetFile(shares, "*.zip", g_localizeStrings.Get(24041), path))
222 CAddonInstaller::Get().InstallFromZip(path);
225 if (!item->m_bIsFolder)
227 // cancel a downloading job
228 if (item->HasProperty("Addon.Downloading"))
230 if (CGUIDialogYesNo::ShowAndGetInput(g_localizeStrings.Get(24000),
231 item->GetProperty("Addon.Name").asString(),
232 g_localizeStrings.Get(24066),""))
234 if (CAddonInstaller::Get().Cancel(item->GetProperty("Addon.ID").asString()))
240 CGUIDialogAddonInfo::ShowForItem(item);
243 if (item->GetPath().Equals("addons://search/"))
244 return Update(item->GetPath());
246 return CGUIMediaWindow::OnClick(iItem);
249 void CGUIWindowAddonBrowser::UpdateButtons()
251 SET_CONTROL_SELECTED(GetID(),CONTROL_AUTOUPDATE, CSettings::Get().GetBool("general.addonautoupdate"));
252 SET_CONTROL_SELECTED(GetID(),CONTROL_SHUTUP, CSettings::Get().GetBool("general.addonnotifications"));
253 SET_CONTROL_SELECTED(GetID(),CONTROL_FOREIGNFILTER, CSettings::Get().GetBool("general.addonforeignfilter"));
254 CGUIMediaWindow::UpdateButtons();
257 static bool FilterVar(bool valid, const CVariant& variant,
258 const std::string& check)
263 if (variant.isNull() || variant.asString().empty())
266 std::string regions = variant.asString();
267 return regions.find(check) == std::string::npos;
270 bool CGUIWindowAddonBrowser::GetDirectory(const CStdString& strDirectory,
271 CFileItemList& items)
274 if (strDirectory.Equals("addons://downloading/"))
277 CAddonInstaller::Get().GetInstallList(addons);
279 CURL url(strDirectory);
280 CAddonsDirectory::GenerateListing(url,addons,items);
282 items.SetProperty("reponame",g_localizeStrings.Get(24067));
283 items.SetPath(strDirectory);
285 if (m_guiState.get() && !m_guiState->HideParentDirItems())
287 CFileItemPtr pItem(new CFileItem(".."));
288 pItem->SetPath(m_history.GetParentPath());
289 pItem->m_bIsFolder = true;
290 pItem->m_bIsShareOrDrive = false;
291 items.AddFront(pItem, 0);
297 result = CGUIMediaWindow::GetDirectory(strDirectory,items);
298 if (CSettings::Get().GetBool("general.addonforeignfilter"))
301 while (i < items.Size())
303 if (!FilterVar(CSettings::Get().GetBool("general.addonforeignfilter"),
304 items[i]->GetProperty("Addon.Language"), "en") ||
305 !FilterVar(CSettings::Get().GetBool("general.addonforeignfilter"),
306 items[i]->GetProperty("Addon.Language"),
307 g_langInfo.GetLanguageLocale()))
317 if (strDirectory.IsEmpty() && CAddonInstaller::Get().IsDownloading())
319 CFileItemPtr item(new CFileItem("addons://downloading/",true));
320 item->SetLabel(g_localizeStrings.Get(24067));
321 item->SetLabelPreformated(true);
322 item->SetIconImage("DefaultNetwork.png");
326 items.SetContent("addons");
328 for (int i=0;i<items.Size();++i)
329 SetItemLabel2(items[i]);
334 void CGUIWindowAddonBrowser::SetItemLabel2(CFileItemPtr item)
336 if (!item || item->m_bIsFolder) return;
337 unsigned int percent;
338 if (CAddonInstaller::Get().GetProgress(item->GetProperty("Addon.ID").asString(), percent))
341 progress.Format(g_localizeStrings.Get(24042).c_str(), percent);
342 item->SetProperty("Addon.Status", progress);
343 item->SetProperty("Addon.Downloading", true);
346 item->ClearProperty("Addon.Downloading");
347 item->SetLabel2(item->GetProperty("Addon.Status").asString());
348 // to avoid the view state overriding label 2
349 item->SetLabelPreformated(true);
352 bool CGUIWindowAddonBrowser::Update(const CStdString &strDirectory, bool updateFilterPath /* = true */)
354 if (m_thumbLoader.IsLoading())
355 m_thumbLoader.StopThread();
357 if (!CGUIMediaWindow::Update(strDirectory, updateFilterPath))
360 m_thumbLoader.Load(*m_vecItems);
365 int CGUIWindowAddonBrowser::SelectAddonID(TYPE type, CStdString &addonID, bool showNone /*= false*/)
367 vector<ADDON::TYPE> types;
368 types.push_back(type);
369 return SelectAddonID(types, addonID, showNone);
372 int CGUIWindowAddonBrowser::SelectAddonID(ADDON::TYPE type, CStdStringArray &addonIDs, bool showNone /*= false*/, bool multipleSelection /*= true*/)
374 vector<ADDON::TYPE> types;
375 types.push_back(type);
376 return SelectAddonID(types, addonIDs, showNone, multipleSelection);
379 int CGUIWindowAddonBrowser::SelectAddonID(const vector<ADDON::TYPE> &types, CStdString &addonID, bool showNone /*= false*/)
381 CStdStringArray addonIDs;
382 if (!addonID.IsEmpty())
383 addonIDs.push_back(addonID);
384 int retval = SelectAddonID(types, addonIDs, showNone, false);
385 if (addonIDs.size() > 0)
386 addonID = addonIDs.at(0);
392 int CGUIWindowAddonBrowser::SelectAddonID(const vector<ADDON::TYPE> &types, CStdStringArray &addonIDs, bool showNone /*= false*/, bool multipleSelection /*= true*/)
394 CGUIDialogSelect *dialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
401 for (vector<ADDON::TYPE>::const_iterator it = types.begin(); it != types.end(); ++it)
403 if (*it == ADDON_UNKNOWN)
405 ADDON::VECADDONS addons;
407 if (*it == ADDON_AUDIO)
408 CAddonsDirectory::GetScriptsAndPlugins("audio",addons);
409 else if (*it == ADDON_EXECUTABLE)
410 CAddonsDirectory::GetScriptsAndPlugins("executable",addons);
411 else if (*it == ADDON_IMAGE)
412 CAddonsDirectory::GetScriptsAndPlugins("image",addons);
413 else if (*it == ADDON_VIDEO)
414 CAddonsDirectory::GetScriptsAndPlugins("video",addons);
416 CAddonMgr::Get().GetAddons(*it, addons);
417 for (ADDON::IVECADDONS it2 = addons.begin() ; it2 != addons.end() ; ++it2)
419 CFileItemPtr item(CAddonsDirectory::FileItemFromAddon(*it2, ""));
420 if (!items.Contains(item->GetPath()))
424 if (!heading.IsEmpty())
426 heading += TranslateType(*it, true);
432 dialog->SetHeading(heading);
434 dialog->SetUseDetails(true);
435 if (multipleSelection)
437 if (multipleSelection || iTypes > 1)
438 dialog->EnableButton(true, 186);
440 dialog->EnableButton(true, 21452);
443 CFileItemPtr item(new CFileItem("", false));
444 item->SetLabel(g_localizeStrings.Get(231));
445 item->SetLabel2(g_localizeStrings.Get(24040));
446 item->SetIconImage("DefaultAddonNone.png");
447 item->SetSpecialSort(SortSpecialOnTop);
450 items.Sort(SortByLabel, SortOrderAscending);
452 if (addonIDs.size() > 0)
454 for (CStdStringArray::const_iterator it = addonIDs.begin(); it != addonIDs.end() ; it++)
456 CFileItemPtr item = items.Get(*it);
461 dialog->SetItems(&items);
462 dialog->SetMultiSelection(multipleSelection);
464 if (!multipleSelection && iTypes == 1 && dialog->IsButtonPressed())
465 { // switch to the addons browser.
466 vector<CStdString> params;
467 params.push_back("addons://all/"+TranslateType(types[0],false)+"/");
468 params.push_back("return");
469 g_windowManager.ActivateWindow(WINDOW_ADDON_BROWSER, params);
472 if (!dialog->IsConfirmed())
475 const CFileItemList& list = dialog->GetSelectedItems();
476 for (int i = 0 ; i < list.Size() ; i++)
477 addonIDs.push_back(list.Get(i)->GetPath());
481 CStdString CGUIWindowAddonBrowser::GetStartFolder(const CStdString &dir)
483 if (StringUtils::StartsWithNoCase(dir, "addons://"))
485 return CGUIMediaWindow::GetStartFolder(dir);