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 "GUIDialogAddonInfo.h"
22 #include "dialogs/GUIDialogYesNo.h"
23 #include "dialogs/GUIDialogOK.h"
24 #include "addons/AddonManager.h"
25 #include "AddonDatabase.h"
27 #include "filesystem/Directory.h"
28 #include "filesystem/SpecialProtocol.h"
29 #include "GUIDialogAddonSettings.h"
30 #include "dialogs/GUIDialogContextMenu.h"
31 #include "dialogs/GUIDialogTextViewer.h"
32 #include "GUIUserMessages.h"
33 #include "guilib/GUIWindowManager.h"
34 #include "guilib/Key.h"
35 #include "utils/JobManager.h"
36 #include "utils/FileOperationJob.h"
37 #include "utils/StringUtils.h"
38 #include "utils/URIUtils.h"
39 #include "utils/log.h"
40 #include "addons/AddonInstaller.h"
41 #include "pvr/PVRManager.h"
44 #define CONTROL_BTN_INSTALL 6
45 #define CONTROL_BTN_ENABLE 7
46 #define CONTROL_BTN_UPDATE 8
47 #define CONTROL_BTN_SETTINGS 9
48 #define CONTROL_BTN_CHANGELOG 10
49 #define CONTROL_BTN_ROLLBACK 11
52 using namespace ADDON;
53 using namespace XFILE;
55 CGUIDialogAddonInfo::CGUIDialogAddonInfo(void)
56 : CGUIDialog(WINDOW_DIALOG_ADDON_INFO, "DialogAddonInfo.xml")
58 m_item = CFileItemPtr(new CFileItem);
59 m_loadType = KEEP_IN_MEMORY;
62 CGUIDialogAddonInfo::~CGUIDialogAddonInfo(void)
66 bool CGUIDialogAddonInfo::OnMessage(CGUIMessage& message)
68 switch ( message.GetMessage() )
70 case GUI_MSG_WINDOW_DEINIT:
73 CJobManager::GetInstance().CancelJob(m_jobid);
79 int iControl = message.GetSenderId();
80 if (iControl == CONTROL_BTN_UPDATE)
85 if (iControl == CONTROL_BTN_INSTALL)
98 else if (iControl == CONTROL_BTN_ENABLE)
100 OnEnable(!m_item->GetProperty("Addon.Enabled").asBoolean());
103 else if (iControl == CONTROL_BTN_SETTINGS)
108 else if (iControl == CONTROL_BTN_CHANGELOG)
113 else if (iControl == CONTROL_BTN_ROLLBACK)
124 return CGUIDialog::OnMessage(message);
127 bool CGUIDialogAddonInfo::OnAction(const CAction &action)
129 if (action.GetID() == ACTION_SHOW_INFO)
134 return CGUIDialog::OnAction(action);
137 void CGUIDialogAddonInfo::OnInitWindow()
140 CGUIDialog::OnInitWindow();
144 void CGUIDialogAddonInfo::UpdateControls()
146 CStdString xbmcPath = CSpecialProtocol::TranslatePath("special://xbmc/addons");
147 bool isInstalled = NULL != m_localAddon.get();
148 bool isSystem = isInstalled && StringUtils::StartsWith(m_localAddon->Path(), xbmcPath);
149 bool isEnabled = isInstalled && m_item->GetProperty("Addon.Enabled").asBoolean();
150 bool isUpdatable = isInstalled && m_item->GetProperty("Addon.UpdateAvail").asBoolean();
152 GrabRollbackVersions();
154 // TODO: System addons should be able to be disabled
155 bool isPVR = isInstalled && m_localAddon->Type() == ADDON_PVRDLL;
156 bool canDisable = isInstalled && (!isSystem || isPVR) && !m_localAddon->IsInUse();
157 bool canInstall = !isInstalled && m_item->GetProperty("Addon.Broken").empty();
158 bool isRepo = (isInstalled && m_localAddon->Type() == ADDON_REPOSITORY) || (m_addon && m_addon->Type() == ADDON_REPOSITORY);
160 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_INSTALL, canDisable || canInstall);
161 SET_CONTROL_LABEL(CONTROL_BTN_INSTALL, isInstalled ? 24037 : 24038);
163 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_ENABLE, canDisable);
164 SET_CONTROL_LABEL(CONTROL_BTN_ENABLE, isEnabled ? 24021 : 24022);
166 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_UPDATE, isUpdatable);
167 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_SETTINGS, isInstalled && m_localAddon->HasSettings());
168 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_CHANGELOG, !isRepo);
169 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_ROLLBACK, m_rollbackVersions.size() > 1);
172 void CGUIDialogAddonInfo::OnUpdate()
174 CStdString referer = StringUtils::Format("Referer=%s-%s.zip",m_localAddon->ID().c_str(),m_localAddon->Version().c_str());
175 CAddonInstaller::Get().Install(m_addon->ID(), true, referer); // force install
179 void CGUIDialogAddonInfo::OnInstall()
181 CAddonInstaller::Get().Install(m_addon->ID());
185 bool CGUIDialogAddonInfo::PromptIfDependency(int heading, int line2)
192 CAddonMgr::Get().GetAllAddons(addons);
193 for (VECADDONS::const_iterator it = addons.begin();
194 it != addons.end();++it)
196 ADDONDEPS::const_iterator i = (*it)->GetDeps().find(m_localAddon->ID());
197 if (i != (*it)->GetDeps().end() && !i->second.second) // non-optional dependency
198 deps.push_back((*it)->Name());
203 string line0 = StringUtils::Format(g_localizeStrings.Get(24046), m_localAddon->Name().c_str());
204 string line1 = StringUtils::Join(deps, ", ");
205 CGUIDialogOK::ShowAndGetInput(heading, line0, line1, line2);
211 void CGUIDialogAddonInfo::OnUninstall()
213 if (!m_localAddon.get())
216 // ensure the addon is not a dependency of other installed addons
217 if (PromptIfDependency(24037, 24047))
220 // prompt user to be sure
221 if (!CGUIDialogYesNo::ShowAndGetInput(24037, 750, 0, 0))
224 // ensure the addon isn't disabled in our database
225 CAddonMgr::Get().DisableAddon(m_localAddon->ID(), false);
227 CJobManager::GetInstance().AddJob(new CAddonUnInstallJob(m_localAddon),
228 &CAddonInstaller::Get());
229 CAddonMgr::Get().RemoveAddon(m_localAddon->ID());
233 void CGUIDialogAddonInfo::OnEnable(bool enable)
235 if (!m_localAddon.get())
238 if (!enable && PromptIfDependency(24075, 24091))
241 CAddonMgr::Get().DisableAddon(m_localAddon->ID(), !enable);
244 g_windowManager.SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE);
247 void CGUIDialogAddonInfo::OnSettings()
249 CGUIDialogAddonSettings::ShowAndGetInput(m_localAddon);
252 void CGUIDialogAddonInfo::OnChangeLog()
254 CGUIDialogTextViewer* pDlgInfo = (CGUIDialogTextViewer*)g_windowManager.GetWindow(WINDOW_DIALOG_TEXT_VIEWER);
257 name = m_addon->Name();
258 else if (m_localAddon)
259 name = m_localAddon->Name();
260 pDlgInfo->SetHeading(g_localizeStrings.Get(24054)+" - "+name);
261 if (m_item->GetProperty("Addon.Changelog").empty())
263 pDlgInfo->SetText(g_localizeStrings.Get(13413));
266 !m_item->GetProperty("Addon.UpdateAvail").asBoolean())
268 items.Add(CFileItemPtr(new CFileItem(m_localAddon->ChangeLog(),false)));
271 items.Add(CFileItemPtr(new CFileItem(m_addon->ChangeLog(),false)));
272 items[0]->Select(true);
273 m_jobid = CJobManager::GetInstance().AddJob(
274 new CFileOperationJob(CFileOperationJob::ActionCopy,items,
275 "special://temp/"),this);
278 pDlgInfo->SetText(m_item->GetProperty("Addon.Changelog").asString());
285 void CGUIDialogAddonInfo::OnRollback()
287 CGUIDialogContextMenu* dlg = (CGUIDialogContextMenu*)g_windowManager.GetWindow(WINDOW_DIALOG_CONTEXT_MENU);
288 CAddonDatabase database;
291 CContextButtons buttons;
292 for (unsigned int i=0;i<m_rollbackVersions.size();++i)
294 CStdString label(m_rollbackVersions[i]);
295 if (m_rollbackVersions[i].Equals(m_localAddon->Version().c_str()))
296 label += " "+g_localizeStrings.Get(24094);
297 if (database.IsAddonBlacklisted(m_localAddon->ID(),label))
298 label += " "+g_localizeStrings.Get(24095);
300 buttons.Add(i,label);
303 if ((choice=dlg->ShowAndGetChoice(buttons)) > -1)
305 // blacklist everything newer
306 for (unsigned int j=choice+1;j<m_rollbackVersions.size();++j)
307 database.BlacklistAddon(m_localAddon->ID(),m_rollbackVersions[j]);
308 CStdString path = "special://home/addons/packages/";
309 path += m_localAddon->ID()+"-"+m_rollbackVersions[choice]+".zip";
310 // needed as cpluff won't downgrade
311 if (!m_localAddon->IsType(ADDON_SERVICE))
312 //we will handle this for service addons in CAddonInstallJob::OnPostInstall
313 CAddonMgr::Get().RemoveAddon(m_localAddon->ID());
314 CAddonInstaller::Get().InstallFromZip(path);
315 database.RemoveAddonFromBlacklist(m_localAddon->ID(),m_rollbackVersions[choice]);
320 bool CGUIDialogAddonInfo::ShowForItem(const CFileItemPtr& item)
322 CGUIDialogAddonInfo* dialog = (CGUIDialogAddonInfo*)g_windowManager.GetWindow(WINDOW_DIALOG_ADDON_INFO);
325 if (!dialog->SetItem(item))
332 bool CGUIDialogAddonInfo::SetItem(const CFileItemPtr& item)
335 m_rollbackVersions.clear();
337 // grab the local addon, if it's available
338 m_localAddon.reset();
340 if (CAddonMgr::Get().GetAddon(item->GetProperty("Addon.ID").asString(), m_localAddon)) // sets m_addon if installed regardless of enabled state
341 m_item->SetProperty("Addon.Enabled", "true");
343 m_item->SetProperty("Addon.Enabled", "false");
344 m_item->SetProperty("Addon.Installed", m_addon ? "true" : "false");
346 CAddonDatabase database;
348 database.GetAddon(item->GetProperty("Addon.ID").asString(),m_addon);
350 if (TranslateType(item->GetProperty("Addon.intType").asString()) == ADDON_REPOSITORY)
352 CAddonDatabase database;
356 database.GetRepository(m_addon->ID(), addons);
357 else if (m_localAddon) // sanity
358 database.GetRepository(m_localAddon->ID(), addons);
360 for (int i = ADDON_UNKNOWN+1;i<ADDON_VIZ_LIBRARY;++i)
363 for (unsigned int j=0;j<addons.size();++j)
365 if (addons[j]->Type() == (TYPE)i)
368 m_item->SetProperty(CStdString("Repo.") + TranslateType((TYPE)i), num);
371 m_item->SetProperty("Repo.Addons", tot);
376 void CGUIDialogAddonInfo::OnJobComplete(unsigned int jobID, bool success,
382 CGUIDialogTextViewer* pDlgInfo = (CGUIDialogTextViewer*)g_windowManager.GetWindow(WINDOW_DIALOG_TEXT_VIEWER);
387 pDlgInfo->SetText(g_localizeStrings.Get(195));
392 if (file.Open("special://temp/"+
393 URIUtils::GetFileName(((CFileOperationJob*)job)->GetItems()[0]->GetPath())))
395 char* temp = new char[(size_t)file.GetLength()+1];
396 file.Read(temp,file.GetLength());
397 temp[file.GetLength()] = '\0';
398 m_item->SetProperty("Addon.Changelog",temp);
399 pDlgInfo->SetText(temp);
403 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, WINDOW_DIALOG_TEXT_VIEWER, 0, GUI_MSG_UPDATE);
404 g_windowManager.SendThreadMessage(msg);
407 void CGUIDialogAddonInfo::GrabRollbackVersions()
410 XFILE::CDirectory::GetDirectory("special://home/addons/packages/",items,".zip",DIR_FLAG_NO_FILE_DIRS);
411 items.Sort(SortByLabel, SortOrderAscending);
414 for (int i=0;i<items.Size();++i)
416 if (items[i]->m_bIsFolder)
418 CStdString ID, version;
419 AddonVersion::SplitFileName(ID,version,items[i]->GetLabel());
420 if (ID.Equals(m_localAddon->ID()))
422 CStdString hash, path(items[i]->GetPath());
423 if (db.GetPackageHash(m_localAddon->ID(), path, hash))
425 CStdString md5 = CUtil::GetFileMD5(path);
427 m_rollbackVersions.push_back(version);
428 else /* The package has been corrupted */
430 CLog::Log(LOGWARNING, "%s: Removing corrupt addon package %s.", __FUNCTION__, path.c_str());
432 db.RemovePackage(path);