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 "view/GUIViewState.h"
22 #include "pvr/windows/GUIViewStatePVR.h"
23 #include "addons/GUIViewStateAddonBrowser.h"
24 #include "music/GUIViewStateMusic.h"
25 #include "video/GUIViewStateVideo.h"
26 #include "pictures/GUIViewStatePictures.h"
27 #include "profiles/ProfilesManager.h"
28 #include "programs/GUIViewStatePrograms.h"
29 #include "PlayListPlayer.h"
30 #include "utils/URIUtils.h"
32 #include "GUIPassword.h"
33 #include "ViewDatabase.h"
34 #include "AutoSwitch.h"
35 #include "guilib/GUIWindowManager.h"
36 #include "addons/Addon.h"
37 #include "addons/AddonManager.h"
38 #include "addons/PluginSource.h"
39 #include "view/ViewState.h"
40 #include "settings/AdvancedSettings.h"
41 #include "settings/MediaSourceSettings.h"
42 #include "settings/Settings.h"
44 #include "guilib/Key.h"
45 #include "filesystem/AddonsDirectory.h"
46 #include "guilib/TextureManager.h"
48 #if defined(TARGET_ANDROID)
49 #include "filesystem/AndroidAppDirectory.h"
52 #define PROPERTY_SORT_ORDER "sort.order"
53 #define PROPERTY_SORT_ASCENDING "sort.ascending"
56 using namespace ADDON;
59 CStdString CGUIViewState::m_strPlaylistDirectory;
60 VECSOURCES CGUIViewState::m_sources;
62 CGUIViewState* CGUIViewState::GetViewState(int windowId, const CFileItemList& items)
64 // don't expect derived classes to clear the sources
68 return GetViewState(g_windowManager.GetActiveWindow(),items);
70 const CURL url=items.GetAsUrl();
72 if (items.IsAddonsPath())
73 return new CGUIViewStateAddonBrowser(items);
75 if (items.HasSortDetails())
76 return new CGUIViewStateFromItems(items);
78 if (url.GetProtocol()=="musicdb")
79 return new CGUIViewStateMusicDatabase(items);
81 if (url.GetProtocol()=="musicsearch")
82 return new CGUIViewStateMusicSearch(items);
84 if (items.IsSmartPlayList() || url.GetProtocol() == "upnp" ||
85 items.IsLibraryFolder())
87 if (items.GetContent() == "songs" ||
88 items.GetContent() == "albums" ||
89 items.GetContent() == "mixed")
90 return new CGUIViewStateMusicSmartPlaylist(items);
91 else if (items.GetContent() == "musicvideos")
92 return new CGUIViewStateVideoMusicVideos(items);
93 else if (items.GetContent() == "tvshows")
94 return new CGUIViewStateVideoTVShows(items);
95 else if (items.GetContent() == "episodes")
96 return new CGUIViewStateVideoEpisodes(items);
97 else if (items.GetContent() == "movies")
98 return new CGUIViewStateVideoMovies(items);
101 if (url.GetProtocol() == "library")
102 return new CGUIViewStateLibrary(items);
104 if (items.IsPlayList())
105 return new CGUIViewStateMusicPlaylist(items);
107 if (items.GetPath() == "special://musicplaylists/")
108 return new CGUIViewStateWindowMusicSongs(items);
110 if (url.GetProtocol() == "androidapp")
111 return new CGUIViewStateWindowPrograms(items);
113 if (windowId==WINDOW_MUSIC_NAV)
114 return new CGUIViewStateWindowMusicNav(items);
116 if (windowId==WINDOW_MUSIC_FILES)
117 return new CGUIViewStateWindowMusicSongs(items);
119 if (windowId==WINDOW_MUSIC_PLAYLIST)
120 return new CGUIViewStateWindowMusicPlaylist(items);
122 if (windowId==WINDOW_MUSIC_PLAYLIST_EDITOR)
123 return new CGUIViewStateWindowMusicSongs(items);
125 if (windowId==WINDOW_VIDEO_FILES)
126 return new CGUIViewStateWindowVideoFiles(items);
128 if (windowId==WINDOW_VIDEO_NAV)
129 return new CGUIViewStateWindowVideoNav(items);
131 if (windowId==WINDOW_VIDEO_PLAYLIST)
132 return new CGUIViewStateWindowVideoPlaylist(items);
134 if (windowId==WINDOW_PVR)
135 return new CGUIViewStatePVR(items);
137 if (windowId==WINDOW_PICTURES)
138 return new CGUIViewStateWindowPictures(items);
140 if (windowId==WINDOW_PROGRAMS)
141 return new CGUIViewStateWindowPrograms(items);
143 if (windowId==WINDOW_ADDON_BROWSER)
144 return new CGUIViewStateAddonBrowser(items);
146 // Use as fallback/default
147 return new CGUIViewStateGeneral(items);
150 CGUIViewState::CGUIViewState(const CFileItemList& items) : m_items(items)
152 m_currentViewAsControl=0;
153 m_currentSortMethod=0;
154 m_playlist = PLAYLIST_NONE;
155 m_sortOrder = SortOrderAscending;
158 CGUIViewState::~CGUIViewState()
162 SortOrder CGUIViewState::GetDisplaySortOrder() const
164 // we actually treat some sort orders in reverse, so that we can have
165 // the one sort order variable to save but it can be ascending usually,
166 // and descending for the views which should be usually descending.
167 // default sort order for date, size, program count + rating is reversed
168 SortDescription sorting = GetSortMethod();
169 if (sorting.sortBy == SortByDate || sorting.sortBy == SortBySize || sorting.sortBy == SortByPlaycount ||
170 sorting.sortBy == SortByRating || sorting.sortBy == SortByProgramCount ||
171 sorting.sortBy == SortByBitrate || sorting.sortBy == SortByListeners)
173 if (m_sortOrder == SortOrderAscending)
174 return SortOrderDescending;
175 if (m_sortOrder == SortOrderDescending)
176 return SortOrderAscending;
182 SortOrder CGUIViewState::SetNextSortOrder()
184 if (m_sortOrder == SortOrderAscending)
185 SetSortOrder(SortOrderDescending);
187 SetSortOrder(SortOrderAscending);
194 int CGUIViewState::GetViewAsControl() const
196 return m_currentViewAsControl;
199 void CGUIViewState::SetViewAsControl(int viewAsControl)
201 if (viewAsControl == DEFAULT_VIEW_AUTO)
202 m_currentViewAsControl = CAutoSwitch::GetView(m_items);
204 m_currentViewAsControl = viewAsControl;
207 void CGUIViewState::SaveViewAsControl(int viewAsControl)
209 SetViewAsControl(viewAsControl);
213 SortDescription CGUIViewState::GetSortMethod() const
215 SortDescription sorting;
216 if (m_currentSortMethod>=0 && m_currentSortMethod<(int)m_sortMethods.size())
217 sorting = m_sortMethods[m_currentSortMethod].m_sortDescription;
218 sorting.sortOrder = m_sortOrder;
223 bool CGUIViewState::HasMultipleSortMethods() const
225 return m_sortMethods.size() > 1;
228 int CGUIViewState::GetSortMethodLabel() const
230 if (m_currentSortMethod>=0 && m_currentSortMethod<(int)m_sortMethods.size())
231 return m_sortMethods[m_currentSortMethod].m_buttonLabel;
233 return 103; // Sort By: Name
236 void CGUIViewState::GetSortMethodLabelMasks(LABEL_MASKS& masks) const
238 if (m_currentSortMethod>=0 && m_currentSortMethod<(int)m_sortMethods.size())
240 masks=m_sortMethods[m_currentSortMethod].m_labelMasks;
244 masks.m_strLabelFile.Empty();
245 masks.m_strLabel2File.Empty();
246 masks.m_strLabelFolder.Empty();
247 masks.m_strLabel2Folder.Empty();
251 void CGUIViewState::AddSortMethod(SortBy sortBy, int buttonLabel, const LABEL_MASKS &labelMasks, SortAttribute sortAttributes /* = SortAttributeNone */)
253 AddSortMethod(sortBy, sortAttributes, buttonLabel, labelMasks);
256 void CGUIViewState::AddSortMethod(SortBy sortBy, SortAttribute sortAttributes, int buttonLabel, const LABEL_MASKS &labelMasks)
258 for (size_t i = 0; i < m_sortMethods.size(); ++i)
259 if (m_sortMethods[i].m_sortDescription.sortBy == sortBy)
262 SORT_METHOD_DETAILS sort;
263 sort.m_sortDescription.sortBy = sortBy;
264 sort.m_sortDescription.sortAttributes = sortAttributes;
265 sort.m_buttonLabel = buttonLabel;
266 sort.m_labelMasks = labelMasks;
267 m_sortMethods.push_back(sort);
270 void CGUIViewState::AddSortMethod(SortDescription sortDescription, int buttonLabel, const LABEL_MASKS &labelMasks)
272 AddSortMethod(sortDescription.sortBy, sortDescription.sortAttributes, buttonLabel, labelMasks);
275 void CGUIViewState::SetCurrentSortMethod(int method)
277 SortBy sortBy = (SortBy)method;
278 SortAttribute sortAttributes = SortAttributeNone;
279 if (CSettings::Get().GetBool("filelists.ignorethewhensorting"))
280 sortAttributes = SortAttributeIgnoreArticle;
282 if (sortBy < SortByNone || sortBy > SortByRandom)
285 SetSortMethod(sortBy, sortAttributes);
289 void CGUIViewState::SetSortMethod(SortBy sortBy, SortAttribute sortAttributes /* = SortAttributeNone */)
291 for (int i = 0; i < (int)m_sortMethods.size(); ++i)
293 if (m_sortMethods[i].m_sortDescription.sortBy == sortBy &&
294 // don't care about SortAttributeIgnoreFolders as it wasn't part of the old sorting comparison
295 m_sortMethods[i].m_sortDescription.sortAttributes == (sortAttributes & ~SortAttributeIgnoreFolders))
297 m_currentSortMethod = i;
301 SetSortOrder(m_sortOrder);
304 void CGUIViewState::SetSortMethod(SortDescription sortDescription)
306 return SetSortMethod(sortDescription.sortBy, sortDescription.sortAttributes);
309 SortDescription CGUIViewState::SetNextSortMethod(int direction /* = 1 */)
311 m_currentSortMethod += direction;
313 if (m_currentSortMethod >= (int)m_sortMethods.size())
314 m_currentSortMethod = 0;
315 if (m_currentSortMethod < 0)
316 m_currentSortMethod = m_sortMethods.size() ? (int)m_sortMethods.size() - 1 : 0;
317 SetSortOrder(m_sortOrder);
321 return GetSortMethod();
324 bool CGUIViewState::HideExtensions()
326 return !CSettings::Get().GetBool("filelists.showextensions");
329 bool CGUIViewState::HideParentDirItems()
331 return !CSettings::Get().GetBool("filelists.showparentdiritems");
334 bool CGUIViewState::DisableAddSourceButtons()
336 if (CProfilesManager::Get().GetCurrentProfile().canWriteSources() || g_passwordManager.bMasterUser)
337 return !CSettings::Get().GetBool("filelists.showaddsourcebuttons");
342 int CGUIViewState::GetPlaylist()
347 const CStdString& CGUIViewState::GetPlaylistDirectory()
349 return m_strPlaylistDirectory;
352 void CGUIViewState::SetPlaylistDirectory(const CStdString& strDirectory)
354 m_strPlaylistDirectory=strDirectory;
355 URIUtils::RemoveSlashAtEnd(m_strPlaylistDirectory);
358 bool CGUIViewState::IsCurrentPlaylistDirectory(const CStdString& strDirectory)
360 if (g_playlistPlayer.GetCurrentPlaylist()!=GetPlaylist())
363 CStdString strDir=strDirectory;
364 URIUtils::RemoveSlashAtEnd(strDir);
366 return (m_strPlaylistDirectory==strDir);
369 bool CGUIViewState::AutoPlayNextItem()
374 CStdString CGUIViewState::GetLockType()
379 CStdString CGUIViewState::GetExtensions()
384 VECSOURCES& CGUIViewState::GetSources()
389 void CGUIViewState::AddAddonsSource(const CStdString &content, const CStdString &label, const CStdString &thumb)
391 if (!g_advancedSettings.m_bVirtualShares)
395 if (XFILE::CAddonsDirectory::GetScriptsAndPlugins(content, items))
396 { // add the plugin source
398 source.strPath = "addons://sources/" + content + "/";
399 source.strName = label;
400 if (!thumb.IsEmpty() && g_TextureManager.HasTexture(thumb))
401 source.m_strThumbnailImage = thumb;
402 source.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL;
403 source.m_ignore = true;
404 m_sources.push_back(source);
408 #if defined(TARGET_ANDROID)
409 void CGUIViewState::AddAndroidSource(const CStdString &content, const CStdString &label, const CStdString &thumb)
412 XFILE::CAndroidAppDirectory apps;
413 if (apps.GetDirectory(content, items))
416 source.strPath = "androidapp://sources/" + content + "/";
417 source.strName = label;
418 if (!thumb.IsEmpty() && g_TextureManager.HasTexture(thumb))
419 source.m_strThumbnailImage = thumb;
420 source.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL;
421 source.m_ignore = true;
422 m_sources.push_back(source);
427 void CGUIViewState::AddLiveTVSources()
429 VECSOURCES *sources = CMediaSourceSettings::Get().GetSources("video");
430 for (IVECSOURCES it = sources->begin(); it != sources->end(); it++)
432 if (URIUtils::IsLiveTV((*it).strPath))
435 source.strPath = (*it).strPath;
436 source.strName = (*it).strName;
437 source.vecPaths = (*it).vecPaths;
438 source.m_strThumbnailImage = "";
439 source.FromNameAndPaths("video", source.strName, source.vecPaths);
440 m_sources.push_back(source);
445 CGUIViewStateGeneral::CGUIViewStateGeneral(const CFileItemList& items) : CGUIViewState(items)
447 AddSortMethod(SortByLabel, 551, LABEL_MASKS("%F", "%I", "%L", "")); // Filename, size | Foldername, empty
448 SetSortMethod(SortByLabel);
450 SetViewAsControl(DEFAULT_VIEW_LIST);
452 SetSortOrder(SortOrderAscending);
455 void CGUIViewState::SetSortOrder(SortOrder sortOrder)
457 if (GetSortMethod().sortBy == SortByNone)
458 m_sortOrder = SortOrderNone;
459 else if (sortOrder == SortOrderNone)
460 m_sortOrder = SortOrderAscending;
462 m_sortOrder = sortOrder;
465 void CGUIViewState::LoadViewState(const CStdString &path, int windowID)
466 { // get our view state from the db
471 if (db.GetViewState(path, windowID, state, CSettings::Get().GetString("lookandfeel.skin")) ||
472 db.GetViewState(path, windowID, state, ""))
474 SetViewAsControl(state.m_viewMode);
475 SetSortMethod(state.m_sortDescription);
476 SetSortOrder(state.m_sortDescription.sortOrder);
482 void CGUIViewState::SaveViewToDb(const CStdString &path, int windowID, CViewState *viewState)
487 SortDescription sorting = GetSortMethod();
488 CViewState state(m_currentViewAsControl, sorting.sortBy, m_sortOrder, sorting.sortAttributes);
491 db.SetViewState(path, windowID, state, CSettings::Get().GetString("lookandfeel.skin"));
494 CSettings::Get().Save();
498 void CGUIViewState::AddPlaylistOrder(const CFileItemList &items, LABEL_MASKS label_masks)
500 SortBy sortBy = SortByPlaylistOrder;
502 SortOrder sortOrder = SortOrderAscending;
503 if (items.HasProperty(PROPERTY_SORT_ORDER))
505 sortBy = (SortBy)items.GetProperty(PROPERTY_SORT_ORDER).asInteger();
506 if (sortBy != SortByNone)
508 sortLabel = SortUtils::GetSortLabel(sortBy);
509 sortOrder = items.GetProperty(PROPERTY_SORT_ASCENDING).asBoolean() ? SortOrderAscending : SortOrderDescending;
512 AddSortMethod(sortBy, sortLabel, label_masks);
513 SetSortMethod(sortBy);
514 SetSortOrder(sortOrder);
518 CGUIViewStateFromItems::CGUIViewStateFromItems(const CFileItemList &items) : CGUIViewState(items)
520 const vector<SORT_METHOD_DETAILS> &details = items.GetSortDetails();
521 for (unsigned int i = 0; i < details.size(); i++)
523 const SORT_METHOD_DETAILS sort = details[i];
524 AddSortMethod(sort.m_sortDescription, sort.m_buttonLabel, sort.m_labelMasks);
526 // TODO: Should default sort/view mode be specified?
527 m_currentSortMethod = 0;
529 SetViewAsControl(DEFAULT_VIEW_LIST);
531 SetSortOrder(SortOrderAscending);
532 if (items.IsPlugin())
534 CURL url(items.GetPath());
536 if (CAddonMgr::Get().GetAddon(url.GetHostName(),addon) && addon)
538 PluginPtr plugin = boost::static_pointer_cast<CPluginSource>(addon);
539 if (plugin->Provides(CPluginSource::AUDIO))
540 m_playlist = PLAYLIST_MUSIC;
541 if (plugin->Provides(CPluginSource::VIDEO))
542 m_playlist = PLAYLIST_VIDEO;
545 LoadViewState(items.GetPath(), g_windowManager.GetActiveWindow());
548 void CGUIViewStateFromItems::SaveViewState()
550 SaveViewToDb(m_items.GetPath(), g_windowManager.GetActiveWindow());
553 CGUIViewStateLibrary::CGUIViewStateLibrary(const CFileItemList &items) : CGUIViewState(items)
555 AddSortMethod(SortByNone, 551, LABEL_MASKS("%F", "%I", "%L", "")); // Filename, Size | Foldername, empty
556 SetSortMethod(SortByNone);
557 SetSortOrder(SortOrderNone);
559 SetViewAsControl(DEFAULT_VIEW_LIST);
561 LoadViewState(items.GetPath(), g_windowManager.GetActiveWindow());
564 void CGUIViewStateLibrary::SaveViewState()
566 SaveViewToDb(m_items.GetPath(), g_windowManager.GetActiveWindow());