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 "threads/SystemClock.h"
23 #include "GUIMediaWindow.h"
24 #include "GUIUserMessages.h"
26 #include "PlayListPlayer.h"
27 #include "addons/AddonManager.h"
28 #include "addons/PluginSource.h"
29 #include "filesystem/PluginDirectory.h"
30 #include "filesystem/MultiPathDirectory.h"
31 #include "GUIPassword.h"
32 #include "Application.h"
33 #include "network/Network.h"
34 #include "utils/RegExp.h"
35 #include "PartyModeManager.h"
36 #include "dialogs/GUIDialogMediaSource.h"
37 #include "GUIWindowFileManager.h"
38 #include "Favourites.h"
39 #include "utils/LabelFormatter.h"
40 #include "dialogs/GUIDialogProgress.h"
41 #include "settings/AdvancedSettings.h"
42 #include "settings/GUISettings.h"
44 #include "dialogs/GUIDialogSmartPlaylistEditor.h"
45 #include "addons/GUIDialogAddonSettings.h"
46 #include "dialogs/GUIDialogYesNo.h"
47 #include "guilib/GUIWindowManager.h"
48 #include "dialogs/GUIDialogOK.h"
49 #include "playlists/PlayList.h"
50 #include "storage/MediaManager.h"
51 #include "settings/Settings.h"
52 #include "utils/StringUtils.h"
53 #include "utils/URIUtils.h"
54 #include "guilib/LocalizeStrings.h"
55 #include "utils/TimeUtils.h"
56 #include "filesystem/FactoryFileDirectory.h"
57 #include "utils/log.h"
58 #include "utils/FileUtils.h"
59 #include "guilib/GUIEditControl.h"
60 #include "dialogs/GUIDialogKeyboard.h"
62 #include "interfaces/python/XBPython.h"
64 #include "interfaces/Builtins.h"
66 #define CONTROL_BTNVIEWASICONS 2
67 #define CONTROL_BTNSORTBY 3
68 #define CONTROL_BTNSORTASC 4
69 #define CONTROL_BTN_FILTER 19
71 #define CONTROL_LABELFILES 12
74 using namespace ADDON;
76 CGUIMediaWindow::CGUIMediaWindow(int id, const char *xmlFile)
77 : CGUIWindow(id, xmlFile)
79 m_vecItems = new CFileItemList;
80 m_unfilteredItems = new CFileItemList;
81 m_vecItems->SetPath("?");
85 m_guiState.reset(CGUIViewState::GetViewState(GetID(), *m_vecItems));
88 CGUIMediaWindow::~CGUIMediaWindow()
91 delete m_unfilteredItems;
94 #define CONTROL_VIEW_START 50
95 #define CONTROL_VIEW_END 59
97 void CGUIMediaWindow::LoadAdditionalTags(TiXmlElement *root)
99 CGUIWindow::LoadAdditionalTags(root);
100 // configure our view control
101 m_viewControl.Reset();
102 m_viewControl.SetParentWindow(GetID());
103 TiXmlElement *element = root->FirstChildElement("views");
104 if (element && element->FirstChild())
105 { // format is <views>50,29,51,95</views>
106 CStdString allViews = element->FirstChild()->Value();
107 CStdStringArray views;
108 StringUtils::SplitString(allViews, ",", views);
109 for (unsigned int i = 0; i < views.size(); i++)
111 int controlID = atol(views[i].c_str());
112 CGUIControl *control = (CGUIControl *)GetControl(controlID);
113 if (control && control->IsContainer())
114 m_viewControl.AddView(control);
118 { // backward compatibility
119 vector<CGUIControl *> controls;
120 GetContainers(controls);
121 for (ciControls it = controls.begin(); it != controls.end(); it++)
123 CGUIControl *control = *it;
124 if (control->GetID() >= CONTROL_VIEW_START && control->GetID() <= CONTROL_VIEW_END)
125 m_viewControl.AddView(control);
128 m_viewControl.SetViewControlID(CONTROL_BTNVIEWASICONS);
131 void CGUIMediaWindow::OnWindowLoaded()
133 SendMessage(GUI_MSG_SET_TYPE, CONTROL_BTN_FILTER, CGUIEditControl::INPUT_TYPE_FILTER);
134 CGUIWindow::OnWindowLoaded();
138 void CGUIMediaWindow::OnWindowUnload()
140 CGUIWindow::OnWindowUnload();
141 m_viewControl.Reset();
144 CFileItemPtr CGUIMediaWindow::GetCurrentListItem(int offset)
146 int item = m_viewControl.GetSelectedItem();
147 if (!m_vecItems->Size() || item < 0)
148 return CFileItemPtr();
149 item = (item + offset) % m_vecItems->Size();
150 if (item < 0) item += m_vecItems->Size();
151 return m_vecItems->Get(item);
154 bool CGUIMediaWindow::OnAction(const CAction &action)
156 if (action.GetID() == ACTION_PARENT_DIR)
162 // the non-contextual menu can be called at any time
163 if (action.GetID() == ACTION_CONTEXT_MENU && !m_viewControl.HasControl(GetFocusedControlID()))
169 if (CGUIWindow::OnAction(action))
173 if (action.GetID() == ACTION_FILTER_CLEAR)
175 CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS);
176 message.SetStringParam("");
181 if (action.GetID() == ACTION_BACKSPACE)
183 CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS, 2); // 2 for delete
188 if (action.GetID() >= ACTION_FILTER_SMS2 && action.GetID() <= ACTION_FILTER_SMS9)
191 filter.Format("%i", (int)(action.GetID() - ACTION_FILTER_SMS2 + 2));
192 CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS, 1); // 1 for append
193 message.SetStringParam(filter);
201 bool CGUIMediaWindow::OnBack(int actionID)
203 if (actionID == ACTION_NAV_BACK && !(m_vecItems->IsVirtualDirectoryRoot() || m_vecItems->GetPath() == m_startDirectory))
208 return CGUIWindow::OnBack(actionID);
211 bool CGUIMediaWindow::OnMessage(CGUIMessage& message)
213 switch ( message.GetMessage() )
215 case GUI_MSG_WINDOW_DEINIT:
217 m_iSelectedItem = m_viewControl.GetSelectedItem();
218 m_iLastControl = GetFocusedControlID();
219 CGUIWindow::OnMessage(message);
220 // Call ClearFileItems() after our window has finished doing any WindowClose
227 case GUI_MSG_CLICKED:
229 int iControl = message.GetSenderId();
230 if (iControl == CONTROL_BTNVIEWASICONS)
232 // view as control could be a select button
234 const CGUIControl *control = GetControl(CONTROL_BTNVIEWASICONS);
235 if (control && control->GetControlType() != CGUIControl::GUICONTROL_BUTTON)
237 CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_BTNVIEWASICONS);
239 viewMode = m_viewControl.GetViewModeNumber(msg.GetParam1());
242 viewMode = m_viewControl.GetNextViewMode();
244 if (m_guiState.get())
245 m_guiState->SaveViewAsControl(viewMode);
250 else if (iControl == CONTROL_BTNSORTASC) // sort asc
252 if (m_guiState.get())
253 m_guiState->SetNextSortOrder();
257 else if (iControl == CONTROL_BTNSORTBY) // sort by
259 if (m_guiState.get())
260 m_guiState->SetNextSortMethod();
264 else if (iControl == CONTROL_BTN_FILTER)
266 if (GetControl(iControl)->GetControlType() == CGUIControl::GUICONTROL_EDIT)
268 CGUIMessage selected(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_BTN_FILTER);
270 OnFilterItems(selected.GetLabel());
273 if (GetProperty("filter").empty())
275 CStdString filter = GetProperty("filter").asString();
276 CGUIDialogKeyboard::ShowAndGetFilter(filter, false);
277 SetProperty("filter", filter);
283 else if (m_viewControl.HasControl(iControl)) // list/thumb control
285 int iItem = m_viewControl.GetSelectedItem();
286 int iAction = message.GetParam1();
287 if (iItem < 0) break;
288 if (iAction == ACTION_SELECT_ITEM || iAction == ACTION_MOUSE_LEFT_CLICK)
292 else if (iAction == ACTION_CONTEXT_MENU || iAction == ACTION_MOUSE_RIGHT_CLICK)
301 case GUI_MSG_SETFOCUS:
303 if (m_viewControl.HasControl(message.GetControlId()) && m_viewControl.GetCurrentControl() != message.GetControlId())
305 m_viewControl.SetFocused();
311 case GUI_MSG_NOTIFY_ALL:
312 { // Message is received even if this window is inactive
313 if (message.GetParam1() == GUI_MSG_WINDOW_RESET)
315 m_vecItems->SetPath("?");
318 else if ( message.GetParam1() == GUI_MSG_REFRESH_THUMBS )
320 for (int i = 0; i < m_vecItems->Size(); i++)
321 m_vecItems->Get(i)->FreeMemory(true);
322 break; // the window will take care of any info images
324 else if (message.GetParam1() == GUI_MSG_REMOVED_MEDIA)
326 if ((m_vecItems->IsVirtualDirectoryRoot() ||
327 m_vecItems->IsSourcesPath()) && IsActive())
329 int iItem = m_viewControl.GetSelectedItem();
330 Update(m_vecItems->GetPath());
331 m_viewControl.SetSelectedItem(iItem);
333 else if (m_vecItems->IsRemovable())
334 { // check that we have this removable share still
335 if (!m_rootDir.IsInSource(m_vecItems->GetPath()))
336 { // don't have this share any more
337 if (IsActive()) Update("");
340 m_history.ClearPathHistory();
341 m_vecItems->SetPath("");
348 else if (message.GetParam1()==GUI_MSG_UPDATE_SOURCES)
349 { // State of the sources changed, so update our view
350 if ((m_vecItems->IsVirtualDirectoryRoot() ||
351 m_vecItems->IsSourcesPath()) && IsActive())
353 int iItem = m_viewControl.GetSelectedItem();
354 Update(m_vecItems->GetPath());
355 m_viewControl.SetSelectedItem(iItem);
359 else if (message.GetParam1()==GUI_MSG_UPDATE && IsActive())
361 if (message.GetNumStringParams())
363 m_vecItems->SetPath(message.GetStringParam());
364 if (message.GetParam2()) // param2 is used for resetting the history
365 SetHistoryForPath(m_vecItems->GetPath());
367 // clear any cached listing
368 m_vecItems->RemoveDiscCache(GetID());
369 Update(m_vecItems->GetPath());
371 else if (message.GetParam1()==GUI_MSG_UPDATE_ITEM && message.GetItem())
373 CFileItemPtr newItem = boost::static_pointer_cast<CFileItem>(message.GetItem());
376 if (m_vecItems->UpdateItem(newItem.get()) && message.GetParam2() == 1)
377 { // need the list updated as well
382 { // need to remove the disc cache
385 URIUtils::GetDirectory(newItem->GetPath(), path);
387 items.RemoveDiscCache(GetID());
390 else if (message.GetParam1()==GUI_MSG_UPDATE_PATH)
394 if((message.GetStringParam() == m_vecItems->GetPath()) ||
395 (m_vecItems->IsMultiPath() && XFILE::CMultiPathDirectory::HasPath(m_vecItems->GetPath(), message.GetStringParam())))
397 Update(m_vecItems->GetPath());
401 else if (message.GetParam1() == GUI_MSG_FILTER_ITEMS && IsActive())
403 CStdString filter(GetProperty("filter").asString());
404 if (message.GetParam2() == 1) // append
405 filter += message.GetStringParam();
406 else if (message.GetParam2() == 2)
409 filter = filter.Left(filter.size() - 1);
412 filter = message.GetStringParam();
413 OnFilterItems(filter);
417 return CGUIWindow::OnMessage(message);
422 case GUI_MSG_PLAYBACK_STARTED:
423 case GUI_MSG_PLAYBACK_ENDED:
424 case GUI_MSG_PLAYBACK_STOPPED:
425 case GUI_MSG_PLAYLIST_CHANGED:
426 case GUI_MSG_PLAYLISTPLAYER_STOPPED:
427 case GUI_MSG_PLAYLISTPLAYER_STARTED:
428 case GUI_MSG_PLAYLISTPLAYER_CHANGED:
429 { // send a notify all to all controls on this window
430 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_REFRESH_LIST);
434 case GUI_MSG_CHANGE_VIEW_MODE:
437 if (message.GetParam1()) // we have an id
438 viewMode = m_viewControl.GetViewModeByID(message.GetParam1());
439 else if (message.GetParam2())
440 viewMode = m_viewControl.GetNextViewMode((int)message.GetParam2());
442 if (m_guiState.get())
443 m_guiState->SaveViewAsControl(viewMode);
448 case GUI_MSG_CHANGE_SORT_METHOD:
450 if (m_guiState.get())
452 if (message.GetParam1())
453 m_guiState->SetCurrentSortMethod((int)message.GetParam1());
454 else if (message.GetParam2())
455 m_guiState->SetNextSortMethod((int)message.GetParam2());
461 case GUI_MSG_CHANGE_SORT_DIRECTION:
463 if (m_guiState.get())
464 m_guiState->SetNextSortOrder();
469 case GUI_MSG_WINDOW_INIT:
471 if (m_vecItems->GetPath() == "?")
472 m_vecItems->SetPath("");
473 CStdString dir = message.GetStringParam(0);
474 const CStdString &ret = message.GetStringParam(1);
475 bool returning = ret.CompareNoCase("return") == 0;
478 m_history.ClearPathHistory();
479 // ensure our directory is valid
480 dir = GetStartFolder(dir);
481 if (!returning || m_vecItems->GetPath().Left(dir.GetLength()) != dir)
482 { // we're not returning to the same path, so set our directory to the requested path
483 m_vecItems->SetPath(dir);
485 // check for network up
486 if (URIUtils::IsRemote(m_vecItems->GetPath()) && !WaitForNetwork())
487 m_vecItems->SetPath("");
488 SetHistoryForPath(m_vecItems->GetPath());
490 if (message.GetParam1() != WINDOW_INVALID)
491 { // first time to this window - make sure we set the root path
492 m_startDirectory = returning ? dir : "";
498 return CGUIWindow::OnMessage(message);
501 // \brief Updates the states (enable, disable, visible...)
502 // of the controls defined by this window
503 // Override this function in a derived class to add new controls
504 void CGUIMediaWindow::UpdateButtons()
506 if (m_guiState.get())
508 // Update sorting controls
509 if (m_guiState->GetDisplaySortOrder()==SORT_ORDER_NONE)
511 CONTROL_DISABLE(CONTROL_BTNSORTASC);
515 CONTROL_ENABLE(CONTROL_BTNSORTASC);
516 if (m_guiState->GetDisplaySortOrder()==SORT_ORDER_ASC)
518 CGUIMessage msg(GUI_MSG_DESELECTED, GetID(), CONTROL_BTNSORTASC);
519 g_windowManager.SendMessage(msg);
523 CGUIMessage msg(GUI_MSG_SELECTED, GetID(), CONTROL_BTNSORTASC);
524 g_windowManager.SendMessage(msg);
528 // Update list/thumb control
529 m_viewControl.SetCurrentView(m_guiState->GetViewAsControl());
531 // Update sort by button
532 if (m_guiState->GetSortMethod()==SORT_METHOD_NONE)
534 CONTROL_DISABLE(CONTROL_BTNSORTBY);
538 CONTROL_ENABLE(CONTROL_BTNSORTBY);
540 CStdString sortLabel;
541 sortLabel.Format(g_localizeStrings.Get(550).c_str(), g_localizeStrings.Get(m_guiState->GetSortMethodLabel()).c_str());
542 SET_CONTROL_LABEL(CONTROL_BTNSORTBY, sortLabel);
546 items.Format("%i %s", m_vecItems->GetObjectCount(), g_localizeStrings.Get(127).c_str());
547 SET_CONTROL_LABEL(CONTROL_LABELFILES, items);
549 //#ifdef PRE_SKIN_VERSION_3
550 SET_CONTROL_SELECTED(GetID(),CONTROL_BTN_FILTER, !GetProperty("filter").empty());
551 SET_CONTROL_LABEL2(CONTROL_BTN_FILTER, GetProperty("filter").asString());
555 void CGUIMediaWindow::ClearFileItems()
557 m_viewControl.Clear();
558 m_vecItems->Clear(); // will clean up everything
559 m_unfilteredItems->Clear();
562 // \brief Sorts Fileitems based on the sort method and sort oder provided by guiViewState
563 void CGUIMediaWindow::SortItems(CFileItemList &items)
565 auto_ptr<CGUIViewState> guiState(CGUIViewState::GetViewState(GetID(), items));
569 items.Sort(guiState->GetSortMethod(), guiState->GetDisplaySortOrder());
571 // Should these items be saved to the hdd
572 if (items.CacheToDiscAlways())
577 // \brief Formats item labels based on the formatting provided by guiViewState
578 void CGUIMediaWindow::FormatItemLabels(CFileItemList &items, const LABEL_MASKS &labelMasks)
580 CLabelFormatter fileFormatter(labelMasks.m_strLabelFile, labelMasks.m_strLabel2File);
581 CLabelFormatter folderFormatter(labelMasks.m_strLabelFolder, labelMasks.m_strLabel2Folder);
582 for (int i=0; i<items.Size(); ++i)
584 CFileItemPtr pItem=items[i];
586 if (pItem->IsLabelPreformated())
589 if (pItem->m_bIsFolder)
590 folderFormatter.FormatLabels(pItem.get());
592 fileFormatter.FormatLabels(pItem.get());
595 if(items.GetSortMethod() == SORT_METHOD_LABEL_IGNORE_THE
596 || items.GetSortMethod() == SORT_METHOD_LABEL)
597 items.ClearSortState();
600 // \brief Prepares and adds the fileitems list/thumb panel
601 void CGUIMediaWindow::FormatAndSort(CFileItemList &items)
603 auto_ptr<CGUIViewState> viewState(CGUIViewState::GetViewState(GetID(), items));
607 LABEL_MASKS labelMasks;
608 viewState->GetSortMethodLabelMasks(labelMasks);
609 FormatItemLabels(items, labelMasks);
615 \brief Overwrite to fill fileitems from a source
616 \param strDirectory Path to read
617 \param items Fill with items specified in \e strDirectory
619 bool CGUIMediaWindow::GetDirectory(const CStdString &strDirectory, CFileItemList &items)
625 CStdString strParentPath=m_history.GetParentPath();
627 CLog::Log(LOGDEBUG,"CGUIMediaWindow::GetDirectory (%s)", strDirectory.c_str());
628 CLog::Log(LOGDEBUG," ParentPath = [%s]", strParentPath.c_str());
630 // see if we can load a previously cached folder
631 CFileItemList cachedItems(strDirectory);
632 if (!strDirectory.IsEmpty() && cachedItems.Load(GetID()))
634 items.Assign(cachedItems);
638 unsigned int time = XbmcThreads::SystemClockMillis();
640 if (strDirectory.IsEmpty())
643 if (!m_rootDir.GetDirectory(strDirectory, items))
646 // took over a second, and not normally cached, so cache it
647 if ((XbmcThreads::SystemClockMillis() - time) > 1000 && items.CacheToDiscIfSlow())
650 // if these items should replace the current listing, then pop it off the top
651 if (items.GetReplaceListing())
652 m_history.RemoveParentPath();
655 if (m_guiState.get() && !m_guiState->HideParentDirItems() && !items.GetPath().IsEmpty())
657 CFileItemPtr pItem(new CFileItem(".."));
658 pItem->SetPath(strParentPath);
659 pItem->m_bIsFolder = true;
660 pItem->m_bIsShareOrDrive = false;
661 items.AddFront(pItem, 0);
664 int iWindow = GetID();
665 CStdStringArray regexps;
667 // TODO: Do we want to limit the directories we apply the video ones to?
668 if (iWindow == WINDOW_VIDEO_NAV)
669 regexps = g_advancedSettings.m_videoExcludeFromListingRegExps;
670 if (iWindow == WINDOW_MUSIC_FILES)
671 regexps = g_advancedSettings.m_audioExcludeFromListingRegExps;
672 if (iWindow == WINDOW_PICTURES)
673 regexps = g_advancedSettings.m_pictureExcludeFromListingRegExps;
677 for (int i=0; i < items.Size();)
679 if (CUtil::ExcludeFileOrFolder(items[i]->GetPath(), regexps))
687 SetProperty("filter", "");
691 // \brief Set window to a specific directory
692 // \param strDirectory The directory to be displayed in list/thumb control
693 // This function calls OnPrepareFileItems() and OnFinalizeFileItems()
694 bool CGUIMediaWindow::Update(const CStdString &strDirectory)
696 // TODO: OnInitWindow calls Update() before window path has been set properly.
697 if (strDirectory == "?")
701 int iItem = m_viewControl.GetSelectedItem();
702 CStdString strSelectedItem = "";
703 if (iItem >= 0 && iItem < m_vecItems->Size())
705 CFileItemPtr pItem = m_vecItems->Get(iItem);
706 if (!pItem->IsParentFolder())
708 GetDirectoryHistoryString(pItem.get(), strSelectedItem);
712 CStdString strOldDirectory = m_vecItems->GetPath();
714 m_history.SetSelectedItem(strSelectedItem, strOldDirectory);
717 if (!GetDirectory(strDirectory, items))
719 CLog::Log(LOGERROR,"CGUIMediaWindow::GetDirectory(%s) failed", strDirectory.c_str());
720 // if the directory is the same as the old directory, then we'll return
721 // false. Else, we assume we can get the previous directory
722 if (strDirectory.Equals(strOldDirectory))
725 // We assume, we can get the parent
726 // directory again, but we have to
727 // return false to be able to eg. show
729 CStdString strParentPath = m_history.GetParentPath();
730 m_history.RemoveParentPath();
731 Update(strParentPath);
735 if (items.GetLabel().IsEmpty())
736 items.SetLabel(CUtil::GetTitleFromPath(items.GetPath(), true));
739 m_vecItems->Copy(items);
741 // if we're getting the root source listing
742 // make sure the path history is clean
743 if (strDirectory.IsEmpty())
744 m_history.ClearPathHistory();
746 int iWindow = GetID();
748 if (strDirectory.IsEmpty() && (iWindow == WINDOW_MUSIC_FILES ||
749 iWindow == WINDOW_FILES ||
750 iWindow == WINDOW_PICTURES ||
751 iWindow == WINDOW_PROGRAMS))
753 if (strDirectory.Equals("sources://video/"))
755 if (showLabel && (m_vecItems->Size() == 0 || !m_guiState->DisableAddSourceButtons())) // add 'add source button'
757 CStdString strLabel = g_localizeStrings.Get(showLabel);
758 CFileItemPtr pItem(new CFileItem(strLabel));
759 pItem->SetPath("add");
760 pItem->SetIconImage("DefaultAddSource.png");
761 pItem->SetLabel(strLabel);
762 pItem->SetLabelPreformated(true);
763 pItem->m_bIsFolder = true;
764 pItem->SetSpecialSort(SORT_ON_BOTTOM);
765 m_vecItems->Add(pItem);
767 m_iLastControl = GetFocusedControlID();
769 // Ask the derived class if it wants to load additional info
770 // for the fileitems like media info or additional
771 // filtering on the items, setting thumbs.
772 OnPrepareFileItems(*m_vecItems);
774 // The idea here is to ensure we have something to focus if our file list
775 // is empty. As such, this check MUST be last and ignore the hide parent
776 // fileitems settings.
777 if (m_vecItems->IsEmpty())
779 CFileItemPtr pItem(new CFileItem(".."));
780 pItem->SetPath(m_history.GetParentPath());
781 pItem->m_bIsFolder = true;
782 pItem->m_bIsShareOrDrive = false;
783 m_vecItems->AddFront(pItem, 0);
786 m_vecItems->FillInDefaultIcons();
788 m_guiState.reset(CGUIViewState::GetViewState(GetID(), *m_vecItems));
790 FormatAndSort(*m_vecItems);
792 // Ask the devived class if it wants to do custom list operations,
793 // eg. changing the label
794 OnFinalizeFileItems(*m_vecItems);
797 m_viewControl.SetItems(*m_vecItems);
799 strSelectedItem = m_history.GetSelectedItem(m_vecItems->GetPath());
801 bool bSelectedFound = false;
802 //int iSongInDirectory = -1;
803 for (int i = 0; i < m_vecItems->Size(); ++i)
805 CFileItemPtr pItem = m_vecItems->Get(i);
807 // Update selected item
810 CStdString strHistory;
811 GetDirectoryHistoryString(pItem.get(), strHistory);
812 if (strHistory == strSelectedItem)
814 m_viewControl.SetSelectedItem(i);
815 bSelectedFound = true;
820 // if we haven't found the selected item, select the first item
822 m_viewControl.SetSelectedItem(0);
824 m_history.AddPath(m_vecItems->GetPath());
826 //m_history.DumpPathHistory();
831 // \brief This function will be called by Update() before the
832 // labels of the fileitems are formatted. Override this function
833 // to set custom thumbs or load additional media info.
834 // It's used to load tag info for music.
835 void CGUIMediaWindow::OnPrepareFileItems(CFileItemList &items)
840 // \brief This function will be called by Update() after the
841 // labels of the fileitems are formatted. Override this function
842 // to modify the fileitems. Eg. to modify the item label
843 void CGUIMediaWindow::OnFinalizeFileItems(CFileItemList &items)
845 m_unfilteredItems->Append(items);
847 CStdString filter(GetProperty("filter").asString());
848 if (!filter.IsEmpty())
851 GetFilteredItems(filter, items);
855 // \brief With this function you can react on a users click in the list/thumb panel.
856 // It returns true, if the click is handled.
857 // This function calls OnPlayMedia()
858 bool CGUIMediaWindow::OnClick(int iItem)
860 if ( iItem < 0 || iItem >= (int)m_vecItems->Size() ) return true;
861 CFileItemPtr pItem = m_vecItems->Get(iItem);
863 if (pItem->IsParentFolder())
868 if (pItem->GetPath() == "add" || pItem->GetPath() == "sources://add/") // 'add source button' in empty root
870 OnContextButton(iItem, CONTEXT_BUTTON_ADD_SOURCE);
874 if (!pItem->m_bIsFolder && pItem->IsFileFolder())
876 XFILE::IFileDirectory *pFileDirectory = NULL;
877 pFileDirectory = XFILE::CFactoryFileDirectory::Create(pItem->GetPath(), pItem.get(), "");
879 pItem->m_bIsFolder = true;
880 else if(pItem->m_bIsFolder)
881 pItem->m_bIsFolder = false;
882 delete pFileDirectory;
885 if (pItem->IsScript())
887 // execute the script
888 CURL url(pItem->GetPath());
890 if (CAddonMgr::Get().GetAddon(url.GetHostName(), addon))
893 if (!g_pythonParser.StopScript(addon->LibPath()))
894 g_pythonParser.evalFile(addon->LibPath(),addon);
900 if (pItem->m_bIsFolder)
902 if ( pItem->m_bIsShareOrDrive )
904 const CStdString& strLockType=m_guiState->GetLockType();
905 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE)
906 if (!strLockType.IsEmpty() && !g_passwordManager.IsItemUnlocked(pItem.get(), strLockType))
909 if (!HaveDiscOrConnection(pItem->m_iDriveType))
913 // check for the partymode playlist items - they may not exist yet
914 if ((pItem->GetPath() == g_settings.GetUserDataItem("PartyMode.xsp")) ||
915 (pItem->GetPath() == g_settings.GetUserDataItem("PartyMode-Video.xsp")))
917 // party mode playlist item - if it doesn't exist, prompt for user to define it
918 if (!XFILE::CFile::Exists(pItem->GetPath()))
920 m_vecItems->RemoveDiscCache(GetID());
921 if (CGUIDialogSmartPlaylistEditor::EditPlaylist(pItem->GetPath()))
922 Update(m_vecItems->GetPath());
927 // remove the directory cache if the folder is not normally cached
928 CFileItemList items(pItem->GetPath());
929 if (!items.AlwaysCache())
930 items.RemoveDiscCache(GetID());
932 CFileItem directory(*pItem);
933 if (!Update(directory.GetPath()))
934 ShowShareErrorMessage(&directory);
938 else if (pItem->IsPlugin() && !pItem->GetProperty("isplayable").asBoolean())
940 return XFILE::CPluginDirectory::RunScriptWithParams(pItem->GetPath());
944 m_iSelectedItem = m_viewControl.GetSelectedItem();
946 if (pItem->GetPath() == "newplaylist://")
948 m_vecItems->RemoveDiscCache(GetID());
949 g_windowManager.ActivateWindow(WINDOW_MUSIC_PLAYLIST_EDITOR,"newplaylist://");
952 else if (pItem->GetPath().Left(19).Equals("newsmartplaylist://"))
954 m_vecItems->RemoveDiscCache(GetID());
955 if (CGUIDialogSmartPlaylistEditor::NewPlaylist(pItem->GetPath().Mid(19)))
956 Update(m_vecItems->GetPath());
959 else if (pItem->GetPath().Left(14).Equals("addons://more/"))
961 CBuiltins::Execute("ActivateWindow(AddonBrowser,addons://all/xbmc.addon." + pItem->GetPath().Mid(14) + ",return)");
965 // If karaoke song is being played AND popup autoselector is enabled, the playlist should not be added
966 bool do_not_add_karaoke = g_guiSettings.GetBool("karaoke.enabled") &&
967 g_guiSettings.GetBool("karaoke.autopopupselector") && pItem->IsKaraoke();
968 bool autoplay = m_guiState.get() && m_guiState->AutoPlayNextItem();
969 int iPlaylist = m_guiState.get()?m_guiState->GetPlaylist():PLAYLIST_MUSIC;
971 if (pItem->IsPlugin())
973 CURL url(pItem->GetPath());
975 if (CAddonMgr::Get().GetAddon(url.GetHostName(),addon))
977 PluginPtr plugin = boost::dynamic_pointer_cast<CPluginSource>(addon);
978 if (plugin && plugin->Provides(CPluginSource::AUDIO) && pItem->IsAudio())
980 iPlaylist = PLAYLIST_MUSIC;
981 autoplay = g_guiSettings.GetBool("musicplayer.autoplaynextitem");
986 if (autoplay && !g_partyModeManager.IsEnabled() &&
987 !pItem->IsPlayList() && !do_not_add_karaoke)
989 return OnPlayAndQueueMedia(pItem);
993 return OnPlayMedia(iItem);
1000 bool CGUIMediaWindow::OnSelect(int item)
1002 return OnClick(item);
1005 // \brief Checks if there is a disc in the dvd drive and whether the
1006 // network is connected or not.
1007 bool CGUIMediaWindow::HaveDiscOrConnection(int iDriveType)
1009 if (iDriveType==CMediaSource::SOURCE_TYPE_DVD)
1011 if (!g_mediaManager.IsDiscInDrive())
1013 CGUIDialogOK::ShowAndGetInput(218, 219, 0, 0);
1017 else if (iDriveType==CMediaSource::SOURCE_TYPE_REMOTE)
1019 // TODO: Handle not connected to a remote share
1020 if ( !g_application.getNetwork().IsConnected() )
1022 CGUIDialogOK::ShowAndGetInput(220, 221, 0, 0);
1030 // \brief Shows a standard errormessage for a given pItem.
1031 void CGUIMediaWindow::ShowShareErrorMessage(CFileItem* pItem)
1033 if (pItem->m_bIsShareOrDrive)
1035 int idMessageText=0;
1036 const CURL& url=pItem->GetAsUrl();
1037 const CStdString& strHostName=url.GetHostName();
1039 if (pItem->m_iDriveType != CMediaSource::SOURCE_TYPE_REMOTE) // Local shares incl. dvd drive
1040 idMessageText=15300;
1041 else if (url.GetProtocol() == "smb" && strHostName.IsEmpty()) // smb workgroup
1042 idMessageText=15303;
1043 else // All other remote shares
1044 idMessageText=15301;
1046 CGUIDialogOK::ShowAndGetInput(220, idMessageText, 0, 0);
1050 // \brief The functon goes up one level in the directory tree
1051 void CGUIMediaWindow::GoParentFolder()
1053 //m_history.DumpPathHistory();
1055 // remove current directory if its on the stack
1056 // there were some issues due some folders having a trailing slash and some not
1057 // so just add a trailing slash to all of them for comparison.
1058 CStdString strPath = m_vecItems->GetPath();
1059 URIUtils::AddSlashAtEnd(strPath);
1060 CStdString strParent = m_history.GetParentPath();
1061 // in case the path history is messed up and the current folder is on
1062 // the stack more than once, keep going until there's nothing left or they
1063 // dont match anymore.
1064 while (!strParent.IsEmpty())
1066 URIUtils::AddSlashAtEnd(strParent);
1067 if (strParent.Equals(strPath))
1068 m_history.RemoveParentPath();
1071 strParent = m_history.GetParentPath();
1074 // if vector is not empty, pop parent
1075 // if vector is empty, parent is root source listing
1076 CStdString strOldPath(m_vecItems->GetPath());
1077 strParent = m_history.RemoveParentPath();
1081 // \brief Override the function to change the default behavior on how
1082 // a selected item history should look like
1083 void CGUIMediaWindow::GetDirectoryHistoryString(const CFileItem* pItem, CStdString& strHistoryString)
1085 if (pItem->m_bIsShareOrDrive)
1087 // We are in the virual directory
1089 // History string of the DVD drive
1090 // must be handel separately
1091 if (pItem->m_iDriveType == CMediaSource::SOURCE_TYPE_DVD)
1093 // Remove disc label from item label
1094 // and use as history string, m_strPath
1095 // can change for new discs
1096 CStdString strLabel = pItem->GetLabel();
1097 int nPosOpen = strLabel.Find('(');
1098 int nPosClose = strLabel.ReverseFind(')');
1099 if (nPosOpen > -1 && nPosClose > -1 && nPosClose > nPosOpen)
1101 strLabel.Delete(nPosOpen + 1, (nPosClose) - (nPosOpen + 1));
1102 strHistoryString = strLabel;
1105 strHistoryString = strLabel;
1109 // Other items in virual directory
1110 CStdString strPath = pItem->GetPath();
1111 URIUtils::RemoveSlashAtEnd(strPath);
1113 strHistoryString = pItem->GetLabel() + strPath;
1116 else if (pItem->m_lEndOffset>pItem->m_lStartOffset && pItem->m_lStartOffset != -1)
1118 // Could be a cue item, all items of a cue share the same filename
1119 // so add the offsets to build the history string
1120 strHistoryString.Format("%ld%ld", pItem->m_lStartOffset, pItem->m_lEndOffset);
1121 strHistoryString += pItem->GetPath();
1125 // Normal directory items
1126 strHistoryString = pItem->GetPath();
1128 URIUtils::RemoveSlashAtEnd(strHistoryString);
1129 strHistoryString.ToLower();
1132 // \brief Call this function to create a directory history for the
1133 // path given by strDirectory.
1134 void CGUIMediaWindow::SetHistoryForPath(const CStdString& strDirectory)
1136 // Make sure our shares are configured
1138 if (!strDirectory.IsEmpty())
1140 // Build the directory history for default path
1141 CStdString strPath, strParentPath;
1142 strPath = strDirectory;
1143 URIUtils::RemoveSlashAtEnd(strPath);
1145 CFileItemList items;
1146 m_rootDir.GetDirectory("", items);
1148 m_history.ClearPathHistory();
1150 while (URIUtils::GetParentPath(strPath, strParentPath))
1152 for (int i = 0; i < (int)items.Size(); ++i)
1154 CFileItemPtr pItem = items[i];
1155 CStdString path(pItem->GetPath());
1156 URIUtils::RemoveSlashAtEnd(path);
1157 if (path == strPath)
1159 CStdString strHistory;
1160 GetDirectoryHistoryString(pItem.get(), strHistory);
1161 m_history.SetSelectedItem(strHistory, "");
1162 URIUtils::AddSlashAtEnd(strPath);
1163 m_history.AddPathFront(strPath);
1164 m_history.AddPathFront("");
1166 //m_history.DumpPathHistory();
1171 URIUtils::AddSlashAtEnd(strPath);
1172 m_history.AddPathFront(strPath);
1173 m_history.SetSelectedItem(strPath, strParentPath);
1174 strPath = strParentPath;
1175 URIUtils::RemoveSlashAtEnd(strPath);
1179 m_history.ClearPathHistory();
1181 //m_history.DumpPathHistory();
1184 // \brief Override if you want to change the default behavior, what is done
1185 // when the user clicks on a file.
1186 // This function is called by OnClick()
1187 bool CGUIMediaWindow::OnPlayMedia(int iItem)
1189 // Reset Playlistplayer, playback started now does
1190 // not use the playlistplayer.
1191 g_playlistPlayer.Reset();
1192 g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_NONE);
1193 CFileItemPtr pItem=m_vecItems->Get(iItem);
1195 bool bResult = false;
1196 if (pItem->IsInternetStream() || pItem->IsPlayList())
1197 bResult = g_application.PlayMedia(*pItem, m_guiState->GetPlaylist());
1199 bResult = g_application.PlayFile(*pItem);
1201 if (pItem->m_lStartOffset == STARTOFFSET_RESUME)
1202 pItem->m_lStartOffset = 0;
1207 // \brief Override if you want to change the default behavior of what is done
1208 // when the user clicks on a file in a "folder" with similar files.
1209 // This function is called by OnClick()
1210 bool CGUIMediaWindow::OnPlayAndQueueMedia(const CFileItemPtr &item)
1212 //play and add current directory to temporary playlist
1213 int iPlaylist = m_guiState->GetPlaylist();
1214 if (iPlaylist != PLAYLIST_NONE)
1216 g_playlistPlayer.ClearPlaylist(iPlaylist);
1217 g_playlistPlayer.Reset();
1218 int mediaToPlay = 0;
1219 CFileItemList queueItems;
1220 for ( int i = 0; i < m_vecItems->Size(); i++ )
1222 CFileItemPtr nItem = m_vecItems->Get(i);
1224 if (nItem->m_bIsFolder)
1227 if (!nItem->IsPlayList() && !nItem->IsZIP() && !nItem->IsRAR())
1228 queueItems.Add(nItem);
1231 { // item that was clicked
1232 mediaToPlay = queueItems.Size() - 1;
1235 g_playlistPlayer.Add(iPlaylist, queueItems);
1237 // Save current window and directory to know where the selected item was
1238 if (m_guiState.get())
1239 m_guiState->SetPlaylistDirectory(m_vecItems->GetPath());
1241 // figure out where we start playback
1242 if (g_playlistPlayer.IsShuffled(iPlaylist))
1244 int iIndex = g_playlistPlayer.GetPlaylist(iPlaylist).FindOrder(mediaToPlay);
1245 g_playlistPlayer.GetPlaylist(iPlaylist).Swap(0, iIndex);
1250 g_playlistPlayer.SetCurrentPlaylist(iPlaylist);
1251 g_playlistPlayer.Play(mediaToPlay);
1256 // \brief Synchonize the fileitems with the playlistplayer
1257 // It recreated the playlist of the playlistplayer based
1258 // on the fileitems of the window
1259 void CGUIMediaWindow::UpdateFileList()
1261 int nItem = m_viewControl.GetSelectedItem();
1262 CStdString strSelected;
1264 strSelected = m_vecItems->Get(nItem)->GetPath();
1266 FormatAndSort(*m_vecItems);
1269 m_viewControl.SetItems(*m_vecItems);
1270 m_viewControl.SetSelectedItem(strSelected);
1272 // set the currently playing item as selected, if its in this directory
1273 if (m_guiState.get() && m_guiState->IsCurrentPlaylistDirectory(m_vecItems->GetPath()))
1275 int iPlaylist=m_guiState->GetPlaylist();
1276 int nSong = g_playlistPlayer.GetCurrentSong();
1277 CFileItem playlistItem;
1278 if (nSong > -1 && iPlaylist > -1)
1279 playlistItem=*g_playlistPlayer.GetPlaylist(iPlaylist)[nSong];
1281 g_playlistPlayer.ClearPlaylist(iPlaylist);
1282 g_playlistPlayer.Reset();
1284 for (int i = 0; i < m_vecItems->Size(); i++)
1286 CFileItemPtr pItem = m_vecItems->Get(i);
1287 if (pItem->m_bIsFolder)
1290 if (!pItem->IsPlayList() && !pItem->IsZIP() && !pItem->IsRAR())
1291 g_playlistPlayer.Add(iPlaylist, pItem);
1293 if (pItem->GetPath() == playlistItem.GetPath() &&
1294 pItem->m_lStartOffset == playlistItem.m_lStartOffset)
1295 g_playlistPlayer.SetCurrentSong(g_playlistPlayer.GetPlaylist(iPlaylist).size() - 1);
1300 void CGUIMediaWindow::OnDeleteItem(int iItem)
1302 if ( iItem < 0 || iItem >= m_vecItems->Size()) return;
1303 CFileItemPtr item = m_vecItems->Get(iItem);
1305 if (item->IsPlayList())
1306 item->m_bIsFolder = false;
1308 if (g_settings.GetCurrentProfile().getLockMode() != LOCK_MODE_EVERYONE && g_settings.GetCurrentProfile().filesLocked())
1309 if (!g_passwordManager.IsMasterLockUnlocked(true))
1312 if (!CFileUtils::DeleteItem(item))
1314 m_vecItems->RemoveDiscCache(GetID());
1315 Update(m_vecItems->GetPath());
1316 m_viewControl.SetSelectedItem(iItem);
1319 void CGUIMediaWindow::OnRenameItem(int iItem)
1321 if ( iItem < 0 || iItem >= m_vecItems->Size()) return;
1323 if (g_settings.GetCurrentProfile().getLockMode() != LOCK_MODE_EVERYONE && g_settings.GetCurrentProfile().filesLocked())
1324 if (!g_passwordManager.IsMasterLockUnlocked(true))
1327 if (!CFileUtils::RenameFile(m_vecItems->Get(iItem)->GetPath()))
1329 m_vecItems->RemoveDiscCache(GetID());
1330 Update(m_vecItems->GetPath());
1331 m_viewControl.SetSelectedItem(iItem);
1334 void CGUIMediaWindow::OnInitWindow()
1336 // initial fetch is done unthreaded to ensure the items are setup prior to skin animations kicking off
1337 m_rootDir.SetAllowThreads(false);
1338 Update(m_vecItems->GetPath());
1339 m_rootDir.SetAllowThreads(true);
1341 if (m_iSelectedItem > -1)
1342 m_viewControl.SetSelectedItem(m_iSelectedItem);
1344 CGUIWindow::OnInitWindow();
1347 CGUIControl *CGUIMediaWindow::GetFirstFocusableControl(int id)
1349 if (m_viewControl.HasControl(id))
1350 id = m_viewControl.GetCurrentControl();
1351 return CGUIWindow::GetFirstFocusableControl(id);
1354 void CGUIMediaWindow::SetupShares()
1356 // Setup shares and filemasks for this window
1357 CFileItemList items;
1358 CGUIViewState* viewState=CGUIViewState::GetViewState(GetID(), items);
1361 m_rootDir.SetMask(viewState->GetExtensions());
1362 m_rootDir.SetSources(viewState->GetSources());
1367 bool CGUIMediaWindow::OnPopupMenu(int iItem)
1369 // popup the context menu
1370 // grab our context menu
1371 CContextButtons buttons;
1372 GetContextButtons(iItem, buttons);
1377 if (iItem >= 0 && iItem < m_vecItems->Size())
1378 m_vecItems->Get(iItem)->Select(true);
1380 int choice = CGUIDialogContextMenu::ShowAndGetChoice(buttons);
1382 // deselect our item
1383 if (iItem >= 0 && iItem < m_vecItems->Size())
1384 m_vecItems->Get(iItem)->Select(false);
1387 return OnContextButton(iItem, (CONTEXT_BUTTON)choice);
1392 void CGUIMediaWindow::GetContextButtons(int itemNumber, CContextButtons &buttons)
1394 CFileItemPtr item = (itemNumber >= 0 && itemNumber < m_vecItems->Size()) ? m_vecItems->Get(itemNumber) : CFileItemPtr();
1399 // user added buttons
1402 for (int i = CONTEXT_BUTTON_USER1; i <= CONTEXT_BUTTON_USER10; i++)
1404 label.Format("contextmenulabel(%i)", i - CONTEXT_BUTTON_USER1);
1405 if (item->GetProperty(label).empty())
1408 action.Format("contextmenuaction(%i)", i - CONTEXT_BUTTON_USER1);
1409 if (item->GetProperty(action).empty())
1412 buttons.Add((CONTEXT_BUTTON)i, item->GetProperty(label).asString());
1415 if (item->GetProperty("pluginreplacecontextitems").asBoolean())
1418 // TODO: FAVOURITES Conditions on masterlock and localisation
1419 if (!item->IsParentFolder() && !item->GetPath().Equals("add") && !item->GetPath().Equals("newplaylist://") &&
1420 !item->GetPath().Left(19).Equals("newsmartplaylist://") && !item->IsAddonsPath())
1422 if (CFavourites::IsFavourite(item.get(), GetID()))
1423 buttons.Add(CONTEXT_BUTTON_ADD_FAVOURITE, 14077); // Remove Favourite
1425 buttons.Add(CONTEXT_BUTTON_ADD_FAVOURITE, 14076); // Add To Favourites;
1429 bool CGUIMediaWindow::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
1433 case CONTEXT_BUTTON_ADD_FAVOURITE:
1435 CFileItemPtr item = m_vecItems->Get(itemNumber);
1436 CFavourites::AddOrRemove(item.get(), GetID());
1439 case CONTEXT_BUTTON_PLUGIN_SETTINGS:
1441 CURL plugin(m_vecItems->Get(itemNumber)->GetPath());
1442 ADDON::AddonPtr addon;
1443 if (CAddonMgr::Get().GetAddon(plugin.GetHostName(), addon, ADDON_PLUGIN))
1444 if (CGUIDialogAddonSettings::ShowAndGetInput(addon))
1445 Update(m_vecItems->GetPath());
1448 case CONTEXT_BUTTON_USER1:
1449 case CONTEXT_BUTTON_USER2:
1450 case CONTEXT_BUTTON_USER3:
1451 case CONTEXT_BUTTON_USER4:
1452 case CONTEXT_BUTTON_USER5:
1453 case CONTEXT_BUTTON_USER6:
1454 case CONTEXT_BUTTON_USER7:
1455 case CONTEXT_BUTTON_USER8:
1456 case CONTEXT_BUTTON_USER9:
1457 case CONTEXT_BUTTON_USER10:
1460 action.Format("contextmenuaction(%i)", button - CONTEXT_BUTTON_USER1);
1461 g_application.getApplicationMessenger().ExecBuiltIn(m_vecItems->Get(itemNumber)->GetProperty(action).asString());
1470 const CGUIViewState *CGUIMediaWindow::GetViewState() const
1472 return m_guiState.get();
1475 const CFileItemList& CGUIMediaWindow::CurrentDirectory() const
1480 bool CGUIMediaWindow::WaitForNetwork() const
1482 if (g_application.getNetwork().IsAvailable())
1485 CGUIDialogProgress *progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
1489 CURL url(m_vecItems->GetPath());
1490 progress->SetHeading(1040); // Loading Directory
1491 progress->SetLine(1, url.GetWithoutUserDetails());
1492 progress->ShowProgressBar(false);
1493 progress->StartModal();
1494 while (!g_application.getNetwork().IsAvailable())
1496 progress->Progress();
1497 if (progress->IsCanceled())
1507 void CGUIMediaWindow::OnFilterItems(const CStdString &filter)
1509 CStdString currentItem;
1510 int item = m_viewControl.GetSelectedItem();
1512 currentItem = m_vecItems->Get(item)->GetPath();
1514 m_viewControl.Clear();
1516 CFileItemList items;
1517 GetFilteredItems(filter, items);
1518 if (filter.IsEmpty() || items.GetObjectCount() > 0)
1520 m_vecItems->ClearItems();
1521 m_vecItems->Append(items);
1522 SetProperty("filter", filter);
1525 // and update our view control + buttons
1526 m_viewControl.SetItems(*m_vecItems);
1527 m_viewControl.SetSelectedItem(currentItem);
1531 void CGUIMediaWindow::GetFilteredItems(const CStdString &filter, CFileItemList &items)
1533 CStdString trimmedFilter(filter);
1534 trimmedFilter.TrimLeft().ToLower();
1536 if (trimmedFilter.IsEmpty())
1538 items.Append(*m_unfilteredItems);
1542 bool numericMatch = StringUtils::IsNaturalNumber(trimmedFilter);
1543 for (int i = 0; i < m_unfilteredItems->Size(); i++)
1545 CFileItemPtr item = m_unfilteredItems->Get(i);
1546 if (item->IsParentFolder())
1551 // TODO: Need to update this to get all labels, ideally out of the displayed info (ie from m_layout and m_focusedLayout)
1552 // though that isn't practical. Perhaps a better idea would be to just grab the info that we should filter on based on
1553 // where we are in the library tree.
1554 // Another idea is tying the filter string to the current level of the tree, so that going deeper disables the filter,
1555 // but it's re-enabled on the way back out.
1557 /* if (item->GetFocusedLayout())
1558 match = item->GetFocusedLayout()->GetAllText();
1559 else if (item->GetLayout())
1560 match = item->GetLayout()->GetAllText();
1562 match = item->GetLabel(); // Filter label only for now
1565 StringUtils::WordToDigits(match);
1567 size_t pos = StringUtils::FindWords(match.c_str(), trimmedFilter.c_str());
1568 if (pos != CStdString::npos)
1573 CStdString CGUIMediaWindow::GetStartFolder(const CStdString &dir)
1575 if (dir.Equals("$ROOT") || dir.Equals("Root"))