2 * Copyright (C) 2005-2008 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, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 #include "GUIMediaWindow.h"
23 #include "GUIUserMessages.h"
25 #include "PlayListPlayer.h"
26 #include "addons/AddonManager.h"
27 #include "addons/PluginSource.h"
28 #include "filesystem/PluginDirectory.h"
29 #include "filesystem/MultiPathDirectory.h"
30 #include "GUIPassword.h"
31 #include "Application.h"
32 #include "network/Network.h"
33 #include "utils/RegExp.h"
34 #include "PartyModeManager.h"
35 #include "dialogs/GUIDialogMediaSource.h"
36 #include "GUIWindowFileManager.h"
37 #include "Favourites.h"
38 #include "utils/LabelFormatter.h"
39 #include "dialogs/GUIDialogProgress.h"
40 #include "settings/AdvancedSettings.h"
41 #include "settings/GUISettings.h"
43 #include "dialogs/GUIDialogSmartPlaylistEditor.h"
44 #include "addons/GUIDialogAddonSettings.h"
45 #include "dialogs/GUIDialogYesNo.h"
46 #include "guilib/GUIWindowManager.h"
47 #include "dialogs/GUIDialogOK.h"
48 #include "playlists/PlayList.h"
49 #include "storage/MediaManager.h"
50 #include "settings/Settings.h"
51 #include "utils/StringUtils.h"
52 #include "utils/URIUtils.h"
53 #include "guilib/LocalizeStrings.h"
54 #include "utils/TimeUtils.h"
55 #include "filesystem/FactoryFileDirectory.h"
56 #include "utils/log.h"
57 #include "utils/FileUtils.h"
58 #include "guilib/GUIEditControl.h"
59 #include "dialogs/GUIDialogKeyboard.h"
61 #include "interfaces/python/XBPython.h"
63 #include "interfaces/Builtins.h"
65 #define CONTROL_BTNVIEWASICONS 2
66 #define CONTROL_BTNSORTBY 3
67 #define CONTROL_BTNSORTASC 4
68 #define CONTROL_BTN_FILTER 19
70 #define CONTROL_LABELFILES 12
73 using namespace ADDON;
75 CGUIMediaWindow::CGUIMediaWindow(int id, const char *xmlFile)
76 : CGUIWindow(id, xmlFile)
78 m_vecItems = new CFileItemList;
79 m_unfilteredItems = new CFileItemList;
80 m_vecItems->m_strPath = "?";
84 m_guiState.reset(CGUIViewState::GetViewState(GetID(), *m_vecItems));
87 CGUIMediaWindow::~CGUIMediaWindow()
90 delete m_unfilteredItems;
93 #define CONTROL_VIEW_START 50
94 #define CONTROL_VIEW_END 59
96 void CGUIMediaWindow::LoadAdditionalTags(TiXmlElement *root)
98 CGUIWindow::LoadAdditionalTags(root);
99 // configure our view control
100 m_viewControl.Reset();
101 m_viewControl.SetParentWindow(GetID());
102 TiXmlElement *element = root->FirstChildElement("views");
103 if (element && element->FirstChild())
104 { // format is <views>50,29,51,95</views>
105 CStdString allViews = element->FirstChild()->Value();
106 CStdStringArray views;
107 StringUtils::SplitString(allViews, ",", views);
108 for (unsigned int i = 0; i < views.size(); i++)
110 int controlID = atol(views[i].c_str());
111 CGUIControl *control = (CGUIControl *)GetControl(controlID);
112 if (control && control->IsContainer())
113 m_viewControl.AddView(control);
117 { // backward compatibility
118 vector<CGUIControl *> controls;
119 GetContainers(controls);
120 for (ciControls it = controls.begin(); it != controls.end(); it++)
122 CGUIControl *control = *it;
123 if (control->GetID() >= CONTROL_VIEW_START && control->GetID() <= CONTROL_VIEW_END)
124 m_viewControl.AddView(control);
127 m_viewControl.SetViewControlID(CONTROL_BTNVIEWASICONS);
130 void CGUIMediaWindow::OnWindowLoaded()
132 SendMessage(GUI_MSG_SET_TYPE, CONTROL_BTN_FILTER, CGUIEditControl::INPUT_TYPE_FILTER);
133 CGUIWindow::OnWindowLoaded();
137 void CGUIMediaWindow::OnWindowUnload()
139 CGUIWindow::OnWindowUnload();
140 m_viewControl.Reset();
143 CFileItemPtr CGUIMediaWindow::GetCurrentListItem(int offset)
145 int item = m_viewControl.GetSelectedItem();
146 if (!m_vecItems->Size() || item < 0)
147 return CFileItemPtr();
148 item = (item + offset) % m_vecItems->Size();
149 if (item < 0) item += m_vecItems->Size();
150 return m_vecItems->Get(item);
153 bool CGUIMediaWindow::OnAction(const CAction &action)
155 if (action.GetID() == ACTION_PARENT_DIR)
157 if ((m_vecItems->IsVirtualDirectoryRoot() || m_vecItems->m_strPath == m_startDirectory) && g_advancedSettings.m_bUseEvilB)
158 g_windowManager.PreviousWindow();
164 if (action.GetID() == ACTION_PREVIOUS_MENU)
166 g_windowManager.PreviousWindow();
170 // the non-contextual menu can be called at any time
171 if (action.GetID() == ACTION_CONTEXT_MENU && !m_viewControl.HasControl(GetFocusedControlID()))
177 if (CGUIWindow::OnAction(action))
181 if (action.GetID() == ACTION_FILTER_CLEAR)
183 CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS);
184 message.SetStringParam("");
189 if (action.GetID() == ACTION_BACKSPACE)
191 CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS, 2); // 2 for delete
196 if (action.GetID() >= ACTION_FILTER_SMS2 && action.GetID() <= ACTION_FILTER_SMS9)
199 filter.Format("%i", (int)(action.GetID() - ACTION_FILTER_SMS2 + 2));
200 CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS, 1); // 1 for append
201 message.SetStringParam(filter);
209 bool CGUIMediaWindow::OnMessage(CGUIMessage& message)
211 switch ( message.GetMessage() )
213 case GUI_MSG_WINDOW_DEINIT:
215 m_iSelectedItem = m_viewControl.GetSelectedItem();
216 m_iLastControl = GetFocusedControlID();
217 CGUIWindow::OnMessage(message);
218 // Call ClearFileItems() after our window has finished doing any WindowClose
225 case GUI_MSG_CLICKED:
227 int iControl = message.GetSenderId();
228 if (iControl == CONTROL_BTNVIEWASICONS)
230 // view as control could be a select button
232 const CGUIControl *control = GetControl(CONTROL_BTNVIEWASICONS);
233 if (control && control->GetControlType() != CGUIControl::GUICONTROL_BUTTON)
235 CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_BTNVIEWASICONS);
237 viewMode = m_viewControl.GetViewModeNumber(msg.GetParam1());
240 viewMode = m_viewControl.GetNextViewMode();
242 if (m_guiState.get())
243 m_guiState->SaveViewAsControl(viewMode);
248 else if (iControl == CONTROL_BTNSORTASC) // sort asc
250 if (m_guiState.get())
251 m_guiState->SetNextSortOrder();
255 else if (iControl == CONTROL_BTNSORTBY) // sort by
257 if (m_guiState.get())
258 m_guiState->SetNextSortMethod();
262 else if (iControl == CONTROL_BTN_FILTER)
264 if (GetControl(iControl)->GetControlType() == CGUIControl::GUICONTROL_EDIT)
266 CGUIMessage selected(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_BTN_FILTER);
268 OnFilterItems(selected.GetLabel());
271 if (GetProperty("filter").IsEmpty())
273 CStdString filter = GetProperty("filter");
274 CGUIDialogKeyboard::ShowAndGetFilter(filter, false);
275 SetProperty("filter", filter);
281 else if (m_viewControl.HasControl(iControl)) // list/thumb control
283 int iItem = m_viewControl.GetSelectedItem();
284 int iAction = message.GetParam1();
285 if (iItem < 0) break;
286 if (iAction == ACTION_SELECT_ITEM || iAction == ACTION_MOUSE_LEFT_CLICK)
290 else if (iAction == ACTION_CONTEXT_MENU || iAction == ACTION_MOUSE_RIGHT_CLICK)
299 case GUI_MSG_SETFOCUS:
301 if (m_viewControl.HasControl(message.GetControlId()) && m_viewControl.GetCurrentControl() != message.GetControlId())
303 m_viewControl.SetFocused();
309 case GUI_MSG_NOTIFY_ALL:
310 { // Message is received even if this window is inactive
311 if (message.GetParam1() == GUI_MSG_WINDOW_RESET)
313 m_vecItems->m_strPath = "?";
316 else if ( message.GetParam1() == GUI_MSG_REFRESH_THUMBS )
318 for (int i = 0; i < m_vecItems->Size(); i++)
319 m_vecItems->Get(i)->FreeMemory(true);
320 break; // the window will take care of any info images
322 else if (message.GetParam1() == GUI_MSG_REMOVED_MEDIA)
324 if (m_vecItems->IsVirtualDirectoryRoot() && IsActive())
326 int iItem = m_viewControl.GetSelectedItem();
327 Update(m_vecItems->m_strPath);
328 m_viewControl.SetSelectedItem(iItem);
330 else if (m_vecItems->IsRemovable())
331 { // check that we have this removable share still
332 if (!m_rootDir.IsInSource(m_vecItems->m_strPath))
333 { // don't have this share any more
334 if (IsActive()) Update("");
337 m_history.ClearPathHistory();
338 m_vecItems->m_strPath="";
345 else if (message.GetParam1()==GUI_MSG_UPDATE_SOURCES)
346 { // State of the sources changed, so update our view
347 if (m_vecItems->IsVirtualDirectoryRoot() && IsActive())
349 int iItem = m_viewControl.GetSelectedItem();
350 Update(m_vecItems->m_strPath);
351 m_viewControl.SetSelectedItem(iItem);
355 else if (message.GetParam1()==GUI_MSG_UPDATE && IsActive())
357 if (message.GetNumStringParams())
359 m_vecItems->m_strPath = message.GetStringParam();
360 if (message.GetParam2()) // param2 is used for resetting the history
361 SetHistoryForPath(m_vecItems->m_strPath);
363 // clear any cached listing
364 m_vecItems->RemoveDiscCache(GetID());
365 Update(m_vecItems->m_strPath);
367 else if (message.GetParam1()==GUI_MSG_UPDATE_ITEM && message.GetItem())
369 CFileItemPtr newItem = boost::static_pointer_cast<CFileItem>(message.GetItem());
372 if (m_vecItems->UpdateItem(newItem.get()) && message.GetParam2() == 1)
373 { // need the list updated as well
378 { // need to remove the disc cache
380 URIUtils::GetDirectory(newItem->m_strPath, items.m_strPath);
381 items.RemoveDiscCache(GetID());
384 else if (message.GetParam1()==GUI_MSG_UPDATE_PATH)
388 if((message.GetStringParam() == m_vecItems->m_strPath) ||
389 (m_vecItems->IsMultiPath() && XFILE::CMultiPathDirectory::HasPath(m_vecItems->m_strPath, message.GetStringParam())))
391 Update(m_vecItems->m_strPath);
395 else if (message.GetParam1() == GUI_MSG_FILTER_ITEMS && IsActive())
397 CStdString filter(GetProperty("filter"));
398 if (message.GetParam2() == 1) // append
399 filter += message.GetStringParam();
400 else if (message.GetParam2() == 2)
403 filter = filter.Left(filter.size() - 1);
406 filter = message.GetStringParam();
407 OnFilterItems(filter);
411 return CGUIWindow::OnMessage(message);
416 case GUI_MSG_PLAYBACK_STARTED:
417 case GUI_MSG_PLAYBACK_ENDED:
418 case GUI_MSG_PLAYBACK_STOPPED:
419 case GUI_MSG_PLAYLIST_CHANGED:
420 case GUI_MSG_PLAYLISTPLAYER_STOPPED:
421 case GUI_MSG_PLAYLISTPLAYER_STARTED:
422 case GUI_MSG_PLAYLISTPLAYER_CHANGED:
423 { // send a notify all to all controls on this window
424 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_REFRESH_LIST);
428 case GUI_MSG_CHANGE_VIEW_MODE:
431 if (message.GetParam1()) // we have an id
432 viewMode = m_viewControl.GetViewModeByID(message.GetParam1());
433 else if (message.GetParam2())
434 viewMode = m_viewControl.GetNextViewMode((int)message.GetParam2());
436 if (m_guiState.get())
437 m_guiState->SaveViewAsControl(viewMode);
442 case GUI_MSG_CHANGE_SORT_METHOD:
444 if (m_guiState.get())
446 if (message.GetParam1())
447 m_guiState->SetCurrentSortMethod((int)message.GetParam1());
448 else if (message.GetParam2())
449 m_guiState->SetNextSortMethod((int)message.GetParam2());
455 case GUI_MSG_CHANGE_SORT_DIRECTION:
457 if (m_guiState.get())
458 m_guiState->SetNextSortOrder();
463 case GUI_MSG_WINDOW_INIT:
465 if (m_vecItems->m_strPath == "?")
466 m_vecItems->m_strPath.Empty();
467 CStdString dir = message.GetStringParam(0);
468 const CStdString &ret = message.GetStringParam(1);
469 bool returning = ret.CompareNoCase("return") == 0;
472 m_history.ClearPathHistory();
473 // ensure our directory is valid
474 dir = GetStartFolder(dir);
475 if (!returning || m_vecItems->m_strPath.Left(dir.GetLength()) != dir)
476 { // we're not returning to the same path, so set our directory to the requested path
477 m_vecItems->m_strPath = dir;
479 // check for network up
480 if (URIUtils::IsRemote(m_vecItems->m_strPath) && !WaitForNetwork())
481 m_vecItems->m_strPath.Empty();
482 SetHistoryForPath(m_vecItems->m_strPath);
484 if (message.GetParam1() != WINDOW_INVALID)
485 { // first time to this window - make sure we set the root path
486 m_startDirectory = returning ? dir : "";
492 return CGUIWindow::OnMessage(message);
495 // \brief Updates the states (enable, disable, visible...)
496 // of the controls defined by this window
497 // Override this function in a derived class to add new controls
498 void CGUIMediaWindow::UpdateButtons()
500 if (m_guiState.get())
502 // Update sorting controls
503 if (m_guiState->GetDisplaySortOrder()==SORT_ORDER_NONE)
505 CONTROL_DISABLE(CONTROL_BTNSORTASC);
509 CONTROL_ENABLE(CONTROL_BTNSORTASC);
510 if (m_guiState->GetDisplaySortOrder()==SORT_ORDER_ASC)
512 CGUIMessage msg(GUI_MSG_DESELECTED, GetID(), CONTROL_BTNSORTASC);
513 g_windowManager.SendMessage(msg);
517 CGUIMessage msg(GUI_MSG_SELECTED, GetID(), CONTROL_BTNSORTASC);
518 g_windowManager.SendMessage(msg);
522 // Update list/thumb control
523 m_viewControl.SetCurrentView(m_guiState->GetViewAsControl());
525 // Update sort by button
526 if (m_guiState->GetSortMethod()==SORT_METHOD_NONE)
528 CONTROL_DISABLE(CONTROL_BTNSORTBY);
532 CONTROL_ENABLE(CONTROL_BTNSORTBY);
534 CStdString sortLabel;
535 sortLabel.Format(g_localizeStrings.Get(550).c_str(), g_localizeStrings.Get(m_guiState->GetSortMethodLabel()).c_str());
536 SET_CONTROL_LABEL(CONTROL_BTNSORTBY, sortLabel);
540 items.Format("%i %s", m_vecItems->GetObjectCount(), g_localizeStrings.Get(127).c_str());
541 SET_CONTROL_LABEL(CONTROL_LABELFILES, items);
543 //#ifdef PRE_SKIN_VERSION_3
544 SET_CONTROL_SELECTED(GetID(),CONTROL_BTN_FILTER, !GetProperty("filter").IsEmpty());
545 SET_CONTROL_LABEL2(CONTROL_BTN_FILTER, GetProperty("filter"));
549 void CGUIMediaWindow::ClearFileItems()
551 m_viewControl.Clear();
552 m_vecItems->Clear(); // will clean up everything
553 m_unfilteredItems->Clear();
556 // \brief Sorts Fileitems based on the sort method and sort oder provided by guiViewState
557 void CGUIMediaWindow::SortItems(CFileItemList &items)
559 auto_ptr<CGUIViewState> guiState(CGUIViewState::GetViewState(GetID(), items));
563 items.Sort(guiState->GetSortMethod(), guiState->GetDisplaySortOrder());
565 // Should these items be saved to the hdd
566 if (items.CacheToDiscAlways())
571 // \brief Formats item labels based on the formatting provided by guiViewState
572 void CGUIMediaWindow::FormatItemLabels(CFileItemList &items, const LABEL_MASKS &labelMasks)
574 CLabelFormatter fileFormatter(labelMasks.m_strLabelFile, labelMasks.m_strLabel2File);
575 CLabelFormatter folderFormatter(labelMasks.m_strLabelFolder, labelMasks.m_strLabel2Folder);
576 for (int i=0; i<items.Size(); ++i)
578 CFileItemPtr pItem=items[i];
580 if (pItem->IsLabelPreformated())
583 if (pItem->m_bIsFolder)
584 folderFormatter.FormatLabels(pItem.get());
586 fileFormatter.FormatLabels(pItem.get());
589 if(items.GetSortMethod() == SORT_METHOD_LABEL_IGNORE_THE
590 || items.GetSortMethod() == SORT_METHOD_LABEL)
591 items.ClearSortState();
594 // \brief Prepares and adds the fileitems list/thumb panel
595 void CGUIMediaWindow::FormatAndSort(CFileItemList &items)
597 auto_ptr<CGUIViewState> viewState(CGUIViewState::GetViewState(GetID(), items));
601 LABEL_MASKS labelMasks;
602 viewState->GetSortMethodLabelMasks(labelMasks);
603 FormatItemLabels(items, labelMasks);
609 \brief Overwrite to fill fileitems from a source
610 \param strDirectory Path to read
611 \param items Fill with items specified in \e strDirectory
613 bool CGUIMediaWindow::GetDirectory(const CStdString &strDirectory, CFileItemList &items)
619 CStdString strParentPath=m_history.GetParentPath();
621 CLog::Log(LOGDEBUG,"CGUIMediaWindow::GetDirectory (%s)", strDirectory.c_str());
622 CLog::Log(LOGDEBUG," ParentPath = [%s]", strParentPath.c_str());
624 // see if we can load a previously cached folder
625 CFileItemList cachedItems(strDirectory);
626 if (!strDirectory.IsEmpty() && cachedItems.Load(GetID()))
628 items.Assign(cachedItems);
632 unsigned int time = CTimeUtils::GetTimeMS();
634 if (strDirectory.IsEmpty())
637 if (!m_rootDir.GetDirectory(strDirectory, items))
640 // took over a second, and not normally cached, so cache it
641 if (time + 1000 < CTimeUtils::GetTimeMS() && items.CacheToDiscIfSlow())
644 // if these items should replace the current listing, then pop it off the top
645 if (items.GetReplaceListing())
646 m_history.RemoveParentPath();
649 if (m_guiState.get() && !m_guiState->HideParentDirItems() && !items.m_strPath.IsEmpty())
651 CFileItemPtr pItem(new CFileItem(".."));
652 pItem->m_strPath = strParentPath;
653 pItem->m_bIsFolder = true;
654 pItem->m_bIsShareOrDrive = false;
655 items.AddFront(pItem, 0);
658 int iWindow = GetID();
659 CStdStringArray regexps;
661 if (iWindow == WINDOW_VIDEO_FILES)
662 regexps = g_advancedSettings.m_videoExcludeFromListingRegExps;
663 if (iWindow == WINDOW_MUSIC_FILES)
664 regexps = g_advancedSettings.m_audioExcludeFromListingRegExps;
665 if (iWindow == WINDOW_PICTURES)
666 regexps = g_advancedSettings.m_pictureExcludeFromListingRegExps;
670 for (int i=0; i < items.Size();)
672 if (CUtil::ExcludeFileOrFolder(items[i]->m_strPath, regexps))
680 SetProperty("filter", "");
684 // \brief Set window to a specific directory
685 // \param strDirectory The directory to be displayed in list/thumb control
686 // This function calls OnPrepareFileItems() and OnFinalizeFileItems()
687 bool CGUIMediaWindow::Update(const CStdString &strDirectory)
689 // TODO: OnInitWindow calls Update() before window path has been set properly.
690 if (strDirectory == "?")
694 int iItem = m_viewControl.GetSelectedItem();
695 CStdString strSelectedItem = "";
696 if (iItem >= 0 && iItem < m_vecItems->Size())
698 CFileItemPtr pItem = m_vecItems->Get(iItem);
699 if (!pItem->IsParentFolder())
701 GetDirectoryHistoryString(pItem.get(), strSelectedItem);
705 CStdString strOldDirectory = m_vecItems->m_strPath;
707 m_history.SetSelectedItem(strSelectedItem, strOldDirectory);
710 if (!GetDirectory(strDirectory, items))
712 CLog::Log(LOGERROR,"CGUIMediaWindow::GetDirectory(%s) failed", strDirectory.c_str());
713 // if the directory is the same as the old directory, then we'll return
714 // false. Else, we assume we can get the previous directory
715 if (strDirectory.Equals(strOldDirectory))
718 // We assume, we can get the parent
719 // directory again, but we have to
720 // return false to be able to eg. show
722 CStdString strParentPath = m_history.GetParentPath();
723 m_history.RemoveParentPath();
724 Update(strParentPath);
728 if (items.GetLabel().IsEmpty())
729 items.SetLabel(CUtil::GetTitleFromPath(items.m_strPath, true));
732 m_vecItems->Copy(items);
734 // if we're getting the root source listing
735 // make sure the path history is clean
736 if (strDirectory.IsEmpty())
737 m_history.ClearPathHistory();
739 int iWindow = GetID();
741 if (strDirectory.IsEmpty() && (iWindow == WINDOW_MUSIC_FILES ||
742 iWindow == WINDOW_FILES ||
743 iWindow == WINDOW_PICTURES ||
744 iWindow == WINDOW_PROGRAMS))
746 if (strDirectory.Equals("sources://video/"))
748 if (showLabel && (m_vecItems->Size() == 0 || !m_guiState->DisableAddSourceButtons())) // add 'add source button'
750 CStdString strLabel = g_localizeStrings.Get(showLabel);
751 CFileItemPtr pItem(new CFileItem(strLabel));
752 pItem->m_strPath = "add";
753 pItem->SetIconImage("DefaultAddSource.png");
754 pItem->SetLabel(strLabel);
755 pItem->SetLabelPreformated(true);
756 m_vecItems->Add(pItem);
758 m_iLastControl = GetFocusedControlID();
760 // Ask the derived class if it wants to load additional info
761 // for the fileitems like media info or additional
762 // filtering on the items, setting thumbs.
763 OnPrepareFileItems(*m_vecItems);
765 m_vecItems->FillInDefaultIcons();
767 m_guiState.reset(CGUIViewState::GetViewState(GetID(), *m_vecItems));
769 FormatAndSort(*m_vecItems);
771 // Ask the devived class if it wants to do custom list operations,
772 // eg. changing the label
773 OnFinalizeFileItems(*m_vecItems);
776 m_viewControl.SetItems(*m_vecItems);
778 strSelectedItem = m_history.GetSelectedItem(m_vecItems->m_strPath);
780 bool bSelectedFound = false;
781 //int iSongInDirectory = -1;
782 for (int i = 0; i < m_vecItems->Size(); ++i)
784 CFileItemPtr pItem = m_vecItems->Get(i);
786 // Update selected item
789 CStdString strHistory;
790 GetDirectoryHistoryString(pItem.get(), strHistory);
791 if (strHistory == strSelectedItem)
793 m_viewControl.SetSelectedItem(i);
794 bSelectedFound = true;
799 // if we haven't found the selected item, select the first item
801 m_viewControl.SetSelectedItem(0);
803 m_history.AddPath(m_vecItems->m_strPath);
805 //m_history.DumpPathHistory();
810 // \brief This function will be called by Update() before the
811 // labels of the fileitems are formatted. Override this function
812 // to set custom thumbs or load additional media info.
813 // It's used to load tag info for music.
814 void CGUIMediaWindow::OnPrepareFileItems(CFileItemList &items)
819 // \brief This function will be called by Update() after the
820 // labels of the fileitems are formatted. Override this function
821 // to modify the fileitems. Eg. to modify the item label
822 void CGUIMediaWindow::OnFinalizeFileItems(CFileItemList &items)
824 m_unfilteredItems->Append(items);
826 CStdString filter(GetProperty("filter"));
827 if (!filter.IsEmpty())
830 GetFilteredItems(filter, items);
833 // The idea here is to ensure we have something to focus if our file list
834 // is empty. As such, this check MUST be last and ignore the hide parent
835 // fileitems settings.
838 CFileItemPtr pItem(new CFileItem(".."));
839 pItem->m_strPath=m_history.GetParentPath();
840 pItem->m_bIsFolder = true;
841 pItem->m_bIsShareOrDrive = false;
842 items.AddFront(pItem, 0);
846 // \brief With this function you can react on a users click in the list/thumb panel.
847 // It returns true, if the click is handled.
848 // This function calls OnPlayMedia()
849 bool CGUIMediaWindow::OnClick(int iItem)
851 if ( iItem < 0 || iItem >= (int)m_vecItems->Size() ) return true;
852 CFileItemPtr pItem = m_vecItems->Get(iItem);
854 if (pItem->IsParentFolder())
859 if (pItem->m_strPath == "add" || pItem->m_strPath == "sources://add/") // 'add source button' in empty root
861 OnContextButton(iItem, CONTEXT_BUTTON_ADD_SOURCE);
865 if (!pItem->m_bIsFolder && pItem->IsFileFolder())
867 XFILE::IFileDirectory *pFileDirectory = NULL;
868 pFileDirectory = XFILE::CFactoryFileDirectory::Create(pItem->m_strPath, pItem.get(), "");
870 pItem->m_bIsFolder = true;
871 else if(pItem->m_bIsFolder)
872 pItem->m_bIsFolder = false;
873 delete pFileDirectory;
876 CURL url(pItem->m_strPath);
877 if (url.GetProtocol() == "script")
879 // execute the script
881 if (CAddonMgr::Get().GetAddon(url.GetHostName(), addon))
884 if (!g_pythonParser.StopScript(addon->LibPath()))
885 g_pythonParser.evalFile(addon->LibPath());
891 if (pItem->m_bIsFolder)
893 if ( pItem->m_bIsShareOrDrive )
895 const CStdString& strLockType=m_guiState->GetLockType();
896 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE)
897 if (!strLockType.IsEmpty() && !g_passwordManager.IsItemUnlocked(pItem.get(), strLockType))
900 if (!HaveDiscOrConnection(pItem->m_strPath, pItem->m_iDriveType))
904 // check for the partymode playlist items - they may not exist yet
905 if ((pItem->m_strPath == g_settings.GetUserDataItem("PartyMode.xsp")) ||
906 (pItem->m_strPath == g_settings.GetUserDataItem("PartyMode-Video.xsp")))
908 // party mode playlist item - if it doesn't exist, prompt for user to define it
909 if (!XFILE::CFile::Exists(pItem->m_strPath))
911 m_vecItems->RemoveDiscCache(GetID());
912 if (CGUIDialogSmartPlaylistEditor::EditPlaylist(pItem->m_strPath))
913 Update(m_vecItems->m_strPath);
918 // remove the directory cache if the folder is not normally cached
919 CFileItemList items(pItem->m_strPath);
920 if (!items.AlwaysCache())
921 items.RemoveDiscCache(GetID());
923 CFileItem directory(*pItem);
924 if (!Update(directory.m_strPath))
925 ShowShareErrorMessage(&directory);
929 else if (pItem->IsPlugin() && pItem->GetProperty("isplayable") != "true")
931 return XFILE::CPluginDirectory::RunScriptWithParams(pItem->m_strPath);
935 m_iSelectedItem = m_viewControl.GetSelectedItem();
937 if (pItem->m_strPath == "newplaylist://")
939 m_vecItems->RemoveDiscCache(GetID());
940 g_windowManager.ActivateWindow(WINDOW_MUSIC_PLAYLIST_EDITOR,"newplaylist://");
943 else if (pItem->m_strPath.Left(19).Equals("newsmartplaylist://"))
945 m_vecItems->RemoveDiscCache(GetID());
946 if (CGUIDialogSmartPlaylistEditor::NewPlaylist(pItem->m_strPath.Mid(19)))
947 Update(m_vecItems->m_strPath);
950 else if (pItem->m_strPath.Left(14).Equals("addons://more/"))
952 CBuiltins::Execute("ActivateWindow(AddonBrowser,addons://all/xbmc.addon." + pItem->m_strPath.Mid(14) + ",return)");
956 // If karaoke song is being played AND popup autoselector is enabled, the playlist should not be added
957 bool do_not_add_karaoke = g_guiSettings.GetBool("karaoke.enabled") &&
958 g_guiSettings.GetBool("karaoke.autopopupselector") && pItem->IsKaraoke();
959 bool autoplay = m_guiState.get() && m_guiState->AutoPlayNextItem();
960 int iPlaylist = m_guiState.get()?m_guiState->GetPlaylist():PLAYLIST_MUSIC;
962 if (pItem->IsPlugin())
964 CURL url(pItem->m_strPath);
966 if (CAddonMgr::Get().GetAddon(url.GetHostName(),addon))
968 PluginPtr plugin = boost::dynamic_pointer_cast<CPluginSource>(addon);
969 if (plugin && plugin->Provides(CPluginSource::AUDIO))
971 iPlaylist = PLAYLIST_MUSIC;
972 autoplay = g_guiSettings.GetBool("musicplayer.autoplaynextitem");
977 if (autoplay && !g_partyModeManager.IsEnabled() &&
978 !pItem->IsPlayList() && !do_not_add_karaoke)
980 return OnPlayAndQueueMedia(pItem);
984 return OnPlayMedia(iItem);
991 bool CGUIMediaWindow::OnSelect(int item)
993 return OnClick(item);
996 // \brief Checks if there is a disc in the dvd drive and whether the
997 // network is connected or not.
998 bool CGUIMediaWindow::HaveDiscOrConnection(CStdString& strPath, int iDriveType)
1000 if (iDriveType==CMediaSource::SOURCE_TYPE_DVD)
1002 if (!g_mediaManager.IsDiscInDrive())
1004 CGUIDialogOK::ShowAndGetInput(218, 219, 0, 0);
1008 else if (iDriveType==CMediaSource::SOURCE_TYPE_REMOTE)
1010 // TODO: Handle not connected to a remote share
1011 if ( !g_application.getNetwork().IsConnected() )
1013 CGUIDialogOK::ShowAndGetInput(220, 221, 0, 0);
1021 // \brief Shows a standard errormessage for a given pItem.
1022 void CGUIMediaWindow::ShowShareErrorMessage(CFileItem* pItem)
1024 if (pItem->m_bIsShareOrDrive)
1026 int idMessageText=0;
1027 const CURL& url=pItem->GetAsUrl();
1028 const CStdString& strHostName=url.GetHostName();
1030 if (pItem->m_iDriveType != CMediaSource::SOURCE_TYPE_REMOTE) // Local shares incl. dvd drive
1031 idMessageText=15300;
1032 else if (url.GetProtocol() == "xbms" && strHostName.IsEmpty()) // xbms server discover
1033 idMessageText=15302;
1034 else if (url.GetProtocol() == "smb" && strHostName.IsEmpty()) // smb workgroup
1035 idMessageText=15303;
1036 else // All other remote shares
1037 idMessageText=15301;
1039 CGUIDialogOK::ShowAndGetInput(220, idMessageText, 0, 0);
1043 // \brief The functon goes up one level in the directory tree
1044 void CGUIMediaWindow::GoParentFolder()
1046 //m_history.DumpPathHistory();
1048 // remove current directory if its on the stack
1049 // there were some issues due some folders having a trailing slash and some not
1050 // so just add a trailing slash to all of them for comparison.
1051 CStdString strPath = m_vecItems->m_strPath;
1052 URIUtils::AddSlashAtEnd(strPath);
1053 CStdString strParent = m_history.GetParentPath();
1054 // in case the path history is messed up and the current folder is on
1055 // the stack more than once, keep going until there's nothing left or they
1056 // dont match anymore.
1057 while (!strParent.IsEmpty())
1059 URIUtils::AddSlashAtEnd(strParent);
1060 if (strParent.Equals(strPath))
1061 m_history.RemoveParentPath();
1064 strParent = m_history.GetParentPath();
1067 // if vector is not empty, pop parent
1068 // if vector is empty, parent is root source listing
1069 CStdString strOldPath(m_vecItems->m_strPath);
1070 strParent = m_history.RemoveParentPath();
1074 // \brief Override the function to change the default behavior on how
1075 // a selected item history should look like
1076 void CGUIMediaWindow::GetDirectoryHistoryString(const CFileItem* pItem, CStdString& strHistoryString)
1078 if (pItem->m_bIsShareOrDrive)
1080 // We are in the virual directory
1082 // History string of the DVD drive
1083 // must be handel separately
1084 if (pItem->m_iDriveType == CMediaSource::SOURCE_TYPE_DVD)
1086 // Remove disc label from item label
1087 // and use as history string, m_strPath
1088 // can change for new discs
1089 CStdString strLabel = pItem->GetLabel();
1090 int nPosOpen = strLabel.Find('(');
1091 int nPosClose = strLabel.ReverseFind(')');
1092 if (nPosOpen > -1 && nPosClose > -1 && nPosClose > nPosOpen)
1094 strLabel.Delete(nPosOpen + 1, (nPosClose) - (nPosOpen + 1));
1095 strHistoryString = strLabel;
1098 strHistoryString = strLabel;
1102 // Other items in virual directory
1103 CStdString strPath = pItem->m_strPath;
1104 URIUtils::RemoveSlashAtEnd(strPath);
1106 strHistoryString = pItem->GetLabel() + strPath;
1109 else if (pItem->m_lEndOffset>pItem->m_lStartOffset && pItem->m_lStartOffset != -1)
1111 // Could be a cue item, all items of a cue share the same filename
1112 // so add the offsets to build the history string
1113 strHistoryString.Format("%ld%ld", pItem->m_lStartOffset, pItem->m_lEndOffset);
1114 strHistoryString += pItem->m_strPath;
1118 // Normal directory items
1119 strHistoryString = pItem->m_strPath;
1121 URIUtils::RemoveSlashAtEnd(strHistoryString);
1122 strHistoryString.ToLower();
1125 // \brief Call this function to create a directory history for the
1126 // path given by strDirectory.
1127 void CGUIMediaWindow::SetHistoryForPath(const CStdString& strDirectory)
1129 // Make sure our shares are configured
1131 if (!strDirectory.IsEmpty())
1133 // Build the directory history for default path
1134 CStdString strPath, strParentPath;
1135 strPath = strDirectory;
1136 URIUtils::RemoveSlashAtEnd(strPath);
1138 CFileItemList items;
1139 m_rootDir.GetDirectory("", items);
1141 m_history.ClearPathHistory();
1143 while (URIUtils::GetParentPath(strPath, strParentPath))
1145 for (int i = 0; i < (int)items.Size(); ++i)
1147 CFileItemPtr pItem = items[i];
1148 URIUtils::RemoveSlashAtEnd(pItem->m_strPath);
1149 if (pItem->m_strPath == strPath)
1151 CStdString strHistory;
1152 GetDirectoryHistoryString(pItem.get(), strHistory);
1153 m_history.SetSelectedItem(strHistory, "");
1154 URIUtils::AddSlashAtEnd(strPath);
1155 m_history.AddPathFront(strPath);
1156 m_history.AddPathFront("");
1158 //m_history.DumpPathHistory();
1163 URIUtils::AddSlashAtEnd(strPath);
1164 m_history.AddPathFront(strPath);
1165 m_history.SetSelectedItem(strPath, strParentPath);
1166 strPath = strParentPath;
1167 URIUtils::RemoveSlashAtEnd(strPath);
1171 m_history.ClearPathHistory();
1173 //m_history.DumpPathHistory();
1176 // \brief Override if you want to change the default behavior, what is done
1177 // when the user clicks on a file.
1178 // This function is called by OnClick()
1179 bool CGUIMediaWindow::OnPlayMedia(int iItem)
1181 // Reset Playlistplayer, playback started now does
1182 // not use the playlistplayer.
1183 g_playlistPlayer.Reset();
1184 g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_NONE);
1185 CFileItemPtr pItem=m_vecItems->Get(iItem);
1187 bool bResult = false;
1188 if (pItem->IsInternetStream() || pItem->IsPlayList())
1189 bResult = g_application.PlayMedia(*pItem, m_guiState->GetPlaylist());
1191 bResult = g_application.PlayFile(*pItem);
1193 if (pItem->m_lStartOffset == STARTOFFSET_RESUME)
1194 pItem->m_lStartOffset = 0;
1199 // \brief Override if you want to change the default behavior of what is done
1200 // when the user clicks on a file in a "folder" with similar files.
1201 // This function is called by OnClick()
1202 bool CGUIMediaWindow::OnPlayAndQueueMedia(const CFileItemPtr &item)
1204 //play and add current directory to temporary playlist
1205 int iPlaylist = m_guiState->GetPlaylist();
1206 if (iPlaylist != PLAYLIST_NONE)
1208 g_playlistPlayer.ClearPlaylist(iPlaylist);
1209 g_playlistPlayer.Reset();
1210 int mediaToPlay = 0;
1211 CFileItemList queueItems;
1212 for ( int i = 0; i < m_vecItems->Size(); i++ )
1214 CFileItemPtr nItem = m_vecItems->Get(i);
1216 if (nItem->m_bIsFolder)
1219 if (!nItem->IsPlayList() && !nItem->IsZIP() && !nItem->IsRAR())
1220 queueItems.Add(nItem);
1223 { // item that was clicked
1224 mediaToPlay = queueItems.Size() - 1;
1227 g_playlistPlayer.Add(iPlaylist, queueItems);
1229 // Save current window and directory to know where the selected item was
1230 if (m_guiState.get())
1231 m_guiState->SetPlaylistDirectory(m_vecItems->m_strPath);
1233 // figure out where we start playback
1234 if (g_playlistPlayer.IsShuffled(iPlaylist))
1236 int iIndex = g_playlistPlayer.GetPlaylist(iPlaylist).FindOrder(mediaToPlay);
1237 g_playlistPlayer.GetPlaylist(iPlaylist).Swap(0, iIndex);
1242 g_playlistPlayer.SetCurrentPlaylist(iPlaylist);
1243 g_playlistPlayer.Play(mediaToPlay);
1248 // \brief Synchonize the fileitems with the playlistplayer
1249 // It recreated the playlist of the playlistplayer based
1250 // on the fileitems of the window
1251 void CGUIMediaWindow::UpdateFileList()
1253 int nItem = m_viewControl.GetSelectedItem();
1254 CStdString strSelected;
1256 strSelected = m_vecItems->Get(nItem)->m_strPath;
1258 FormatAndSort(*m_vecItems);
1261 m_viewControl.SetItems(*m_vecItems);
1262 m_viewControl.SetSelectedItem(strSelected);
1264 // set the currently playing item as selected, if its in this directory
1265 if (m_guiState.get() && m_guiState->IsCurrentPlaylistDirectory(m_vecItems->m_strPath))
1267 int iPlaylist=m_guiState->GetPlaylist();
1268 int nSong = g_playlistPlayer.GetCurrentSong();
1269 CFileItem playlistItem;
1270 if (nSong > -1 && iPlaylist > -1)
1271 playlistItem=*g_playlistPlayer.GetPlaylist(iPlaylist)[nSong];
1273 g_playlistPlayer.ClearPlaylist(iPlaylist);
1274 g_playlistPlayer.Reset();
1276 for (int i = 0; i < m_vecItems->Size(); i++)
1278 CFileItemPtr pItem = m_vecItems->Get(i);
1279 if (pItem->m_bIsFolder)
1282 if (!pItem->IsPlayList() && !pItem->IsZIP() && !pItem->IsRAR())
1283 g_playlistPlayer.Add(iPlaylist, pItem);
1285 if (pItem->m_strPath == playlistItem.m_strPath &&
1286 pItem->m_lStartOffset == playlistItem.m_lStartOffset)
1287 g_playlistPlayer.SetCurrentSong(g_playlistPlayer.GetPlaylist(iPlaylist).size() - 1);
1292 void CGUIMediaWindow::OnDeleteItem(int iItem)
1294 if ( iItem < 0 || iItem >= m_vecItems->Size()) return;
1295 CFileItemPtr item = m_vecItems->Get(iItem);
1297 if (item->IsPlayList())
1298 item->m_bIsFolder = false;
1300 if (g_settings.GetCurrentProfile().getLockMode() != LOCK_MODE_EVERYONE && g_settings.GetCurrentProfile().filesLocked())
1301 if (!g_passwordManager.IsMasterLockUnlocked(true))
1304 if (!CFileUtils::DeleteItem(item))
1306 m_vecItems->RemoveDiscCache(GetID());
1307 Update(m_vecItems->m_strPath);
1308 m_viewControl.SetSelectedItem(iItem);
1311 void CGUIMediaWindow::OnRenameItem(int iItem)
1313 if ( iItem < 0 || iItem >= m_vecItems->Size()) return;
1315 if (g_settings.GetCurrentProfile().getLockMode() != LOCK_MODE_EVERYONE && g_settings.GetCurrentProfile().filesLocked())
1316 if (!g_passwordManager.IsMasterLockUnlocked(true))
1319 if (!CFileUtils::RenameFile(m_vecItems->Get(iItem)->m_strPath))
1321 m_vecItems->RemoveDiscCache(GetID());
1322 Update(m_vecItems->m_strPath);
1323 m_viewControl.SetSelectedItem(iItem);
1326 void CGUIMediaWindow::OnInitWindow()
1328 // initial fetch is done unthreaded to ensure the items are setup prior to skin animations kicking off
1329 m_rootDir.SetAllowThreads(false);
1330 Update(m_vecItems->m_strPath);
1331 m_rootDir.SetAllowThreads(true);
1333 if (m_iSelectedItem > -1)
1334 m_viewControl.SetSelectedItem(m_iSelectedItem);
1336 CGUIWindow::OnInitWindow();
1339 CGUIControl *CGUIMediaWindow::GetFirstFocusableControl(int id)
1341 if (m_viewControl.HasControl(id))
1342 id = m_viewControl.GetCurrentControl();
1343 return CGUIWindow::GetFirstFocusableControl(id);
1346 void CGUIMediaWindow::SetupShares()
1348 // Setup shares and filemasks for this window
1349 CFileItemList items;
1350 CGUIViewState* viewState=CGUIViewState::GetViewState(GetID(), items);
1353 m_rootDir.SetMask(viewState->GetExtensions());
1354 m_rootDir.SetSources(viewState->GetSources());
1359 bool CGUIMediaWindow::OnPopupMenu(int iItem)
1361 // popup the context menu
1362 // grab our context menu
1363 CContextButtons buttons;
1364 GetContextButtons(iItem, buttons);
1369 if (iItem >= 0 && iItem < m_vecItems->Size())
1370 m_vecItems->Get(iItem)->Select(true);
1372 int choice = CGUIDialogContextMenu::ShowAndGetChoice(buttons);
1374 // deselect our item
1375 if (iItem >= 0 && iItem < m_vecItems->Size())
1376 m_vecItems->Get(iItem)->Select(false);
1379 return OnContextButton(iItem, (CONTEXT_BUTTON)choice);
1384 void CGUIMediaWindow::GetContextButtons(int itemNumber, CContextButtons &buttons)
1386 CFileItemPtr item = (itemNumber >= 0 && itemNumber < m_vecItems->Size()) ? m_vecItems->Get(itemNumber) : CFileItemPtr();
1391 // user added buttons
1394 for (int i = CONTEXT_BUTTON_USER1; i <= CONTEXT_BUTTON_USER10; i++)
1396 label.Format("contextmenulabel(%i)", i - CONTEXT_BUTTON_USER1);
1397 if (item->GetProperty(label).IsEmpty())
1400 action.Format("contextmenuaction(%i)", i - CONTEXT_BUTTON_USER1);
1401 if (item->GetProperty(action).IsEmpty())
1404 buttons.Add((CONTEXT_BUTTON)i, item->GetProperty(label));
1407 if (item->GetPropertyBOOL("pluginreplacecontextitems"))
1410 // TODO: FAVOURITES Conditions on masterlock and localisation
1411 if (!item->IsParentFolder() && !item->m_strPath.Equals("add") && !item->m_strPath.Equals("newplaylist://") && !item->m_strPath.Left(19).Equals("newsmartplaylist://"))
1413 if (CFavourites::IsFavourite(item.get(), GetID()))
1414 buttons.Add(CONTEXT_BUTTON_ADD_FAVOURITE, 14077); // Remove Favourite
1416 buttons.Add(CONTEXT_BUTTON_ADD_FAVOURITE, 14076); // Add To Favourites;
1420 bool CGUIMediaWindow::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
1424 case CONTEXT_BUTTON_ADD_FAVOURITE:
1426 CFileItemPtr item = m_vecItems->Get(itemNumber);
1427 CFavourites::AddOrRemove(item.get(), GetID());
1430 case CONTEXT_BUTTON_PLUGIN_SETTINGS:
1432 CURL plugin(m_vecItems->Get(itemNumber)->m_strPath);
1433 ADDON::AddonPtr addon;
1434 if (CAddonMgr::Get().GetAddon(plugin.GetHostName(), addon, ADDON_PLUGIN))
1435 if (CGUIDialogAddonSettings::ShowAndGetInput(addon))
1436 Update(m_vecItems->m_strPath);
1439 case CONTEXT_BUTTON_USER1:
1440 case CONTEXT_BUTTON_USER2:
1441 case CONTEXT_BUTTON_USER3:
1442 case CONTEXT_BUTTON_USER4:
1443 case CONTEXT_BUTTON_USER5:
1444 case CONTEXT_BUTTON_USER6:
1445 case CONTEXT_BUTTON_USER7:
1446 case CONTEXT_BUTTON_USER8:
1447 case CONTEXT_BUTTON_USER9:
1448 case CONTEXT_BUTTON_USER10:
1451 action.Format("contextmenuaction(%i)", button - CONTEXT_BUTTON_USER1);
1452 g_application.getApplicationMessenger().ExecBuiltIn(m_vecItems->Get(itemNumber)->GetProperty(action));
1461 const CGUIViewState *CGUIMediaWindow::GetViewState() const
1463 return m_guiState.get();
1466 const CFileItemList& CGUIMediaWindow::CurrentDirectory() const
1471 bool CGUIMediaWindow::WaitForNetwork() const
1473 if (g_application.getNetwork().IsAvailable())
1476 CGUIDialogProgress *progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
1480 CURL url(m_vecItems->m_strPath);
1481 progress->SetHeading(1040); // Loading Directory
1482 progress->SetLine(1, url.GetWithoutUserDetails());
1483 progress->ShowProgressBar(false);
1484 progress->StartModal();
1485 while (!g_application.getNetwork().IsAvailable())
1487 progress->Progress();
1488 if (progress->IsCanceled())
1498 void CGUIMediaWindow::OnFilterItems(const CStdString &filter)
1500 CStdString currentItem;
1501 int item = m_viewControl.GetSelectedItem();
1503 currentItem = m_vecItems->Get(item)->m_strPath;
1505 m_viewControl.Clear();
1507 CFileItemList items;
1508 GetFilteredItems(filter, items);
1509 if (filter.IsEmpty() || items.GetObjectCount() > 0)
1511 m_vecItems->ClearItems();
1512 m_vecItems->Append(items);
1513 SetProperty("filter", filter);
1516 // and update our view control + buttons
1517 m_viewControl.SetItems(*m_vecItems);
1518 m_viewControl.SetSelectedItem(currentItem);
1522 void CGUIMediaWindow::GetFilteredItems(const CStdString &filter, CFileItemList &items)
1524 CStdString trimmedFilter(filter);
1525 trimmedFilter.TrimLeft().ToLower();
1527 if (trimmedFilter.IsEmpty())
1529 items.Append(*m_unfilteredItems);
1533 bool numericMatch = StringUtils::IsNaturalNumber(trimmedFilter);
1534 for (int i = 0; i < m_unfilteredItems->Size(); i++)
1536 CFileItemPtr item = m_unfilteredItems->Get(i);
1537 if (item->IsParentFolder())
1542 // TODO: Need to update this to get all labels, ideally out of the displayed info (ie from m_layout and m_focusedLayout)
1543 // though that isn't practical. Perhaps a better idea would be to just grab the info that we should filter on based on
1544 // where we are in the library tree.
1545 // Another idea is tying the filter string to the current level of the tree, so that going deeper disables the filter,
1546 // but it's re-enabled on the way back out.
1548 /* if (item->GetFocusedLayout())
1549 match = item->GetFocusedLayout()->GetAllText();
1550 else if (item->GetLayout())
1551 match = item->GetLayout()->GetAllText();
1553 match = item->GetLabel(); // Filter label only for now
1556 StringUtils::WordToDigits(match);
1558 size_t pos = StringUtils::FindWords(match.c_str(), trimmedFilter.c_str());
1559 if (pos != CStdString::npos)
1564 CStdString CGUIMediaWindow::GetStartFolder(const CStdString &dir)
1566 if (dir.Equals("$ROOT") || dir.Equals("Root"))