changed: New label formatting that more logically drops separators.
[xbmc:xbmc-antiquated.git] / xbmc / GUIMediaWindow.cpp
1 /*
2  *      Copyright (C) 2005-2007 Team XboxMediaCenter
3  *      http://www.xboxmediacenter.com
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 GNU Make; 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 "stdafx.h"
23 #include "GUIMediaWindow.h"
24 #include "util.h"
25 #include "detectdvdtype.h"
26 #include "PlayListPlayer.h"
27 #include "FileSystem/ZipManager.h"
28 #include "GUIPassword.h"
29 #include "Application.h"
30 #include "xbox/network.h"
31 #include "PartyModeManager.h"
32 #include "GUIDialogMediaSource.h"
33 #include "GUIWindowFileManager.h"
34 #include "Favourites.h"
35 #include "utils/LabelFormatter.h"
36
37 #include "GUIImage.h"
38 #include "GUIMultiImage.h"
39 #include "GUIDialogSmartPlaylistEditor.h"
40
41 #ifdef PRE_SKIN_VERSION_2_1_COMPATIBILITY
42 #include "SkinInfo.h"
43 #endif
44
45 #define CONTROL_BTNVIEWASICONS     2
46 #define CONTROL_BTNSORTBY          3
47 #define CONTROL_BTNSORTASC         4
48 #define CONTROL_VIEW_START        50
49 #define CONTROL_VIEW_END          59
50
51 #define CONTROL_LABELFILES        12
52
53
54 CGUIMediaWindow::CGUIMediaWindow(DWORD id, const char *xmlFile)
55     : CGUIWindow(id, xmlFile)
56 {
57   m_vecItems.m_strPath = "?";
58   m_iLastControl = -1;
59   m_iSelectedItem = -1;
60
61   m_guiState.reset(CGUIViewState::GetViewState(GetID(), m_vecItems));
62 }
63
64 CGUIMediaWindow::~CGUIMediaWindow()
65 {
66 }
67
68 void CGUIMediaWindow::OnWindowLoaded()
69 {
70   CGUIWindow::OnWindowLoaded();
71   m_viewControl.Reset();
72   m_viewControl.SetParentWindow(GetID());
73   vector<CGUIControl *> controls;
74   GetContainers(controls);
75   for (ciControls it = controls.begin(); it != controls.end(); it++)
76   {
77     CGUIControl *control = *it;
78     if (control->GetID() >= CONTROL_VIEW_START && control->GetID() <= CONTROL_VIEW_END)
79       m_viewControl.AddView(control);
80   }
81   m_viewControl.SetViewControlID(CONTROL_BTNVIEWASICONS);
82   SetupShares();
83 }
84
85 void CGUIMediaWindow::OnWindowUnload()
86 {
87   CGUIWindow::OnWindowUnload();
88   m_viewControl.Reset();
89 }
90
91 CFileItem *CGUIMediaWindow::GetCurrentListItem(int offset)
92 {
93   int item = m_viewControl.GetSelectedItem();
94   if (!m_vecItems.Size() || item < 0)
95     return NULL;
96   item = (item + offset) % m_vecItems.Size();
97   if (item < 0) item += m_vecItems.Size();
98   return m_vecItems[item];
99 }
100
101 bool CGUIMediaWindow::OnAction(const CAction &action)
102 {
103   if (action.wID == ACTION_PARENT_DIR)
104   {
105     if (m_vecItems.IsVirtualDirectoryRoot())
106       m_gWindowManager.PreviousWindow();
107     else
108       GoParentFolder();
109     return true;
110   }
111
112   if (action.wID == ACTION_PREVIOUS_MENU)
113   {
114     m_gWindowManager.PreviousWindow();
115     return true;
116   }
117
118   // the non-contextual menu can be called at any time
119   if (action.wID == ACTION_CONTEXT_MENU && !m_viewControl.HasControl(GetFocusedControlID()))
120   {
121     OnPopupMenu(-1);
122     return true;
123   }
124
125   return CGUIWindow::OnAction(action);
126 }
127
128 bool CGUIMediaWindow::OnMessage(CGUIMessage& message)
129 {
130   switch ( message.GetMessage() )
131   {
132   case GUI_MSG_WINDOW_DEINIT:
133     {
134       m_iSelectedItem = m_viewControl.GetSelectedItem();
135       m_iLastControl = GetFocusedControlID();
136       CGUIWindow::OnMessage(message);
137       // Call ClearFileItems() after our window has finished doing any WindowClose
138       // animations
139       ClearFileItems();
140       return true;
141     }
142     break;
143
144   case GUI_MSG_CLICKED:
145     {
146       int iControl = message.GetSenderId();
147       if (iControl == CONTROL_BTNVIEWASICONS)
148       {
149         // view as control could be a select button
150         int viewMode = 0;
151         const CGUIControl *control = GetControl(CONTROL_BTNVIEWASICONS);
152         if (control && control->GetControlType() != CGUIControl::GUICONTROL_BUTTON)
153         {
154           CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_BTNVIEWASICONS);
155           OnMessage(msg);
156           viewMode = m_viewControl.GetViewModeNumber(msg.GetParam1());
157         }
158         else
159           viewMode = m_viewControl.GetNextViewMode();
160
161         if (m_guiState.get())
162           m_guiState->SaveViewAsControl(viewMode);
163
164         UpdateButtons();
165         return true;
166       }
167       else if (iControl == CONTROL_BTNSORTASC) // sort asc
168       {
169         if (m_guiState.get())
170           m_guiState->SetNextSortOrder();
171         UpdateFileList();
172         return true;
173       }
174       else if (iControl == CONTROL_BTNSORTBY) // sort by
175       {
176         if (m_guiState.get())
177           m_guiState->SetNextSortMethod();
178         UpdateFileList();
179         return true;
180       }
181       else if (m_viewControl.HasControl(iControl))  // list/thumb control
182       {
183         int iItem = m_viewControl.GetSelectedItem();
184         int iAction = message.GetParam1();
185         if (iItem < 0) break;
186         if (iAction == ACTION_SELECT_ITEM || iAction == ACTION_MOUSE_LEFT_CLICK)
187         {
188           OnClick(iItem);
189         }
190         else if (iAction == ACTION_CONTEXT_MENU || iAction == ACTION_MOUSE_RIGHT_CLICK)
191         {
192           OnPopupMenu(iItem);
193           return true;
194         }
195       }
196     }
197     break;
198
199   case GUI_MSG_SETFOCUS:
200     {
201       if (m_viewControl.HasControl(message.GetControlId()) && m_viewControl.GetCurrentControl() != message.GetControlId())
202       {
203         m_viewControl.SetFocused();
204         return true;
205       }
206     }
207     break;
208
209   case GUI_MSG_NOTIFY_ALL:
210     { // Message is received even if this window is inactive
211       if (message.GetParam1() == GUI_MSG_WINDOW_RESET)
212       {
213         m_vecItems.m_strPath = "?";
214         return true;
215       }
216       else if ( message.GetParam1() == GUI_MSG_REFRESH_THUMBS )
217       {
218         for (int i = 0; i < m_vecItems.Size(); i++)
219           m_vecItems[i]->FreeMemory();
220         break;  // the window will take care of any info images
221       }
222       else if (message.GetParam1() == GUI_MSG_REMOVED_MEDIA)
223       {
224         if (m_vecItems.IsVirtualDirectoryRoot() && IsActive())
225         {
226           int iItem = m_viewControl.GetSelectedItem();
227           Update(m_vecItems.m_strPath);
228           m_viewControl.SetSelectedItem(iItem);
229         }
230         else if (m_vecItems.IsRemovable())
231         { // check that we have this removable share still
232           if (!m_rootDir.IsInShare(m_vecItems.m_strPath))
233           { // don't have this share any more
234             if (IsActive()) Update("");
235             else
236             {
237               m_history.ClearPathHistory();
238               m_vecItems.m_strPath="";
239             }
240           }
241         }
242
243         return true;
244       }
245       else if (message.GetParam1()==GUI_MSG_UPDATE_SOURCES)
246       { // State of the sources changed, so update our view
247         if (m_vecItems.IsVirtualDirectoryRoot() && IsActive())
248         {
249           int iItem = m_viewControl.GetSelectedItem();
250           Update(m_vecItems.m_strPath);
251           m_viewControl.SetSelectedItem(iItem);
252         }
253         return true;
254       }
255       else if (message.GetParam1()==GUI_MSG_UPDATE)
256       {
257         int iItem = m_viewControl.GetSelectedItem();
258         Update(m_vecItems.m_strPath);
259         m_viewControl.SetSelectedItem(iItem);        
260       }
261       else if (message.GetParam1()==GUI_MSG_UPDATE_ITEM && message.GetLPVOID())
262       {
263         CFileItem *newItem = (CFileItem *)message.GetLPVOID();
264         if (IsActive())
265           m_vecItems.UpdateItem(newItem);
266         else  
267         { // need to remove the disc cache
268           CFileItemList items;
269           CUtil::GetDirectory(newItem->m_strPath, items.m_strPath);
270           items.RemoveDiscCache();
271         }
272       }
273       else
274         return CGUIWindow::OnMessage(message);
275
276       return true;
277     }
278     break;
279   case GUI_MSG_PLAYBACK_STARTED:
280   case GUI_MSG_PLAYBACK_ENDED:
281   case GUI_MSG_PLAYBACK_STOPPED:
282   case GUI_MSG_PLAYLIST_CHANGED:
283   case GUI_MSG_PLAYLISTPLAYER_STOPPED:
284   case GUI_MSG_PLAYLISTPLAYER_STARTED:
285   case GUI_MSG_PLAYLISTPLAYER_CHANGED:
286     { // send a notify all to all controls on this window
287       CGUIMessage msg(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_REFRESH_LIST);
288       OnMessage(msg);
289     }
290   }
291
292   return CGUIWindow::OnMessage(message);
293 }
294
295 // \brief Updates the states (enable, disable, visible...)
296 // of the controls defined by this window
297 // Override this function in a derived class to add new controls
298 void CGUIMediaWindow::UpdateButtons()
299 {
300   if (m_guiState.get())
301   {
302     // Update sorting controls
303     if (m_guiState->GetDisplaySortOrder()==SORT_ORDER_NONE)
304     {
305       CONTROL_DISABLE(CONTROL_BTNSORTASC);
306     }
307     else
308     {
309       CONTROL_ENABLE(CONTROL_BTNSORTASC);
310       if (m_guiState->GetDisplaySortOrder()==SORT_ORDER_ASC)
311       {
312         CGUIMessage msg(GUI_MSG_DESELECTED, GetID(), CONTROL_BTNSORTASC);
313         g_graphicsContext.SendMessage(msg);
314       }
315       else
316       {
317         CGUIMessage msg(GUI_MSG_SELECTED, GetID(), CONTROL_BTNSORTASC);
318         g_graphicsContext.SendMessage(msg);
319       }
320     }
321
322     // Update list/thumb control
323     m_viewControl.SetCurrentView(m_guiState->GetViewAsControl());
324
325     // Update sort by button
326     if (m_guiState->GetSortMethod()==SORT_METHOD_NONE)
327     {
328       CONTROL_DISABLE(CONTROL_BTNSORTBY);
329     }
330     else
331     {
332       CONTROL_ENABLE(CONTROL_BTNSORTBY);
333     }
334     CStdString sortLabel;
335     sortLabel.Format(g_localizeStrings.Get(550).c_str(), g_localizeStrings.Get(m_guiState->GetSortMethodLabel()).c_str());
336     SET_CONTROL_LABEL(CONTROL_BTNSORTBY, sortLabel);
337   }
338
339   int iItems = m_vecItems.Size();
340   if (iItems)
341   {
342     CFileItem* pItem = m_vecItems[0];
343     if (pItem->IsParentFolder()) iItems--;
344   }
345   CStdString items;
346   items.Format("%i %s", iItems, g_localizeStrings.Get(127).c_str());
347   SET_CONTROL_LABEL(CONTROL_LABELFILES, items);
348 }
349
350 void CGUIMediaWindow::ClearFileItems()
351 {
352   m_viewControl.Clear();
353   m_vecItems.Clear(); // will clean up everything
354 }
355
356 // \brief Sorts Fileitems based on the sort method and sort oder provided by guiViewState
357 void CGUIMediaWindow::SortItems(CFileItemList &items)
358 {
359   auto_ptr<CGUIViewState> guiState(CGUIViewState::GetViewState(GetID(), items));
360
361   if (guiState.get())
362   {
363     items.Sort(guiState->GetSortMethod(), guiState->GetDisplaySortOrder());
364
365     // Should these items be saved to the hdd
366     if (items.GetCacheToDisc())
367       items.Save();
368   }
369 }
370
371 // \brief Formats item labels based on the formatting provided by guiViewState
372 void CGUIMediaWindow::FormatItemLabels(CFileItemList &items, const CGUIViewState::LABEL_MASKS &labelMasks)
373 {
374   CLabelFormatter fileFormatter(labelMasks.m_strLabelFile, labelMasks.m_strLabel2File);
375   CLabelFormatter folderFormatter(labelMasks.m_strLabelFolder, labelMasks.m_strLabel2Folder);
376   for (int i=0; i<items.Size(); ++i)
377   {
378     CFileItem* pItem=items[i];
379
380     if (pItem->IsLabelPreformated())
381       continue;
382
383     if (pItem->m_bIsFolder)
384       folderFormatter.FormatLabels(pItem);
385     else
386       fileFormatter.FormatLabels(pItem);
387   }
388 }
389
390 // \brief Prepares and adds the fileitems list/thumb panel
391 void CGUIMediaWindow::OnSort()
392 {
393   if (m_guiState.get())
394   {
395     CGUIViewState::LABEL_MASKS labelMasks;
396     m_guiState->GetSortMethodLabelMasks(labelMasks);
397     FormatItemLabels(m_vecItems, labelMasks);
398   }
399   SortItems(m_vecItems);
400 }
401
402 /*!
403   \brief Overwrite to fill fileitems from a source
404   \param strDirectory Path to read
405   \param items Fill with items specified in \e strDirectory
406   */
407 bool CGUIMediaWindow::GetDirectory(const CStdString &strDirectory, CFileItemList &items)
408 {
409   // cleanup items
410   if (items.Size())
411     items.Clear();
412
413   CStdString strParentPath=m_history.GetParentPath();
414
415   CLog::Log(LOGDEBUG,"CGUIMediaWindow::GetDirectory (%s)", strDirectory.c_str());
416   CLog::Log(LOGDEBUG,"  ParentPath = [%s]", strParentPath.c_str());
417
418   if (m_guiState.get() && !m_guiState->HideParentDirItems())
419   {
420     CFileItem *pItem = new CFileItem("..");
421     pItem->m_strPath = strParentPath;
422     pItem->m_bIsFolder = true;
423     pItem->m_bIsShareOrDrive = false;
424     items.Add(pItem);
425   }
426
427   // see if we can load a previously cached folder
428   CFileItemList cachedItems(strDirectory);
429   if (!strDirectory.IsEmpty() && cachedItems.Load())
430   {
431     items.m_strPath = cachedItems.m_strPath;
432     items.AppendPointer(cachedItems);
433     cachedItems.ClearKeepPointer();
434   }
435   else
436   {
437     DWORD time = timeGetTime();
438
439     if (!m_rootDir.GetDirectory(strDirectory, items))
440       return false;
441
442     // took over a second, and not normally cached, so cache it
443     if (time + 1000 < timeGetTime() && !items.GetCacheToDisc())
444       items.Save();
445   }
446   return true;
447 }
448
449 // \brief Set window to a specific directory
450 // \param strDirectory The directory to be displayed in list/thumb control
451 // This function calls OnPrepareFileItems() and OnFinalizeFileItems()
452 bool CGUIMediaWindow::Update(const CStdString &strDirectory)
453 {
454   // get selected item
455   int iItem = m_viewControl.GetSelectedItem();
456   CStdString strSelectedItem = "";
457   if (iItem >= 0 && iItem < m_vecItems.Size())
458   {
459     CFileItem* pItem = m_vecItems[iItem];
460     if (!pItem->IsParentFolder())
461     {
462       GetDirectoryHistoryString(pItem, strSelectedItem);
463     }
464   }
465
466   CStdString strOldDirectory = m_vecItems.m_strPath;
467
468   m_history.SetSelectedItem(strSelectedItem, strOldDirectory);
469
470   ClearFileItems();
471
472   if (!GetDirectory(strDirectory, m_vecItems))
473   {
474     CLog::Log(LOGERROR,"CGUIMediaWindow::GetDirectory(%s) failed", strDirectory.c_str());
475     // if the directory is the same as the old directory, then we'll return
476     // false.  Else, we assume we can get the previous directory
477     if (strDirectory.Equals(strOldDirectory))
478       return false;
479
480     // We assume, we can get the parent
481     // directory again, but we have to
482     // return false to be able to eg. show
483     // an error message.
484     CStdString strParentPath = m_history.GetParentPath();
485     m_history.RemoveParentPath();
486     Update(strParentPath);
487     return false;
488   }
489
490   // if we're getting the root source listing
491   // make sure the path history is clean
492   if (strDirectory.IsEmpty())
493     m_history.ClearPathHistory();
494
495   int iWindow = GetID();
496   bool bOkay = (iWindow == WINDOW_MUSIC_FILES || iWindow == WINDOW_VIDEO_FILES || iWindow == WINDOW_FILES || iWindow == WINDOW_PICTURES || iWindow == WINDOW_PROGRAMS);
497   if (strDirectory.IsEmpty() && bOkay && (m_vecItems.Size() == 0 || !m_guiState->DisableAddSourceButtons())) // add 'add source button'
498   {
499     CStdString strLabel = g_localizeStrings.Get(1026);
500     CFileItem *pItem = new CFileItem(strLabel);
501     pItem->m_strPath = "add";
502     pItem->SetThumbnailImage("DefaultAddSource.png");
503     pItem->SetLabel(strLabel);
504     pItem->SetLabelPreformated(true);
505     m_vecItems.Add(pItem);
506   }
507   m_iLastControl = GetFocusedControlID();
508
509   //  Ask the derived class if it wants to load additional info
510   //  for the fileitems like media info or additional
511   //  filtering on the items, setting thumbs.
512   OnPrepareFileItems(m_vecItems);
513
514   m_vecItems.FillInDefaultIcons();
515
516   m_guiState.reset(CGUIViewState::GetViewState(GetID(), m_vecItems));
517
518   OnSort();
519
520   // Ask the devived class if it wants to do custom list operations,
521   // eg. changing the label
522   OnFinalizeFileItems(m_vecItems);
523   UpdateButtons();
524
525   m_viewControl.SetItems(m_vecItems);
526
527   strSelectedItem = m_history.GetSelectedItem(m_vecItems.m_strPath);
528
529   bool bSelectedFound = false;
530   //int iSongInDirectory = -1;
531   for (int i = 0; i < m_vecItems.Size(); ++i)
532   {
533     CFileItem* pItem = m_vecItems[i];
534
535     // Update selected item
536     if (!bSelectedFound)
537     {
538       CStdString strHistory;
539       GetDirectoryHistoryString(pItem, strHistory);
540       if (strHistory == strSelectedItem)
541       {
542         m_viewControl.SetSelectedItem(i);
543         bSelectedFound = true;
544       }
545     }
546   }
547
548   // if we haven't found the selected item, select the first item
549   if (!bSelectedFound)
550     m_viewControl.SetSelectedItem(0);
551
552   m_history.AddPath(m_vecItems.m_strPath);
553
554   //m_history.DumpPathHistory();
555
556   return true;
557 }
558
559 // \brief This function will be called by Update() before the
560 // labels of the fileitems are formatted. Override this function
561 // to set custom thumbs or load additional media info.
562 // It's used to load tag info for music.
563 void CGUIMediaWindow::OnPrepareFileItems(CFileItemList &items)
564 {
565
566 }
567
568 // \brief This function will be called by Update() after the
569 // labels of the fileitems are formatted. Override this function
570 // to modify the fileitems. Eg. to modify the item label
571 void CGUIMediaWindow::OnFinalizeFileItems(CFileItemList &items)
572 {
573
574 }
575
576 // \brief With this function you can react on a users click in the list/thumb panel.
577 // It returns true, if the click is handled.
578 // This function calls OnPlayMedia()
579 bool CGUIMediaWindow::OnClick(int iItem)
580 {
581   if ( iItem < 0 || iItem >= (int)m_vecItems.Size() ) return true;
582   CFileItem* pItem = m_vecItems[iItem];
583
584   if (pItem->IsParentFolder())
585   {
586     GoParentFolder();
587     return true;
588   }
589   else if (pItem->m_bIsFolder)
590   {
591     if ( pItem->m_bIsShareOrDrive )
592     {
593       const CStdString& strLockType=m_guiState->GetLockType();
594       if (g_settings.m_vecProfiles[0].getLockMode() != LOCK_MODE_EVERYONE)
595         if (!strLockType.IsEmpty() && !g_passwordManager.IsItemUnlocked(pItem, strLockType))
596             return true;
597
598       if (!HaveDiscOrConnection(pItem->m_strPath, pItem->m_iDriveType))
599         return true;
600     }
601
602     // remove the directory cache if the folder is not normally cached
603     CFileItemList items(pItem->m_strPath);
604     if (!items.AlwaysCache())
605       items.RemoveDiscCache();
606
607     CFileItem directory(*pItem);
608     if (!Update(directory.m_strPath))
609       ShowShareErrorMessage(&directory);
610
611     return true;
612   }
613   else
614   {
615     m_iSelectedItem = m_viewControl.GetSelectedItem();
616
617     if (pItem->m_strPath == "newplaylist://")
618     {
619       m_gWindowManager.ActivateWindow(WINDOW_MUSIC_PLAYLIST_EDITOR);
620       return true;
621     }
622     else if (pItem->m_strPath == "newsmartplaylist://")
623     {
624       if (CGUIDialogSmartPlaylistEditor::NewPlaylist())
625         Update(m_vecItems.m_strPath);
626       return true;
627     }
628
629     // this is particular to music as only music allows "auto play next item"
630     if (m_guiState.get() && m_guiState->AutoPlayNextItem() && !g_partyModeManager.IsEnabled() && !pItem->IsPlayList())
631     {
632       if (pItem->m_strPath == "add" && pItem->GetLabel() == g_localizeStrings.Get(1026)) // 'add source button' in empty root
633       {
634         if (CGUIDialogMediaSource::ShowAndAddMediaSource("music"))
635         {
636           Update("");
637           return true;
638         }
639         return false;
640       }
641
642       //play and add current directory to temporary playlist
643       int iPlaylist=m_guiState->GetPlaylist();
644       if (iPlaylist!=PLAYLIST_NONE)
645       {
646         g_playlistPlayer.ClearPlaylist(iPlaylist);
647         g_playlistPlayer.Reset();
648         int songToPlay = 0;
649         CFileItemList queueItems;
650         for ( int i = 0; i < m_vecItems.Size(); i++ )
651         {
652           CFileItem* item = m_vecItems[i];
653
654           if (item->m_bIsFolder)
655             continue;
656
657           if (!item->IsPlayList() && !item->IsZIP() && !item->IsRAR())
658             queueItems.Add(item);
659
660           if (item == pItem)
661           { // item that was clicked
662             songToPlay = queueItems.Size() - 1;
663           }
664         }
665         g_playlistPlayer.Add(iPlaylist, queueItems);
666         queueItems.ClearKeepPointer();
667
668         // Save current window and directory to know where the selected item was
669         if (m_guiState.get())
670           m_guiState->SetPlaylistDirectory(m_vecItems.m_strPath);
671
672         // figure out where we start playback
673         if (g_playlistPlayer.IsShuffled(iPlaylist))
674         {
675           int iIndex = g_playlistPlayer.GetPlaylist(iPlaylist).FindOrder(songToPlay);
676           g_playlistPlayer.GetPlaylist(iPlaylist).Swap(0, iIndex);
677           songToPlay = 0;
678         }
679
680         // play
681         g_playlistPlayer.SetCurrentPlaylist(iPlaylist);
682         g_playlistPlayer.Play(songToPlay);
683       }
684       return true;
685     }
686     else
687     {
688       return OnPlayMedia(iItem);
689     }
690   }
691
692   return false;
693 }
694
695 // \brief Checks if there is a disc in the dvd drive and whether the
696 // network is connected or not.
697 bool CGUIMediaWindow::HaveDiscOrConnection(CStdString& strPath, int iDriveType)
698 {
699   if (iDriveType==SHARE_TYPE_DVD)
700   {
701     MEDIA_DETECT::CDetectDVDMedia::WaitMediaReady();
702     if (!MEDIA_DETECT::CDetectDVDMedia::IsDiscInDrive())
703     {
704       CGUIDialogOK::ShowAndGetInput(218, 219, 0, 0);
705       return false;
706     }
707   }
708   else if (iDriveType==SHARE_TYPE_REMOTE)
709   {
710     // TODO: Handle not connected to a remote share
711     if ( !g_network.IsEthernetConnected() )
712     {
713       CGUIDialogOK::ShowAndGetInput(220, 221, 0, 0);
714       return false;
715     }
716   }
717
718   return true;
719 }
720
721 // \brief Shows a standard errormessage for a given pItem.
722 void CGUIMediaWindow::ShowShareErrorMessage(CFileItem* pItem)
723 {
724   if (pItem->m_bIsShareOrDrive)
725   {
726     int idMessageText=0;
727     const CURL& url=pItem->GetAsUrl();
728     const CStdString& strHostName=url.GetHostName();
729
730     if (pItem->m_iDriveType!=SHARE_TYPE_REMOTE) //  Local shares incl. dvd drive
731       idMessageText=15300;
732     else if (url.GetProtocol()=="xbms" && strHostName.IsEmpty()) //  xbms server discover
733       idMessageText=15302;
734     else if (url.GetProtocol()=="smb" && strHostName.IsEmpty()) //  smb workgroup
735       idMessageText=15303;
736     else  //  All other remote shares
737       idMessageText=15301;
738
739     CGUIDialogOK::ShowAndGetInput(220, idMessageText, 0, 0);
740   }
741 }
742
743 // \brief The functon goes up one level in the directory tree
744 void CGUIMediaWindow::GoParentFolder()
745 {
746   //m_history.DumpPathHistory();
747
748   // remove current directory if its on the stack
749   // there were some issues due some folders having a trailing slash and some not
750   // so just add a trailing slash to all of them for comparison.
751   CStdString strPath = m_vecItems.m_strPath;
752   CUtil::AddSlashAtEnd(strPath);
753   CStdString strParent = m_history.GetParentPath();
754   // in case the path history is messed up and the current folder is on
755   // the stack more than once, keep going until there's nothing left or they
756   // dont match anymore.
757   while (!strParent.IsEmpty())
758   {
759     CUtil::AddSlashAtEnd(strParent);
760     if (strParent.Equals(strPath))
761       m_history.RemoveParentPath();
762     else
763       break;
764     strParent = m_history.GetParentPath();
765   }
766
767   // if vector is not empty, pop parent
768   // if vector is empty, parent is root source listing
769   CStdString strOldPath(m_vecItems.m_strPath);
770   strParent = m_history.RemoveParentPath();
771   Update(strParent);
772
773   if (!g_guiSettings.GetBool("filelists.fulldirectoryhistory"))
774     m_history.RemoveSelectedItem(strOldPath); //Delete current path
775 }
776
777 // \brief Override the function to change the default behavior on how
778 // a selected item history should look like
779 void CGUIMediaWindow::GetDirectoryHistoryString(const CFileItem* pItem, CStdString& strHistoryString)
780 {
781   if (pItem->m_bIsShareOrDrive)
782   {
783     // We are in the virual directory
784
785     // History string of the DVD drive
786     // must be handel separately
787     if (pItem->m_iDriveType == SHARE_TYPE_DVD)
788     {
789       // Remove disc label from item label
790       // and use as history string, m_strPath
791       // can change for new discs
792       CStdString strLabel = pItem->GetLabel();
793       int nPosOpen = strLabel.Find('(');
794       int nPosClose = strLabel.ReverseFind(')');
795       if (nPosOpen > -1 && nPosClose > -1 && nPosClose > nPosOpen)
796       {
797         strLabel.Delete(nPosOpen + 1, (nPosClose) - (nPosOpen + 1));
798         strHistoryString = strLabel;
799       }
800       else
801         strHistoryString = strLabel;
802     }
803     else
804     {
805       // Other items in virual directory
806       CStdString strPath = pItem->m_strPath;
807       while (CUtil::HasSlashAtEnd(strPath))
808         strPath.Delete(strPath.size() - 1);
809
810       strHistoryString = pItem->GetLabel() + strPath;
811     }
812   }
813   else if (pItem->m_lEndOffset>pItem->m_lStartOffset && pItem->m_lStartOffset != -1)
814   {
815     // Could be a cue item, all items of a cue share the same filename
816     // so add the offsets to build the history string
817     strHistoryString.Format("%ld%ld", pItem->m_lStartOffset, pItem->m_lEndOffset);
818     strHistoryString += pItem->m_strPath;
819
820     if (CUtil::HasSlashAtEnd(strHistoryString))
821       strHistoryString.Delete(strHistoryString.size() - 1);
822   }
823   else
824   {
825     // Normal directory items
826     strHistoryString = pItem->m_strPath;
827
828     while (CUtil::HasSlashAtEnd(strHistoryString)) // to match CDirectoryHistory::GetSelectedItem
829       strHistoryString.Delete(strHistoryString.size() - 1);
830   }
831   strHistoryString.ToLower();
832 }
833
834 // \brief Call this function to create a directory history for the
835 // path given by strDirectory.
836 void CGUIMediaWindow::SetHistoryForPath(const CStdString& strDirectory)
837 {
838   // Make sure our shares are configured
839   SetupShares();
840   if (!strDirectory.IsEmpty())
841   {
842     // Build the directory history for default path
843     CStdString strPath, strParentPath;
844     strPath = strDirectory;
845     while (CUtil::HasSlashAtEnd(strPath))
846       strPath.Delete(strPath.size() - 1);
847
848     CFileItemList items;
849     m_rootDir.GetDirectory("", items);
850
851     m_history.ClearPathHistory();
852
853     while (CUtil::GetParentPath(strPath, strParentPath))
854     {
855       bool bSet = false;
856       for (int i = 0; i < (int)items.Size(); ++i)
857       {
858         CFileItem* pItem = items[i];
859         while (CUtil::HasSlashAtEnd(pItem->m_strPath))
860           pItem->m_strPath.Delete(pItem->m_strPath.size() - 1);
861         if (pItem->m_strPath == strPath)
862         {
863           CStdString strHistory;
864           GetDirectoryHistoryString(pItem, strHistory);
865           m_history.SetSelectedItem(strHistory, "");
866           CUtil::AddSlashAtEnd(strPath);
867           m_history.AddPathFront(strPath);
868           m_history.AddPathFront("");
869
870           //m_history.DumpPathHistory();
871           return ;
872         }
873       }
874
875       CUtil::AddSlashAtEnd(strPath);
876       m_history.AddPathFront(strPath);
877       m_history.SetSelectedItem(strPath, strParentPath);
878       strPath = strParentPath;
879       while (CUtil::HasSlashAtEnd(strPath))
880         strPath.Delete(strPath.size() - 1);
881     }
882   }
883   else
884     m_history.ClearPathHistory();
885
886   //m_history.DumpPathHistory();
887 }
888
889 // \brief Override if you want to change the default behavior, what is done
890 // when the user clicks on a file.
891 // This function is called by OnClick()
892 bool CGUIMediaWindow::OnPlayMedia(int iItem)
893 {
894   // Reset Playlistplayer, playback started now does
895   // not use the playlistplayer.
896   g_playlistPlayer.Reset();
897   g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_NONE);
898   CFileItem* pItem=m_vecItems[iItem];
899
900   bool bResult = false;
901   if (pItem->IsInternetStream() || pItem->IsPlayList())
902     bResult = g_application.PlayMedia(*pItem, m_guiState->GetPlaylist());
903   else
904     bResult = g_application.PlayFile(*pItem);
905
906   if (pItem->m_lStartOffset == STARTOFFSET_RESUME)
907     pItem->m_lStartOffset = 0;
908
909   return bResult;
910 }
911
912 // \brief Synchonize the fileitems with the playlistplayer
913 // It recreated the playlist of the playlistplayer based
914 // on the fileitems of the window
915 void CGUIMediaWindow::UpdateFileList()
916 {
917   int nItem = m_viewControl.GetSelectedItem();
918   CFileItem* pItem = m_vecItems[nItem];
919   const CStdString& strSelected = pItem->m_strPath;
920
921   OnSort();
922   UpdateButtons();
923
924   m_viewControl.SetItems(m_vecItems);
925   m_viewControl.SetSelectedItem(strSelected);
926
927   //  set the currently playing item as selected, if its in this directory
928   if (m_guiState.get() && m_guiState->IsCurrentPlaylistDirectory(m_vecItems.m_strPath))
929   {
930     int iPlaylist=m_guiState->GetPlaylist();
931     int nSong = g_playlistPlayer.GetCurrentSong();
932     CFileItem playlistItem;
933     if (nSong > -1 && iPlaylist > -1)
934       playlistItem=g_playlistPlayer.GetPlaylist(iPlaylist)[nSong];
935
936     g_playlistPlayer.ClearPlaylist(iPlaylist);
937     g_playlistPlayer.Reset();
938
939     for (int i = 0; i < m_vecItems.Size(); i++)
940     {
941       CFileItem* pItem = m_vecItems[i];
942       if (pItem->m_bIsFolder)
943         continue;
944
945       if (!pItem->IsPlayList() && !pItem->IsZIP() && !pItem->IsRAR())
946         g_playlistPlayer.Add(iPlaylist, pItem);
947
948       if (pItem->m_strPath == playlistItem.m_strPath &&
949           pItem->m_lStartOffset == playlistItem.m_lStartOffset)
950         g_playlistPlayer.SetCurrentSong(g_playlistPlayer.GetPlaylist(iPlaylist).size() - 1);
951     }
952   }
953 }
954
955 void CGUIMediaWindow::OnDeleteItem(int iItem)
956 {
957   if ( iItem < 0 || iItem >= m_vecItems.Size()) return;
958   CFileItem item(*m_vecItems[iItem]);
959
960   if (item.IsPlayList())
961     item.m_bIsFolder = false;
962
963   if (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].getLockMode() != LOCK_MODE_EVERYONE && g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].filesLocked())
964     if (!g_passwordManager.IsMasterLockUnlocked(true))
965       return;
966
967   if (!CGUIWindowFileManager::DeleteItem(&item))
968     return;
969   Update(m_vecItems.m_strPath);
970   m_viewControl.SetSelectedItem(iItem);
971 }
972
973 void CGUIMediaWindow::OnRenameItem(int iItem)
974 {
975   if ( iItem < 0 || iItem >= m_vecItems.Size()) return;
976
977   if (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].getLockMode() != LOCK_MODE_EVERYONE && g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].filesLocked())
978     if (!g_passwordManager.IsMasterLockUnlocked(true))
979       return;
980
981   if (!CGUIWindowFileManager::RenameFile(m_vecItems[iItem]->m_strPath))
982     return;
983   Update(m_vecItems.m_strPath);
984   m_viewControl.SetSelectedItem(iItem);
985 }
986
987 void CGUIMediaWindow::OnInitWindow()
988 {
989   Update(m_vecItems.m_strPath);
990
991   if (m_iSelectedItem > -1)
992     m_viewControl.SetSelectedItem(m_iSelectedItem);
993
994   CGUIWindow::OnInitWindow();
995 }
996
997 CGUIControl *CGUIMediaWindow::GetFirstFocusableControl(int id)
998 {
999   if (m_viewControl.HasControl(id))
1000     id = m_viewControl.GetCurrentControl();
1001   return CGUIWindow::GetFirstFocusableControl(id);
1002 }
1003
1004 void CGUIMediaWindow::SetupShares()
1005 {
1006   // Setup shares and filemasks for this window
1007   CFileItemList items;
1008   CGUIViewState* viewState=CGUIViewState::GetViewState(GetID(), items);
1009   if (viewState)
1010   {
1011     m_rootDir.SetMask(viewState->GetExtensions());
1012     m_rootDir.SetShares(viewState->GetShares());
1013     delete viewState;
1014   }
1015 }
1016
1017 bool CGUIMediaWindow::OnPopupMenu(int iItem)
1018 {
1019   // popup the context menu
1020   // grab our context menu
1021   CContextButtons buttons;
1022   GetContextButtons(iItem, buttons);
1023
1024   if (buttons.size())
1025   {
1026     // mark the item
1027     if (iItem >= 0 && iItem < m_vecItems.Size())
1028       m_vecItems[iItem]->Select(true);
1029
1030     CGUIDialogContextMenu *pMenu = (CGUIDialogContextMenu *)m_gWindowManager.GetWindow(WINDOW_DIALOG_CONTEXT_MENU);
1031     if (!pMenu) return false;
1032     // load our menu
1033     pMenu->Initialize();
1034
1035     // add the buttons and execute it
1036     for (CContextButtons::iterator it = buttons.begin(); it != buttons.end(); it++)
1037       pMenu->AddButton((*it).second);
1038
1039     // position it correctly
1040     float posX = 200;
1041     float posY = 100;
1042     const CGUIControl *pList = GetControl(CONTROL_VIEW_START);
1043     if (pList)
1044     {
1045       posX = pList->GetXPosition() + pList->GetWidth() / 2;
1046       posY = pList->GetYPosition() + pList->GetHeight() / 2;
1047     }
1048     pMenu->SetPosition(posX - pMenu->GetWidth() / 2, posY - pMenu->GetHeight() / 2);
1049     pMenu->DoModal();
1050
1051     // translate our button press
1052     CONTEXT_BUTTON btn = CONTEXT_BUTTON_CANCELLED;
1053     if (pMenu->GetButton() > 0 && pMenu->GetButton() <= (int)buttons.size())
1054       btn = buttons[pMenu->GetButton() - 1].first;
1055
1056     // deselect our item
1057     if (iItem >= 0 && iItem < m_vecItems.Size())
1058       m_vecItems[iItem]->Select(false);
1059
1060     if (btn != CONTEXT_BUTTON_CANCELLED)
1061       return OnContextButton(iItem, btn);
1062   }
1063   return false;
1064 }
1065
1066 void CGUIMediaWindow::GetContextButtons(int itemNumber, CContextButtons &buttons)
1067 {
1068   CFileItem *item = (itemNumber >= 0 && itemNumber < m_vecItems.Size()) ? m_vecItems[itemNumber] : NULL;
1069
1070 #ifdef PRE_SKIN_VERSION_2_1_COMPATIBILITY
1071   // check if the skin even supports favourites
1072   RESOLUTION res;
1073   CStdString favourites(g_SkinInfo.GetSkinPath("dialogfavourites.xml", &res));
1074   if (XFILE::CFile::Exists(favourites))
1075   {
1076 #endif
1077   // TODO: FAVOURITES Conditions on masterlock and localisation
1078   if (item && !item->IsParentFolder() && !item->m_strPath.Equals("add"))
1079   {
1080     if (CFavourites::IsFavourite(item, GetID()))
1081       buttons.Add(CONTEXT_BUTTON_ADD_FAVOURITE, 14077);     // Remove Favourite
1082     else
1083       buttons.Add(CONTEXT_BUTTON_ADD_FAVOURITE, 14076);     // Add To Favourites;
1084   }
1085 #ifdef PRE_SKIN_VERSION_2_1_COMPATIBILITY
1086   }
1087 #endif
1088 }
1089
1090 bool CGUIMediaWindow::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
1091 {
1092   switch (button)
1093   {
1094   case CONTEXT_BUTTON_ADD_FAVOURITE:
1095     CFavourites::AddOrRemove(m_vecItems[itemNumber], GetID());
1096     return true;
1097   }
1098   return false;
1099 }