Merge branch 'container_foldername'
[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 "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 "network/Network.h"
33 #include "utils/RegExp.h"
34 #include "PartyModeManager.h"
35 #include "dialogs/GUIDialogMediaSource.h"
36 #include "GUIWindowFileManager.h"
37 #include "Favourites.h"
38 #include "utils/LabelFormatter.h"
39 #include "dialogs/GUIDialogProgress.h"
40 #include "settings/AdvancedSettings.h"
41 #include "settings/GUISettings.h"
42
43 #include "dialogs/GUIDialogSmartPlaylistEditor.h"
44 #include "addons/GUIDialogAddonSettings.h"
45 #include "dialogs/GUIDialogYesNo.h"
46 #include "guilib/GUIWindowManager.h"
47 #include "dialogs/GUIDialogOK.h"
48 #include "playlists/PlayList.h"
49 #include "storage/MediaManager.h"
50 #include "settings/Settings.h"
51 #include "utils/StringUtils.h"
52 #include "utils/URIUtils.h"
53 #include "guilib/LocalizeStrings.h"
54 #include "utils/TimeUtils.h"
55 #include "filesystem/FactoryFileDirectory.h"
56 #include "utils/log.h"
57 #include "utils/FileUtils.h"
58 #include "guilib/GUIEditControl.h"
59 #include "dialogs/GUIDialogKeyboard.h"
60 #ifdef HAS_PYTHON
61 #include "interfaces/python/XBPython.h"
62 #endif
63 #include "interfaces/Builtins.h"
64
65 #define CONTROL_BTNVIEWASICONS     2
66 #define CONTROL_BTNSORTBY          3
67 #define CONTROL_BTNSORTASC         4
68 #define CONTROL_BTN_FILTER        19
69
70 #define CONTROL_LABELFILES        12
71
72 using namespace std;
73 using namespace ADDON;
74
75 CGUIMediaWindow::CGUIMediaWindow(int id, const char *xmlFile)
76     : CGUIWindow(id, xmlFile)
77 {
78   m_vecItems = new CFileItemList;
79   m_unfilteredItems = new CFileItemList;
80   m_vecItems->m_strPath = "?";
81   m_iLastControl = -1;
82   m_iSelectedItem = -1;
83
84   m_guiState.reset(CGUIViewState::GetViewState(GetID(), *m_vecItems));
85 }
86
87 CGUIMediaWindow::~CGUIMediaWindow()
88 {
89   delete m_vecItems;
90   delete m_unfilteredItems;
91 }
92
93 #define CONTROL_VIEW_START        50
94 #define CONTROL_VIEW_END          59
95
96 void CGUIMediaWindow::LoadAdditionalTags(TiXmlElement *root)
97 {
98   CGUIWindow::LoadAdditionalTags(root);
99   // configure our view control
100   m_viewControl.Reset();
101   m_viewControl.SetParentWindow(GetID());
102   TiXmlElement *element = root->FirstChildElement("views");
103   if (element && element->FirstChild())
104   { // format is <views>50,29,51,95</views>
105     CStdString allViews = element->FirstChild()->Value();
106     CStdStringArray views;
107     StringUtils::SplitString(allViews, ",", views);
108     for (unsigned int i = 0; i < views.size(); i++)
109     {
110       int controlID = atol(views[i].c_str());
111       CGUIControl *control = (CGUIControl *)GetControl(controlID);
112       if (control && control->IsContainer())
113         m_viewControl.AddView(control);
114     }
115   }
116   else
117   { // backward compatibility
118     vector<CGUIControl *> controls;
119     GetContainers(controls);
120     for (ciControls it = controls.begin(); it != controls.end(); it++)
121     {
122       CGUIControl *control = *it;
123       if (control->GetID() >= CONTROL_VIEW_START && control->GetID() <= CONTROL_VIEW_END)
124         m_viewControl.AddView(control);
125     }
126   }
127   m_viewControl.SetViewControlID(CONTROL_BTNVIEWASICONS);
128 }
129
130 void CGUIMediaWindow::OnWindowLoaded()
131 {
132   SendMessage(GUI_MSG_SET_TYPE, CONTROL_BTN_FILTER, CGUIEditControl::INPUT_TYPE_FILTER);
133   CGUIWindow::OnWindowLoaded();
134   SetupShares();
135 }
136
137 void CGUIMediaWindow::OnWindowUnload()
138 {
139   CGUIWindow::OnWindowUnload();
140   m_viewControl.Reset();
141 }
142
143 CFileItemPtr CGUIMediaWindow::GetCurrentListItem(int offset)
144 {
145   int item = m_viewControl.GetSelectedItem();
146   if (!m_vecItems->Size() || item < 0)
147     return CFileItemPtr();
148   item = (item + offset) % m_vecItems->Size();
149   if (item < 0) item += m_vecItems->Size();
150   return m_vecItems->Get(item);
151 }
152
153 bool CGUIMediaWindow::OnAction(const CAction &action)
154 {
155   if (action.GetID() == ACTION_PARENT_DIR)
156   {
157     if ((m_vecItems->IsVirtualDirectoryRoot() || m_vecItems->m_strPath == m_startDirectory) && g_advancedSettings.m_bUseEvilB)
158       g_windowManager.PreviousWindow();
159     else
160       GoParentFolder();
161     return true;
162   }
163
164   if (action.GetID() == ACTION_PREVIOUS_MENU)
165   {
166     g_windowManager.PreviousWindow();
167     return true;
168   }
169
170   // the non-contextual menu can be called at any time
171   if (action.GetID() == ACTION_CONTEXT_MENU && !m_viewControl.HasControl(GetFocusedControlID()))
172   {
173     OnPopupMenu(-1);
174     return true;
175   }
176
177   if (CGUIWindow::OnAction(action))
178     return true;
179
180   // live filtering
181   if (action.GetID() == ACTION_FILTER_CLEAR)
182   {
183     CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS);
184     message.SetStringParam("");
185     OnMessage(message);
186     return true;
187   }
188
189   if (action.GetID() == ACTION_BACKSPACE)
190   {
191     CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS, 2); // 2 for delete
192     OnMessage(message);
193     return true;
194   }
195
196   if (action.GetID() >= ACTION_FILTER_SMS2 && action.GetID() <= ACTION_FILTER_SMS9)
197   {
198     CStdString filter;
199     filter.Format("%i", (int)(action.GetID() - ACTION_FILTER_SMS2 + 2));
200     CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS, 1); // 1 for append
201     message.SetStringParam(filter);
202     OnMessage(message);
203     return true;
204   }
205
206   return false;
207 }
208
209 bool CGUIMediaWindow::OnMessage(CGUIMessage& message)
210 {
211   switch ( message.GetMessage() )
212   {
213   case GUI_MSG_WINDOW_DEINIT:
214     {
215       m_iSelectedItem = m_viewControl.GetSelectedItem();
216       m_iLastControl = GetFocusedControlID();
217       CGUIWindow::OnMessage(message);
218       // Call ClearFileItems() after our window has finished doing any WindowClose
219       // animations
220       ClearFileItems();
221       return true;
222     }
223     break;
224
225   case GUI_MSG_CLICKED:
226     {
227       int iControl = message.GetSenderId();
228       if (iControl == CONTROL_BTNVIEWASICONS)
229       {
230         // view as control could be a select button
231         int viewMode = 0;
232         const CGUIControl *control = GetControl(CONTROL_BTNVIEWASICONS);
233         if (control && control->GetControlType() != CGUIControl::GUICONTROL_BUTTON)
234         {
235           CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_BTNVIEWASICONS);
236           OnMessage(msg);
237           viewMode = m_viewControl.GetViewModeNumber(msg.GetParam1());
238         }
239         else
240           viewMode = m_viewControl.GetNextViewMode();
241
242         if (m_guiState.get())
243           m_guiState->SaveViewAsControl(viewMode);
244
245         UpdateButtons();
246         return true;
247       }
248       else if (iControl == CONTROL_BTNSORTASC) // sort asc
249       {
250         if (m_guiState.get())
251           m_guiState->SetNextSortOrder();
252         UpdateFileList();
253         return true;
254       }
255       else if (iControl == CONTROL_BTNSORTBY) // sort by
256       {
257         if (m_guiState.get())
258           m_guiState->SetNextSortMethod();
259         UpdateFileList();
260         return true;
261       }
262       else if (iControl == CONTROL_BTN_FILTER)
263       {
264         if (GetControl(iControl)->GetControlType() == CGUIControl::GUICONTROL_EDIT)
265         { // filter updated
266           CGUIMessage selected(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_BTN_FILTER);
267           OnMessage(selected);
268           OnFilterItems(selected.GetLabel());
269           return true;
270         }
271         if (GetProperty("filter").IsEmpty())
272         {
273           CStdString filter = GetProperty("filter");
274           CGUIDialogKeyboard::ShowAndGetFilter(filter, false);
275           SetProperty("filter", filter);
276         }
277         else
278           OnFilterItems("");
279         return true;
280       }
281       else if (m_viewControl.HasControl(iControl))  // list/thumb control
282       {
283         int iItem = m_viewControl.GetSelectedItem();
284         int iAction = message.GetParam1();
285         if (iItem < 0) break;
286         if (iAction == ACTION_SELECT_ITEM || iAction == ACTION_MOUSE_LEFT_CLICK)
287         {
288           OnSelect(iItem);
289         }
290         else if (iAction == ACTION_CONTEXT_MENU || iAction == ACTION_MOUSE_RIGHT_CLICK)
291         {
292           OnPopupMenu(iItem);
293           return true;
294         }
295       }
296     }
297     break;
298
299   case GUI_MSG_SETFOCUS:
300     {
301       if (m_viewControl.HasControl(message.GetControlId()) && m_viewControl.GetCurrentControl() != message.GetControlId())
302       {
303         m_viewControl.SetFocused();
304         return true;
305       }
306     }
307     break;
308
309   case GUI_MSG_NOTIFY_ALL:
310     { // Message is received even if this window is inactive
311       if (message.GetParam1() == GUI_MSG_WINDOW_RESET)
312       {
313         m_vecItems->m_strPath = "?";
314         return true;
315       }
316       else if ( message.GetParam1() == GUI_MSG_REFRESH_THUMBS )
317       {
318         for (int i = 0; i < m_vecItems->Size(); i++)
319           m_vecItems->Get(i)->FreeMemory(true);
320         break;  // the window will take care of any info images
321       }
322       else if (message.GetParam1() == GUI_MSG_REMOVED_MEDIA)
323       {
324         if (m_vecItems->IsVirtualDirectoryRoot() && IsActive())
325         {
326           int iItem = m_viewControl.GetSelectedItem();
327           Update(m_vecItems->m_strPath);
328           m_viewControl.SetSelectedItem(iItem);
329         }
330         else if (m_vecItems->IsRemovable())
331         { // check that we have this removable share still
332           if (!m_rootDir.IsInSource(m_vecItems->m_strPath))
333           { // don't have this share any more
334             if (IsActive()) Update("");
335             else
336             {
337               m_history.ClearPathHistory();
338               m_vecItems->m_strPath="";
339             }
340           }
341         }
342
343         return true;
344       }
345       else if (message.GetParam1()==GUI_MSG_UPDATE_SOURCES)
346       { // State of the sources changed, so update our view
347         if (m_vecItems->IsVirtualDirectoryRoot() && IsActive())
348         {
349           int iItem = m_viewControl.GetSelectedItem();
350           Update(m_vecItems->m_strPath);
351           m_viewControl.SetSelectedItem(iItem);
352         }
353         return true;
354       }
355       else if (message.GetParam1()==GUI_MSG_UPDATE && IsActive())
356       {
357         if (message.GetNumStringParams())
358         {
359           m_vecItems->m_strPath = message.GetStringParam();
360           if (message.GetParam2()) // param2 is used for resetting the history
361             SetHistoryForPath(m_vecItems->m_strPath);
362         }
363         // clear any cached listing
364         m_vecItems->RemoveDiscCache(GetID());
365         Update(m_vecItems->m_strPath);
366       }
367       else if (message.GetParam1()==GUI_MSG_UPDATE_ITEM && message.GetItem())
368       {
369         CFileItemPtr newItem = boost::static_pointer_cast<CFileItem>(message.GetItem());
370         if (IsActive())
371         {
372           if (m_vecItems->UpdateItem(newItem.get()) && message.GetParam2() == 1)
373           { // need the list updated as well
374             UpdateFileList();
375           }
376         }
377         else if (newItem)
378         { // need to remove the disc cache
379           CFileItemList items;
380           URIUtils::GetDirectory(newItem->m_strPath, items.m_strPath);
381           items.RemoveDiscCache(GetID());
382         }
383       }
384       else if (message.GetParam1()==GUI_MSG_UPDATE_PATH)
385       {
386         if (IsActive())
387         {
388           if((message.GetStringParam() == m_vecItems->m_strPath) ||
389              (m_vecItems->IsMultiPath() && XFILE::CMultiPathDirectory::HasPath(m_vecItems->m_strPath, message.GetStringParam())))
390           {
391             Update(m_vecItems->m_strPath);
392           }
393         }
394       }
395       else if (message.GetParam1() == GUI_MSG_FILTER_ITEMS && IsActive())
396       {
397         CStdString filter(GetProperty("filter"));
398         if (message.GetParam2() == 1) // append
399           filter += message.GetStringParam();
400         else if (message.GetParam2() == 2)
401         { // delete
402           if (filter.size())
403             filter = filter.Left(filter.size() - 1);
404         }
405         else
406           filter = message.GetStringParam();
407         OnFilterItems(filter);
408         return true;
409       }
410       else
411         return CGUIWindow::OnMessage(message);
412
413       return true;
414     }
415     break;
416   case GUI_MSG_PLAYBACK_STARTED:
417   case GUI_MSG_PLAYBACK_ENDED:
418   case GUI_MSG_PLAYBACK_STOPPED:
419   case GUI_MSG_PLAYLIST_CHANGED:
420   case GUI_MSG_PLAYLISTPLAYER_STOPPED:
421   case GUI_MSG_PLAYLISTPLAYER_STARTED:
422   case GUI_MSG_PLAYLISTPLAYER_CHANGED:
423     { // send a notify all to all controls on this window
424       CGUIMessage msg(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_REFRESH_LIST);
425       OnMessage(msg);
426       break;
427     }
428   case GUI_MSG_CHANGE_VIEW_MODE:
429     {
430       int viewMode = 0;
431       if (message.GetParam1())  // we have an id
432         viewMode = m_viewControl.GetViewModeByID(message.GetParam1());
433       else if (message.GetParam2())
434         viewMode = m_viewControl.GetNextViewMode((int)message.GetParam2());
435
436       if (m_guiState.get())
437         m_guiState->SaveViewAsControl(viewMode);
438       UpdateButtons();
439       return true;
440     }
441     break;
442   case GUI_MSG_CHANGE_SORT_METHOD:
443     {
444       if (m_guiState.get())
445       {
446         if (message.GetParam1())
447           m_guiState->SetCurrentSortMethod((int)message.GetParam1());
448         else if (message.GetParam2())
449           m_guiState->SetNextSortMethod((int)message.GetParam2());
450       }
451       UpdateFileList();
452       return true;
453     }
454     break;
455   case GUI_MSG_CHANGE_SORT_DIRECTION:
456     {
457       if (m_guiState.get())
458         m_guiState->SetNextSortOrder();
459       UpdateFileList();
460       return true;
461     }
462     break;
463   case GUI_MSG_WINDOW_INIT:
464     {
465       if (m_vecItems->m_strPath == "?")
466         m_vecItems->m_strPath.Empty();
467       CStdString dir = message.GetStringParam(0);
468       const CStdString &ret = message.GetStringParam(1);
469       bool returning = ret.CompareNoCase("return") == 0;
470       if (!dir.IsEmpty())
471       {
472         m_history.ClearPathHistory();
473         // ensure our directory is valid
474         dir = GetStartFolder(dir);
475         if (!returning || m_vecItems->m_strPath.Left(dir.GetLength()) != dir)
476         { // we're not returning to the same path, so set our directory to the requested path
477           m_vecItems->m_strPath = dir;
478         }
479         // check for network up
480         if (URIUtils::IsRemote(m_vecItems->m_strPath) && !WaitForNetwork())
481           m_vecItems->m_strPath.Empty();
482         SetHistoryForPath(m_vecItems->m_strPath);
483       }
484       if (message.GetParam1() != WINDOW_INVALID)
485       { // first time to this window - make sure we set the root path
486         m_startDirectory = returning ? dir : "";
487       }
488     }
489     break;
490   }
491
492   return CGUIWindow::OnMessage(message);
493 }
494
495 // \brief Updates the states (enable, disable, visible...)
496 // of the controls defined by this window
497 // Override this function in a derived class to add new controls
498 void CGUIMediaWindow::UpdateButtons()
499 {
500   if (m_guiState.get())
501   {
502     // Update sorting controls
503     if (m_guiState->GetDisplaySortOrder()==SORT_ORDER_NONE)
504     {
505       CONTROL_DISABLE(CONTROL_BTNSORTASC);
506     }
507     else
508     {
509       CONTROL_ENABLE(CONTROL_BTNSORTASC);
510       if (m_guiState->GetDisplaySortOrder()==SORT_ORDER_ASC)
511       {
512         CGUIMessage msg(GUI_MSG_DESELECTED, GetID(), CONTROL_BTNSORTASC);
513         g_windowManager.SendMessage(msg);
514       }
515       else
516       {
517         CGUIMessage msg(GUI_MSG_SELECTED, GetID(), CONTROL_BTNSORTASC);
518         g_windowManager.SendMessage(msg);
519       }
520     }
521
522     // Update list/thumb control
523     m_viewControl.SetCurrentView(m_guiState->GetViewAsControl());
524
525     // Update sort by button
526     if (m_guiState->GetSortMethod()==SORT_METHOD_NONE)
527     {
528       CONTROL_DISABLE(CONTROL_BTNSORTBY);
529     }
530     else
531     {
532       CONTROL_ENABLE(CONTROL_BTNSORTBY);
533     }
534     CStdString sortLabel;
535     sortLabel.Format(g_localizeStrings.Get(550).c_str(), g_localizeStrings.Get(m_guiState->GetSortMethodLabel()).c_str());
536     SET_CONTROL_LABEL(CONTROL_BTNSORTBY, sortLabel);
537   }
538
539   CStdString items;
540   items.Format("%i %s", m_vecItems->GetObjectCount(), g_localizeStrings.Get(127).c_str());
541   SET_CONTROL_LABEL(CONTROL_LABELFILES, items);
542
543   //#ifdef PRE_SKIN_VERSION_3
544   SET_CONTROL_SELECTED(GetID(),CONTROL_BTN_FILTER, !GetProperty("filter").IsEmpty());
545   SET_CONTROL_LABEL2(CONTROL_BTN_FILTER, GetProperty("filter"));
546   //#endif
547 }
548
549 void CGUIMediaWindow::ClearFileItems()
550 {
551   m_viewControl.Clear();
552   m_vecItems->Clear(); // will clean up everything
553   m_unfilteredItems->Clear();
554 }
555
556 // \brief Sorts Fileitems based on the sort method and sort oder provided by guiViewState
557 void CGUIMediaWindow::SortItems(CFileItemList &items)
558 {
559   auto_ptr<CGUIViewState> guiState(CGUIViewState::GetViewState(GetID(), items));
560
561   if (guiState.get())
562   {
563     items.Sort(guiState->GetSortMethod(), guiState->GetDisplaySortOrder());
564
565     // Should these items be saved to the hdd
566     if (items.CacheToDiscAlways())
567       items.Save(GetID());
568   }
569 }
570
571 // \brief Formats item labels based on the formatting provided by guiViewState
572 void CGUIMediaWindow::FormatItemLabels(CFileItemList &items, const LABEL_MASKS &labelMasks)
573 {
574   CLabelFormatter fileFormatter(labelMasks.m_strLabelFile, labelMasks.m_strLabel2File);
575   CLabelFormatter folderFormatter(labelMasks.m_strLabelFolder, labelMasks.m_strLabel2Folder);
576   for (int i=0; i<items.Size(); ++i)
577   {
578     CFileItemPtr pItem=items[i];
579
580     if (pItem->IsLabelPreformated())
581       continue;
582
583     if (pItem->m_bIsFolder)
584       folderFormatter.FormatLabels(pItem.get());
585     else
586       fileFormatter.FormatLabels(pItem.get());
587   }
588
589   if(items.GetSortMethod() == SORT_METHOD_LABEL_IGNORE_THE
590   || items.GetSortMethod() == SORT_METHOD_LABEL)
591     items.ClearSortState();
592 }
593
594 // \brief Prepares and adds the fileitems list/thumb panel
595 void CGUIMediaWindow::FormatAndSort(CFileItemList &items)
596 {
597   auto_ptr<CGUIViewState> viewState(CGUIViewState::GetViewState(GetID(), items));
598
599   if (viewState.get())
600   {
601     LABEL_MASKS labelMasks;
602     viewState->GetSortMethodLabelMasks(labelMasks);
603     FormatItemLabels(items, labelMasks);
604   }
605   SortItems(items);
606 }
607
608 /*!
609   \brief Overwrite to fill fileitems from a source
610   \param strDirectory Path to read
611   \param items Fill with items specified in \e strDirectory
612   */
613 bool CGUIMediaWindow::GetDirectory(const CStdString &strDirectory, CFileItemList &items)
614 {
615   // cleanup items
616   if (items.Size())
617     items.Clear();
618
619   CStdString strParentPath=m_history.GetParentPath();
620
621   CLog::Log(LOGDEBUG,"CGUIMediaWindow::GetDirectory (%s)", strDirectory.c_str());
622   CLog::Log(LOGDEBUG,"  ParentPath = [%s]", strParentPath.c_str());
623
624   // see if we can load a previously cached folder
625   CFileItemList cachedItems(strDirectory);
626   if (!strDirectory.IsEmpty() && cachedItems.Load(GetID()))
627   {
628     items.Assign(cachedItems);
629   }
630   else
631   {
632     unsigned int time = CTimeUtils::GetTimeMS();
633
634     if (strDirectory.IsEmpty())
635       SetupShares();
636
637     if (!m_rootDir.GetDirectory(strDirectory, items))
638       return false;
639
640     // took over a second, and not normally cached, so cache it
641     if (time + 1000 < CTimeUtils::GetTimeMS() && items.CacheToDiscIfSlow())
642       items.Save(GetID());
643
644     // if these items should replace the current listing, then pop it off the top
645     if (items.GetReplaceListing())
646       m_history.RemoveParentPath();
647   }
648
649   if (m_guiState.get() && !m_guiState->HideParentDirItems() && !items.m_strPath.IsEmpty())
650   {
651     CFileItemPtr pItem(new CFileItem(".."));
652     pItem->m_strPath = strParentPath;
653     pItem->m_bIsFolder = true;
654     pItem->m_bIsShareOrDrive = false;
655     items.AddFront(pItem, 0);
656   }
657
658   int iWindow = GetID();
659   CStdStringArray regexps;
660
661   if (iWindow == WINDOW_VIDEO_FILES)
662     regexps = g_advancedSettings.m_videoExcludeFromListingRegExps;
663   if (iWindow == WINDOW_MUSIC_FILES)
664     regexps = g_advancedSettings.m_audioExcludeFromListingRegExps;
665   if (iWindow == WINDOW_PICTURES)
666     regexps = g_advancedSettings.m_pictureExcludeFromListingRegExps;
667
668   if (regexps.size())
669   {
670     for (int i=0; i < items.Size();)
671     {
672       if (CUtil::ExcludeFileOrFolder(items[i]->m_strPath, regexps))
673         items.Remove(i);
674       else
675         i++;
676     }
677   }
678
679   // clear the filter
680   SetProperty("filter", "");
681   return true;
682 }
683
684 // \brief Set window to a specific directory
685 // \param strDirectory The directory to be displayed in list/thumb control
686 // This function calls OnPrepareFileItems() and OnFinalizeFileItems()
687 bool CGUIMediaWindow::Update(const CStdString &strDirectory)
688 {
689   // TODO: OnInitWindow calls Update() before window path has been set properly.
690   if (strDirectory == "?")
691     return false;
692
693   // get selected item
694   int iItem = m_viewControl.GetSelectedItem();
695   CStdString strSelectedItem = "";
696   if (iItem >= 0 && iItem < m_vecItems->Size())
697   {
698     CFileItemPtr pItem = m_vecItems->Get(iItem);
699     if (!pItem->IsParentFolder())
700     {
701       GetDirectoryHistoryString(pItem.get(), strSelectedItem);
702     }
703   }
704
705   CStdString strOldDirectory = m_vecItems->m_strPath;
706
707   m_history.SetSelectedItem(strSelectedItem, strOldDirectory);
708
709   CFileItemList items;
710   if (!GetDirectory(strDirectory, items))
711   {
712     CLog::Log(LOGERROR,"CGUIMediaWindow::GetDirectory(%s) failed", strDirectory.c_str());
713     // if the directory is the same as the old directory, then we'll return
714     // false.  Else, we assume we can get the previous directory
715     if (strDirectory.Equals(strOldDirectory))
716       return false;
717
718     // We assume, we can get the parent
719     // directory again, but we have to
720     // return false to be able to eg. show
721     // an error message.
722     CStdString strParentPath = m_history.GetParentPath();
723     m_history.RemoveParentPath();
724     Update(strParentPath);
725     return false;
726   }
727
728   if (items.GetLabel().IsEmpty())
729     items.SetLabel(CUtil::GetTitleFromPath(items.m_strPath, true));
730
731   ClearFileItems();
732   m_vecItems->Copy(items);
733
734   // if we're getting the root source listing
735   // make sure the path history is clean
736   if (strDirectory.IsEmpty())
737     m_history.ClearPathHistory();
738
739   int iWindow = GetID();
740   int showLabel = 0;
741   if (strDirectory.IsEmpty() && (iWindow == WINDOW_MUSIC_FILES ||
742                                  iWindow == WINDOW_FILES ||
743                                  iWindow == WINDOW_PICTURES ||
744                                  iWindow == WINDOW_PROGRAMS))
745     showLabel = 1026;
746   if (strDirectory.Equals("sources://video/"))
747     showLabel = 999;
748   if (showLabel && (m_vecItems->Size() == 0 || !m_guiState->DisableAddSourceButtons())) // add 'add source button'
749   {
750     CStdString strLabel = g_localizeStrings.Get(showLabel);
751     CFileItemPtr pItem(new CFileItem(strLabel));
752     pItem->m_strPath = "add";
753     pItem->SetIconImage("DefaultAddSource.png");
754     pItem->SetLabel(strLabel);
755     pItem->SetLabelPreformated(true);
756     m_vecItems->Add(pItem);
757   }
758   m_iLastControl = GetFocusedControlID();
759
760   //  Ask the derived class if it wants to load additional info
761   //  for the fileitems like media info or additional
762   //  filtering on the items, setting thumbs.
763   OnPrepareFileItems(*m_vecItems);
764
765   m_vecItems->FillInDefaultIcons();
766
767   m_guiState.reset(CGUIViewState::GetViewState(GetID(), *m_vecItems));
768
769   FormatAndSort(*m_vecItems);
770
771   // Ask the devived class if it wants to do custom list operations,
772   // eg. changing the label
773   OnFinalizeFileItems(*m_vecItems);
774   UpdateButtons();
775
776   m_viewControl.SetItems(*m_vecItems);
777
778   strSelectedItem = m_history.GetSelectedItem(m_vecItems->m_strPath);
779
780   bool bSelectedFound = false;
781   //int iSongInDirectory = -1;
782   for (int i = 0; i < m_vecItems->Size(); ++i)
783   {
784     CFileItemPtr pItem = m_vecItems->Get(i);
785
786     // Update selected item
787     if (!bSelectedFound)
788     {
789       CStdString strHistory;
790       GetDirectoryHistoryString(pItem.get(), strHistory);
791       if (strHistory == strSelectedItem)
792       {
793         m_viewControl.SetSelectedItem(i);
794         bSelectedFound = true;
795       }
796     }
797   }
798
799   // if we haven't found the selected item, select the first item
800   if (!bSelectedFound)
801     m_viewControl.SetSelectedItem(0);
802
803   m_history.AddPath(m_vecItems->m_strPath);
804
805   //m_history.DumpPathHistory();
806
807   return true;
808 }
809
810 // \brief This function will be called by Update() before the
811 // labels of the fileitems are formatted. Override this function
812 // to set custom thumbs or load additional media info.
813 // It's used to load tag info for music.
814 void CGUIMediaWindow::OnPrepareFileItems(CFileItemList &items)
815 {
816
817 }
818
819 // \brief This function will be called by Update() after the
820 // labels of the fileitems are formatted. Override this function
821 // to modify the fileitems. Eg. to modify the item label
822 void CGUIMediaWindow::OnFinalizeFileItems(CFileItemList &items)
823 {
824   m_unfilteredItems->Append(items);
825   
826   CStdString filter(GetProperty("filter"));
827   if (!filter.IsEmpty())
828   {
829     items.ClearItems();
830     GetFilteredItems(filter, items);
831   }
832
833   // The idea here is to ensure we have something to focus if our file list
834   // is empty.  As such, this check MUST be last and ignore the hide parent
835   // fileitems settings.
836   if (items.IsEmpty())
837   {
838     CFileItemPtr pItem(new CFileItem(".."));
839     pItem->m_strPath=m_history.GetParentPath();
840     pItem->m_bIsFolder = true;
841     pItem->m_bIsShareOrDrive = false;
842     items.AddFront(pItem, 0);
843   }
844 }
845
846 // \brief With this function you can react on a users click in the list/thumb panel.
847 // It returns true, if the click is handled.
848 // This function calls OnPlayMedia()
849 bool CGUIMediaWindow::OnClick(int iItem)
850 {
851   if ( iItem < 0 || iItem >= (int)m_vecItems->Size() ) return true;
852   CFileItemPtr pItem = m_vecItems->Get(iItem);
853
854   if (pItem->IsParentFolder())
855   {
856     GoParentFolder();
857     return true;
858   }
859   if (pItem->m_strPath == "add" || pItem->m_strPath == "sources://add/") // 'add source button' in empty root
860   {
861     OnContextButton(iItem, CONTEXT_BUTTON_ADD_SOURCE);
862     return true;
863   }
864
865   if (!pItem->m_bIsFolder && pItem->IsFileFolder())
866   {
867     XFILE::IFileDirectory *pFileDirectory = NULL;
868     pFileDirectory = XFILE::CFactoryFileDirectory::Create(pItem->m_strPath, pItem.get(), "");
869     if(pFileDirectory)
870       pItem->m_bIsFolder = true;
871     else if(pItem->m_bIsFolder)
872       pItem->m_bIsFolder = false;
873     delete pFileDirectory;
874   }
875
876   CURL url(pItem->m_strPath);
877   if (url.GetProtocol() == "script")
878   {
879     // execute the script
880     AddonPtr addon;
881     if (CAddonMgr::Get().GetAddon(url.GetHostName(), addon))
882     {
883 #ifdef HAS_PYTHON
884       if (!g_pythonParser.StopScript(addon->LibPath()))
885         g_pythonParser.evalFile(addon->LibPath());
886 #endif
887       return true;
888     }
889   }
890
891   if (pItem->m_bIsFolder)
892   {
893     if ( pItem->m_bIsShareOrDrive )
894     {
895       const CStdString& strLockType=m_guiState->GetLockType();
896       if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE)
897         if (!strLockType.IsEmpty() && !g_passwordManager.IsItemUnlocked(pItem.get(), strLockType))
898             return true;
899
900       if (!HaveDiscOrConnection(pItem->m_strPath, pItem->m_iDriveType))
901         return true;
902     }
903
904     // check for the partymode playlist items - they may not exist yet
905     if ((pItem->m_strPath == g_settings.GetUserDataItem("PartyMode.xsp")) ||
906         (pItem->m_strPath == g_settings.GetUserDataItem("PartyMode-Video.xsp")))
907     {
908       // party mode playlist item - if it doesn't exist, prompt for user to define it
909       if (!XFILE::CFile::Exists(pItem->m_strPath))
910       {
911         m_vecItems->RemoveDiscCache(GetID());
912         if (CGUIDialogSmartPlaylistEditor::EditPlaylist(pItem->m_strPath))
913           Update(m_vecItems->m_strPath);
914         return true;
915       }
916     }
917
918     // remove the directory cache if the folder is not normally cached
919     CFileItemList items(pItem->m_strPath);
920     if (!items.AlwaysCache())
921       items.RemoveDiscCache(GetID());
922
923     CFileItem directory(*pItem);
924     if (!Update(directory.m_strPath))
925       ShowShareErrorMessage(&directory);
926
927     return true;
928   }
929   else if (pItem->IsPlugin() && pItem->GetProperty("isplayable") != "true")
930   {
931     return XFILE::CPluginDirectory::RunScriptWithParams(pItem->m_strPath);
932   }
933   else
934   {
935     m_iSelectedItem = m_viewControl.GetSelectedItem();
936
937     if (pItem->m_strPath == "newplaylist://")
938     {
939       m_vecItems->RemoveDiscCache(GetID());
940       g_windowManager.ActivateWindow(WINDOW_MUSIC_PLAYLIST_EDITOR,"newplaylist://");
941       return true;
942     }
943     else if (pItem->m_strPath.Left(19).Equals("newsmartplaylist://"))
944     {
945       m_vecItems->RemoveDiscCache(GetID());
946       if (CGUIDialogSmartPlaylistEditor::NewPlaylist(pItem->m_strPath.Mid(19)))
947         Update(m_vecItems->m_strPath);
948       return true;
949     }
950     else if (pItem->m_strPath.Left(14).Equals("addons://more/"))
951     {
952       CBuiltins::Execute("ActivateWindow(AddonBrowser,addons://all/xbmc.addon." + pItem->m_strPath.Mid(14) + ",return)");
953       return true;
954     }
955
956     // If karaoke song is being played AND popup autoselector is enabled, the playlist should not be added
957     bool do_not_add_karaoke = g_guiSettings.GetBool("karaoke.enabled") &&
958       g_guiSettings.GetBool("karaoke.autopopupselector") && pItem->IsKaraoke();
959     bool autoplay = m_guiState.get() && m_guiState->AutoPlayNextItem();
960     int iPlaylist = m_guiState.get()?m_guiState->GetPlaylist():PLAYLIST_MUSIC;
961
962     if (pItem->IsPlugin())
963     {
964       CURL url(pItem->m_strPath);
965       AddonPtr addon;
966       if (CAddonMgr::Get().GetAddon(url.GetHostName(),addon))
967       {
968         PluginPtr plugin = boost::dynamic_pointer_cast<CPluginSource>(addon);
969         if (plugin && plugin->Provides(CPluginSource::AUDIO))
970         {
971           iPlaylist = PLAYLIST_MUSIC;
972           autoplay = g_guiSettings.GetBool("musicplayer.autoplaynextitem");
973         }
974       }
975     }
976
977     if (autoplay && !g_partyModeManager.IsEnabled() && 
978         !pItem->IsPlayList() && !do_not_add_karaoke)
979     {
980       return OnPlayAndQueueMedia(pItem);
981     }
982     else
983     {
984       return OnPlayMedia(iItem);
985     }
986   }
987
988   return false;
989 }
990
991 bool CGUIMediaWindow::OnSelect(int item)
992 {
993   return OnClick(item);
994 }
995
996 // \brief Checks if there is a disc in the dvd drive and whether the
997 // network is connected or not.
998 bool CGUIMediaWindow::HaveDiscOrConnection(CStdString& strPath, int iDriveType)
999 {
1000   if (iDriveType==CMediaSource::SOURCE_TYPE_DVD)
1001   {
1002     if (!g_mediaManager.IsDiscInDrive())
1003     {
1004       CGUIDialogOK::ShowAndGetInput(218, 219, 0, 0);
1005       return false;
1006     }
1007   }
1008   else if (iDriveType==CMediaSource::SOURCE_TYPE_REMOTE)
1009   {
1010     // TODO: Handle not connected to a remote share
1011     if ( !g_application.getNetwork().IsConnected() )
1012     {
1013       CGUIDialogOK::ShowAndGetInput(220, 221, 0, 0);
1014       return false;
1015     }
1016   }
1017
1018   return true;
1019 }
1020
1021 // \brief Shows a standard errormessage for a given pItem.
1022 void CGUIMediaWindow::ShowShareErrorMessage(CFileItem* pItem)
1023 {
1024   if (pItem->m_bIsShareOrDrive)
1025   {
1026     int idMessageText=0;
1027     const CURL& url=pItem->GetAsUrl();
1028     const CStdString& strHostName=url.GetHostName();
1029
1030     if (pItem->m_iDriveType != CMediaSource::SOURCE_TYPE_REMOTE) //  Local shares incl. dvd drive
1031       idMessageText=15300;
1032     else if (url.GetProtocol() == "xbms" && strHostName.IsEmpty()) //  xbms server discover
1033       idMessageText=15302;
1034     else if (url.GetProtocol() == "smb" && strHostName.IsEmpty()) //  smb workgroup
1035       idMessageText=15303;
1036     else  //  All other remote shares
1037       idMessageText=15301;
1038
1039     CGUIDialogOK::ShowAndGetInput(220, idMessageText, 0, 0);
1040   }
1041 }
1042
1043 // \brief The functon goes up one level in the directory tree
1044 void CGUIMediaWindow::GoParentFolder()
1045 {
1046   //m_history.DumpPathHistory();
1047
1048   // remove current directory if its on the stack
1049   // there were some issues due some folders having a trailing slash and some not
1050   // so just add a trailing slash to all of them for comparison.
1051   CStdString strPath = m_vecItems->m_strPath;
1052   URIUtils::AddSlashAtEnd(strPath);
1053   CStdString strParent = m_history.GetParentPath();
1054   // in case the path history is messed up and the current folder is on
1055   // the stack more than once, keep going until there's nothing left or they
1056   // dont match anymore.
1057   while (!strParent.IsEmpty())
1058   {
1059     URIUtils::AddSlashAtEnd(strParent);
1060     if (strParent.Equals(strPath))
1061       m_history.RemoveParentPath();
1062     else
1063       break;
1064     strParent = m_history.GetParentPath();
1065   }
1066
1067   // if vector is not empty, pop parent
1068   // if vector is empty, parent is root source listing
1069   CStdString strOldPath(m_vecItems->m_strPath);
1070   strParent = m_history.RemoveParentPath();
1071   Update(strParent);
1072 }
1073
1074 // \brief Override the function to change the default behavior on how
1075 // a selected item history should look like
1076 void CGUIMediaWindow::GetDirectoryHistoryString(const CFileItem* pItem, CStdString& strHistoryString)
1077 {
1078   if (pItem->m_bIsShareOrDrive)
1079   {
1080     // We are in the virual directory
1081
1082     // History string of the DVD drive
1083     // must be handel separately
1084     if (pItem->m_iDriveType == CMediaSource::SOURCE_TYPE_DVD)
1085     {
1086       // Remove disc label from item label
1087       // and use as history string, m_strPath
1088       // can change for new discs
1089       CStdString strLabel = pItem->GetLabel();
1090       int nPosOpen = strLabel.Find('(');
1091       int nPosClose = strLabel.ReverseFind(')');
1092       if (nPosOpen > -1 && nPosClose > -1 && nPosClose > nPosOpen)
1093       {
1094         strLabel.Delete(nPosOpen + 1, (nPosClose) - (nPosOpen + 1));
1095         strHistoryString = strLabel;
1096       }
1097       else
1098         strHistoryString = strLabel;
1099     }
1100     else
1101     {
1102       // Other items in virual directory
1103       CStdString strPath = pItem->m_strPath;
1104       URIUtils::RemoveSlashAtEnd(strPath);
1105
1106       strHistoryString = pItem->GetLabel() + strPath;
1107     }
1108   }
1109   else if (pItem->m_lEndOffset>pItem->m_lStartOffset && pItem->m_lStartOffset != -1)
1110   {
1111     // Could be a cue item, all items of a cue share the same filename
1112     // so add the offsets to build the history string
1113     strHistoryString.Format("%ld%ld", pItem->m_lStartOffset, pItem->m_lEndOffset);
1114     strHistoryString += pItem->m_strPath;
1115   }
1116   else
1117   {
1118     // Normal directory items
1119     strHistoryString = pItem->m_strPath;
1120   }
1121   URIUtils::RemoveSlashAtEnd(strHistoryString);
1122   strHistoryString.ToLower();
1123 }
1124
1125 // \brief Call this function to create a directory history for the
1126 // path given by strDirectory.
1127 void CGUIMediaWindow::SetHistoryForPath(const CStdString& strDirectory)
1128 {
1129   // Make sure our shares are configured
1130   SetupShares();
1131   if (!strDirectory.IsEmpty())
1132   {
1133     // Build the directory history for default path
1134     CStdString strPath, strParentPath;
1135     strPath = strDirectory;
1136     URIUtils::RemoveSlashAtEnd(strPath);
1137
1138     CFileItemList items;
1139     m_rootDir.GetDirectory("", items);
1140
1141     m_history.ClearPathHistory();
1142
1143     while (URIUtils::GetParentPath(strPath, strParentPath))
1144     {
1145       for (int i = 0; i < (int)items.Size(); ++i)
1146       {
1147         CFileItemPtr pItem = items[i];
1148         URIUtils::RemoveSlashAtEnd(pItem->m_strPath);
1149         if (pItem->m_strPath == strPath)
1150         {
1151           CStdString strHistory;
1152           GetDirectoryHistoryString(pItem.get(), strHistory);
1153           m_history.SetSelectedItem(strHistory, "");
1154           URIUtils::AddSlashAtEnd(strPath);
1155           m_history.AddPathFront(strPath);
1156           m_history.AddPathFront("");
1157
1158           //m_history.DumpPathHistory();
1159           return ;
1160         }
1161       }
1162
1163       URIUtils::AddSlashAtEnd(strPath);
1164       m_history.AddPathFront(strPath);
1165       m_history.SetSelectedItem(strPath, strParentPath);
1166       strPath = strParentPath;
1167       URIUtils::RemoveSlashAtEnd(strPath);
1168     }
1169   }
1170   else
1171     m_history.ClearPathHistory();
1172
1173   //m_history.DumpPathHistory();
1174 }
1175
1176 // \brief Override if you want to change the default behavior, what is done
1177 // when the user clicks on a file.
1178 // This function is called by OnClick()
1179 bool CGUIMediaWindow::OnPlayMedia(int iItem)
1180 {
1181   // Reset Playlistplayer, playback started now does
1182   // not use the playlistplayer.
1183   g_playlistPlayer.Reset();
1184   g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_NONE);
1185   CFileItemPtr pItem=m_vecItems->Get(iItem);
1186
1187   bool bResult = false;
1188   if (pItem->IsInternetStream() || pItem->IsPlayList())
1189     bResult = g_application.PlayMedia(*pItem, m_guiState->GetPlaylist());
1190   else
1191     bResult = g_application.PlayFile(*pItem);
1192
1193   if (pItem->m_lStartOffset == STARTOFFSET_RESUME)
1194     pItem->m_lStartOffset = 0;
1195
1196   return bResult;
1197 }
1198
1199 // \brief Override if you want to change the default behavior of what is done
1200 // when the user clicks on a file in a "folder" with similar files.
1201 // This function is called by OnClick()
1202 bool CGUIMediaWindow::OnPlayAndQueueMedia(const CFileItemPtr &item)
1203 {
1204   //play and add current directory to temporary playlist
1205   int iPlaylist = m_guiState->GetPlaylist();
1206   if (iPlaylist != PLAYLIST_NONE)
1207   {
1208     g_playlistPlayer.ClearPlaylist(iPlaylist);
1209     g_playlistPlayer.Reset();
1210     int mediaToPlay = 0;
1211     CFileItemList queueItems;
1212     for ( int i = 0; i < m_vecItems->Size(); i++ )
1213     {
1214       CFileItemPtr nItem = m_vecItems->Get(i);
1215
1216       if (nItem->m_bIsFolder)
1217         continue;
1218
1219       if (!nItem->IsPlayList() && !nItem->IsZIP() && !nItem->IsRAR())
1220         queueItems.Add(nItem);
1221
1222       if (nItem == item)
1223       { // item that was clicked
1224         mediaToPlay = queueItems.Size() - 1;
1225       }
1226     }
1227     g_playlistPlayer.Add(iPlaylist, queueItems);
1228
1229     // Save current window and directory to know where the selected item was
1230     if (m_guiState.get())
1231       m_guiState->SetPlaylistDirectory(m_vecItems->m_strPath);
1232
1233     // figure out where we start playback
1234     if (g_playlistPlayer.IsShuffled(iPlaylist))
1235     {
1236       int iIndex = g_playlistPlayer.GetPlaylist(iPlaylist).FindOrder(mediaToPlay);
1237       g_playlistPlayer.GetPlaylist(iPlaylist).Swap(0, iIndex);
1238       mediaToPlay = 0;
1239     }
1240
1241     // play
1242     g_playlistPlayer.SetCurrentPlaylist(iPlaylist);
1243     g_playlistPlayer.Play(mediaToPlay);
1244   }
1245   return true;
1246 }
1247
1248 // \brief Synchonize the fileitems with the playlistplayer
1249 // It recreated the playlist of the playlistplayer based
1250 // on the fileitems of the window
1251 void CGUIMediaWindow::UpdateFileList()
1252 {
1253   int nItem = m_viewControl.GetSelectedItem();
1254   CStdString strSelected;
1255   if (nItem >= 0)
1256     strSelected = m_vecItems->Get(nItem)->m_strPath;
1257
1258   FormatAndSort(*m_vecItems);
1259   UpdateButtons();
1260
1261   m_viewControl.SetItems(*m_vecItems);
1262   m_viewControl.SetSelectedItem(strSelected);
1263
1264   //  set the currently playing item as selected, if its in this directory
1265   if (m_guiState.get() && m_guiState->IsCurrentPlaylistDirectory(m_vecItems->m_strPath))
1266   {
1267     int iPlaylist=m_guiState->GetPlaylist();
1268     int nSong = g_playlistPlayer.GetCurrentSong();
1269     CFileItem playlistItem;
1270     if (nSong > -1 && iPlaylist > -1)
1271       playlistItem=*g_playlistPlayer.GetPlaylist(iPlaylist)[nSong];
1272
1273     g_playlistPlayer.ClearPlaylist(iPlaylist);
1274     g_playlistPlayer.Reset();
1275
1276     for (int i = 0; i < m_vecItems->Size(); i++)
1277     {
1278       CFileItemPtr pItem = m_vecItems->Get(i);
1279       if (pItem->m_bIsFolder)
1280         continue;
1281
1282       if (!pItem->IsPlayList() && !pItem->IsZIP() && !pItem->IsRAR())
1283         g_playlistPlayer.Add(iPlaylist, pItem);
1284
1285       if (pItem->m_strPath == playlistItem.m_strPath &&
1286           pItem->m_lStartOffset == playlistItem.m_lStartOffset)
1287         g_playlistPlayer.SetCurrentSong(g_playlistPlayer.GetPlaylist(iPlaylist).size() - 1);
1288     }
1289   }
1290 }
1291
1292 void CGUIMediaWindow::OnDeleteItem(int iItem)
1293 {
1294   if ( iItem < 0 || iItem >= m_vecItems->Size()) return;
1295   CFileItemPtr item = m_vecItems->Get(iItem);
1296
1297   if (item->IsPlayList())
1298     item->m_bIsFolder = false;
1299
1300   if (g_settings.GetCurrentProfile().getLockMode() != LOCK_MODE_EVERYONE && g_settings.GetCurrentProfile().filesLocked())
1301     if (!g_passwordManager.IsMasterLockUnlocked(true))
1302       return;
1303
1304   if (!CFileUtils::DeleteItem(item))
1305     return;
1306   m_vecItems->RemoveDiscCache(GetID());
1307   Update(m_vecItems->m_strPath);
1308   m_viewControl.SetSelectedItem(iItem);
1309 }
1310
1311 void CGUIMediaWindow::OnRenameItem(int iItem)
1312 {
1313   if ( iItem < 0 || iItem >= m_vecItems->Size()) return;
1314
1315   if (g_settings.GetCurrentProfile().getLockMode() != LOCK_MODE_EVERYONE && g_settings.GetCurrentProfile().filesLocked())
1316     if (!g_passwordManager.IsMasterLockUnlocked(true))
1317       return;
1318
1319   if (!CFileUtils::RenameFile(m_vecItems->Get(iItem)->m_strPath))
1320     return;
1321   m_vecItems->RemoveDiscCache(GetID());
1322   Update(m_vecItems->m_strPath);
1323   m_viewControl.SetSelectedItem(iItem);
1324 }
1325
1326 void CGUIMediaWindow::OnInitWindow()
1327 {
1328   // initial fetch is done unthreaded to ensure the items are setup prior to skin animations kicking off
1329   m_rootDir.SetAllowThreads(false);
1330   Update(m_vecItems->m_strPath);
1331   m_rootDir.SetAllowThreads(true);
1332
1333   if (m_iSelectedItem > -1)
1334     m_viewControl.SetSelectedItem(m_iSelectedItem);
1335
1336   CGUIWindow::OnInitWindow();
1337 }
1338
1339 CGUIControl *CGUIMediaWindow::GetFirstFocusableControl(int id)
1340 {
1341   if (m_viewControl.HasControl(id))
1342     id = m_viewControl.GetCurrentControl();
1343   return CGUIWindow::GetFirstFocusableControl(id);
1344 }
1345
1346 void CGUIMediaWindow::SetupShares()
1347 {
1348   // Setup shares and filemasks for this window
1349   CFileItemList items;
1350   CGUIViewState* viewState=CGUIViewState::GetViewState(GetID(), items);
1351   if (viewState)
1352   {
1353     m_rootDir.SetMask(viewState->GetExtensions());
1354     m_rootDir.SetSources(viewState->GetSources());
1355     delete viewState;
1356   }
1357 }
1358
1359 bool CGUIMediaWindow::OnPopupMenu(int iItem)
1360 {
1361   // popup the context menu
1362   // grab our context menu
1363   CContextButtons buttons;
1364   GetContextButtons(iItem, buttons);
1365
1366   if (buttons.size())
1367   {
1368     // mark the item
1369     if (iItem >= 0 && iItem < m_vecItems->Size())
1370       m_vecItems->Get(iItem)->Select(true);
1371
1372     int choice = CGUIDialogContextMenu::ShowAndGetChoice(buttons);
1373
1374     // deselect our item
1375     if (iItem >= 0 && iItem < m_vecItems->Size())
1376       m_vecItems->Get(iItem)->Select(false);
1377
1378     if (choice >= 0)
1379       return OnContextButton(iItem, (CONTEXT_BUTTON)choice);
1380   }
1381   return false;
1382 }
1383
1384 void CGUIMediaWindow::GetContextButtons(int itemNumber, CContextButtons &buttons)
1385 {
1386   CFileItemPtr item = (itemNumber >= 0 && itemNumber < m_vecItems->Size()) ? m_vecItems->Get(itemNumber) : CFileItemPtr();
1387
1388   if (!item)
1389     return;
1390
1391   // user added buttons
1392   CStdString label;
1393   CStdString action;
1394   for (int i = CONTEXT_BUTTON_USER1; i <= CONTEXT_BUTTON_USER10; i++)
1395   {
1396     label.Format("contextmenulabel(%i)", i - CONTEXT_BUTTON_USER1);
1397     if (item->GetProperty(label).IsEmpty())
1398       break;
1399
1400     action.Format("contextmenuaction(%i)", i - CONTEXT_BUTTON_USER1);
1401     if (item->GetProperty(action).IsEmpty())
1402       break;
1403
1404     buttons.Add((CONTEXT_BUTTON)i, item->GetProperty(label));
1405   }
1406
1407   if (item->GetPropertyBOOL("pluginreplacecontextitems"))
1408     return;
1409
1410   // TODO: FAVOURITES Conditions on masterlock and localisation
1411   if (!item->IsParentFolder() && !item->m_strPath.Equals("add") && !item->m_strPath.Equals("newplaylist://") && !item->m_strPath.Left(19).Equals("newsmartplaylist://"))
1412   {
1413     if (CFavourites::IsFavourite(item.get(), GetID()))
1414       buttons.Add(CONTEXT_BUTTON_ADD_FAVOURITE, 14077);     // Remove Favourite
1415     else
1416       buttons.Add(CONTEXT_BUTTON_ADD_FAVOURITE, 14076);     // Add To Favourites;
1417   }
1418 }
1419
1420 bool CGUIMediaWindow::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
1421 {
1422   switch (button)
1423   {
1424   case CONTEXT_BUTTON_ADD_FAVOURITE:
1425     {
1426       CFileItemPtr item = m_vecItems->Get(itemNumber);
1427       CFavourites::AddOrRemove(item.get(), GetID());
1428       return true;
1429     }
1430   case CONTEXT_BUTTON_PLUGIN_SETTINGS:
1431     {
1432       CURL plugin(m_vecItems->Get(itemNumber)->m_strPath);
1433       ADDON::AddonPtr addon;
1434       if (CAddonMgr::Get().GetAddon(plugin.GetHostName(), addon, ADDON_PLUGIN))
1435         if (CGUIDialogAddonSettings::ShowAndGetInput(addon))
1436           Update(m_vecItems->m_strPath);
1437       return true;
1438     }
1439   case CONTEXT_BUTTON_USER1:
1440   case CONTEXT_BUTTON_USER2:
1441   case CONTEXT_BUTTON_USER3:
1442   case CONTEXT_BUTTON_USER4:
1443   case CONTEXT_BUTTON_USER5:
1444   case CONTEXT_BUTTON_USER6:
1445   case CONTEXT_BUTTON_USER7:
1446   case CONTEXT_BUTTON_USER8:
1447   case CONTEXT_BUTTON_USER9:
1448   case CONTEXT_BUTTON_USER10:
1449     {
1450       CStdString action;
1451       action.Format("contextmenuaction(%i)", button - CONTEXT_BUTTON_USER1);
1452       g_application.getApplicationMessenger().ExecBuiltIn(m_vecItems->Get(itemNumber)->GetProperty(action));
1453       return true;
1454     }
1455   default:
1456     break;
1457   }
1458   return false;
1459 }
1460
1461 const CGUIViewState *CGUIMediaWindow::GetViewState() const
1462 {
1463   return m_guiState.get();
1464 }
1465
1466 const CFileItemList& CGUIMediaWindow::CurrentDirectory() const
1467 {
1468   return *m_vecItems;
1469 }
1470
1471 bool CGUIMediaWindow::WaitForNetwork() const
1472 {
1473   if (g_application.getNetwork().IsAvailable())
1474     return true;
1475
1476   CGUIDialogProgress *progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
1477   if (!progress)
1478     return true;
1479
1480   CURL url(m_vecItems->m_strPath);
1481   progress->SetHeading(1040); // Loading Directory
1482   progress->SetLine(1, url.GetWithoutUserDetails());
1483   progress->ShowProgressBar(false);
1484   progress->StartModal();
1485   while (!g_application.getNetwork().IsAvailable())
1486   {
1487     progress->Progress();
1488     if (progress->IsCanceled())
1489     {
1490       progress->Close();
1491       return false;
1492     }
1493   }
1494   progress->Close();
1495   return true;
1496 }
1497
1498 void CGUIMediaWindow::OnFilterItems(const CStdString &filter)
1499 {
1500   CStdString currentItem;
1501   int item = m_viewControl.GetSelectedItem();
1502   if (item >= 0)
1503     currentItem = m_vecItems->Get(item)->m_strPath;
1504   
1505   m_viewControl.Clear();
1506   
1507   CFileItemList items;
1508   GetFilteredItems(filter, items);
1509   if (filter.IsEmpty() || items.GetObjectCount() > 0)
1510   {
1511     m_vecItems->ClearItems();
1512     m_vecItems->Append(items);
1513     SetProperty("filter", filter);
1514   }
1515   
1516   // and update our view control + buttons
1517   m_viewControl.SetItems(*m_vecItems);
1518   m_viewControl.SetSelectedItem(currentItem);
1519   UpdateButtons();
1520 }
1521
1522 void CGUIMediaWindow::GetFilteredItems(const CStdString &filter, CFileItemList &items)
1523 {
1524   CStdString trimmedFilter(filter);
1525   trimmedFilter.TrimLeft().ToLower();
1526   
1527   if (trimmedFilter.IsEmpty())
1528   {
1529     items.Append(*m_unfilteredItems);
1530     return;
1531   }
1532   
1533   bool numericMatch = StringUtils::IsNaturalNumber(trimmedFilter);
1534   for (int i = 0; i < m_unfilteredItems->Size(); i++)
1535   {
1536     CFileItemPtr item = m_unfilteredItems->Get(i);
1537     if (item->IsParentFolder())
1538     {
1539       items.Add(item);
1540       continue;
1541     }
1542     // TODO: Need to update this to get all labels, ideally out of the displayed info (ie from m_layout and m_focusedLayout)
1543     // though that isn't practical.  Perhaps a better idea would be to just grab the info that we should filter on based on
1544     // where we are in the library tree.
1545     // Another idea is tying the filter string to the current level of the tree, so that going deeper disables the filter,
1546     // but it's re-enabled on the way back out.
1547     CStdString match;
1548     /*    if (item->GetFocusedLayout())
1549      match = item->GetFocusedLayout()->GetAllText();
1550      else if (item->GetLayout())
1551      match = item->GetLayout()->GetAllText();
1552      else*/
1553     match = item->GetLabel(); // Filter label only for now
1554     
1555     if (numericMatch)
1556       StringUtils::WordToDigits(match);
1557     
1558     size_t pos = StringUtils::FindWords(match.c_str(), trimmedFilter.c_str());
1559     if (pos != CStdString::npos)
1560       items.Add(item);
1561   }
1562 }
1563
1564 CStdString CGUIMediaWindow::GetStartFolder(const CStdString &dir)
1565 {
1566   if (dir.Equals("$ROOT") || dir.Equals("Root"))
1567     return "";
1568   return dir;
1569 }