Merge pull request #5095 from koying/fixdroidappcrash
[vuplus_xbmc] / xbmc / filesystem / FavouritesDirectory.cpp
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 "FavouritesDirectory.h"
22 #include "File.h"
23 #include "Util.h"
24 #include "profiles/ProfilesManager.h"
25 #include "FileItem.h"
26 #include "utils/XBMCTinyXML.h"
27 #include "utils/log.h"
28 #include "utils/StringUtils.h"
29 #include "utils/URIUtils.h"
30 #include "settings/AdvancedSettings.h"
31 #include "video/VideoInfoTag.h"
32 #include "music/tags/MusicInfoTag.h"
33 #include "URL.h"
34
35 namespace XFILE
36 {
37
38
39 bool CFavouritesDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
40 {
41   items.Clear();
42   CURL url(strPath);
43
44   if (url.GetProtocol() == "favourites")
45   {
46     return Load(items); //load the default favourite files
47   }
48   return LoadFavourites(strPath, items); //directly load the given file
49 }
50
51 bool CFavouritesDirectory::Exists(const char* strPath)
52 {
53   CURL url(strPath);
54
55   if (url.GetProtocol() == "favourites")
56   {
57     return XFILE::CFile::Exists("special://xbmc/system/favourites.xml") 
58         || XFILE::CFile::Exists(URIUtils::AddFileToFolder(CProfilesManager::Get().GetProfileUserDataFolder(), "favourites.xml"));
59   }
60   return XFILE::CFile::Exists(strPath); //directly load the given file
61 }
62
63 bool CFavouritesDirectory::Load(CFileItemList &items)
64 {
65   items.Clear();
66   CStdString favourites;
67
68   favourites = "special://xbmc/system/favourites.xml";
69   if(XFILE::CFile::Exists(favourites))
70     CFavouritesDirectory::LoadFavourites(favourites, items);
71   else
72     CLog::Log(LOGDEBUG, "CFavourites::Load - no system favourites found, skipping");
73   favourites = URIUtils::AddFileToFolder(CProfilesManager::Get().GetProfileUserDataFolder(), "favourites.xml");
74   if(XFILE::CFile::Exists(favourites))
75     CFavouritesDirectory::LoadFavourites(favourites, items);
76   else
77     CLog::Log(LOGDEBUG, "CFavourites::Load - no userdata favourites found, skipping");
78
79   return true;
80 }
81
82 bool CFavouritesDirectory::LoadFavourites(const CStdString& strPath, CFileItemList& items)
83 {
84   CXBMCTinyXML doc;
85   if (!doc.LoadFile(strPath))
86   {
87     CLog::Log(LOGERROR, "Unable to load %s (row %i column %i)", strPath.c_str(), doc.Row(), doc.Column());
88     return false;
89   }
90   TiXmlElement *root = doc.RootElement();
91   if (!root || strcmp(root->Value(), "favourites"))
92   {
93     CLog::Log(LOGERROR, "Favourites.xml doesn't contain the <favourites> root element");
94     return false;
95   }
96
97   TiXmlElement *favourite = root->FirstChildElement("favourite");
98   while (favourite)
99   {
100     // format:
101     // <favourite name="Cool Video" thumb="foo.jpg">PlayMedia(c:\videos\cool_video.avi)</favourite>
102     // <favourite name="My Album" thumb="bar.tbn">ActivateWindow(MyMusic,c:\music\my album)</favourite>
103     // <favourite name="Apple Movie Trailers" thumb="path_to_thumb.png">RunScript(special://xbmc/scripts/apple movie trailers/default.py)</favourite>
104     const char *name = favourite->Attribute("name");
105     const char *thumb = favourite->Attribute("thumb");
106     if (name && favourite->FirstChild())
107     {
108       if(!items.Contains(favourite->FirstChild()->Value()))
109       {
110         CFileItemPtr item(new CFileItem(name));
111         item->SetPath(favourite->FirstChild()->Value());
112         if (thumb) item->SetArt("thumb", thumb);
113         items.Add(item);
114       }
115     }
116     favourite = favourite->NextSiblingElement("favourite");
117   }
118   return true;
119 }
120
121 bool CFavouritesDirectory::Save(const CFileItemList &items)
122 {
123   CStdString favourites;
124   CXBMCTinyXML doc;
125   TiXmlElement xmlRootElement("favourites");
126   TiXmlNode *rootNode = doc.InsertEndChild(xmlRootElement);
127   if (!rootNode) return false;
128
129   for (int i = 0; i < items.Size(); i++)
130   {
131     const CFileItemPtr item = items[i];
132     TiXmlElement favNode("favourite");
133     favNode.SetAttribute("name", item->GetLabel().c_str());
134     if (item->HasArt("thumb"))
135       favNode.SetAttribute("thumb", item->GetArt("thumb").c_str());
136     TiXmlText execute(item->GetPath());
137     favNode.InsertEndChild(execute);
138     rootNode->InsertEndChild(favNode);
139   }
140
141   favourites = URIUtils::AddFileToFolder(CProfilesManager::Get().GetProfileUserDataFolder(), "favourites.xml");
142   return doc.SaveFile(favourites);
143 }
144
145 bool CFavouritesDirectory::AddOrRemove(CFileItem *item, int contextWindow)
146 {
147   if (!item) return false;
148
149   // load our list
150   CFileItemList items;
151   Load(items);
152
153   CStdString executePath(GetExecutePath(*item, contextWindow));
154
155   CFileItemPtr match = items.Get(executePath);
156   if (match)
157   { // remove the item
158     items.Remove(match.get());
159   }
160   else
161   { // create our new favourite item
162     CFileItemPtr favourite(new CFileItem(item->GetLabel()));
163     if (item->GetLabel().empty())
164       favourite->SetLabel(CUtil::GetTitleFromPath(item->GetPath(), item->m_bIsFolder));
165     favourite->SetArt("thumb", item->GetArt("thumb"));
166     favourite->SetPath(executePath);
167     items.Add(favourite);
168   }
169
170   // and save our list again
171   return Save(items);
172 }
173
174 bool CFavouritesDirectory::IsFavourite(CFileItem *item, int contextWindow)
175 {
176   CFileItemList items;
177   if (!Load(items)) return false;
178
179   return items.Contains(GetExecutePath(*item, contextWindow));
180 }
181
182 CStdString CFavouritesDirectory::GetExecutePath(const CFileItem &item, int contextWindow)
183 {
184   return GetExecutePath(item, StringUtils::Format("%i", contextWindow));
185 }
186
187 CStdString CFavouritesDirectory::GetExecutePath(const CFileItem &item, const std::string &contextWindow)
188 {
189   CStdString execute;
190   if (item.m_bIsFolder && (g_advancedSettings.m_playlistAsFolders ||
191                             !(item.IsSmartPlayList() || item.IsPlayList())))
192   {
193     if (!contextWindow.empty())
194       execute = StringUtils::Format("ActivateWindow(%s,%s,return)", contextWindow.c_str(), StringUtils::Paramify(item.GetPath()).c_str());
195   }
196   /* TODO:STRING_CLEANUP */
197   else if (item.IsScript() && item.GetPath().size() > 9) // plugin://<foo>
198     execute = StringUtils::Format("RunScript(%s)", StringUtils::Paramify(item.GetPath().substr(9)).c_str());
199   else if (item.IsAndroidApp() && item.GetPath().size() > 26) // androidapp://sources/apps/<foo>
200     execute = StringUtils::Format("StartAndroidActivity(%s)", StringUtils::Paramify(item.GetPath().substr(26)).c_str());
201   else  // assume a media file
202   {
203     if (item.IsVideoDb() && item.HasVideoInfoTag())
204       execute = StringUtils::Format("PlayMedia(%s)", StringUtils::Paramify(item.GetVideoInfoTag()->m_strFileNameAndPath).c_str());
205     else if (item.IsMusicDb() && item.HasMusicInfoTag())
206       execute = StringUtils::Format("PlayMedia(%s)", StringUtils::Paramify(item.GetMusicInfoTag()->GetURL()).c_str());
207     else
208       execute = StringUtils::Format("PlayMedia(%s)", StringUtils::Paramify(item.GetPath()).c_str());
209   }
210   return execute;
211 }
212
213 }