only call IPlayerCallback::OnPlayBackSpeedChanged if the speed has actually changed
[vuplus_xbmc] / xbmc / windows / GUIMediaWindow.cpp
1 /*
2  *      Copyright (C) 2005-2008 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, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "threads/SystemClock.h"
23 #include "GUIMediaWindow.h"
24 #include "GUIUserMessages.h"
25 #include "Util.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"
43
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"
61 #ifdef HAS_PYTHON
62 #include "interfaces/python/XBPython.h"
63 #endif
64 #include "interfaces/Builtins.h"
65
66 #define CONTROL_BTNVIEWASICONS     2
67 #define CONTROL_BTNSORTBY          3
68 #define CONTROL_BTNSORTASC         4
69 #define CONTROL_BTN_FILTER        19
70
71 #define CONTROL_LABELFILES        12
72
73 using namespace std;
74 using namespace ADDON;
75
76 CGUIMediaWindow::CGUIMediaWindow(int id, const char *xmlFile)
77     : CGUIWindow(id, xmlFile)
78 {
79   m_vecItems = new CFileItemList;
80   m_unfilteredItems = new CFileItemList;
81   m_vecItems->SetPath("?");
82   m_iLastControl = -1;
83   m_iSelectedItem = -1;
84
85   m_guiState.reset(CGUIViewState::GetViewState(GetID(), *m_vecItems));
86 }
87
88 CGUIMediaWindow::~CGUIMediaWindow()
89 {
90   delete m_vecItems;
91   delete m_unfilteredItems;
92 }
93
94 #define CONTROL_VIEW_START        50
95 #define CONTROL_VIEW_END          59
96
97 void CGUIMediaWindow::LoadAdditionalTags(TiXmlElement *root)
98 {
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++)
110     {
111       int controlID = atol(views[i].c_str());
112       CGUIControl *control = (CGUIControl *)GetControl(controlID);
113       if (control && control->IsContainer())
114         m_viewControl.AddView(control);
115     }
116   }
117   else
118   { // backward compatibility
119     vector<CGUIControl *> controls;
120     GetContainers(controls);
121     for (ciControls it = controls.begin(); it != controls.end(); it++)
122     {
123       CGUIControl *control = *it;
124       if (control->GetID() >= CONTROL_VIEW_START && control->GetID() <= CONTROL_VIEW_END)
125         m_viewControl.AddView(control);
126     }
127   }
128   m_viewControl.SetViewControlID(CONTROL_BTNVIEWASICONS);
129 }
130
131 void CGUIMediaWindow::OnWindowLoaded()
132 {
133   SendMessage(GUI_MSG_SET_TYPE, CONTROL_BTN_FILTER, CGUIEditControl::INPUT_TYPE_FILTER);
134   CGUIWindow::OnWindowLoaded();
135   SetupShares();
136 }
137
138 void CGUIMediaWindow::OnWindowUnload()
139 {
140   CGUIWindow::OnWindowUnload();
141   m_viewControl.Reset();
142 }
143
144 CFileItemPtr CGUIMediaWindow::GetCurrentListItem(int offset)
145 {
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);
152 }
153
154 bool CGUIMediaWindow::OnAction(const CAction &action)
155 {
156   if (action.GetID() == ACTION_PARENT_DIR)
157   {
158     GoParentFolder();
159     return true;
160   }
161
162   // the non-contextual menu can be called at any time
163   if (action.GetID() == ACTION_CONTEXT_MENU && !m_viewControl.HasControl(GetFocusedControlID()))
164   {
165     OnPopupMenu(-1);
166     return true;
167   }
168
169   if (CGUIWindow::OnAction(action))
170     return true;
171
172   // live filtering
173   if (action.GetID() == ACTION_FILTER_CLEAR)
174   {
175     CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS);
176     message.SetStringParam("");
177     OnMessage(message);
178     return true;
179   }
180
181   if (action.GetID() == ACTION_BACKSPACE)
182   {
183     CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS, 2); // 2 for delete
184     OnMessage(message);
185     return true;
186   }
187
188   if (action.GetID() >= ACTION_FILTER_SMS2 && action.GetID() <= ACTION_FILTER_SMS9)
189   {
190     CStdString filter;
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);
194     OnMessage(message);
195     return true;
196   }
197
198   return false;
199 }
200
201 bool CGUIMediaWindow::OnBack(int actionID)
202 {
203   if (actionID == ACTION_NAV_BACK && !(m_vecItems->IsVirtualDirectoryRoot() || m_vecItems->GetPath() == m_startDirectory))
204   {
205     GoParentFolder();
206     return true;
207   }
208   return CGUIWindow::OnBack(actionID);
209 }
210
211 bool CGUIMediaWindow::OnMessage(CGUIMessage& message)
212 {
213   switch ( message.GetMessage() )
214   {
215   case GUI_MSG_WINDOW_DEINIT:
216     {
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
221       // animations
222       ClearFileItems();
223       return true;
224     }
225     break;
226
227   case GUI_MSG_CLICKED:
228     {
229       int iControl = message.GetSenderId();
230       if (iControl == CONTROL_BTNVIEWASICONS)
231       {
232         // view as control could be a select button
233         int viewMode = 0;
234         const CGUIControl *control = GetControl(CONTROL_BTNVIEWASICONS);
235         if (control && control->GetControlType() != CGUIControl::GUICONTROL_BUTTON)
236         {
237           CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_BTNVIEWASICONS);
238           OnMessage(msg);
239           viewMode = m_viewControl.GetViewModeNumber(msg.GetParam1());
240         }
241         else
242           viewMode = m_viewControl.GetNextViewMode();
243
244         if (m_guiState.get())
245           m_guiState->SaveViewAsControl(viewMode);
246
247         UpdateButtons();
248         return true;
249       }
250       else if (iControl == CONTROL_BTNSORTASC) // sort asc
251       {
252         if (m_guiState.get())
253           m_guiState->SetNextSortOrder();
254         UpdateFileList();
255         return true;
256       }
257       else if (iControl == CONTROL_BTNSORTBY) // sort by
258       {
259         if (m_guiState.get())
260           m_guiState->SetNextSortMethod();
261         UpdateFileList();
262         return true;
263       }
264       else if (iControl == CONTROL_BTN_FILTER)
265       {
266         if (GetControl(iControl)->GetControlType() == CGUIControl::GUICONTROL_EDIT)
267         { // filter updated
268           CGUIMessage selected(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_BTN_FILTER);
269           OnMessage(selected);
270           OnFilterItems(selected.GetLabel());
271           return true;
272         }
273         if (GetProperty("filter").empty())
274         {
275           CStdString filter = GetProperty("filter").asString();
276           CGUIDialogKeyboard::ShowAndGetFilter(filter, false);
277           SetProperty("filter", filter);
278         }
279         else
280           OnFilterItems("");
281         return true;
282       }
283       else if (m_viewControl.HasControl(iControl))  // list/thumb control
284       {
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)
289         {
290           OnSelect(iItem);
291         }
292         else if (iAction == ACTION_CONTEXT_MENU || iAction == ACTION_MOUSE_RIGHT_CLICK)
293         {
294           OnPopupMenu(iItem);
295           return true;
296         }
297       }
298     }
299     break;
300
301   case GUI_MSG_SETFOCUS:
302     {
303       if (m_viewControl.HasControl(message.GetControlId()) && m_viewControl.GetCurrentControl() != message.GetControlId())
304       {
305         m_viewControl.SetFocused();
306         return true;
307       }
308     }
309     break;
310
311   case GUI_MSG_NOTIFY_ALL:
312     { // Message is received even if this window is inactive
313       if (message.GetParam1() == GUI_MSG_WINDOW_RESET)
314       {
315         m_vecItems->SetPath("?");
316         return true;
317       }
318       else if ( message.GetParam1() == GUI_MSG_REFRESH_THUMBS )
319       {
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
323       }
324       else if (message.GetParam1() == GUI_MSG_REMOVED_MEDIA)
325       {
326         if ((m_vecItems->IsVirtualDirectoryRoot() ||
327              m_vecItems->IsSourcesPath()) && IsActive())
328         {
329           int iItem = m_viewControl.GetSelectedItem();
330           Update(m_vecItems->GetPath());
331           m_viewControl.SetSelectedItem(iItem);
332         }
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("");
338             else
339             {
340               m_history.ClearPathHistory();
341               m_vecItems->SetPath("");
342             }
343           }
344         }
345
346         return true;
347       }
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())
352         {
353           int iItem = m_viewControl.GetSelectedItem();
354           Update(m_vecItems->GetPath());
355           m_viewControl.SetSelectedItem(iItem);
356         }
357         return true;
358       }
359       else if (message.GetParam1()==GUI_MSG_UPDATE && IsActive())
360       {
361         if (message.GetNumStringParams())
362         {
363           m_vecItems->SetPath(message.GetStringParam());
364           if (message.GetParam2()) // param2 is used for resetting the history
365             SetHistoryForPath(m_vecItems->GetPath());
366         }
367         // clear any cached listing
368         m_vecItems->RemoveDiscCache(GetID());
369         Update(m_vecItems->GetPath());
370       }
371       else if (message.GetParam1()==GUI_MSG_UPDATE_ITEM && message.GetItem())
372       {
373         CFileItemPtr newItem = boost::static_pointer_cast<CFileItem>(message.GetItem());
374         if (IsActive())
375         {
376           if (m_vecItems->UpdateItem(newItem.get()) && message.GetParam2() == 1)
377           { // need the list updated as well
378             UpdateFileList();
379           }
380         }
381         else if (newItem)
382         { // need to remove the disc cache
383           CFileItemList items;
384           CStdString path;
385           URIUtils::GetDirectory(newItem->GetPath(), path);
386           items.SetPath(path);
387           items.RemoveDiscCache(GetID());
388         }
389       }
390       else if (message.GetParam1()==GUI_MSG_UPDATE_PATH)
391       {
392         if (IsActive())
393         {
394           if((message.GetStringParam() == m_vecItems->GetPath()) ||
395              (m_vecItems->IsMultiPath() && XFILE::CMultiPathDirectory::HasPath(m_vecItems->GetPath(), message.GetStringParam())))
396           {
397             Update(m_vecItems->GetPath());
398           }
399         }
400       }
401       else if (message.GetParam1() == GUI_MSG_FILTER_ITEMS && IsActive())
402       {
403         CStdString filter(GetProperty("filter").asString());
404         if (message.GetParam2() == 1) // append
405           filter += message.GetStringParam();
406         else if (message.GetParam2() == 2)
407         { // delete
408           if (filter.size())
409             filter = filter.Left(filter.size() - 1);
410         }
411         else
412           filter = message.GetStringParam();
413         OnFilterItems(filter);
414         return true;
415       }
416       else
417         return CGUIWindow::OnMessage(message);
418
419       return true;
420     }
421     break;
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);
431       OnMessage(msg);
432       break;
433     }
434   case GUI_MSG_CHANGE_VIEW_MODE:
435     {
436       int viewMode = 0;
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());
441
442       if (m_guiState.get())
443         m_guiState->SaveViewAsControl(viewMode);
444       UpdateButtons();
445       return true;
446     }
447     break;
448   case GUI_MSG_CHANGE_SORT_METHOD:
449     {
450       if (m_guiState.get())
451       {
452         if (message.GetParam1())
453           m_guiState->SetCurrentSortMethod((int)message.GetParam1());
454         else if (message.GetParam2())
455           m_guiState->SetNextSortMethod((int)message.GetParam2());
456       }
457       UpdateFileList();
458       return true;
459     }
460     break;
461   case GUI_MSG_CHANGE_SORT_DIRECTION:
462     {
463       if (m_guiState.get())
464         m_guiState->SetNextSortOrder();
465       UpdateFileList();
466       return true;
467     }
468     break;
469   case GUI_MSG_WINDOW_INIT:
470     {
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;
476       if (!dir.IsEmpty())
477       {
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);
484         }
485         // check for network up
486         if (URIUtils::IsRemote(m_vecItems->GetPath()) && !WaitForNetwork())
487           m_vecItems->SetPath("");
488         SetHistoryForPath(m_vecItems->GetPath());
489       }
490       if (message.GetParam1() != WINDOW_INVALID)
491       { // first time to this window - make sure we set the root path
492         m_startDirectory = returning ? dir : "";
493       }
494     }
495     break;
496   }
497
498   return CGUIWindow::OnMessage(message);
499 }
500
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()
505 {
506   if (m_guiState.get())
507   {
508     // Update sorting controls
509     if (m_guiState->GetDisplaySortOrder()==SORT_ORDER_NONE)
510     {
511       CONTROL_DISABLE(CONTROL_BTNSORTASC);
512     }
513     else
514     {
515       CONTROL_ENABLE(CONTROL_BTNSORTASC);
516       if (m_guiState->GetDisplaySortOrder()==SORT_ORDER_ASC)
517       {
518         CGUIMessage msg(GUI_MSG_DESELECTED, GetID(), CONTROL_BTNSORTASC);
519         g_windowManager.SendMessage(msg);
520       }
521       else
522       {
523         CGUIMessage msg(GUI_MSG_SELECTED, GetID(), CONTROL_BTNSORTASC);
524         g_windowManager.SendMessage(msg);
525       }
526     }
527
528     // Update list/thumb control
529     m_viewControl.SetCurrentView(m_guiState->GetViewAsControl());
530
531     // Update sort by button
532     if (m_guiState->GetSortMethod()==SORT_METHOD_NONE)
533     {
534       CONTROL_DISABLE(CONTROL_BTNSORTBY);
535     }
536     else
537     {
538       CONTROL_ENABLE(CONTROL_BTNSORTBY);
539     }
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);
543   }
544
545   CStdString items;
546   items.Format("%i %s", m_vecItems->GetObjectCount(), g_localizeStrings.Get(127).c_str());
547   SET_CONTROL_LABEL(CONTROL_LABELFILES, items);
548
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());
552   //#endif
553 }
554
555 void CGUIMediaWindow::ClearFileItems()
556 {
557   m_viewControl.Clear();
558   m_vecItems->Clear(); // will clean up everything
559   m_unfilteredItems->Clear();
560 }
561
562 // \brief Sorts Fileitems based on the sort method and sort oder provided by guiViewState
563 void CGUIMediaWindow::SortItems(CFileItemList &items)
564 {
565   auto_ptr<CGUIViewState> guiState(CGUIViewState::GetViewState(GetID(), items));
566
567   if (guiState.get())
568   {
569     items.Sort(guiState->GetSortMethod(), guiState->GetDisplaySortOrder());
570
571     // Should these items be saved to the hdd
572     if (items.CacheToDiscAlways())
573       items.Save(GetID());
574   }
575 }
576
577 // \brief Formats item labels based on the formatting provided by guiViewState
578 void CGUIMediaWindow::FormatItemLabels(CFileItemList &items, const LABEL_MASKS &labelMasks)
579 {
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)
583   {
584     CFileItemPtr pItem=items[i];
585
586     if (pItem->IsLabelPreformated())
587       continue;
588
589     if (pItem->m_bIsFolder)
590       folderFormatter.FormatLabels(pItem.get());
591     else
592       fileFormatter.FormatLabels(pItem.get());
593   }
594
595   if(items.GetSortMethod() == SORT_METHOD_LABEL_IGNORE_THE
596   || items.GetSortMethod() == SORT_METHOD_LABEL)
597     items.ClearSortState();
598 }
599
600 // \brief Prepares and adds the fileitems list/thumb panel
601 void CGUIMediaWindow::FormatAndSort(CFileItemList &items)
602 {
603   auto_ptr<CGUIViewState> viewState(CGUIViewState::GetViewState(GetID(), items));
604
605   if (viewState.get())
606   {
607     LABEL_MASKS labelMasks;
608     viewState->GetSortMethodLabelMasks(labelMasks);
609     FormatItemLabels(items, labelMasks);
610   }
611   SortItems(items);
612 }
613
614 /*!
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
618   */
619 bool CGUIMediaWindow::GetDirectory(const CStdString &strDirectory, CFileItemList &items)
620 {
621   // cleanup items
622   if (items.Size())
623     items.Clear();
624
625   CStdString strParentPath=m_history.GetParentPath();
626
627   CLog::Log(LOGDEBUG,"CGUIMediaWindow::GetDirectory (%s)", strDirectory.c_str());
628   CLog::Log(LOGDEBUG,"  ParentPath = [%s]", strParentPath.c_str());
629
630   // see if we can load a previously cached folder
631   CFileItemList cachedItems(strDirectory);
632   if (!strDirectory.IsEmpty() && cachedItems.Load(GetID()))
633   {
634     items.Assign(cachedItems);
635   }
636   else
637   {
638     unsigned int time = XbmcThreads::SystemClockMillis();
639
640     if (strDirectory.IsEmpty())
641       SetupShares();
642
643     if (!m_rootDir.GetDirectory(strDirectory, items))
644       return false;
645
646     // took over a second, and not normally cached, so cache it
647     if ((XbmcThreads::SystemClockMillis() - time) > 1000  && items.CacheToDiscIfSlow())
648       items.Save(GetID());
649
650     // if these items should replace the current listing, then pop it off the top
651     if (items.GetReplaceListing())
652       m_history.RemoveParentPath();
653   }
654
655   if (m_guiState.get() && !m_guiState->HideParentDirItems() && !items.GetPath().IsEmpty())
656   {
657     CFileItemPtr pItem(new CFileItem(".."));
658     pItem->SetPath(strParentPath);
659     pItem->m_bIsFolder = true;
660     pItem->m_bIsShareOrDrive = false;
661     items.AddFront(pItem, 0);
662   }
663
664   int iWindow = GetID();
665   CStdStringArray regexps;
666
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;
674
675   if (regexps.size())
676   {
677     for (int i=0; i < items.Size();)
678     {
679       if (CUtil::ExcludeFileOrFolder(items[i]->GetPath(), regexps))
680         items.Remove(i);
681       else
682         i++;
683     }
684   }
685
686   // clear the filter
687   SetProperty("filter", "");
688   return true;
689 }
690
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)
695 {
696   // TODO: OnInitWindow calls Update() before window path has been set properly.
697   if (strDirectory == "?")
698     return false;
699
700   // get selected item
701   int iItem = m_viewControl.GetSelectedItem();
702   CStdString strSelectedItem = "";
703   if (iItem >= 0 && iItem < m_vecItems->Size())
704   {
705     CFileItemPtr pItem = m_vecItems->Get(iItem);
706     if (!pItem->IsParentFolder())
707     {
708       GetDirectoryHistoryString(pItem.get(), strSelectedItem);
709     }
710   }
711
712   CStdString strOldDirectory = m_vecItems->GetPath();
713
714   m_history.SetSelectedItem(strSelectedItem, strOldDirectory);
715
716   CFileItemList items;
717   if (!GetDirectory(strDirectory, items))
718   {
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))
723       return false;
724
725     // We assume, we can get the parent
726     // directory again, but we have to
727     // return false to be able to eg. show
728     // an error message.
729     CStdString strParentPath = m_history.GetParentPath();
730     m_history.RemoveParentPath();
731     Update(strParentPath);
732     return false;
733   }
734
735   if (items.GetLabel().IsEmpty())
736     items.SetLabel(CUtil::GetTitleFromPath(items.GetPath(), true));
737
738   ClearFileItems();
739   m_vecItems->Copy(items);
740
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();
745
746   int iWindow = GetID();
747   int showLabel = 0;
748   if (strDirectory.IsEmpty() && (iWindow == WINDOW_MUSIC_FILES ||
749                                  iWindow == WINDOW_FILES ||
750                                  iWindow == WINDOW_PICTURES ||
751                                  iWindow == WINDOW_PROGRAMS))
752     showLabel = 1026;
753   if (strDirectory.Equals("sources://video/"))
754     showLabel = 999;
755   if (showLabel && (m_vecItems->Size() == 0 || !m_guiState->DisableAddSourceButtons())) // add 'add source button'
756   {
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);
766   }
767   m_iLastControl = GetFocusedControlID();
768
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);
773
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())
778   {
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);
784   }
785
786   m_vecItems->FillInDefaultIcons();
787
788   m_guiState.reset(CGUIViewState::GetViewState(GetID(), *m_vecItems));
789
790   FormatAndSort(*m_vecItems);
791
792   // Ask the devived class if it wants to do custom list operations,
793   // eg. changing the label
794   OnFinalizeFileItems(*m_vecItems);
795   UpdateButtons();
796
797   m_viewControl.SetItems(*m_vecItems);
798
799   strSelectedItem = m_history.GetSelectedItem(m_vecItems->GetPath());
800
801   bool bSelectedFound = false;
802   //int iSongInDirectory = -1;
803   for (int i = 0; i < m_vecItems->Size(); ++i)
804   {
805     CFileItemPtr pItem = m_vecItems->Get(i);
806
807     // Update selected item
808     if (!bSelectedFound)
809     {
810       CStdString strHistory;
811       GetDirectoryHistoryString(pItem.get(), strHistory);
812       if (strHistory == strSelectedItem)
813       {
814         m_viewControl.SetSelectedItem(i);
815         bSelectedFound = true;
816       }
817     }
818   }
819
820   // if we haven't found the selected item, select the first item
821   if (!bSelectedFound)
822     m_viewControl.SetSelectedItem(0);
823
824   m_history.AddPath(m_vecItems->GetPath());
825
826   //m_history.DumpPathHistory();
827
828   return true;
829 }
830
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)
836 {
837
838 }
839
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)
844 {
845   m_unfilteredItems->Append(items);
846   
847   CStdString filter(GetProperty("filter").asString());
848   if (!filter.IsEmpty())
849   {
850     items.ClearItems();
851     GetFilteredItems(filter, items);
852   }
853 }
854
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)
859 {
860   if ( iItem < 0 || iItem >= (int)m_vecItems->Size() ) return true;
861   CFileItemPtr pItem = m_vecItems->Get(iItem);
862
863   if (pItem->IsParentFolder())
864   {
865     GoParentFolder();
866     return true;
867   }
868   if (pItem->GetPath() == "add" || pItem->GetPath() == "sources://add/") // 'add source button' in empty root
869   {
870     OnContextButton(iItem, CONTEXT_BUTTON_ADD_SOURCE);
871     return true;
872   }
873
874   if (!pItem->m_bIsFolder && pItem->IsFileFolder())
875   {
876     XFILE::IFileDirectory *pFileDirectory = NULL;
877     pFileDirectory = XFILE::CFactoryFileDirectory::Create(pItem->GetPath(), pItem.get(), "");
878     if(pFileDirectory)
879       pItem->m_bIsFolder = true;
880     else if(pItem->m_bIsFolder)
881       pItem->m_bIsFolder = false;
882     delete pFileDirectory;
883   }
884
885   if (pItem->IsScript())
886   {
887     // execute the script
888     CURL url(pItem->GetPath());
889     AddonPtr addon;
890     if (CAddonMgr::Get().GetAddon(url.GetHostName(), addon))
891     {
892 #ifdef HAS_PYTHON
893       if (!g_pythonParser.StopScript(addon->LibPath()))
894         g_pythonParser.evalFile(addon->LibPath(),addon);
895 #endif
896       return true;
897     }
898   }
899
900   if (pItem->m_bIsFolder)
901   {
902     if ( pItem->m_bIsShareOrDrive )
903     {
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))
907             return true;
908
909       if (!HaveDiscOrConnection(pItem->m_iDriveType))
910         return true;
911     }
912
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")))
916     {
917       // party mode playlist item - if it doesn't exist, prompt for user to define it
918       if (!XFILE::CFile::Exists(pItem->GetPath()))
919       {
920         m_vecItems->RemoveDiscCache(GetID());
921         if (CGUIDialogSmartPlaylistEditor::EditPlaylist(pItem->GetPath()))
922           Update(m_vecItems->GetPath());
923         return true;
924       }
925     }
926
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());
931
932     CFileItem directory(*pItem);
933     if (!Update(directory.GetPath()))
934       ShowShareErrorMessage(&directory);
935
936     return true;
937   }
938   else if (pItem->IsPlugin() && !pItem->GetProperty("isplayable").asBoolean())
939   {
940     return XFILE::CPluginDirectory::RunScriptWithParams(pItem->GetPath());
941   }
942   else
943   {
944     m_iSelectedItem = m_viewControl.GetSelectedItem();
945
946     if (pItem->GetPath() == "newplaylist://")
947     {
948       m_vecItems->RemoveDiscCache(GetID());
949       g_windowManager.ActivateWindow(WINDOW_MUSIC_PLAYLIST_EDITOR,"newplaylist://");
950       return true;
951     }
952     else if (pItem->GetPath().Left(19).Equals("newsmartplaylist://"))
953     {
954       m_vecItems->RemoveDiscCache(GetID());
955       if (CGUIDialogSmartPlaylistEditor::NewPlaylist(pItem->GetPath().Mid(19)))
956         Update(m_vecItems->GetPath());
957       return true;
958     }
959     else if (pItem->GetPath().Left(14).Equals("addons://more/"))
960     {
961       CBuiltins::Execute("ActivateWindow(AddonBrowser,addons://all/xbmc.addon." + pItem->GetPath().Mid(14) + ",return)");
962       return true;
963     }
964
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;
970
971     if (pItem->IsPlugin())
972     {
973       CURL url(pItem->GetPath());
974       AddonPtr addon;
975       if (CAddonMgr::Get().GetAddon(url.GetHostName(),addon))
976       {
977         PluginPtr plugin = boost::dynamic_pointer_cast<CPluginSource>(addon);
978         if (plugin && plugin->Provides(CPluginSource::AUDIO) && pItem->IsAudio())
979         {
980           iPlaylist = PLAYLIST_MUSIC;
981           autoplay = g_guiSettings.GetBool("musicplayer.autoplaynextitem");
982         }
983       }
984     }
985
986     if (autoplay && !g_partyModeManager.IsEnabled() && 
987         !pItem->IsPlayList() && !do_not_add_karaoke)
988     {
989       return OnPlayAndQueueMedia(pItem);
990     }
991     else
992     {
993       return OnPlayMedia(iItem);
994     }
995   }
996
997   return false;
998 }
999
1000 bool CGUIMediaWindow::OnSelect(int item)
1001 {
1002   return OnClick(item);
1003 }
1004
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)
1008 {
1009   if (iDriveType==CMediaSource::SOURCE_TYPE_DVD)
1010   {
1011     if (!g_mediaManager.IsDiscInDrive())
1012     {
1013       CGUIDialogOK::ShowAndGetInput(218, 219, 0, 0);
1014       return false;
1015     }
1016   }
1017   else if (iDriveType==CMediaSource::SOURCE_TYPE_REMOTE)
1018   {
1019     // TODO: Handle not connected to a remote share
1020     if ( !g_application.getNetwork().IsConnected() )
1021     {
1022       CGUIDialogOK::ShowAndGetInput(220, 221, 0, 0);
1023       return false;
1024     }
1025   }
1026
1027   return true;
1028 }
1029
1030 // \brief Shows a standard errormessage for a given pItem.
1031 void CGUIMediaWindow::ShowShareErrorMessage(CFileItem* pItem)
1032 {
1033   if (pItem->m_bIsShareOrDrive)
1034   {
1035     int idMessageText=0;
1036     const CURL& url=pItem->GetAsUrl();
1037     const CStdString& strHostName=url.GetHostName();
1038
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;
1045
1046     CGUIDialogOK::ShowAndGetInput(220, idMessageText, 0, 0);
1047   }
1048 }
1049
1050 // \brief The functon goes up one level in the directory tree
1051 void CGUIMediaWindow::GoParentFolder()
1052 {
1053   //m_history.DumpPathHistory();
1054
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())
1065   {
1066     URIUtils::AddSlashAtEnd(strParent);
1067     if (strParent.Equals(strPath))
1068       m_history.RemoveParentPath();
1069     else
1070       break;
1071     strParent = m_history.GetParentPath();
1072   }
1073
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();
1078   Update(strParent);
1079 }
1080
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)
1084 {
1085   if (pItem->m_bIsShareOrDrive)
1086   {
1087     // We are in the virual directory
1088
1089     // History string of the DVD drive
1090     // must be handel separately
1091     if (pItem->m_iDriveType == CMediaSource::SOURCE_TYPE_DVD)
1092     {
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)
1100       {
1101         strLabel.Delete(nPosOpen + 1, (nPosClose) - (nPosOpen + 1));
1102         strHistoryString = strLabel;
1103       }
1104       else
1105         strHistoryString = strLabel;
1106     }
1107     else
1108     {
1109       // Other items in virual directory
1110       CStdString strPath = pItem->GetPath();
1111       URIUtils::RemoveSlashAtEnd(strPath);
1112
1113       strHistoryString = pItem->GetLabel() + strPath;
1114     }
1115   }
1116   else if (pItem->m_lEndOffset>pItem->m_lStartOffset && pItem->m_lStartOffset != -1)
1117   {
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();
1122   }
1123   else
1124   {
1125     // Normal directory items
1126     strHistoryString = pItem->GetPath();
1127   }
1128   URIUtils::RemoveSlashAtEnd(strHistoryString);
1129   strHistoryString.ToLower();
1130 }
1131
1132 // \brief Call this function to create a directory history for the
1133 // path given by strDirectory.
1134 void CGUIMediaWindow::SetHistoryForPath(const CStdString& strDirectory)
1135 {
1136   // Make sure our shares are configured
1137   SetupShares();
1138   if (!strDirectory.IsEmpty())
1139   {
1140     // Build the directory history for default path
1141     CStdString strPath, strParentPath;
1142     strPath = strDirectory;
1143     URIUtils::RemoveSlashAtEnd(strPath);
1144
1145     CFileItemList items;
1146     m_rootDir.GetDirectory("", items);
1147
1148     m_history.ClearPathHistory();
1149
1150     while (URIUtils::GetParentPath(strPath, strParentPath))
1151     {
1152       for (int i = 0; i < (int)items.Size(); ++i)
1153       {
1154         CFileItemPtr pItem = items[i];
1155         CStdString path(pItem->GetPath());
1156         URIUtils::RemoveSlashAtEnd(path);
1157         if (path == strPath)
1158         {
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("");
1165
1166           //m_history.DumpPathHistory();
1167           return ;
1168         }
1169       }
1170
1171       URIUtils::AddSlashAtEnd(strPath);
1172       m_history.AddPathFront(strPath);
1173       m_history.SetSelectedItem(strPath, strParentPath);
1174       strPath = strParentPath;
1175       URIUtils::RemoveSlashAtEnd(strPath);
1176     }
1177   }
1178   else
1179     m_history.ClearPathHistory();
1180
1181   //m_history.DumpPathHistory();
1182 }
1183
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)
1188 {
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);
1194
1195   bool bResult = false;
1196   if (pItem->IsInternetStream() || pItem->IsPlayList())
1197     bResult = g_application.PlayMedia(*pItem, m_guiState->GetPlaylist());
1198   else
1199     bResult = g_application.PlayFile(*pItem);
1200
1201   if (pItem->m_lStartOffset == STARTOFFSET_RESUME)
1202     pItem->m_lStartOffset = 0;
1203
1204   return bResult;
1205 }
1206
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)
1211 {
1212   //play and add current directory to temporary playlist
1213   int iPlaylist = m_guiState->GetPlaylist();
1214   if (iPlaylist != PLAYLIST_NONE)
1215   {
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++ )
1221     {
1222       CFileItemPtr nItem = m_vecItems->Get(i);
1223
1224       if (nItem->m_bIsFolder)
1225         continue;
1226
1227       if (!nItem->IsPlayList() && !nItem->IsZIP() && !nItem->IsRAR())
1228         queueItems.Add(nItem);
1229
1230       if (nItem == item)
1231       { // item that was clicked
1232         mediaToPlay = queueItems.Size() - 1;
1233       }
1234     }
1235     g_playlistPlayer.Add(iPlaylist, queueItems);
1236
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());
1240
1241     // figure out where we start playback
1242     if (g_playlistPlayer.IsShuffled(iPlaylist))
1243     {
1244       int iIndex = g_playlistPlayer.GetPlaylist(iPlaylist).FindOrder(mediaToPlay);
1245       g_playlistPlayer.GetPlaylist(iPlaylist).Swap(0, iIndex);
1246       mediaToPlay = 0;
1247     }
1248
1249     // play
1250     g_playlistPlayer.SetCurrentPlaylist(iPlaylist);
1251     g_playlistPlayer.Play(mediaToPlay);
1252   }
1253   return true;
1254 }
1255
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()
1260 {
1261   int nItem = m_viewControl.GetSelectedItem();
1262   CStdString strSelected;
1263   if (nItem >= 0)
1264     strSelected = m_vecItems->Get(nItem)->GetPath();
1265
1266   FormatAndSort(*m_vecItems);
1267   UpdateButtons();
1268
1269   m_viewControl.SetItems(*m_vecItems);
1270   m_viewControl.SetSelectedItem(strSelected);
1271
1272   //  set the currently playing item as selected, if its in this directory
1273   if (m_guiState.get() && m_guiState->IsCurrentPlaylistDirectory(m_vecItems->GetPath()))
1274   {
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];
1280
1281     g_playlistPlayer.ClearPlaylist(iPlaylist);
1282     g_playlistPlayer.Reset();
1283
1284     for (int i = 0; i < m_vecItems->Size(); i++)
1285     {
1286       CFileItemPtr pItem = m_vecItems->Get(i);
1287       if (pItem->m_bIsFolder)
1288         continue;
1289
1290       if (!pItem->IsPlayList() && !pItem->IsZIP() && !pItem->IsRAR())
1291         g_playlistPlayer.Add(iPlaylist, pItem);
1292
1293       if (pItem->GetPath() == playlistItem.GetPath() &&
1294           pItem->m_lStartOffset == playlistItem.m_lStartOffset)
1295         g_playlistPlayer.SetCurrentSong(g_playlistPlayer.GetPlaylist(iPlaylist).size() - 1);
1296     }
1297   }
1298 }
1299
1300 void CGUIMediaWindow::OnDeleteItem(int iItem)
1301 {
1302   if ( iItem < 0 || iItem >= m_vecItems->Size()) return;
1303   CFileItemPtr item = m_vecItems->Get(iItem);
1304
1305   if (item->IsPlayList())
1306     item->m_bIsFolder = false;
1307
1308   if (g_settings.GetCurrentProfile().getLockMode() != LOCK_MODE_EVERYONE && g_settings.GetCurrentProfile().filesLocked())
1309     if (!g_passwordManager.IsMasterLockUnlocked(true))
1310       return;
1311
1312   if (!CFileUtils::DeleteItem(item))
1313     return;
1314   m_vecItems->RemoveDiscCache(GetID());
1315   Update(m_vecItems->GetPath());
1316   m_viewControl.SetSelectedItem(iItem);
1317 }
1318
1319 void CGUIMediaWindow::OnRenameItem(int iItem)
1320 {
1321   if ( iItem < 0 || iItem >= m_vecItems->Size()) return;
1322
1323   if (g_settings.GetCurrentProfile().getLockMode() != LOCK_MODE_EVERYONE && g_settings.GetCurrentProfile().filesLocked())
1324     if (!g_passwordManager.IsMasterLockUnlocked(true))
1325       return;
1326
1327   if (!CFileUtils::RenameFile(m_vecItems->Get(iItem)->GetPath()))
1328     return;
1329   m_vecItems->RemoveDiscCache(GetID());
1330   Update(m_vecItems->GetPath());
1331   m_viewControl.SetSelectedItem(iItem);
1332 }
1333
1334 void CGUIMediaWindow::OnInitWindow()
1335 {
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);
1340
1341   if (m_iSelectedItem > -1)
1342     m_viewControl.SetSelectedItem(m_iSelectedItem);
1343
1344   CGUIWindow::OnInitWindow();
1345 }
1346
1347 CGUIControl *CGUIMediaWindow::GetFirstFocusableControl(int id)
1348 {
1349   if (m_viewControl.HasControl(id))
1350     id = m_viewControl.GetCurrentControl();
1351   return CGUIWindow::GetFirstFocusableControl(id);
1352 }
1353
1354 void CGUIMediaWindow::SetupShares()
1355 {
1356   // Setup shares and filemasks for this window
1357   CFileItemList items;
1358   CGUIViewState* viewState=CGUIViewState::GetViewState(GetID(), items);
1359   if (viewState)
1360   {
1361     m_rootDir.SetMask(viewState->GetExtensions());
1362     m_rootDir.SetSources(viewState->GetSources());
1363     delete viewState;
1364   }
1365 }
1366
1367 bool CGUIMediaWindow::OnPopupMenu(int iItem)
1368 {
1369   // popup the context menu
1370   // grab our context menu
1371   CContextButtons buttons;
1372   GetContextButtons(iItem, buttons);
1373
1374   if (buttons.size())
1375   {
1376     // mark the item
1377     if (iItem >= 0 && iItem < m_vecItems->Size())
1378       m_vecItems->Get(iItem)->Select(true);
1379
1380     int choice = CGUIDialogContextMenu::ShowAndGetChoice(buttons);
1381
1382     // deselect our item
1383     if (iItem >= 0 && iItem < m_vecItems->Size())
1384       m_vecItems->Get(iItem)->Select(false);
1385
1386     if (choice >= 0)
1387       return OnContextButton(iItem, (CONTEXT_BUTTON)choice);
1388   }
1389   return false;
1390 }
1391
1392 void CGUIMediaWindow::GetContextButtons(int itemNumber, CContextButtons &buttons)
1393 {
1394   CFileItemPtr item = (itemNumber >= 0 && itemNumber < m_vecItems->Size()) ? m_vecItems->Get(itemNumber) : CFileItemPtr();
1395
1396   if (!item)
1397     return;
1398
1399   // user added buttons
1400   CStdString label;
1401   CStdString action;
1402   for (int i = CONTEXT_BUTTON_USER1; i <= CONTEXT_BUTTON_USER10; i++)
1403   {
1404     label.Format("contextmenulabel(%i)", i - CONTEXT_BUTTON_USER1);
1405     if (item->GetProperty(label).empty())
1406       break;
1407
1408     action.Format("contextmenuaction(%i)", i - CONTEXT_BUTTON_USER1);
1409     if (item->GetProperty(action).empty())
1410       break;
1411
1412     buttons.Add((CONTEXT_BUTTON)i, item->GetProperty(label).asString());
1413   }
1414
1415   if (item->GetProperty("pluginreplacecontextitems").asBoolean())
1416     return;
1417
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())
1421   {
1422     if (CFavourites::IsFavourite(item.get(), GetID()))
1423       buttons.Add(CONTEXT_BUTTON_ADD_FAVOURITE, 14077);     // Remove Favourite
1424     else
1425       buttons.Add(CONTEXT_BUTTON_ADD_FAVOURITE, 14076);     // Add To Favourites;
1426   }
1427 }
1428
1429 bool CGUIMediaWindow::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
1430 {
1431   switch (button)
1432   {
1433   case CONTEXT_BUTTON_ADD_FAVOURITE:
1434     {
1435       CFileItemPtr item = m_vecItems->Get(itemNumber);
1436       CFavourites::AddOrRemove(item.get(), GetID());
1437       return true;
1438     }
1439   case CONTEXT_BUTTON_PLUGIN_SETTINGS:
1440     {
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());
1446       return true;
1447     }
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:
1458     {
1459       CStdString action;
1460       action.Format("contextmenuaction(%i)", button - CONTEXT_BUTTON_USER1);
1461       g_application.getApplicationMessenger().ExecBuiltIn(m_vecItems->Get(itemNumber)->GetProperty(action).asString());
1462       return true;
1463     }
1464   default:
1465     break;
1466   }
1467   return false;
1468 }
1469
1470 const CGUIViewState *CGUIMediaWindow::GetViewState() const
1471 {
1472   return m_guiState.get();
1473 }
1474
1475 const CFileItemList& CGUIMediaWindow::CurrentDirectory() const
1476 {
1477   return *m_vecItems;
1478 }
1479
1480 bool CGUIMediaWindow::WaitForNetwork() const
1481 {
1482   if (g_application.getNetwork().IsAvailable())
1483     return true;
1484
1485   CGUIDialogProgress *progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
1486   if (!progress)
1487     return true;
1488
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())
1495   {
1496     progress->Progress();
1497     if (progress->IsCanceled())
1498     {
1499       progress->Close();
1500       return false;
1501     }
1502   }
1503   progress->Close();
1504   return true;
1505 }
1506
1507 void CGUIMediaWindow::OnFilterItems(const CStdString &filter)
1508 {
1509   CStdString currentItem;
1510   int item = m_viewControl.GetSelectedItem();
1511   if (item >= 0)
1512     currentItem = m_vecItems->Get(item)->GetPath();
1513   
1514   m_viewControl.Clear();
1515   
1516   CFileItemList items;
1517   GetFilteredItems(filter, items);
1518   if (filter.IsEmpty() || items.GetObjectCount() > 0)
1519   {
1520     m_vecItems->ClearItems();
1521     m_vecItems->Append(items);
1522     SetProperty("filter", filter);
1523   }
1524   
1525   // and update our view control + buttons
1526   m_viewControl.SetItems(*m_vecItems);
1527   m_viewControl.SetSelectedItem(currentItem);
1528   UpdateButtons();
1529 }
1530
1531 void CGUIMediaWindow::GetFilteredItems(const CStdString &filter, CFileItemList &items)
1532 {
1533   CStdString trimmedFilter(filter);
1534   trimmedFilter.TrimLeft().ToLower();
1535   
1536   if (trimmedFilter.IsEmpty())
1537   {
1538     items.Append(*m_unfilteredItems);
1539     return;
1540   }
1541   
1542   bool numericMatch = StringUtils::IsNaturalNumber(trimmedFilter);
1543   for (int i = 0; i < m_unfilteredItems->Size(); i++)
1544   {
1545     CFileItemPtr item = m_unfilteredItems->Get(i);
1546     if (item->IsParentFolder())
1547     {
1548       items.Add(item);
1549       continue;
1550     }
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.
1556     CStdString match;
1557     /*    if (item->GetFocusedLayout())
1558      match = item->GetFocusedLayout()->GetAllText();
1559      else if (item->GetLayout())
1560      match = item->GetLayout()->GetAllText();
1561      else*/
1562     match = item->GetLabel(); // Filter label only for now
1563     
1564     if (numericMatch)
1565       StringUtils::WordToDigits(match);
1566     
1567     size_t pos = StringUtils::FindWords(match.c_str(), trimmedFilter.c_str());
1568     if (pos != CStdString::npos)
1569       items.Add(item);
1570   }
1571 }
1572
1573 CStdString CGUIMediaWindow::GetStartFolder(const CStdString &dir)
1574 {
1575   if (dir.Equals("$ROOT") || dir.Equals("Root"))
1576     return "";
1577   return dir;
1578 }