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