remove incorrect 'add source' entries
[vuplus_xbmc] / xbmc / windows / GUIMediaWindow.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "threads/SystemClock.h"
22 #include "GUIMediaWindow.h"
23 #include "GUIUserMessages.h"
24 #include "Util.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 "ApplicationMessenger.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"
43 #include "URL.h"
44
45 #include "dialogs/GUIDialogSmartPlaylistEditor.h"
46 #include "addons/GUIDialogAddonSettings.h"
47 #include "dialogs/GUIDialogYesNo.h"
48 #include "guilib/GUIWindowManager.h"
49 #include "dialogs/GUIDialogOK.h"
50 #include "playlists/PlayList.h"
51 #include "storage/MediaManager.h"
52 #include "settings/Settings.h"
53 #include "utils/StringUtils.h"
54 #include "utils/URIUtils.h"
55 #include "guilib/LocalizeStrings.h"
56 #include "utils/TimeUtils.h"
57 #include "filesystem/File.h"
58 #include "filesystem/FileDirectoryFactory.h"
59 #include "utils/log.h"
60 #include "utils/FileUtils.h"
61 #include "guilib/GUIEditControl.h"
62 #include "guilib/GUIKeyboardFactory.h"
63 #ifdef HAS_PYTHON
64 #include "interfaces/python/XBPython.h"
65 #endif
66 #include "interfaces/Builtins.h"
67 #include "dialogs/GUIDialogKaiToast.h"
68 #include "dialogs/GUIDialogMediaFilter.h"
69 #include "filesystem/SmartPlaylistDirectory.h"
70 #if defined(TARGET_ANDROID)
71 #include "xbmc/android/activity/XBMCApp.h"
72 #endif
73
74 #define CONTROL_BTNVIEWASICONS       2
75 #define CONTROL_BTNSORTBY            3
76 #define CONTROL_BTNSORTASC           4
77 #define CONTROL_BTN_FILTER          19
78
79 #define CONTROL_LABELFILES          12
80
81 #define PROPERTY_PATH_DB            "path.db"
82 #define PROPERTY_SORT_ORDER         "sort.order"
83 #define PROPERTY_SORT_ASCENDING     "sort.ascending"
84
85 using namespace std;
86 using namespace ADDON;
87
88 CGUIMediaWindow::CGUIMediaWindow(int id, const char *xmlFile)
89     : CGUIWindow(id, xmlFile)
90 {
91   m_loadType = KEEP_IN_MEMORY;
92   m_vecItems = new CFileItemList;
93   m_unfilteredItems = new CFileItemList;
94   m_vecItems->SetPath("?");
95   m_iLastControl = -1;
96   m_iSelectedItem = -1;
97   m_canFilterAdvanced = false;
98
99   m_guiState.reset(CGUIViewState::GetViewState(GetID(), *m_vecItems));
100 }
101
102 CGUIMediaWindow::~CGUIMediaWindow()
103 {
104   delete m_vecItems;
105   delete m_unfilteredItems;
106 }
107
108 #define CONTROL_VIEW_START        50
109 #define CONTROL_VIEW_END          59
110
111 void CGUIMediaWindow::LoadAdditionalTags(TiXmlElement *root)
112 {
113   CGUIWindow::LoadAdditionalTags(root);
114   // configure our view control
115   m_viewControl.Reset();
116   m_viewControl.SetParentWindow(GetID());
117   TiXmlElement *element = root->FirstChildElement("views");
118   if (element && element->FirstChild())
119   { // format is <views>50,29,51,95</views>
120     CStdString allViews = element->FirstChild()->Value();
121     CStdStringArray views;
122     StringUtils::SplitString(allViews, ",", views);
123     for (unsigned int i = 0; i < views.size(); i++)
124     {
125       int controlID = atol(views[i].c_str());
126       CGUIControl *control = (CGUIControl *)GetControl(controlID);
127       if (control && control->IsContainer())
128         m_viewControl.AddView(control);
129     }
130   }
131   else
132   { // backward compatibility
133     vector<CGUIControl *> controls;
134     GetContainers(controls);
135     for (ciControls it = controls.begin(); it != controls.end(); it++)
136     {
137       CGUIControl *control = *it;
138       if (control->GetID() >= CONTROL_VIEW_START && control->GetID() <= CONTROL_VIEW_END)
139         m_viewControl.AddView(control);
140     }
141   }
142   m_viewControl.SetViewControlID(CONTROL_BTNVIEWASICONS);
143 }
144
145 void CGUIMediaWindow::OnWindowLoaded()
146 {
147   SendMessage(GUI_MSG_SET_TYPE, CONTROL_BTN_FILTER, CGUIEditControl::INPUT_TYPE_FILTER);
148   CGUIWindow::OnWindowLoaded();
149   SetupShares();
150 }
151
152 void CGUIMediaWindow::OnWindowUnload()
153 {
154   CGUIWindow::OnWindowUnload();
155   m_viewControl.Reset();
156 }
157
158 CFileItemPtr CGUIMediaWindow::GetCurrentListItem(int offset)
159 {
160   int item = m_viewControl.GetSelectedItem();
161   if (!m_vecItems->Size() || item < 0)
162     return CFileItemPtr();
163   item = (item + offset) % m_vecItems->Size();
164   if (item < 0) item += m_vecItems->Size();
165   return m_vecItems->Get(item);
166 }
167
168 bool CGUIMediaWindow::OnAction(const CAction &action)
169 {
170   if (action.GetID() == ACTION_PARENT_DIR)
171   {
172     GoParentFolder();
173     return true;
174   }
175
176   // the non-contextual menu can be called at any time
177   if (action.GetID() == ACTION_CONTEXT_MENU && !m_viewControl.HasControl(GetFocusedControlID()))
178   {
179     OnPopupMenu(-1);
180     return true;
181   }
182
183   if (CGUIWindow::OnAction(action))
184     return true;
185
186   if (action.GetID() == ACTION_FILTER)
187     return Filter();
188
189   // live filtering
190   if (action.GetID() == ACTION_FILTER_CLEAR)
191   {
192     CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS);
193     message.SetStringParam("");
194     OnMessage(message);
195     return true;
196   }
197
198   if (action.GetID() == ACTION_BACKSPACE)
199   {
200     CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS, 2); // 2 for delete
201     OnMessage(message);
202     return true;
203   }
204
205   if (action.GetID() >= ACTION_FILTER_SMS2 && action.GetID() <= ACTION_FILTER_SMS9)
206   {
207     CStdString filter;
208     filter.Format("%i", (int)(action.GetID() - ACTION_FILTER_SMS2 + 2));
209     CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS, 1); // 1 for append
210     message.SetStringParam(filter);
211     OnMessage(message);
212     return true;
213   }
214
215   return false;
216 }
217
218 bool CGUIMediaWindow::OnBack(int actionID)
219 {
220   CURL filterUrl(m_strFilterPath);
221   if (actionID == ACTION_NAV_BACK && !m_vecItems->IsVirtualDirectoryRoot() &&
222      (m_vecItems->GetPath() != m_startDirectory || (m_canFilterAdvanced && filterUrl.HasOption("filter"))))
223   {
224     GoParentFolder();
225     return true;
226   }
227   return CGUIWindow::OnBack(actionID);
228 }
229
230 bool CGUIMediaWindow::OnMessage(CGUIMessage& message)
231 {
232   switch ( message.GetMessage() )
233   {
234   case GUI_MSG_WINDOW_DEINIT:
235     {
236       m_iSelectedItem = m_viewControl.GetSelectedItem();
237       m_iLastControl = GetFocusedControlID();
238       CGUIWindow::OnMessage(message);
239       CGUIDialogContextMenu* pDlg = (CGUIDialogContextMenu*)g_windowManager.GetWindow(WINDOW_DIALOG_CONTEXT_MENU);
240       if (pDlg && pDlg->IsActive())
241         pDlg->Close();
242
243       // get rid of any active filtering
244       if (m_canFilterAdvanced)
245       {
246         m_canFilterAdvanced = false;
247         m_filter.Reset();
248       }
249       m_strFilterPath.clear();
250       
251       // Call ClearFileItems() after our window has finished doing any WindowClose
252       // animations
253       ClearFileItems();
254       return true;
255     }
256     break;
257
258   case GUI_MSG_CLICKED:
259     {
260       int iControl = message.GetSenderId();
261       if (iControl == CONTROL_BTNVIEWASICONS)
262       {
263         // view as control could be a select button
264         int viewMode = 0;
265         const CGUIControl *control = GetControl(CONTROL_BTNVIEWASICONS);
266         if (control && control->GetControlType() != CGUIControl::GUICONTROL_BUTTON)
267         {
268           CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_BTNVIEWASICONS);
269           OnMessage(msg);
270           viewMode = m_viewControl.GetViewModeNumber(msg.GetParam1());
271         }
272         else
273           viewMode = m_viewControl.GetNextViewMode();
274
275         if (m_guiState.get())
276           m_guiState->SaveViewAsControl(viewMode);
277
278         UpdateButtons();
279         return true;
280       }
281       else if (iControl == CONTROL_BTNSORTASC) // sort asc
282       {
283         if (m_guiState.get())
284           m_guiState->SetNextSortOrder();
285         UpdateFileList();
286         return true;
287       }
288       else if (iControl == CONTROL_BTNSORTBY) // sort by
289       {
290         if (m_guiState.get())
291           m_guiState->SetNextSortMethod();
292         UpdateFileList();
293         return true;
294       }
295       else if (iControl == CONTROL_BTN_FILTER)
296       {
297         if (m_canFilterAdvanced)
298           return true;
299
300         return Filter();
301       }
302       else if (m_viewControl.HasControl(iControl))  // list/thumb control
303       {
304         int iItem = m_viewControl.GetSelectedItem();
305         int iAction = message.GetParam1();
306         if (iItem < 0) break;
307         if (iAction == ACTION_SELECT_ITEM || iAction == ACTION_MOUSE_LEFT_CLICK)
308         {
309           OnSelect(iItem);
310         }
311         else if (iAction == ACTION_CONTEXT_MENU || iAction == ACTION_MOUSE_RIGHT_CLICK)
312         {
313           OnPopupMenu(iItem);
314           return true;
315         }
316       }
317     }
318     break;
319
320   case GUI_MSG_SETFOCUS:
321     {
322       if (m_viewControl.HasControl(message.GetControlId()) && m_viewControl.GetCurrentControl() != message.GetControlId())
323       {
324         m_viewControl.SetFocused();
325         return true;
326       }
327     }
328     break;
329
330   case GUI_MSG_NOTIFY_ALL:
331     { // Message is received even if this window is inactive
332       if (message.GetParam1() == GUI_MSG_WINDOW_RESET)
333       {
334         m_vecItems->SetPath("?");
335         return true;
336       }
337       else if ( message.GetParam1() == GUI_MSG_REFRESH_THUMBS )
338       {
339         for (int i = 0; i < m_vecItems->Size(); i++)
340           m_vecItems->Get(i)->FreeMemory(true);
341         break;  // the window will take care of any info images
342       }
343       else if (message.GetParam1() == GUI_MSG_REMOVED_MEDIA)
344       {
345         if ((m_vecItems->IsVirtualDirectoryRoot() ||
346              m_vecItems->IsSourcesPath()) && IsActive())
347         {
348           int iItem = m_viewControl.GetSelectedItem();
349           Refresh();
350           m_viewControl.SetSelectedItem(iItem);
351         }
352         else if (m_vecItems->IsRemovable())
353         { // check that we have this removable share still
354           if (!m_rootDir.IsInSource(m_vecItems->GetPath()))
355           { // don't have this share any more
356             if (IsActive()) Update("");
357             else
358             {
359               m_history.ClearPathHistory();
360               m_vecItems->SetPath("");
361             }
362           }
363         }
364
365         return true;
366       }
367       else if (message.GetParam1()==GUI_MSG_UPDATE_SOURCES)
368       { // State of the sources changed, so update our view
369         if ((m_vecItems->IsVirtualDirectoryRoot() ||
370              m_vecItems->IsSourcesPath()) && IsActive())
371         {
372           int iItem = m_viewControl.GetSelectedItem();
373           Refresh();
374           m_viewControl.SetSelectedItem(iItem);
375         }
376         return true;
377       }
378       else if (message.GetParam1()==GUI_MSG_UPDATE && IsActive())
379       {
380         if (message.GetNumStringParams())
381         {
382           if (message.GetParam2()) // param2 is used for resetting the history
383             SetHistoryForPath(message.GetStringParam());
384
385           CFileItemList list(message.GetStringParam());
386           list.RemoveDiscCache(GetID());
387           Update(message.GetStringParam());
388         }
389         else
390           Refresh(true); // refresh the listing
391       }
392       else if (message.GetParam1()==GUI_MSG_UPDATE_ITEM && message.GetItem())
393       {
394         CFileItemPtr newItem = boost::static_pointer_cast<CFileItem>(message.GetItem());
395         if (IsActive())
396         {
397           if (m_vecItems->UpdateItem(newItem.get()) && message.GetParam2() == 1)
398           { // need the list updated as well
399             UpdateFileList();
400           }
401         }
402         else if (newItem)
403         { // need to remove the disc cache
404           CFileItemList items;
405           CStdString path;
406           URIUtils::GetDirectory(newItem->GetPath(), path);
407           items.SetPath(path);
408           items.RemoveDiscCache(GetID());
409         }
410       }
411       else if (message.GetParam1()==GUI_MSG_UPDATE_PATH)
412       {
413         if (IsActive())
414         {
415           if((message.GetStringParam() == m_vecItems->GetPath()) ||
416              (m_vecItems->IsMultiPath() && XFILE::CMultiPathDirectory::HasPath(m_vecItems->GetPath(), message.GetStringParam())))
417             Refresh();
418         }
419       }
420       else if (message.GetParam1() == GUI_MSG_FILTER_ITEMS && IsActive())
421       {
422         CStdString filter;
423         // check if this is meant for advanced filtering
424         if (message.GetParam2() != 10)
425         {
426           filter = GetProperty("filter").asString();
427           if (message.GetParam2() == 1) // append
428             filter += message.GetStringParam();
429           else if (message.GetParam2() == 2)
430           { // delete
431             if (filter.size())
432               filter = filter.Left(filter.size() - 1);
433           }
434           else
435             filter = message.GetStringParam();
436         }
437         OnFilterItems(filter);
438         return true;
439       }
440       else
441         return CGUIWindow::OnMessage(message);
442
443       return true;
444     }
445     break;
446   case GUI_MSG_PLAYBACK_STARTED:
447   case GUI_MSG_PLAYBACK_ENDED:
448   case GUI_MSG_PLAYBACK_STOPPED:
449   case GUI_MSG_PLAYLIST_CHANGED:
450   case GUI_MSG_PLAYLISTPLAYER_STOPPED:
451   case GUI_MSG_PLAYLISTPLAYER_STARTED:
452   case GUI_MSG_PLAYLISTPLAYER_CHANGED:
453     { // send a notify all to all controls on this window
454       CGUIMessage msg(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_REFRESH_LIST);
455       OnMessage(msg);
456       break;
457     }
458   case GUI_MSG_CHANGE_VIEW_MODE:
459     {
460       int viewMode = 0;
461       if (message.GetParam1())  // we have an id
462         viewMode = m_viewControl.GetViewModeByID(message.GetParam1());
463       else if (message.GetParam2())
464         viewMode = m_viewControl.GetNextViewMode((int)message.GetParam2());
465
466       if (m_guiState.get())
467         m_guiState->SaveViewAsControl(viewMode);
468       UpdateButtons();
469       return true;
470     }
471     break;
472   case GUI_MSG_CHANGE_SORT_METHOD:
473     {
474       if (m_guiState.get())
475       {
476         if (message.GetParam1())
477           m_guiState->SetCurrentSortMethod((int)message.GetParam1());
478         else if (message.GetParam2())
479           m_guiState->SetNextSortMethod((int)message.GetParam2());
480       }
481       UpdateFileList();
482       return true;
483     }
484     break;
485   case GUI_MSG_CHANGE_SORT_DIRECTION:
486     {
487       if (m_guiState.get())
488         m_guiState->SetNextSortOrder();
489       UpdateFileList();
490       return true;
491     }
492     break;
493   case GUI_MSG_WINDOW_INIT:
494     {
495       if (m_vecItems->GetPath() == "?")
496         m_vecItems->SetPath("");
497       CStdString dir = message.GetStringParam(0);
498       const CStdString &ret = message.GetStringParam(1);
499       bool returning = ret.CompareNoCase("return") == 0;
500       if (!dir.IsEmpty())
501       {
502         m_history.ClearPathHistory();
503         // ensure our directory is valid
504         dir = GetStartFolder(dir);
505         if (!returning || m_vecItems->GetPath().Left(dir.GetLength()) != dir)
506         { // we're not returning to the same path, so set our directory to the requested path
507           m_vecItems->SetPath(dir);
508         }
509         // check for network up
510         if (URIUtils::IsRemote(m_vecItems->GetPath()) && !WaitForNetwork())
511           m_vecItems->SetPath("");
512         SetHistoryForPath(m_vecItems->GetPath());
513       }
514       if (message.GetParam1() != WINDOW_INVALID)
515       { // first time to this window - make sure we set the root path
516         m_startDirectory = returning ? dir : "";
517       }
518     }
519     break;
520   }
521
522   return CGUIWindow::OnMessage(message);
523 }
524
525 // \brief Updates the states (enable, disable, visible...)
526 // of the controls defined by this window
527 // Override this function in a derived class to add new controls
528 void CGUIMediaWindow::UpdateButtons()
529 {
530   if (m_guiState.get())
531   {
532     // Update sorting controls
533     if (m_guiState->GetDisplaySortOrder() == SortOrderNone)
534     {
535       CONTROL_DISABLE(CONTROL_BTNSORTASC);
536     }
537     else
538     {
539       CONTROL_ENABLE(CONTROL_BTNSORTASC);
540       if (m_guiState->GetDisplaySortOrder() == SortOrderAscending)
541       {
542         CGUIMessage msg(GUI_MSG_DESELECTED, GetID(), CONTROL_BTNSORTASC);
543         g_windowManager.SendMessage(msg);
544       }
545       else
546       {
547         CGUIMessage msg(GUI_MSG_SELECTED, GetID(), CONTROL_BTNSORTASC);
548         g_windowManager.SendMessage(msg);
549       }
550     }
551
552     // Update list/thumb control
553     m_viewControl.SetCurrentView(m_guiState->GetViewAsControl());
554
555     // Update sort by button
556     if (m_guiState->GetSortMethod()==SORT_METHOD_NONE)
557     {
558       CONTROL_DISABLE(CONTROL_BTNSORTBY);
559     }
560     else
561     {
562       CONTROL_ENABLE(CONTROL_BTNSORTBY);
563     }
564     CStdString sortLabel;
565     sortLabel.Format(g_localizeStrings.Get(550).c_str(), g_localizeStrings.Get(m_guiState->GetSortMethodLabel()).c_str());
566     SET_CONTROL_LABEL(CONTROL_BTNSORTBY, sortLabel);
567   }
568
569   CStdString items;
570   items.Format("%i %s", m_vecItems->GetObjectCount(), g_localizeStrings.Get(127).c_str());
571   SET_CONTROL_LABEL(CONTROL_LABELFILES, items);
572
573   if (!m_canFilterAdvanced)
574     SET_CONTROL_LABEL2(CONTROL_BTN_FILTER, GetProperty("filter").asString());
575 }
576
577 void CGUIMediaWindow::ClearFileItems()
578 {
579   m_viewControl.Clear();
580   m_vecItems->Clear();
581   m_unfilteredItems->Clear();
582 }
583
584 // \brief Sorts Fileitems based on the sort method and sort oder provided by guiViewState
585 void CGUIMediaWindow::SortItems(CFileItemList &items)
586 {
587   auto_ptr<CGUIViewState> guiState(CGUIViewState::GetViewState(GetID(), items));
588
589   if (guiState.get())
590   {
591     bool sorted = false;
592     SORT_METHOD sortMethod = guiState->GetSortMethod();
593     // If the sort method is "sort by playlist" and we have a specific
594     // sort order available we can use the specified sort order to do the sorting
595     // We do this as the new SortBy methods are a superset of the SORT_METHOD methods, thus
596     // not all are available. This may be removed once SORT_METHOD_* have been replaced by
597     // SortBy.
598     if ((sortMethod == SORT_METHOD_PLAYLIST_ORDER) && items.HasProperty(PROPERTY_SORT_ORDER))
599     {
600       SortBy sortBy = (SortBy)items.GetProperty(PROPERTY_SORT_ORDER).asInteger();
601       if (sortBy != SortByNone && sortBy != SortByPlaylistOrder && sortBy != SortByProgramCount)
602       {
603         SortDescription sorting;
604         sorting.sortBy = sortBy;
605         sorting.sortOrder = items.GetProperty(PROPERTY_SORT_ASCENDING).asBoolean() ? SortOrderAscending : SortOrderDescending;
606         sorting.sortAttributes = g_guiSettings.GetBool("filelists.ignorethewhensorting") ? SortAttributeIgnoreArticle : SortAttributeNone;
607
608         // if the sort order is descending, we need to switch the original sort order, as we assume
609         // in CGUIViewState::AddPlaylistOrder that SORT_METHOD_PLAYLIST_ORDER is ascending.
610         if (guiState->GetDisplaySortOrder() == SortOrderDescending)
611           sorting.sortOrder = sorting.sortOrder == SortOrderDescending ? SortOrderAscending : SortOrderDescending;
612
613         items.Sort(sorting);
614         sorted = true;
615       }
616     }
617
618     if (!sorted)
619       items.Sort(sortMethod, guiState->GetDisplaySortOrder());
620   }
621 }
622
623 // \brief Formats item labels based on the formatting provided by guiViewState
624 void CGUIMediaWindow::FormatItemLabels(CFileItemList &items, const LABEL_MASKS &labelMasks)
625 {
626   CLabelFormatter fileFormatter(labelMasks.m_strLabelFile, labelMasks.m_strLabel2File);
627   CLabelFormatter folderFormatter(labelMasks.m_strLabelFolder, labelMasks.m_strLabel2Folder);
628   for (int i=0; i<items.Size(); ++i)
629   {
630     CFileItemPtr pItem=items[i];
631
632     if (pItem->IsLabelPreformated())
633       continue;
634
635     if (pItem->m_bIsFolder)
636       folderFormatter.FormatLabels(pItem.get());
637     else
638       fileFormatter.FormatLabels(pItem.get());
639   }
640
641   if(items.GetSortMethod() == SORT_METHOD_LABEL_IGNORE_THE
642   || items.GetSortMethod() == SORT_METHOD_LABEL)
643     items.ClearSortState();
644 }
645
646 // \brief Prepares and adds the fileitems list/thumb panel
647 void CGUIMediaWindow::FormatAndSort(CFileItemList &items)
648 {
649   auto_ptr<CGUIViewState> viewState(CGUIViewState::GetViewState(GetID(), items));
650
651   if (viewState.get())
652   {
653     LABEL_MASKS labelMasks;
654     viewState->GetSortMethodLabelMasks(labelMasks);
655     FormatItemLabels(items, labelMasks);
656
657     items.Sort(viewState->GetSortMethod(), viewState->GetDisplaySortOrder());
658   }
659 }
660
661 /*!
662   \brief Overwrite to fill fileitems from a source
663   \param strDirectory Path to read
664   \param items Fill with items specified in \e strDirectory
665   */
666 bool CGUIMediaWindow::GetDirectory(const CStdString &strDirectory, CFileItemList &items)
667 {
668   // cleanup items
669   if (items.Size())
670     items.Clear();
671
672   CStdString strParentPath = m_history.GetParentPath();
673
674   CLog::Log(LOGDEBUG,"CGUIMediaWindow::GetDirectory (%s)", strDirectory.c_str());
675   CLog::Log(LOGDEBUG,"  ParentPath = [%s]", strParentPath.c_str());
676
677   // see if we can load a previously cached folder
678   CFileItemList cachedItems(strDirectory);
679   if (!strDirectory.IsEmpty() && cachedItems.Load(GetID()))
680   {
681     items.Assign(cachedItems);
682   }
683   else
684   {
685     unsigned int time = XbmcThreads::SystemClockMillis();
686
687     if (strDirectory.IsEmpty())
688       SetupShares();
689
690     if (!m_rootDir.GetDirectory(strDirectory, items))
691       return false;
692
693     // took over a second, and not normally cached, so cache it
694     if ((XbmcThreads::SystemClockMillis() - time) > 1000  && items.CacheToDiscIfSlow())
695       items.Save(GetID());
696
697     // if these items should replace the current listing, then pop it off the top
698     if (items.GetReplaceListing())
699       m_history.RemoveParentPath();
700   }
701
702   if (m_guiState.get() && !m_guiState->HideParentDirItems() && !items.GetPath().IsEmpty())
703   {
704     CFileItemPtr pItem(new CFileItem(".."));
705     pItem->SetPath(strParentPath);
706     pItem->m_bIsFolder = true;
707     pItem->m_bIsShareOrDrive = false;
708     items.AddFront(pItem, 0);
709   }
710
711   int iWindow = GetID();
712   CStdStringArray regexps;
713
714   // TODO: Do we want to limit the directories we apply the video ones to?
715   if (iWindow == WINDOW_VIDEO_NAV)
716     regexps = g_advancedSettings.m_videoExcludeFromListingRegExps;
717   if (iWindow == WINDOW_MUSIC_FILES)
718     regexps = g_advancedSettings.m_audioExcludeFromListingRegExps;
719   if (iWindow == WINDOW_PICTURES)
720     regexps = g_advancedSettings.m_pictureExcludeFromListingRegExps;
721
722   if (regexps.size())
723   {
724     for (int i=0; i < items.Size();)
725     {
726       if (CUtil::ExcludeFileOrFolder(items[i]->GetPath(), regexps))
727         items.Remove(i);
728       else
729         i++;
730     }
731   }
732
733   // clear the filter
734   SetProperty("filter", "");
735   m_canFilterAdvanced = false;
736   m_filter.Reset();
737   return true;
738 }
739
740 // \brief Set window to a specific directory
741 // \param strDirectory The directory to be displayed in list/thumb control
742 // This function calls OnPrepareFileItems() and OnFinalizeFileItems()
743 bool CGUIMediaWindow::Update(const CStdString &strDirectory, bool updateFilterPath /* = true */)
744 {
745   // TODO: OnInitWindow calls Update() before window path has been set properly.
746   if (strDirectory == "?")
747     return false;
748
749   // get selected item
750   int iItem = m_viewControl.GetSelectedItem();
751   CStdString strSelectedItem = "";
752   if (iItem >= 0 && iItem < m_vecItems->Size())
753   {
754     CFileItemPtr pItem = m_vecItems->Get(iItem);
755     if (!pItem->IsParentFolder())
756     {
757       GetDirectoryHistoryString(pItem.get(), strSelectedItem);
758     }
759   }
760   
761   CStdString strCurrentDirectory = m_vecItems->GetPath();
762   m_history.SetSelectedItem(strSelectedItem, strCurrentDirectory);
763
764   CStdString directory = strDirectory;
765   // check if the path contains a filter and temporarily remove it
766   // so that the retrieved list of items is unfiltered
767   bool canfilter = CanContainFilter(directory);
768   CStdString filter;
769   CURL url(directory);
770   if (canfilter && url.HasOption("filter"))
771   {
772     filter = url.GetOption("filter");
773     directory = RemoveParameterFromPath(directory, "filter");
774   }
775
776   CFileItemList items;
777   if (!GetDirectory(directory, items))
778   {
779     CLog::Log(LOGERROR,"CGUIMediaWindow::GetDirectory(%s) failed", strDirectory.c_str());
780     // if the directory is the same as the old directory, then we'll return
781     // false.  Else, we assume we can get the previous directory
782     if (strDirectory.Equals(strCurrentDirectory))
783       return false;
784
785     // We assume, we can get the parent
786     // directory again, but we have to
787     // return false to be able to eg. show
788     // an error message.
789     Update(m_history.RemoveParentPath());
790     return false;
791   }
792
793   if (items.GetLabel().IsEmpty())
794     items.SetLabel(CUtil::GetTitleFromPath(items.GetPath(), true));
795   
796   ClearFileItems();
797   m_vecItems->Copy(items);
798
799   // only set the filter path if it hasn't been marked
800   // as preset or if it's empty
801   if (updateFilterPath || m_strFilterPath.empty())
802   {
803     if (items.HasProperty(PROPERTY_PATH_DB))
804       m_strFilterPath = items.GetProperty(PROPERTY_PATH_DB).asString();
805     else
806       m_strFilterPath = items.GetPath();
807   }
808   
809   // maybe the filter path can contain a filter
810   if (!canfilter && CanContainFilter(m_strFilterPath))
811     canfilter = true;
812
813   // check if the filter path contains a filter
814   CURL filterPathUrl(m_strFilterPath);
815   if (canfilter && filter.empty())
816   {
817     if (filterPathUrl.HasOption("filter"))
818       filter = filterPathUrl.GetOption("filter");
819   }
820
821   // check if there is a filter and re-apply it
822   if (canfilter && !filter.empty())
823   {
824     if (!m_filter.LoadFromJson(filter))
825     {
826       CLog::Log(LOGWARNING, "CGUIMediaWindow::Update: unable to load existing filter (%s)", filter.c_str());
827       m_filter.Reset();
828       m_strFilterPath = m_vecItems->GetPath();
829     }
830     else
831     {
832       // add the filter to the filter path
833       filterPathUrl.SetOption("filter", filter);
834       m_strFilterPath = filterPathUrl.Get();
835     }
836   }
837     
838   // if we're getting the root source listing
839   // make sure the path history is clean
840   if (strDirectory.IsEmpty())
841     m_history.ClearPathHistory();
842
843   int iWindow = GetID();
844   int showLabel = 0;
845   if (strDirectory.IsEmpty())
846   {
847     if (iWindow == WINDOW_PICTURES)
848       showLabel = 997;
849     else if (iWindow == WINDOW_MUSIC_FILES)
850       showLabel = 998;
851     else if (iWindow == WINDOW_FILES || iWindow == WINDOW_PROGRAMS)
852       showLabel = 1026;
853   }
854   if (strDirectory.Equals("sources://video/"))
855     showLabel = 999;
856   if (showLabel && (m_vecItems->Size() == 0 || !m_guiState->DisableAddSourceButtons())) // add 'add source button'
857   {
858     CStdString strLabel = g_localizeStrings.Get(showLabel);
859     CFileItemPtr pItem(new CFileItem(strLabel));
860     pItem->SetPath("add");
861     pItem->SetIconImage("DefaultAddSource.png");
862     pItem->SetLabel(strLabel);
863     pItem->SetLabelPreformated(true);
864     pItem->m_bIsFolder = true;
865     pItem->SetSpecialSort(SortSpecialOnBottom);
866     m_vecItems->Add(pItem);
867   }
868   m_iLastControl = GetFocusedControlID();
869
870   // Check whether to enabled advanced filtering based on the content type
871   m_canFilterAdvanced = CheckFilterAdvanced(*m_vecItems);
872   if (m_canFilterAdvanced)
873     m_filter.SetType(m_vecItems->GetContent());
874
875   //  Ask the derived class if it wants to load additional info
876   //  for the fileitems like media info or additional
877   //  filtering on the items, setting thumbs.
878   OnPrepareFileItems(*m_vecItems);
879
880   m_vecItems->FillInDefaultIcons();
881
882   m_guiState.reset(CGUIViewState::GetViewState(GetID(), *m_vecItems));
883
884   // remember the original (untouched) list of items (for filtering etc)
885   m_unfilteredItems->SetPath(m_vecItems->GetPath()); // use the original path - it'll likely be relied on for other things later.
886   m_unfilteredItems->Append(*m_vecItems);
887
888   // Cache the list of items if possible
889   OnCacheFileItems(*m_vecItems);
890
891   // Filter and group the items if necessary
892   CStdString titleFilter = GetProperty("filter").asString();
893   OnFilterItems(titleFilter);
894
895   // Ask the devived class if it wants to do custom list operations,
896   // eg. changing the label
897   OnFinalizeFileItems(*m_vecItems);
898   UpdateButtons();
899
900   strSelectedItem = m_history.GetSelectedItem(m_vecItems->GetPath());
901
902   bool bSelectedFound = false;
903   //int iSongInDirectory = -1;
904   for (int i = 0; i < m_vecItems->Size(); ++i)
905   {
906     CFileItemPtr pItem = m_vecItems->Get(i);
907
908     // Update selected item
909     CStdString strHistory;
910     GetDirectoryHistoryString(pItem.get(), strHistory);
911     if (strHistory == strSelectedItem)
912     {
913       m_viewControl.SetSelectedItem(i);
914       bSelectedFound = true;
915       break;
916     }
917   }
918
919   // if we haven't found the selected item, select the first item
920   if (!bSelectedFound)
921     m_viewControl.SetSelectedItem(0);
922
923   if (iWindow != WINDOW_PVR || (iWindow == WINDOW_PVR && m_vecItems->GetPath().Left(17) == "pvr://recordings/"))
924     m_history.AddPath(m_vecItems->GetPath(), m_strFilterPath);
925
926   //m_history.DumpPathHistory();
927
928   return true;
929 }
930
931 bool CGUIMediaWindow::Refresh(bool clearCache /* = false */)
932 {
933   CStdString strCurrentDirectory = m_vecItems->GetPath();
934   if (strCurrentDirectory.Equals("?"))
935     return false;
936
937   if (clearCache)
938     m_vecItems->RemoveDiscCache(GetID());
939
940   // get the original number of items
941   if (!Update(strCurrentDirectory, false))
942     return false;
943
944   return true;
945 }
946
947 // \brief This function will be called by Update() before the
948 // labels of the fileitems are formatted. Override this function
949 // to set custom thumbs or load additional media info.
950 // It's used to load tag info for music.
951 void CGUIMediaWindow::OnPrepareFileItems(CFileItemList &items)
952 {
953
954 }
955
956 // \brief This function will be called by Update() before
957 // any additional formatting, filtering or sorting is applied.
958 // Override this function to define a custom caching behaviour.
959 void CGUIMediaWindow::OnCacheFileItems(CFileItemList &items)
960 {
961   // Should these items be saved to the hdd
962   if (items.CacheToDiscAlways() && !IsFiltered())
963     items.Save(GetID());
964 }
965
966 // \brief This function will be called by Update() after the
967 // labels of the fileitems are formatted. Override this function
968 // to modify the fileitems. Eg. to modify the item label
969 void CGUIMediaWindow::OnFinalizeFileItems(CFileItemList &items)
970 {
971
972 }
973
974 // \brief With this function you can react on a users click in the list/thumb panel.
975 // It returns true, if the click is handled.
976 // This function calls OnPlayMedia()
977 bool CGUIMediaWindow::OnClick(int iItem)
978 {
979   if ( iItem < 0 || iItem >= (int)m_vecItems->Size() ) return true;
980   CFileItemPtr pItem = m_vecItems->Get(iItem);
981
982   if (pItem->IsParentFolder())
983   {
984     GoParentFolder();
985     return true;
986   }
987   if (pItem->GetPath() == "add" || pItem->GetPath() == "sources://add/") // 'add source button' in empty root
988   {
989     OnContextButton(iItem, CONTEXT_BUTTON_ADD_SOURCE);
990     return true;
991   }
992
993   if (!pItem->m_bIsFolder && pItem->IsFileFolder())
994   {
995     XFILE::IFileDirectory *pFileDirectory = NULL;
996     pFileDirectory = XFILE::CFileDirectoryFactory::Create(pItem->GetPath(), pItem.get(), "");
997     if(pFileDirectory)
998       pItem->m_bIsFolder = true;
999     else if(pItem->m_bIsFolder)
1000       pItem->m_bIsFolder = false;
1001     delete pFileDirectory;
1002   }
1003
1004   if (pItem->IsScript())
1005   {
1006     // execute the script
1007     CURL url(pItem->GetPath());
1008     AddonPtr addon;
1009     if (CAddonMgr::Get().GetAddon(url.GetHostName(), addon, ADDON_SCRIPT))
1010     {
1011 #ifdef HAS_PYTHON
1012       if (!g_pythonParser.StopScript(addon->LibPath()))
1013         g_pythonParser.evalFile(addon->LibPath(),addon);
1014 #endif
1015       return true;
1016     }
1017   }
1018
1019   if (pItem->m_bIsFolder)
1020   {
1021     if ( pItem->m_bIsShareOrDrive )
1022     {
1023       const CStdString& strLockType=m_guiState->GetLockType();
1024       if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE)
1025         if (!strLockType.IsEmpty() && !g_passwordManager.IsItemUnlocked(pItem.get(), strLockType))
1026             return true;
1027
1028       if (!HaveDiscOrConnection(pItem->GetPath(), pItem->m_iDriveType))
1029         return true;
1030     }
1031
1032     // check for the partymode playlist items - they may not exist yet
1033     if ((pItem->GetPath() == g_settings.GetUserDataItem("PartyMode.xsp")) ||
1034         (pItem->GetPath() == g_settings.GetUserDataItem("PartyMode-Video.xsp")))
1035     {
1036       // party mode playlist item - if it doesn't exist, prompt for user to define it
1037       if (!XFILE::CFile::Exists(pItem->GetPath()))
1038       {
1039         m_vecItems->RemoveDiscCache(GetID());
1040         if (CGUIDialogSmartPlaylistEditor::EditPlaylist(pItem->GetPath()))
1041           Refresh();
1042         return true;
1043       }
1044     }
1045
1046     // remove the directory cache if the folder is not normally cached
1047     CFileItemList items(pItem->GetPath());
1048     if (!items.AlwaysCache())
1049       items.RemoveDiscCache(GetID());
1050
1051     // if we have a filtered list, we need to add the filtered
1052     // path to be able to come back to the filtered view
1053     CStdString strCurrentDirectory = m_vecItems->GetPath();
1054     if (m_canFilterAdvanced && !m_filter.IsEmpty() &&
1055       !m_strFilterPath.Equals(strCurrentDirectory))
1056     {
1057       m_history.RemoveParentPath();
1058       m_history.AddPath(strCurrentDirectory, m_strFilterPath);
1059     }
1060
1061     CFileItem directory(*pItem);
1062     if (!Update(directory.GetPath()))
1063       ShowShareErrorMessage(&directory);
1064
1065     return true;
1066   }
1067   else if (pItem->IsPlugin() && !pItem->GetProperty("isplayable").asBoolean())
1068   {
1069     return XFILE::CPluginDirectory::RunScriptWithParams(pItem->GetPath());
1070   }
1071 #if defined(TARGET_ANDROID)
1072   else if (pItem->IsAndroidApp())
1073   {
1074     CStdString appName = URIUtils::GetFileName(pItem->GetPath());
1075     CLog::Log(LOGDEBUG, "CGUIMediaWindow::OnClick Trying to run: %s",appName.c_str());
1076     return CXBMCApp::StartActivity(appName);
1077   }
1078 #endif
1079   else
1080   {
1081     m_iSelectedItem = m_viewControl.GetSelectedItem();
1082
1083     if (pItem->GetPath() == "newplaylist://")
1084     {
1085       m_vecItems->RemoveDiscCache(GetID());
1086       g_windowManager.ActivateWindow(WINDOW_MUSIC_PLAYLIST_EDITOR,"newplaylist://");
1087       return true;
1088     }
1089     else if (pItem->GetPath().Left(19).Equals("newsmartplaylist://"))
1090     {
1091       m_vecItems->RemoveDiscCache(GetID());
1092       if (CGUIDialogSmartPlaylistEditor::NewPlaylist(pItem->GetPath().Mid(19)))
1093         Refresh();
1094       return true;
1095     }
1096     else if (pItem->GetPath().Left(14).Equals("addons://more/"))
1097     {
1098       CBuiltins::Execute("ActivateWindow(AddonBrowser,addons://all/xbmc.addon." + pItem->GetPath().Mid(14) + ",return)");
1099       return true;
1100     }
1101
1102     // If karaoke song is being played AND popup autoselector is enabled, the playlist should not be added
1103     bool do_not_add_karaoke = g_guiSettings.GetBool("karaoke.enabled") &&
1104       g_guiSettings.GetBool("karaoke.autopopupselector") && pItem->IsKaraoke();
1105     bool autoplay = m_guiState.get() && m_guiState->AutoPlayNextItem();
1106
1107     if (m_vecItems->IsPlugin())
1108     {
1109       CURL url(m_vecItems->GetPath());
1110       AddonPtr addon;
1111       if (CAddonMgr::Get().GetAddon(url.GetHostName(),addon))
1112       {
1113         PluginPtr plugin = boost::dynamic_pointer_cast<CPluginSource>(addon);
1114         if (plugin && plugin->Provides(CPluginSource::AUDIO))
1115         {
1116           CFileItemList items;
1117           auto_ptr<CGUIViewState> state(CGUIViewState::GetViewState(GetID(), items));
1118           autoplay = state.get() && state->AutoPlayNextItem();
1119         }
1120       }
1121     }
1122
1123     if (autoplay && !g_partyModeManager.IsEnabled() && 
1124         !pItem->IsPlayList() && !do_not_add_karaoke)
1125     {
1126       return OnPlayAndQueueMedia(pItem);
1127     }
1128     else
1129     {
1130       return OnPlayMedia(iItem);
1131     }
1132   }
1133
1134   return false;
1135 }
1136
1137 bool CGUIMediaWindow::OnSelect(int item)
1138 {
1139   return OnClick(item);
1140 }
1141
1142 // \brief Checks if there is a disc in the dvd drive and whether the
1143 // network is connected or not.
1144 bool CGUIMediaWindow::HaveDiscOrConnection(const CStdString& strPath, int iDriveType)
1145 {
1146   if (iDriveType==CMediaSource::SOURCE_TYPE_DVD)
1147   {
1148     if (!g_mediaManager.IsDiscInDrive(strPath))
1149     {
1150       CGUIDialogOK::ShowAndGetInput(218, 219, 0, 0);
1151       return false;
1152     }
1153   }
1154   else if (iDriveType==CMediaSource::SOURCE_TYPE_REMOTE)
1155   {
1156     // TODO: Handle not connected to a remote share
1157     if ( !g_application.getNetwork().IsConnected() )
1158     {
1159       CGUIDialogOK::ShowAndGetInput(220, 221, 0, 0);
1160       return false;
1161     }
1162   }
1163
1164   return true;
1165 }
1166
1167 // \brief Shows a standard errormessage for a given pItem.
1168 void CGUIMediaWindow::ShowShareErrorMessage(CFileItem* pItem)
1169 {
1170   if (pItem->m_bIsShareOrDrive)
1171   {
1172     int idMessageText=0;
1173     const CURL& url=pItem->GetAsUrl();
1174     const CStdString& strHostName=url.GetHostName();
1175
1176     if (pItem->m_iDriveType != CMediaSource::SOURCE_TYPE_REMOTE) //  Local shares incl. dvd drive
1177       idMessageText=15300;
1178     else if (url.GetProtocol() == "smb" && strHostName.IsEmpty()) //  smb workgroup
1179       idMessageText=15303;
1180     else  //  All other remote shares
1181       idMessageText=15301;
1182
1183     CGUIDialogOK::ShowAndGetInput(220, idMessageText, 0, 0);
1184   }
1185 }
1186
1187 // \brief The functon goes up one level in the directory tree
1188 void CGUIMediaWindow::GoParentFolder()
1189 {
1190   //m_history.DumpPathHistory();
1191
1192   // remove current directory if its on the stack
1193   // there were some issues due some folders having a trailing slash and some not
1194   // so just add a trailing slash to all of them for comparison.
1195   CStdString strPath = m_vecItems->GetPath();
1196   URIUtils::AddSlashAtEnd(strPath);
1197   CStdString strParent = m_history.GetParentPath();
1198   // in case the path history is messed up and the current folder is on
1199   // the stack more than once, keep going until there's nothing left or they
1200   // dont match anymore.
1201   while (!strParent.IsEmpty())
1202   {
1203     URIUtils::AddSlashAtEnd(strParent);
1204     if (strParent.Equals(strPath))
1205       m_history.RemoveParentPath();
1206     else
1207       break;
1208     strParent = m_history.GetParentPath();
1209   }
1210
1211   // remove the current filter but only if the parent
1212   // item doesn't have a filter as well
1213   CURL filterUrl(m_strFilterPath);
1214   if (filterUrl.HasOption("filter"))
1215   {
1216     CURL parentUrl(m_history.GetParentPath(true));
1217     if (!parentUrl.HasOption("filter"))
1218     {
1219       // we need to overwrite m_strFilterPath because
1220       // Refresh() will set updateFilterPath to false
1221       m_strFilterPath.clear();
1222       Refresh();
1223       return;
1224     }
1225   }
1226
1227   // if vector is not empty, pop parent
1228   // if vector is empty, parent is root source listing
1229   m_strFilterPath = m_history.GetParentPath(true);
1230   strParent = m_history.RemoveParentPath();
1231   if (!Update(strParent, false))
1232     return;
1233
1234   // No items to show so go another level up
1235   if (!m_vecItems->GetPath().empty() && (m_filter.IsEmpty() ? m_vecItems->Size() : m_unfilteredItems->Size()) <= 0)
1236   {
1237     CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, g_localizeStrings.Get(2080), g_localizeStrings.Get(2081));
1238     GoParentFolder();
1239   }
1240 }
1241
1242 // \brief Override the function to change the default behavior on how
1243 // a selected item history should look like
1244 void CGUIMediaWindow::GetDirectoryHistoryString(const CFileItem* pItem, CStdString& strHistoryString)
1245 {
1246   if (pItem->m_bIsShareOrDrive)
1247   {
1248     // We are in the virual directory
1249
1250     // History string of the DVD drive
1251     // must be handel separately
1252     if (pItem->m_iDriveType == CMediaSource::SOURCE_TYPE_DVD)
1253     {
1254       // Remove disc label from item label
1255       // and use as history string, m_strPath
1256       // can change for new discs
1257       CStdString strLabel = pItem->GetLabel();
1258       int nPosOpen = strLabel.Find('(');
1259       int nPosClose = strLabel.ReverseFind(')');
1260       if (nPosOpen > -1 && nPosClose > -1 && nPosClose > nPosOpen)
1261       {
1262         strLabel.Delete(nPosOpen + 1, (nPosClose) - (nPosOpen + 1));
1263         strHistoryString = strLabel;
1264       }
1265       else
1266         strHistoryString = strLabel;
1267     }
1268     else
1269     {
1270       // Other items in virual directory
1271       CStdString strPath = pItem->GetPath();
1272       URIUtils::RemoveSlashAtEnd(strPath);
1273
1274       strHistoryString = pItem->GetLabel() + strPath;
1275     }
1276   }
1277   else if (pItem->m_lEndOffset>pItem->m_lStartOffset && pItem->m_lStartOffset != -1)
1278   {
1279     // Could be a cue item, all items of a cue share the same filename
1280     // so add the offsets to build the history string
1281     strHistoryString.Format("%ld%ld", pItem->m_lStartOffset, pItem->m_lEndOffset);
1282     strHistoryString += pItem->GetPath();
1283   }
1284   else
1285   {
1286     // Normal directory items
1287     strHistoryString = pItem->GetPath();
1288   }
1289
1290   // remove any filter
1291   if (CanContainFilter(strHistoryString))
1292     strHistoryString = RemoveParameterFromPath(strHistoryString, "filter");
1293
1294   URIUtils::RemoveSlashAtEnd(strHistoryString);
1295   strHistoryString.ToLower();
1296 }
1297
1298 // \brief Call this function to create a directory history for the
1299 // path given by strDirectory.
1300 void CGUIMediaWindow::SetHistoryForPath(const CStdString& strDirectory)
1301 {
1302   // Make sure our shares are configured
1303   SetupShares();
1304   if (!strDirectory.IsEmpty())
1305   {
1306     // Build the directory history for default path
1307     CStdString strPath, strParentPath;
1308     strPath = strDirectory;
1309     URIUtils::RemoveSlashAtEnd(strPath);
1310
1311     CFileItemList items;
1312     m_rootDir.GetDirectory("", items);
1313
1314     m_history.ClearPathHistory();
1315
1316     while (URIUtils::GetParentPath(strPath, strParentPath))
1317     {
1318       for (int i = 0; i < (int)items.Size(); ++i)
1319       {
1320         CFileItemPtr pItem = items[i];
1321         CStdString path(pItem->GetPath());
1322         URIUtils::RemoveSlashAtEnd(path);
1323         if (path == strPath)
1324         {
1325           CStdString strHistory;
1326           GetDirectoryHistoryString(pItem.get(), strHistory);
1327           m_history.SetSelectedItem(strHistory, "");
1328           URIUtils::AddSlashAtEnd(strPath);
1329           m_history.AddPathFront(strPath);
1330           m_history.AddPathFront("");
1331
1332           //m_history.DumpPathHistory();
1333           return ;
1334         }
1335       }
1336
1337       if (URIUtils::IsVideoDb(strPath))
1338       {
1339         CURL url(strParentPath);
1340         url.SetOptions(""); // clear any URL options from recreated parent path
1341         strParentPath = url.Get();
1342       }
1343
1344       URIUtils::AddSlashAtEnd(strPath);
1345       m_history.AddPathFront(strPath);
1346       m_history.SetSelectedItem(strPath, strParentPath);
1347       strPath = strParentPath;
1348       URIUtils::RemoveSlashAtEnd(strPath);
1349     }
1350   }
1351   else
1352     m_history.ClearPathHistory();
1353
1354   //m_history.DumpPathHistory();
1355 }
1356
1357 // \brief Override if you want to change the default behavior, what is done
1358 // when the user clicks on a file.
1359 // This function is called by OnClick()
1360 bool CGUIMediaWindow::OnPlayMedia(int iItem)
1361 {
1362   // Reset Playlistplayer, playback started now does
1363   // not use the playlistplayer.
1364   g_playlistPlayer.Reset();
1365   g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_NONE);
1366   CFileItemPtr pItem=m_vecItems->Get(iItem);
1367
1368   CLog::Log(LOGDEBUG, "%s %s", __FUNCTION__, pItem->GetPath().c_str());
1369
1370   bool bResult = false;
1371   if (pItem->IsInternetStream() || pItem->IsPlayList())
1372     bResult = g_application.PlayMedia(*pItem, m_guiState->GetPlaylist());
1373   else
1374     bResult = g_application.PlayFile(*pItem);
1375
1376   if (pItem->m_lStartOffset == STARTOFFSET_RESUME)
1377     pItem->m_lStartOffset = 0;
1378
1379   return bResult;
1380 }
1381
1382 // \brief Override if you want to change the default behavior of what is done
1383 // when the user clicks on a file in a "folder" with similar files.
1384 // This function is called by OnClick()
1385 bool CGUIMediaWindow::OnPlayAndQueueMedia(const CFileItemPtr &item)
1386 {
1387   //play and add current directory to temporary playlist
1388   int iPlaylist = m_guiState->GetPlaylist();
1389   if (iPlaylist != PLAYLIST_NONE)
1390   {
1391     g_playlistPlayer.ClearPlaylist(iPlaylist);
1392     g_playlistPlayer.Reset();
1393     int mediaToPlay = 0;
1394     for ( int i = 0; i < m_vecItems->Size(); i++ )
1395     {
1396       CFileItemPtr nItem = m_vecItems->Get(i);
1397
1398       if (nItem->m_bIsFolder)
1399         continue;
1400
1401       if (!nItem->IsPlayList() && !nItem->IsZIP() && !nItem->IsRAR())
1402         g_playlistPlayer.Add(iPlaylist, nItem);
1403
1404       if (item->IsSamePath(nItem.get()))
1405       { // item that was clicked
1406         mediaToPlay = g_playlistPlayer.GetPlaylist(iPlaylist).size() - 1;
1407       }
1408     }
1409
1410     // Save current window and directory to know where the selected item was
1411     if (m_guiState.get())
1412       m_guiState->SetPlaylistDirectory(m_vecItems->GetPath());
1413
1414     // figure out where we start playback
1415     if (g_playlistPlayer.IsShuffled(iPlaylist))
1416     {
1417       int iIndex = g_playlistPlayer.GetPlaylist(iPlaylist).FindOrder(mediaToPlay);
1418       g_playlistPlayer.GetPlaylist(iPlaylist).Swap(0, iIndex);
1419       mediaToPlay = 0;
1420     }
1421
1422     // play
1423     g_playlistPlayer.SetCurrentPlaylist(iPlaylist);
1424     g_playlistPlayer.Play(mediaToPlay);
1425   }
1426   return true;
1427 }
1428
1429 // \brief Synchonize the fileitems with the playlistplayer
1430 // It recreated the playlist of the playlistplayer based
1431 // on the fileitems of the window
1432 void CGUIMediaWindow::UpdateFileList()
1433 {
1434   int nItem = m_viewControl.GetSelectedItem();
1435   CStdString strSelected;
1436   if (nItem >= 0)
1437     strSelected = m_vecItems->Get(nItem)->GetPath();
1438
1439   FormatAndSort(*m_vecItems);
1440   UpdateButtons();
1441
1442   m_viewControl.SetItems(*m_vecItems);
1443   m_viewControl.SetSelectedItem(strSelected);
1444
1445   //  set the currently playing item as selected, if its in this directory
1446   if (m_guiState.get() && m_guiState->IsCurrentPlaylistDirectory(m_vecItems->GetPath()))
1447   {
1448     int iPlaylist=m_guiState->GetPlaylist();
1449     int nSong = g_playlistPlayer.GetCurrentSong();
1450     CFileItem playlistItem;
1451     if (nSong > -1 && iPlaylist > -1)
1452       playlistItem=*g_playlistPlayer.GetPlaylist(iPlaylist)[nSong];
1453
1454     g_playlistPlayer.ClearPlaylist(iPlaylist);
1455     g_playlistPlayer.Reset();
1456
1457     for (int i = 0; i < m_vecItems->Size(); i++)
1458     {
1459       CFileItemPtr pItem = m_vecItems->Get(i);
1460       if (pItem->m_bIsFolder)
1461         continue;
1462
1463       if (!pItem->IsPlayList() && !pItem->IsZIP() && !pItem->IsRAR())
1464         g_playlistPlayer.Add(iPlaylist, pItem);
1465
1466       if (pItem->GetPath() == playlistItem.GetPath() &&
1467           pItem->m_lStartOffset == playlistItem.m_lStartOffset)
1468         g_playlistPlayer.SetCurrentSong(g_playlistPlayer.GetPlaylist(iPlaylist).size() - 1);
1469     }
1470   }
1471 }
1472
1473 void CGUIMediaWindow::OnDeleteItem(int iItem)
1474 {
1475   if ( iItem < 0 || iItem >= m_vecItems->Size()) return;
1476   CFileItemPtr item = m_vecItems->Get(iItem);
1477
1478   if (item->IsPlayList())
1479     item->m_bIsFolder = false;
1480
1481   if (g_settings.GetCurrentProfile().getLockMode() != LOCK_MODE_EVERYONE && g_settings.GetCurrentProfile().filesLocked())
1482     if (!g_passwordManager.IsMasterLockUnlocked(true))
1483       return;
1484
1485   if (!CFileUtils::DeleteItem(item))
1486     return;
1487   Refresh(true);
1488   m_viewControl.SetSelectedItem(iItem);
1489 }
1490
1491 void CGUIMediaWindow::OnRenameItem(int iItem)
1492 {
1493   if ( iItem < 0 || iItem >= m_vecItems->Size()) return;
1494
1495   if (g_settings.GetCurrentProfile().getLockMode() != LOCK_MODE_EVERYONE && g_settings.GetCurrentProfile().filesLocked())
1496     if (!g_passwordManager.IsMasterLockUnlocked(true))
1497       return;
1498
1499   if (!CFileUtils::RenameFile(m_vecItems->Get(iItem)->GetPath()))
1500     return;
1501   Refresh(true);
1502   m_viewControl.SetSelectedItem(iItem);
1503 }
1504
1505 void CGUIMediaWindow::OnInitWindow()
1506 {
1507   // initial fetch is done unthreaded to ensure the items are setup prior to skin animations kicking off
1508   m_rootDir.SetAllowThreads(false);
1509   Refresh();
1510   m_rootDir.SetAllowThreads(true);
1511
1512   if (m_iSelectedItem > -1)
1513     m_viewControl.SetSelectedItem(m_iSelectedItem);
1514
1515   CGUIWindow::OnInitWindow();
1516 }
1517
1518 CGUIControl *CGUIMediaWindow::GetFirstFocusableControl(int id)
1519 {
1520   if (m_viewControl.HasControl(id))
1521     id = m_viewControl.GetCurrentControl();
1522   return CGUIWindow::GetFirstFocusableControl(id);
1523 }
1524
1525 void CGUIMediaWindow::SetupShares()
1526 {
1527   // Setup shares and filemasks for this window
1528   CFileItemList items;
1529   CGUIViewState* viewState=CGUIViewState::GetViewState(GetID(), items);
1530   if (viewState)
1531   {
1532     m_rootDir.SetMask(viewState->GetExtensions());
1533     m_rootDir.SetSources(viewState->GetSources());
1534     delete viewState;
1535   }
1536 }
1537
1538 bool CGUIMediaWindow::OnPopupMenu(int iItem)
1539 {
1540   // popup the context menu
1541   // grab our context menu
1542   CContextButtons buttons;
1543   GetContextButtons(iItem, buttons);
1544
1545   if (buttons.size())
1546   {
1547     // mark the item
1548     if (iItem >= 0 && iItem < m_vecItems->Size())
1549       m_vecItems->Get(iItem)->Select(true);
1550
1551     int choice = CGUIDialogContextMenu::ShowAndGetChoice(buttons);
1552
1553     // deselect our item
1554     if (iItem >= 0 && iItem < m_vecItems->Size())
1555       m_vecItems->Get(iItem)->Select(false);
1556
1557     if (choice >= 0)
1558       return OnContextButton(iItem, (CONTEXT_BUTTON)choice);
1559   }
1560   return false;
1561 }
1562
1563 void CGUIMediaWindow::GetContextButtons(int itemNumber, CContextButtons &buttons)
1564 {
1565   CFileItemPtr item = (itemNumber >= 0 && itemNumber < m_vecItems->Size()) ? m_vecItems->Get(itemNumber) : CFileItemPtr();
1566
1567   if (!item)
1568     return;
1569
1570   // user added buttons
1571   CStdString label;
1572   CStdString action;
1573   for (int i = CONTEXT_BUTTON_USER1; i <= CONTEXT_BUTTON_USER10; i++)
1574   {
1575     label.Format("contextmenulabel(%i)", i - CONTEXT_BUTTON_USER1);
1576     if (item->GetProperty(label).empty())
1577       break;
1578
1579     action.Format("contextmenuaction(%i)", i - CONTEXT_BUTTON_USER1);
1580     if (item->GetProperty(action).empty())
1581       break;
1582
1583     buttons.Add((CONTEXT_BUTTON)i, item->GetProperty(label).asString());
1584   }
1585
1586   if (item->GetProperty("pluginreplacecontextitems").asBoolean())
1587     return;
1588
1589   // TODO: FAVOURITES Conditions on masterlock and localisation
1590   if (!item->IsParentFolder() && !item->GetPath().Equals("add") && !item->GetPath().Equals("newplaylist://") &&
1591       !item->GetPath().Left(19).Equals("newsmartplaylist://") && !item->GetPath().Left(9).Equals("newtag://"))
1592   {
1593     if (CFavourites::IsFavourite(item.get(), GetID()))
1594       buttons.Add(CONTEXT_BUTTON_ADD_FAVOURITE, 14077);     // Remove Favourite
1595     else
1596       buttons.Add(CONTEXT_BUTTON_ADD_FAVOURITE, 14076);     // Add To Favourites;
1597   }
1598 }
1599
1600 bool CGUIMediaWindow::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
1601 {
1602   switch (button)
1603   {
1604   case CONTEXT_BUTTON_ADD_FAVOURITE:
1605     {
1606       CFileItemPtr item = m_vecItems->Get(itemNumber);
1607       CFavourites::AddOrRemove(item.get(), GetID());
1608       return true;
1609     }
1610   case CONTEXT_BUTTON_PLUGIN_SETTINGS:
1611     {
1612       CURL plugin(m_vecItems->Get(itemNumber)->GetPath());
1613       ADDON::AddonPtr addon;
1614       if (CAddonMgr::Get().GetAddon(plugin.GetHostName(), addon))
1615         if (CGUIDialogAddonSettings::ShowAndGetInput(addon))
1616           Refresh();
1617       return true;
1618     }
1619   case CONTEXT_BUTTON_USER1:
1620   case CONTEXT_BUTTON_USER2:
1621   case CONTEXT_BUTTON_USER3:
1622   case CONTEXT_BUTTON_USER4:
1623   case CONTEXT_BUTTON_USER5:
1624   case CONTEXT_BUTTON_USER6:
1625   case CONTEXT_BUTTON_USER7:
1626   case CONTEXT_BUTTON_USER8:
1627   case CONTEXT_BUTTON_USER9:
1628   case CONTEXT_BUTTON_USER10:
1629     {
1630       CStdString action;
1631       action.Format("contextmenuaction(%i)", button - CONTEXT_BUTTON_USER1);
1632       CApplicationMessenger::Get().ExecBuiltIn(m_vecItems->Get(itemNumber)->GetProperty(action).asString());
1633       return true;
1634     }
1635   default:
1636     break;
1637   }
1638   return false;
1639 }
1640
1641 const CGUIViewState *CGUIMediaWindow::GetViewState() const
1642 {
1643   return m_guiState.get();
1644 }
1645
1646 const CFileItemList& CGUIMediaWindow::CurrentDirectory() const
1647 {
1648   return *m_vecItems;
1649 }
1650
1651 bool CGUIMediaWindow::WaitForNetwork() const
1652 {
1653   if (g_application.getNetwork().IsAvailable())
1654     return true;
1655
1656   CGUIDialogProgress *progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
1657   if (!progress)
1658     return true;
1659
1660   CURL url(m_vecItems->GetPath());
1661   progress->SetHeading(1040); // Loading Directory
1662   progress->SetLine(1, url.GetWithoutUserDetails());
1663   progress->ShowProgressBar(false);
1664   progress->StartModal();
1665   while (!g_application.getNetwork().IsAvailable())
1666   {
1667     progress->Progress();
1668     if (progress->IsCanceled())
1669     {
1670       progress->Close();
1671       return false;
1672     }
1673   }
1674   progress->Close();
1675   return true;
1676 }
1677
1678 void CGUIMediaWindow::OnFilterItems(const CStdString &filter)
1679 {
1680   CFileItemPtr currentItem;
1681   CStdString currentItemPath;
1682   int item = m_viewControl.GetSelectedItem();
1683   if (item >= 0 && item < m_vecItems->Size())
1684   {
1685     currentItem = m_vecItems->Get(item);
1686     currentItemPath = currentItem->GetPath();
1687   }
1688   
1689   m_viewControl.Clear();
1690   
1691   CFileItemList items(m_vecItems->GetPath()); // use the original path - it'll likely be relied on for other things later.
1692   items.Append(*m_unfilteredItems);
1693   bool filtered = GetFilteredItems(filter, items);
1694
1695   m_vecItems->ClearItems();
1696   // we need to clear the sort state and re-sort the items
1697   m_vecItems->ClearSortState();
1698   m_vecItems->Append(items);
1699   
1700   // if the filter has changed, get the new filter path
1701   if (filtered && m_canFilterAdvanced)
1702   {
1703     if (items.HasProperty(PROPERTY_PATH_DB))
1704       m_strFilterPath = items.GetProperty(PROPERTY_PATH_DB).asString();
1705     // only set m_strFilterPath if it hasn't been set before
1706     // otherwise we might overwrite it with a non-filter path
1707     // in case GetFilteredItems() returns true even though no
1708     // db-based filter (e.g. watched filter) has been applied
1709     else if (m_strFilterPath.empty())
1710       m_strFilterPath = items.GetPath();
1711   }
1712   
1713   GetGroupedItems(*m_vecItems);
1714   FormatAndSort(*m_vecItems);
1715
1716   // get the "filter" option
1717   CStdString filterOption;
1718   CURL filterUrl(m_strFilterPath);
1719   if (filterUrl.HasOption("filter"))
1720     filterOption = filterUrl.GetOption("filter");
1721
1722   // apply the "filter" option to any folder item so that
1723   // the filter can be passed down to the sub-directory
1724   for (int index = 0; index < m_vecItems->Size(); index++)
1725   {
1726     CFileItemPtr pItem = m_vecItems->Get(index);
1727     // if the item is a folder we need to copy the path of
1728     // the filtered item to be able to keep the applied filters
1729     if (pItem->m_bIsFolder)
1730     {
1731       CURL itemUrl(pItem->GetPath());
1732       if (!filterOption.empty())
1733         itemUrl.SetOption("filter", filterOption);
1734       else
1735         itemUrl.RemoveOption("filter");
1736       pItem->SetPath(itemUrl.Get());
1737     }
1738   }
1739
1740   if (filtered)
1741   {
1742     if (!m_canFilterAdvanced)
1743       SetProperty("filter", filter);
1744     else
1745     {
1746       // to be able to select the same item as before we need to adjust
1747       // the path of the item i.e. add or remove the "filter=" URL option
1748       // but that's only necessary for folder items
1749       if (currentItem.get() != NULL && currentItem->m_bIsFolder)
1750       {
1751         CURL curUrl(currentItemPath), newUrl(m_strFilterPath);
1752         if (newUrl.HasOption("filter"))
1753           curUrl.SetOption("filter", newUrl.GetOption("filter"));
1754         else if (curUrl.HasOption("filter"))
1755           curUrl.RemoveOption("filter");
1756
1757         currentItemPath = curUrl.Get();
1758       }
1759     }
1760   }
1761
1762   // The idea here is to ensure we have something to focus if our file list
1763   // is empty.  As such, this check MUST be last and ignore the hide parent
1764   // fileitems settings.
1765   if (m_vecItems->IsEmpty())
1766   {
1767     CFileItemPtr pItem(new CFileItem(".."));
1768     pItem->SetPath(m_history.GetParentPath());
1769     pItem->m_bIsFolder = true;
1770     pItem->m_bIsShareOrDrive = false;
1771     m_vecItems->AddFront(pItem, 0);
1772   }
1773
1774   // and update our view control + buttons
1775   m_viewControl.SetItems(*m_vecItems);
1776   m_viewControl.SetSelectedItem(currentItemPath);
1777   UpdateButtons();
1778 }
1779
1780 bool CGUIMediaWindow::GetFilteredItems(const CStdString &filter, CFileItemList &items)
1781 {
1782   if (m_canFilterAdvanced)
1783     return GetAdvanceFilteredItems(items);
1784
1785   CStdString trimmedFilter(filter);
1786   trimmedFilter.TrimLeft().ToLower();
1787   
1788   if (trimmedFilter.IsEmpty())
1789     return true;
1790
1791   CFileItemList filteredItems(items.GetPath()); // use the original path - it'll likely be relied on for other things later.
1792   bool numericMatch = StringUtils::IsNaturalNumber(trimmedFilter);
1793   for (int i = 0; i < items.Size(); i++)
1794   {
1795     CFileItemPtr item = items.Get(i);
1796     if (item->IsParentFolder())
1797     {
1798       filteredItems.Add(item);
1799       continue;
1800     }
1801     // TODO: Need to update this to get all labels, ideally out of the displayed info (ie from m_layout and m_focusedLayout)
1802     // though that isn't practical.  Perhaps a better idea would be to just grab the info that we should filter on based on
1803     // where we are in the library tree.
1804     // Another idea is tying the filter string to the current level of the tree, so that going deeper disables the filter,
1805     // but it's re-enabled on the way back out.
1806     CStdString match;
1807     /*    if (item->GetFocusedLayout())
1808      match = item->GetFocusedLayout()->GetAllText();
1809      else if (item->GetLayout())
1810      match = item->GetLayout()->GetAllText();
1811      else*/
1812     match = item->GetLabel(); // Filter label only for now
1813     
1814     if (numericMatch)
1815       StringUtils::WordToDigits(match);
1816     
1817     size_t pos = StringUtils::FindWords(match.c_str(), trimmedFilter.c_str());
1818     if (pos != CStdString::npos)
1819       filteredItems.Add(item);
1820   }
1821
1822   items.ClearItems();
1823   items.Append(filteredItems);
1824
1825   return items.GetObjectCount() > 0;
1826 }
1827
1828 bool CGUIMediaWindow::GetAdvanceFilteredItems(CFileItemList &items)
1829 {
1830   // don't run the advanced filter if the filter is empty
1831   // and there hasn't been a filter applied before which
1832   // would have to be removed
1833   CURL url(m_strFilterPath);
1834   if (m_filter.IsEmpty() && !url.HasOption("filter"))
1835     return false;
1836
1837   CFileItemList resultItems;
1838   XFILE::CSmartPlaylistDirectory::GetDirectory(m_filter, resultItems, m_strFilterPath, true);
1839
1840   // put together a lookup map for faster path comparison
1841   map<CStdString, CFileItemPtr> lookup;
1842   for (int j = 0; j < resultItems.Size(); j++)
1843   {
1844     CStdString itemPath = RemoveParameterFromPath(resultItems[j]->GetPath(), "filter");
1845     itemPath.ToLower();
1846
1847     lookup[itemPath] = resultItems[j];
1848   }
1849
1850   // loop through all the original items and find
1851   // those which are still part of the filter
1852   CFileItemList filteredItems;
1853   for (int i = 0; i < items.Size(); i++)
1854   {
1855     CFileItemPtr item = items.Get(i);
1856     if (item->IsParentFolder())
1857     {
1858       filteredItems.Add(item);
1859       continue;
1860     }
1861
1862     // check if the item is part of the resultItems list
1863     // by comparing their paths (but ignoring any special
1864     // options because they differ from filter to filter)
1865     CStdString path = RemoveParameterFromPath(item->GetPath(), "filter");
1866     path.ToLower();
1867
1868     map<CStdString, CFileItemPtr>::iterator itItem = lookup.find(path);
1869     if (itItem != lookup.end())
1870     {
1871       // add the item to the list of filtered items
1872       filteredItems.Add(item);
1873
1874       // remove the item from the lists
1875       resultItems.Remove(itItem->second.get());
1876       lookup.erase(itItem);
1877     }
1878   }
1879
1880   if (resultItems.Size() > 0)
1881     CLog::Log(LOGWARNING, "CGUIMediaWindow::GetAdvanceFilteredItems(): %d unknown items", resultItems.Size());
1882
1883   items.ClearItems();
1884   items.Append(filteredItems);
1885   items.SetPath(resultItems.GetPath());
1886   if (resultItems.HasProperty(PROPERTY_PATH_DB))
1887     items.SetProperty(PROPERTY_PATH_DB, resultItems.GetProperty(PROPERTY_PATH_DB));
1888   return true;
1889 }
1890
1891 bool CGUIMediaWindow::IsFiltered()
1892 {
1893   return (!m_canFilterAdvanced && !GetProperty("filter").empty()) ||
1894          (m_canFilterAdvanced && !m_filter.IsEmpty());
1895 }
1896
1897 bool CGUIMediaWindow::Filter()
1898 {
1899   // basic filtering
1900   if (!m_canFilterAdvanced)
1901   {
1902     const CGUIControl *btnFilter = GetControl(CONTROL_BTN_FILTER);
1903     if (btnFilter != NULL && btnFilter->GetControlType() == CGUIControl::GUICONTROL_EDIT)
1904     { // filter updated
1905       CGUIMessage selected(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_BTN_FILTER);
1906       OnMessage(selected);
1907       OnFilterItems(selected.GetLabel());
1908       return true;
1909     }
1910     if (GetProperty("filter").empty())
1911     {
1912       CStdString filter = GetProperty("filter").asString();
1913       CGUIKeyboardFactory::ShowAndGetFilter(filter, false);
1914       SetProperty("filter", filter);
1915     }
1916     else
1917       OnFilterItems("");
1918   }
1919   // advanced filtering
1920   else
1921     CGUIDialogMediaFilter::ShowAndEditMediaFilter(m_strFilterPath, m_filter);
1922
1923   return true;
1924 }
1925
1926 CStdString CGUIMediaWindow::GetStartFolder(const CStdString &dir)
1927 {
1928   if (dir.Equals("$ROOT") || dir.Equals("Root"))
1929     return "";
1930   return dir;
1931 }
1932
1933 CStdString CGUIMediaWindow::RemoveParameterFromPath(const CStdString &strDirectory, const CStdString &strParameter)
1934 {
1935   CURL url(strDirectory);
1936   if (url.HasOption(strParameter))
1937   {
1938     url.RemoveOption(strParameter);
1939     return url.Get();
1940   }
1941
1942   return strDirectory;
1943 }