summaryrefslogtreecommitdiffstats
path: root/xbmc/addons/GUIDialogAddonInfo.cpp
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2015-03-03 16:53:59 +0100
committermanuel <manuel@mausz.at>2015-03-03 16:53:59 +0100
commitffca21f2743a7b367fa212799c6e2fea6190dd5d (patch)
tree0608ea3a29cf644ec9ab204e2b4bb9bfaae1c381 /xbmc/addons/GUIDialogAddonInfo.cpp
downloadkodi-pvr-build-ffca21f2743a7b367fa212799c6e2fea6190dd5d.tar.gz
kodi-pvr-build-ffca21f2743a7b367fa212799c6e2fea6190dd5d.tar.bz2
kodi-pvr-build-ffca21f2743a7b367fa212799c6e2fea6190dd5d.zip
initial commit for kodi master
Diffstat (limited to 'xbmc/addons/GUIDialogAddonInfo.cpp')
-rw-r--r--xbmc/addons/GUIDialogAddonInfo.cpp458
1 files changed, 458 insertions, 0 deletions
diff --git a/xbmc/addons/GUIDialogAddonInfo.cpp b/xbmc/addons/GUIDialogAddonInfo.cpp
new file mode 100644
index 0000000..fe3484f
--- /dev/null
+++ b/xbmc/addons/GUIDialogAddonInfo.cpp
@@ -0,0 +1,458 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://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, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "GUIDialogAddonInfo.h"
22#include "dialogs/GUIDialogYesNo.h"
23#include "dialogs/GUIDialogOK.h"
24#include "addons/AddonManager.h"
25#include "AddonDatabase.h"
26#include "FileItem.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 "input/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"
42#include "Util.h"
43#include "interfaces/Builtins.h"
44
45#define CONTROL_BTN_INSTALL 6
46#define CONTROL_BTN_ENABLE 7
47#define CONTROL_BTN_UPDATE 8
48#define CONTROL_BTN_SETTINGS 9
49#define CONTROL_BTN_CHANGELOG 10
50#define CONTROL_BTN_ROLLBACK 11
51#define CONTROL_BTN_SELECT 12
52
53using namespace std;
54using namespace ADDON;
55using namespace XFILE;
56
57CGUIDialogAddonInfo::CGUIDialogAddonInfo(void)
58 : CGUIDialog(WINDOW_DIALOG_ADDON_INFO, "DialogAddonInfo.xml"), m_jobid(0)
59{
60 m_item = CFileItemPtr(new CFileItem);
61 m_loadType = KEEP_IN_MEMORY;
62}
63
64CGUIDialogAddonInfo::~CGUIDialogAddonInfo(void)
65{
66}
67
68bool CGUIDialogAddonInfo::OnMessage(CGUIMessage& message)
69{
70 switch ( message.GetMessage() )
71 {
72 case GUI_MSG_WINDOW_DEINIT:
73 {
74 if (m_jobid)
75 CJobManager::GetInstance().CancelJob(m_jobid);
76 }
77 break;
78
79 case GUI_MSG_CLICKED:
80 {
81 int iControl = message.GetSenderId();
82 if (iControl == CONTROL_BTN_UPDATE)
83 {
84 OnUpdate();
85 return true;
86 }
87 if (iControl == CONTROL_BTN_INSTALL)
88 {
89 if (!m_localAddon)
90 {
91 OnInstall();
92 return true;
93 }
94 else
95 {
96 OnUninstall();
97 return true;
98 }
99 }
100 else if (iControl == CONTROL_BTN_SELECT)
101 {
102 OnLaunch();
103 return true;
104 }
105 else if (iControl == CONTROL_BTN_ENABLE)
106 {
107 OnEnable(!m_item->GetProperty("Addon.Enabled").asBoolean());
108 return true;
109 }
110 else if (iControl == CONTROL_BTN_SETTINGS)
111 {
112 OnSettings();
113 return true;
114 }
115 else if (iControl == CONTROL_BTN_CHANGELOG)
116 {
117 OnChangeLog();
118 return true;
119 }
120 else if (iControl == CONTROL_BTN_ROLLBACK)
121 {
122 OnRollback();
123 return true;
124 }
125 }
126 break;
127default:
128 break;
129 }
130
131 return CGUIDialog::OnMessage(message);
132}
133
134bool CGUIDialogAddonInfo::OnAction(const CAction &action)
135{
136 if (action.GetID() == ACTION_SHOW_INFO)
137 {
138 Close();
139 return true;
140 }
141 return CGUIDialog::OnAction(action);
142}
143
144void CGUIDialogAddonInfo::OnInitWindow()
145{
146 UpdateControls();
147 CGUIDialog::OnInitWindow();
148 m_changelog = false;
149}
150
151void CGUIDialogAddonInfo::UpdateControls()
152{
153 bool isInstalled = NULL != m_localAddon.get();
154 bool isEnabled = isInstalled && m_item->GetProperty("Addon.Enabled").asBoolean();
155 bool isUpdatable = isInstalled && m_item->GetProperty("Addon.UpdateAvail").asBoolean();
156 bool isExecutable = isInstalled && (m_localAddon->Type() == ADDON_PLUGIN || m_localAddon->Type() == ADDON_SCRIPT);
157 if (isInstalled)
158 GrabRollbackVersions();
159
160 bool canDisable = isInstalled && CAddonMgr::Get().CanAddonBeDisabled(m_localAddon->ID());
161 bool canInstall = !isInstalled && m_item->GetProperty("Addon.Broken").empty();
162 bool isRepo = (isInstalled && m_localAddon->Type() == ADDON_REPOSITORY) || (m_addon && m_addon->Type() == ADDON_REPOSITORY);
163
164 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_INSTALL, canDisable || canInstall);
165 SET_CONTROL_LABEL(CONTROL_BTN_INSTALL, isInstalled ? 24037 : 24038);
166
167 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_ENABLE, canDisable);
168 SET_CONTROL_LABEL(CONTROL_BTN_ENABLE, isEnabled ? 24021 : 24022);
169
170 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_UPDATE, isUpdatable);
171 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_SETTINGS, isInstalled && m_localAddon->HasSettings());
172 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_SELECT, isExecutable);
173 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_CHANGELOG, !isRepo);
174 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_ROLLBACK, m_rollbackVersions.size() > 1);
175}
176
177void CGUIDialogAddonInfo::OnUpdate()
178{
179 std::string referer = StringUtils::Format("Referer=%s-%s.zip",m_localAddon->ID().c_str(),m_localAddon->Version().asString().c_str());
180 CAddonInstaller::Get().Install(m_addon->ID(), true, referer); // force install
181 Close();
182}
183
184void CGUIDialogAddonInfo::OnInstall()
185{
186 CAddonInstaller::Get().Install(m_addon->ID());
187 Close();
188}
189
190void CGUIDialogAddonInfo::OnLaunch()
191{
192 if (!m_localAddon)
193 return;
194
195 CBuiltins::Execute("RunAddon(" + m_localAddon->ID() + ")");
196 Close();
197}
198
199bool CGUIDialogAddonInfo::PromptIfDependency(int heading, int line2)
200{
201 if (!m_localAddon)
202 return false;
203
204 VECADDONS addons;
205 vector<string> deps;
206 CAddonMgr::Get().GetAllAddons(addons);
207 for (VECADDONS::const_iterator it = addons.begin();
208 it != addons.end();++it)
209 {
210 ADDONDEPS::const_iterator i = (*it)->GetDeps().find(m_localAddon->ID());
211 if (i != (*it)->GetDeps().end() && !i->second.second) // non-optional dependency
212 deps.push_back((*it)->Name());
213 }
214
215 if (!deps.empty())
216 {
217 string line0 = StringUtils::Format(g_localizeStrings.Get(24046).c_str(), m_localAddon->Name().c_str());
218 string line1 = StringUtils::Join(deps, ", ");
219 CGUIDialogOK::ShowAndGetInput(heading, line0, line1, line2);
220 return true;
221 }
222 return false;
223}
224
225void CGUIDialogAddonInfo::OnUninstall()
226{
227 if (!m_localAddon.get())
228 return;
229
230 if (!g_passwordManager.CheckMenuLock(WINDOW_ADDON_BROWSER))
231 return;
232
233 // ensure the addon is not a dependency of other installed addons
234 if (PromptIfDependency(24037, 24047))
235 return;
236
237 // prompt user to be sure
238 if (!CGUIDialogYesNo::ShowAndGetInput(24037, 750, 0, 0))
239 return;
240
241 // ensure the addon isn't disabled in our database
242 CAddonMgr::Get().DisableAddon(m_localAddon->ID(), false);
243
244 CJobManager::GetInstance().AddJob(new CAddonUnInstallJob(m_localAddon),
245 &CAddonInstaller::Get());
246 CAddonMgr::Get().RemoveAddon(m_localAddon->ID());
247 Close();
248}
249
250void CGUIDialogAddonInfo::OnEnable(bool enable)
251{
252 if (!m_localAddon.get())
253 return;
254
255 if (!g_passwordManager.CheckMenuLock(WINDOW_ADDON_BROWSER))
256 return;
257
258 if (!enable && PromptIfDependency(24075, 24091))
259 return;
260
261 CAddonMgr::Get().DisableAddon(m_localAddon->ID(), !enable);
262 SetItem(m_item);
263 UpdateControls();
264 g_windowManager.SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE);
265}
266
267void CGUIDialogAddonInfo::OnSettings()
268{
269 CGUIDialogAddonSettings::ShowAndGetInput(m_localAddon);
270}
271
272void CGUIDialogAddonInfo::OnChangeLog()
273{
274 CGUIDialogTextViewer* pDlgInfo = (CGUIDialogTextViewer*)g_windowManager.GetWindow(WINDOW_DIALOG_TEXT_VIEWER);
275 std::string name;
276 if (m_addon)
277 name = m_addon->Name();
278 else if (m_localAddon)
279 name = m_localAddon->Name();
280 pDlgInfo->SetHeading(g_localizeStrings.Get(24054)+" - "+name);
281 if (m_item->GetProperty("Addon.Changelog").empty())
282 {
283 pDlgInfo->SetText(g_localizeStrings.Get(13413));
284 CFileItemList items;
285 if (m_localAddon &&
286 !m_item->GetProperty("Addon.UpdateAvail").asBoolean())
287 {
288 items.Add(CFileItemPtr(new CFileItem(m_localAddon->ChangeLog(),false)));
289 }
290 else
291 items.Add(CFileItemPtr(new CFileItem(m_addon->ChangeLog(),false)));
292 items[0]->Select(true);
293 m_jobid = CJobManager::GetInstance().AddJob(
294 new CFileOperationJob(CFileOperationJob::ActionCopy,items,
295 "special://temp/"),this);
296 }
297 else
298 pDlgInfo->SetText(m_item->GetProperty("Addon.Changelog").asString());
299
300 m_changelog = true;
301 pDlgInfo->DoModal();
302 m_changelog = false;
303}
304
305void CGUIDialogAddonInfo::OnRollback()
306{
307 if (!g_passwordManager.CheckMenuLock(WINDOW_ADDON_BROWSER))
308 return;
309
310 CGUIDialogContextMenu* dlg = (CGUIDialogContextMenu*)g_windowManager.GetWindow(WINDOW_DIALOG_CONTEXT_MENU);
311 CAddonDatabase database;
312 database.Open();
313
314 CContextButtons buttons;
315 for (unsigned int i=0;i<m_rollbackVersions.size();++i)
316 {
317 std::string label(m_rollbackVersions[i]);
318 if (m_rollbackVersions[i] == m_localAddon->Version().asString())
319 label += " "+g_localizeStrings.Get(24094);
320 if (database.IsAddonBlacklisted(m_localAddon->ID(),label))
321 label += " "+g_localizeStrings.Get(24095);
322
323 buttons.Add(i,label);
324 }
325 int choice;
326 if ((choice=dlg->ShowAndGetChoice(buttons)) > -1)
327 {
328 // blacklist everything newer
329 for (unsigned int j=choice+1;j<m_rollbackVersions.size();++j)
330 database.BlacklistAddon(m_localAddon->ID(),m_rollbackVersions[j]);
331 std::string path = "special://home/addons/packages/";
332 path += m_localAddon->ID()+"-"+m_rollbackVersions[choice]+".zip";
333 // needed as cpluff won't downgrade
334 if (!m_localAddon->IsType(ADDON_SERVICE))
335 //we will handle this for service addons in CAddonInstallJob::OnPostInstall
336 CAddonMgr::Get().RemoveAddon(m_localAddon->ID());
337 CAddonInstaller::Get().InstallFromZip(path);
338 database.RemoveAddonFromBlacklist(m_localAddon->ID(),m_rollbackVersions[choice]);
339 Close();
340 }
341}
342
343bool CGUIDialogAddonInfo::ShowForItem(const CFileItemPtr& item)
344{
345 CGUIDialogAddonInfo* dialog = (CGUIDialogAddonInfo*)g_windowManager.GetWindow(WINDOW_DIALOG_ADDON_INFO);
346 if (!dialog)
347 return false;
348 if (!dialog->SetItem(item))
349 return false;
350
351 dialog->DoModal();
352 return true;
353}
354
355bool CGUIDialogAddonInfo::SetItem(const CFileItemPtr& item)
356{
357 *m_item = *item;
358 m_rollbackVersions.clear();
359
360 // grab the local addon, if it's available
361 m_localAddon.reset();
362 m_addon.reset();
363 if (CAddonMgr::Get().GetAddon(item->GetProperty("Addon.ID").asString(), m_localAddon)) // sets m_localAddon if installed regardless of enabled state
364 m_item->SetProperty("Addon.Enabled", "true");
365 else
366 m_item->SetProperty("Addon.Enabled", "false");
367 m_item->SetProperty("Addon.Installed", m_localAddon ? "true" : "false");
368
369 CAddonDatabase database;
370 database.Open();
371 database.GetAddon(item->GetProperty("Addon.ID").asString(),m_addon);
372
373 if (TranslateType(item->GetProperty("Addon.intType").asString()) == ADDON_REPOSITORY)
374 {
375 CAddonDatabase database;
376 database.Open();
377 VECADDONS addons;
378 if (m_addon)
379 database.GetRepository(m_addon->ID(), addons);
380 else if (m_localAddon) // sanity
381 database.GetRepository(m_localAddon->ID(), addons);
382 int tot=0;
383 for (int i = ADDON_UNKNOWN+1;i<ADDON_MAX;++i)
384 {
385 int num=0;
386 for (unsigned int j=0;j<addons.size();++j)
387 {
388 if (addons[j]->Type() == (TYPE)i)
389 ++num;
390 }
391 m_item->SetProperty("Repo." + TranslateType((TYPE)i), num);
392 tot += num;
393 }
394 m_item->SetProperty("Repo.Addons", tot);
395 }
396 return true;
397}
398
399void CGUIDialogAddonInfo::OnJobComplete(unsigned int jobID, bool success,
400 CJob* job)
401{
402 if (!m_changelog)
403 return;
404
405 CGUIDialogTextViewer* pDlgInfo = (CGUIDialogTextViewer*)g_windowManager.GetWindow(WINDOW_DIALOG_TEXT_VIEWER);
406
407 m_jobid = 0;
408 if (!success)
409 {
410 pDlgInfo->SetText(g_localizeStrings.Get(195));
411 }
412 else
413 {
414 CFile file;
415 XFILE::auto_buffer buf;
416 if (file.LoadFile("special://temp/" +
417 URIUtils::GetFileName(((CFileOperationJob*)job)->GetItems()[0]->GetPath()), buf) > 0)
418 {
419 std::string str(buf.get(), buf.length());
420 m_item->SetProperty("Addon.Changelog", str);
421 pDlgInfo->SetText(str);
422 }
423 }
424 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, WINDOW_DIALOG_TEXT_VIEWER, 0, GUI_MSG_UPDATE);
425 g_windowManager.SendThreadMessage(msg);
426}
427
428void CGUIDialogAddonInfo::GrabRollbackVersions()
429{
430 CFileItemList items;
431 XFILE::CDirectory::GetDirectory("special://home/addons/packages/",items,".zip",DIR_FLAG_NO_FILE_DIRS);
432 items.Sort(SortByLabel, SortOrderAscending);
433 CAddonDatabase db;
434 db.Open();
435 for (int i=0;i<items.Size();++i)
436 {
437 if (items[i]->m_bIsFolder)
438 continue;
439 std::string ID, version;
440 AddonVersion::SplitFileName(ID,version,items[i]->GetLabel());
441 if (ID == m_localAddon->ID())
442 {
443 std::string hash, path(items[i]->GetPath());
444 if (db.GetPackageHash(m_localAddon->ID(), path, hash))
445 {
446 std::string md5 = CUtil::GetFileMD5(path);
447 if (md5 == hash)
448 m_rollbackVersions.push_back(version);
449 else /* The package has been corrupted */
450 {
451 CLog::Log(LOGWARNING, "%s: Removing corrupt addon package %s.", __FUNCTION__, path.c_str());
452 CFile::Delete(path);
453 db.RemovePackage(path);
454 }
455 }
456 }
457 }
458}