[bluray] Fix stream info/language retrieval for blurays in non-nav mode.
[vuplus_xbmc] / xbmc / windows / GUIWindowFileManager.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "system.h"
22 #include "GUIWindowFileManager.h"
23 #include "Application.h"
24 #include "ApplicationMessenger.h"
25 #include "Util.h"
26 #include "filesystem/Directory.h"
27 #include "filesystem/ZipManager.h"
28 #include "filesystem/FileDirectoryFactory.h"
29 #include "dialogs/GUIDialogContextMenu.h"
30 #include "guilib/GUIListContainer.h"
31 #include "dialogs/GUIDialogMediaSource.h"
32 #include "GUIPassword.h"
33 #include "GUIUserMessages.h"
34 #ifdef HAS_PYTHON
35 #include "interfaces/python/XBPython.h"
36 #endif
37 #include "pictures/GUIWindowSlideShow.h"
38 #include "playlists/PlayListFactory.h"
39 #include "network/Network.h"
40 #include "guilib/GUIWindowManager.h"
41 #include "guilib/Key.h"
42 #include "dialogs/GUIDialogOK.h"
43 #include "dialogs/GUIDialogYesNo.h"
44 #include "guilib/GUIKeyboardFactory.h"
45 #include "dialogs/GUIDialogProgress.h"
46 #include "dialogs/GUIDialogExtendedProgressBar.h"
47 #include "filesystem/FavouritesDirectory.h"
48 #include "playlists/PlayList.h"
49 #include "utils/AsyncFileCopy.h"
50 #include "storage/MediaManager.h"
51 #include "settings/AdvancedSettings.h"
52 #include "settings/MediaSourceSettings.h"
53 #include "settings/Settings.h"
54 #include "input/MouseStat.h"
55 #include "guilib/LocalizeStrings.h"
56 #include "utils/StringUtils.h"
57 #include "utils/log.h"
58
59 #include "utils/JobManager.h"
60 #include "utils/FileOperationJob.h"
61 #include "utils/FileUtils.h"
62 #include "utils/URIUtils.h"
63 #include "Autorun.h"
64 #include "URL.h"
65
66 using namespace std;
67 using namespace XFILE;
68 using namespace PLAYLIST;
69
70 #define ACTION_COPY                     1
71 #define ACTION_MOVE                     2
72 #define ACTION_DELETE                   3
73 #define ACTION_CREATEFOLDER             4
74 #define ACTION_DELETEFOLDER             5
75
76 #define CONTROL_BTNVIEWASICONS          2
77 #define CONTROL_BTNSORTBY               3
78 #define CONTROL_BTNSORTASC              4
79 #define CONTROL_BTNNEWFOLDER            6
80 #define CONTROL_BTNSELECTALL            7
81 #define CONTROL_BTNCOPY                10
82 #define CONTROL_BTNMOVE                11
83 #define CONTROL_BTNDELETE               8
84 #define CONTROL_BTNRENAME               9
85
86 #define CONTROL_NUMFILES_LEFT          12
87 #define CONTROL_NUMFILES_RIGHT         13
88
89 #define CONTROL_LEFT_LIST              20
90 #define CONTROL_RIGHT_LIST             21
91
92 #define CONTROL_CURRENTDIRLABEL_LEFT  101
93 #define CONTROL_CURRENTDIRLABEL_RIGHT 102
94
95 CGUIWindowFileManager::CGUIWindowFileManager(void)
96     : CGUIWindow(WINDOW_FILES, "FileManager.xml"),
97       CJobQueue(false,2)
98 {
99   m_Directory[0] = new CFileItem;
100   m_Directory[1] = new CFileItem;
101   m_vecItems[0] = new CFileItemList;
102   m_vecItems[1] = new CFileItemList;
103   m_Directory[0]->SetPath("?");
104   m_Directory[1]->SetPath("?");
105   m_Directory[0]->m_bIsFolder = true;
106   m_Directory[1]->m_bIsFolder = true;
107   bCheckShareConnectivity = true;
108   m_loadType = KEEP_IN_MEMORY;
109 }
110
111 CGUIWindowFileManager::~CGUIWindowFileManager(void)
112 {
113   delete m_Directory[0];
114   delete m_Directory[1];
115   delete m_vecItems[0];
116   delete m_vecItems[1];
117 }
118
119 bool CGUIWindowFileManager::OnAction(const CAction &action)
120 {
121   int list = GetFocusedList();
122   if (list >= 0 && list <= 1)
123   {
124     int item;
125
126     // the non-contextual menu can be called at any time
127     if (action.GetID() == ACTION_CONTEXT_MENU && m_vecItems[list]->Size() == 0)
128     {
129       OnPopupMenu(list,-1, false);
130       return true;
131     }
132     if (action.GetID() == ACTION_DELETE_ITEM)
133     {
134       if (CanDelete(list))
135       {
136         bool bDeselect = SelectItem(list, item);
137         OnDelete(list);
138         if (bDeselect) m_vecItems[list]->Get(item)->Select(false);
139       }
140       return true;
141     }
142     if (action.GetID() == ACTION_COPY_ITEM)
143     {
144       if (CanCopy(list))
145       {
146         bool bDeselect = SelectItem(list, item);
147         OnCopy(list);
148         if (bDeselect) m_vecItems[list]->Get(item)->Select(false);
149       }
150       return true;
151     }
152     if (action.GetID() == ACTION_MOVE_ITEM)
153     {
154       if (CanMove(list))
155       {
156         bool bDeselect = SelectItem(list, item);
157         OnMove(list);
158         if (bDeselect) m_vecItems[list]->Get(item)->Select(false);
159       }
160       return true;
161     }
162     if (action.GetID() == ACTION_RENAME_ITEM)
163     {
164       if (CanRename(list))
165       {
166         bool bDeselect = SelectItem(list, item);
167         OnRename(list);
168         if (bDeselect) m_vecItems[list]->Get(item)->Select(false);
169       }
170       return true;
171     }
172     if (action.GetID() == ACTION_PARENT_DIR)
173     {
174       GoParentFolder(list);
175       return true;
176     }
177     if (action.GetID() == ACTION_PLAYER_PLAY)
178     {
179 #ifdef HAS_DVD_DRIVE
180       if (m_vecItems[list]->Get(GetSelectedItem(list))->IsDVD())
181         return MEDIA_DETECT::CAutorun::PlayDiscAskResume(m_vecItems[list]->Get(GetSelectedItem(list))->GetPath());
182 #endif
183     }
184   }
185   return CGUIWindow::OnAction(action);
186 }
187
188 bool CGUIWindowFileManager::OnBack(int actionID)
189 {
190   int list = GetFocusedList();
191   if (list >= 0 && list <= 1 && actionID == ACTION_NAV_BACK && !m_vecItems[list]->IsVirtualDirectoryRoot())
192   {
193     GoParentFolder(list);
194     return true;
195   }
196   return CGUIWindow::OnBack(actionID);
197 }
198
199 bool CGUIWindowFileManager::OnMessage(CGUIMessage& message)
200 {
201   switch ( message.GetMessage() )
202   {
203   case GUI_MSG_NOTIFY_ALL:
204     { // Message is received even if window is inactive
205       if (message.GetParam1() == GUI_MSG_WINDOW_RESET)
206       {
207         m_Directory[0]->SetPath("?");
208         m_Directory[1]->SetPath("?");
209         m_Directory[0]->m_bIsFolder = true;
210         m_Directory[1]->m_bIsFolder = true;
211         return true;
212       }
213
214       //  handle removable media
215       if (message.GetParam1() == GUI_MSG_REMOVED_MEDIA)
216       {
217         for (int i = 0; i < 2; i++)
218         {
219           if (m_Directory[i]->IsVirtualDirectoryRoot() && IsActive())
220           {
221             int iItem = GetSelectedItem(i);
222             Update(i, m_Directory[i]->GetPath());
223             CONTROL_SELECT_ITEM(CONTROL_LEFT_LIST + i, iItem);
224           }
225           else if (m_Directory[i]->IsRemovable() && !m_rootDir.IsInSource(m_Directory[i]->GetPath()))
226           { //
227             if (IsActive())
228               Update(i, "");
229             else
230               m_Directory[i]->SetPath("");
231           }
232         }
233         return true;
234       }
235       else if (message.GetParam1()==GUI_MSG_UPDATE_SOURCES)
236       { // State of the sources changed, so update our view
237         for (int i = 0; i < 2; i++)
238         {
239           if (m_Directory[i]->IsVirtualDirectoryRoot() && IsActive())
240           {
241             int iItem = GetSelectedItem(i);
242             Update(i, m_Directory[i]->GetPath());
243             CONTROL_SELECT_ITEM(CONTROL_LEFT_LIST + i, iItem);
244           }
245         }
246         return true;
247       }
248       else if (message.GetParam1()==GUI_MSG_UPDATE && IsActive())
249       {
250         Refresh();
251         return true;
252       }
253     }
254     break;
255   case GUI_MSG_PLAYBACK_STARTED:
256   case GUI_MSG_PLAYBACK_ENDED:
257   case GUI_MSG_PLAYBACK_STOPPED:
258   case GUI_MSG_PLAYLIST_CHANGED:
259   case GUI_MSG_PLAYLISTPLAYER_STOPPED:
260   case GUI_MSG_PLAYLISTPLAYER_STARTED:
261   case GUI_MSG_PLAYLISTPLAYER_CHANGED:
262     { // send a notify all to all controls on this window
263       CGUIMessage msg(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_REFRESH_LIST);
264       OnMessage(msg);
265       break;
266     }
267   case GUI_MSG_WINDOW_DEINIT:
268     {
269       CGUIWindow::OnMessage(message);
270       ClearFileItems(0);
271       ClearFileItems(1);
272       return true;
273     }
274     break;
275
276   case GUI_MSG_WINDOW_INIT:
277     {
278       SetInitialPath(message.GetStringParam());
279       message.SetStringParam("");
280
281       return CGUIWindow::OnMessage(message);
282     }
283     break;
284   case GUI_MSG_CLICKED:
285     {
286       int iControl = message.GetSenderId();
287
288       if (iControl == CONTROL_LEFT_LIST || iControl == CONTROL_RIGHT_LIST)  // list/thumb control
289       {
290         // get selected item
291         int list = iControl - CONTROL_LEFT_LIST;
292         int iItem = GetSelectedItem(list);
293         int iAction = message.GetParam1();
294
295         // iItem is checked for validity inside these routines
296         if (iAction == ACTION_HIGHLIGHT_ITEM || iAction == ACTION_MOUSE_LEFT_CLICK)
297         {
298           OnMark(list, iItem);
299           if (!g_Mouse.IsActive())
300           {
301             //move to next item
302             CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), iControl, iItem + 1);
303             g_windowManager.SendMessage(msg);
304           }
305         }
306         else if (iAction == ACTION_SELECT_ITEM || iAction == ACTION_MOUSE_DOUBLE_CLICK)
307         {
308           OnClick(list, iItem);
309         }
310         else if (iAction == ACTION_CONTEXT_MENU || iAction == ACTION_MOUSE_RIGHT_CLICK)
311         {
312           OnPopupMenu(list, iItem);
313         }
314       }
315     }
316     break;
317   }
318   return CGUIWindow::OnMessage(message);
319 }
320
321 void CGUIWindowFileManager::OnSort(int iList)
322 {
323   // always sort the list by label in ascending order
324   for (int i = 0; i < m_vecItems[iList]->Size(); i++)
325   {
326     CFileItemPtr pItem = m_vecItems[iList]->Get(i);
327     if (pItem->m_bIsFolder && (!pItem->m_dwSize || pItem->GetPath().Equals("add")))
328       pItem->SetLabel2("");
329     else
330       pItem->SetFileSizeLabel();
331
332     // Set free space on disc
333     if (pItem->m_bIsShareOrDrive)
334     {
335       if (pItem->IsHD())
336       {
337         ULARGE_INTEGER ulBytesFree;
338         if (GetDiskFreeSpaceEx(pItem->GetPath().c_str(), &ulBytesFree, NULL, NULL))
339         {
340           pItem->m_dwSize = ulBytesFree.QuadPart;
341           pItem->SetFileSizeLabel();
342         }
343       }
344       else if (pItem->IsDVD() && g_mediaManager.IsDiscInDrive())
345       {
346         ULARGE_INTEGER ulBytesTotal;
347         if (GetDiskFreeSpaceEx(pItem->GetPath().c_str(), NULL, &ulBytesTotal, NULL))
348         {
349           pItem->m_dwSize = ulBytesTotal.QuadPart;
350           pItem->SetFileSizeLabel();
351         }
352       }
353     } // if (pItem->m_bIsShareOrDrive)
354
355   }
356
357   m_vecItems[iList]->Sort(SORT_METHOD_LABEL, SortOrderAscending);
358 }
359
360 void CGUIWindowFileManager::ClearFileItems(int iList)
361 {
362   CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), iList + CONTROL_LEFT_LIST);
363   g_windowManager.SendMessage(msg);
364
365   m_vecItems[iList]->Clear(); // will clean up everything
366 }
367
368 void CGUIWindowFileManager::UpdateButtons()
369 {
370   // update our current directory labels
371   CStdString strDir = CURL(m_Directory[0]->GetPath()).GetWithoutUserDetails();
372   if (strDir.IsEmpty())
373   {
374     SET_CONTROL_LABEL(CONTROL_CURRENTDIRLABEL_LEFT,g_localizeStrings.Get(20108));
375   }
376   else
377   {
378     SET_CONTROL_LABEL(CONTROL_CURRENTDIRLABEL_LEFT, strDir);
379   }
380   strDir = CURL(m_Directory[1]->GetPath()).GetWithoutUserDetails();
381   if (strDir.IsEmpty())
382   {
383     SET_CONTROL_LABEL(CONTROL_CURRENTDIRLABEL_RIGHT,g_localizeStrings.Get(20108));
384   }
385   else
386   {
387     SET_CONTROL_LABEL(CONTROL_CURRENTDIRLABEL_RIGHT, strDir);
388   }
389
390   // update the number of items in each list
391   UpdateItemCounts();
392 }
393
394 void CGUIWindowFileManager::UpdateItemCounts()
395 {
396   for (int i = 0; i < 2; i++)
397   {
398     unsigned int selectedCount = 0;
399     unsigned int totalCount = 0;
400     int64_t selectedSize = 0;
401     int64_t totalSize = 0;
402     for (int j = 0; j < m_vecItems[i]->Size(); j++)
403     {
404       CFileItemPtr item = m_vecItems[i]->Get(j);
405       if (item->IsParentFolder()) continue;
406       if (item->IsSelected())
407       {
408         selectedCount++;
409         selectedSize += item->m_dwSize;
410       }
411       totalCount++;
412       totalSize += item->m_dwSize;
413     }
414     CStdString items;
415     if (selectedCount > 0)
416       items.Format("%i/%i %s (%s)", selectedCount, totalCount, g_localizeStrings.Get(127).c_str(), StringUtils::SizeToString(selectedSize).c_str());
417     else
418       items.Format("%i %s", totalCount, g_localizeStrings.Get(127).c_str());
419     SET_CONTROL_LABEL(CONTROL_NUMFILES_LEFT + i, items);
420   }
421 }
422
423 bool CGUIWindowFileManager::Update(int iList, const CStdString &strDirectory)
424 {
425   // get selected item
426   int iItem = GetSelectedItem(iList);
427   CStdString strSelectedItem = "";
428
429   if (iItem >= 0 && iItem < (int)m_vecItems[iList]->Size())
430   {
431     CFileItemPtr pItem = m_vecItems[iList]->Get(iItem);
432     if (!pItem->IsParentFolder())
433     {
434       GetDirectoryHistoryString(pItem.get(), strSelectedItem);
435       m_history[iList].SetSelectedItem(strSelectedItem, m_Directory[iList]->GetPath());
436     }
437   }
438
439   CStdString strOldDirectory=m_Directory[iList]->GetPath();
440   m_Directory[iList]->SetPath(strDirectory);
441
442   CFileItemList items;
443   if (!GetDirectory(iList, m_Directory[iList]->GetPath(), items))
444   {
445     if (strDirectory != strOldDirectory && GetDirectory(iList, strOldDirectory, items))
446       m_Directory[iList]->SetPath(strOldDirectory); // Fallback to old (previous) path)
447     else
448       Update(iList, ""); // Fallback to root
449
450     return false;
451   }
452
453   m_history[iList].SetSelectedItem(strSelectedItem, strOldDirectory);
454
455   ClearFileItems(iList);
456
457   m_vecItems[iList]->Append(items);
458   m_vecItems[iList]->SetPath(items.GetPath());
459
460   CStdString strParentPath;
461   URIUtils::GetParentPath(strDirectory, strParentPath);
462   if (strDirectory.IsEmpty() && (m_vecItems[iList]->Size() == 0 || CSettings::Get().GetBool("filelists.showaddsourcebuttons")))
463   { // add 'add source button'
464     CStdString strLabel = g_localizeStrings.Get(1026);
465     CFileItemPtr pItem(new CFileItem(strLabel));
466     pItem->SetPath("add");
467     pItem->SetIconImage("DefaultAddSource.png");
468     pItem->SetLabel(strLabel);
469     pItem->SetLabelPreformated(true);
470     pItem->m_bIsFolder = true;
471     pItem->SetSpecialSort(SortSpecialOnBottom);
472     m_vecItems[iList]->Add(pItem);
473   }
474   else if (items.IsEmpty() || CSettings::Get().GetBool("filelists.showparentdiritems"))
475   {
476     CFileItemPtr pItem(new CFileItem(".."));
477     pItem->SetPath(m_rootDir.IsSource(strDirectory) ? "" : strParentPath);
478     pItem->m_bIsFolder = true;
479     pItem->m_bIsShareOrDrive = false;
480     m_vecItems[iList]->AddFront(pItem, 0);
481   }
482
483   m_strParentPath[iList] = (m_rootDir.IsSource(strDirectory) ? "" : strParentPath);
484
485   if (strDirectory.IsEmpty())
486   {
487     CFileItemPtr pItem(new CFileItem("special://profile/", true));
488     pItem->SetLabel(g_localizeStrings.Get(20070));
489     pItem->SetArt("thumb", "DefaultFolder.png");
490     pItem->SetLabelPreformated(true);
491     m_vecItems[iList]->Add(pItem);
492   }
493
494   // if we have a .tbn file, use itself as the thumb
495   for (int i = 0; i < (int)m_vecItems[iList]->Size(); i++)
496   {
497     CFileItemPtr pItem = m_vecItems[iList]->Get(i);
498     if (pItem->IsHD() &&
499         URIUtils::HasExtension(pItem->GetPath(), ".tbn"))
500     {
501       pItem->SetArt("thumb", pItem->GetPath());
502     }
503   }
504   m_vecItems[iList]->FillInDefaultIcons();
505
506   OnSort(iList);
507   UpdateButtons();
508
509   int item = 0;
510   strSelectedItem = m_history[iList].GetSelectedItem(m_Directory[iList]->GetPath());
511   for (int i = 0; i < m_vecItems[iList]->Size(); ++i)
512   {
513     CFileItemPtr pItem = m_vecItems[iList]->Get(i);
514     CStdString strHistory;
515     GetDirectoryHistoryString(pItem.get(), strHistory);
516     if (strHistory == strSelectedItem)
517     {
518       item = i;
519       break;
520     }
521   }
522   UpdateControl(iList, item);
523   return true;
524 }
525
526
527 void CGUIWindowFileManager::OnClick(int iList, int iItem)
528 {
529   if ( iList < 0 || iList >= 2) return ;
530   if ( iItem < 0 || iItem >= m_vecItems[iList]->Size() ) return ;
531
532   CFileItemPtr pItem = m_vecItems[iList]->Get(iItem);
533   if (pItem->GetPath() == "add" && pItem->GetLabel() == g_localizeStrings.Get(1026)) // 'add source button' in empty root
534   {
535     if (CGUIDialogMediaSource::ShowAndAddMediaSource("files"))
536     {
537       m_rootDir.SetSources(*CMediaSourceSettings::Get().GetSources("files"));
538       Update(0,m_Directory[0]->GetPath());
539       Update(1,m_Directory[1]->GetPath());
540     }
541     return;
542   }
543
544   if (!pItem->m_bIsFolder && pItem->IsFileFolder(EFILEFOLDER_MASK_ALL))
545   {
546     XFILE::IFileDirectory *pFileDirectory = NULL;
547     pFileDirectory = XFILE::CFileDirectoryFactory::Create(pItem->GetPath(), pItem.get(), "");
548     if(pFileDirectory)
549       pItem->m_bIsFolder = true;
550     else if(pItem->m_bIsFolder)
551       pItem->m_bIsFolder = false;
552     delete pFileDirectory;
553   }
554
555   if (pItem->m_bIsFolder)
556   {
557     // save path + drive type because of the possible refresh
558     CStdString strPath = pItem->GetPath();
559     int iDriveType = pItem->m_iDriveType;
560     if ( pItem->m_bIsShareOrDrive )
561     {
562       if ( !g_passwordManager.IsItemUnlocked( pItem.get(), "files" ) )
563       {
564         Refresh();
565         return ;
566       }
567
568       if ( !HaveDiscOrConnection( strPath, iDriveType ) )
569         return ;
570     }
571     if (!Update(iList, strPath))
572       ShowShareErrorMessage(pItem.get());
573   }
574   else if (pItem->IsZIP() || pItem->IsCBZ()) // mount zip archive
575   {
576     CStdString strArcivedPath;
577     URIUtils::CreateArchivePath(strArcivedPath, "zip", pItem->GetPath(), "");
578     Update(iList, strArcivedPath);
579   }
580   else if (pItem->IsRAR() || pItem->IsCBR())
581   {
582     CStdString strArcivedPath;
583     URIUtils::CreateArchivePath(strArcivedPath, "rar", pItem->GetPath(), "");
584     Update(iList, strArcivedPath);
585   }
586   else
587   {
588     OnStart(pItem.get());
589     return ;
590   }
591   // UpdateButtons();
592 }
593
594 // TODO 2.0: Can this be removed, or should we run without the "special" file directories while
595 // in filemanager view.
596 void CGUIWindowFileManager::OnStart(CFileItem *pItem)
597 {
598   // start playlists from file manager
599   if (pItem->IsPlayList())
600   {
601     CStdString strPlayList = pItem->GetPath();
602     auto_ptr<CPlayList> pPlayList (CPlayListFactory::Create(strPlayList));
603     if (NULL != pPlayList.get())
604     {
605       if (!pPlayList->Load(strPlayList))
606       {
607         CGUIDialogOK::ShowAndGetInput(6, 0, 477, 0);
608         return;
609       }
610     }
611     g_application.ProcessAndStartPlaylist(strPlayList, *pPlayList, PLAYLIST_MUSIC);
612     return;
613   }
614   if (pItem->IsAudio() || pItem->IsVideo())
615   {
616     g_application.PlayFile(*pItem);
617     return ;
618   }
619 #ifdef HAS_PYTHON
620   if (pItem->IsPythonScript())
621   {
622     g_pythonParser.evalFile(pItem->GetPath().c_str(),ADDON::AddonPtr());
623     return ;
624   }
625 #endif
626   if (pItem->IsPicture())
627   {
628     CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
629     if (!pSlideShow)
630       return ;
631     if (g_application.IsPlayingVideo())
632       g_application.StopPlaying();
633
634     pSlideShow->Reset();
635     pSlideShow->Add(pItem);
636     pSlideShow->Select(pItem->GetPath());
637
638     g_windowManager.ActivateWindow(WINDOW_SLIDESHOW);
639   }
640 }
641
642 bool CGUIWindowFileManager::HaveDiscOrConnection( CStdString& strPath, int iDriveType )
643 {
644   if ( iDriveType == CMediaSource::SOURCE_TYPE_DVD )
645   {
646     if ( !g_mediaManager.IsDiscInDrive(strPath) )
647     {
648       CGUIDialogOK::ShowAndGetInput(218, 219, 0, 0);
649       int iList = GetFocusedList();
650       int iItem = GetSelectedItem(iList);
651       Update(iList, "");
652       CONTROL_SELECT_ITEM(iList + CONTROL_LEFT_LIST, iItem);
653       return false;
654     }
655   }
656   else if ( iDriveType == CMediaSource::SOURCE_TYPE_REMOTE )
657   {
658     // TODO: Handle not connected to a remote share
659     if ( !g_application.getNetwork().IsConnected() )
660     {
661       CGUIDialogOK::ShowAndGetInput(220, 221, 0, 0);
662       return false;
663     }
664   }
665   else
666     return true;
667   return true;
668 }
669
670 void CGUIWindowFileManager::UpdateControl(int iList, int item)
671 {
672   CGUIMessage msg(GUI_MSG_LABEL_BIND, GetID(), iList + CONTROL_LEFT_LIST, item, 0, m_vecItems[iList]);
673   g_windowManager.SendMessage(msg);
674 }
675
676 void CGUIWindowFileManager::OnMark(int iList, int iItem)
677 {
678   CFileItemPtr pItem = m_vecItems[iList]->Get(iItem);
679
680   if (!pItem->m_bIsShareOrDrive)
681   {
682     if (!pItem->IsParentFolder())
683     {
684       // MARK file
685       pItem->Select(!pItem->IsSelected());
686     }
687   }
688
689   UpdateItemCounts();
690   // UpdateButtons();
691 }
692
693 void CGUIWindowFileManager::OnCopy(int iList)
694 {
695   if (!CGUIDialogYesNo::ShowAndGetInput(120, 123, 0, 0))
696     return;
697
698   AddJob(new CFileOperationJob(CFileOperationJob::ActionCopy, 
699                                 *m_vecItems[iList],
700                                 m_Directory[1 - iList]->GetPath(),
701                                 true, 16201, 16202));
702 }
703
704 void CGUIWindowFileManager::OnMove(int iList)
705 {
706   if (!CGUIDialogYesNo::ShowAndGetInput(121, 124, 0, 0))
707     return;
708
709   AddJob(new CFileOperationJob(CFileOperationJob::ActionMove,
710                                *m_vecItems[iList],
711                                m_Directory[1 - iList]->GetPath(),
712                                true, 16203, 16204));
713 }
714
715 void CGUIWindowFileManager::OnDelete(int iList)
716 {
717   if (!CGUIDialogYesNo::ShowAndGetInput(122, 125, 0, 0))
718     return;
719
720   AddJob(new CFileOperationJob(CFileOperationJob::ActionDelete,
721                                *m_vecItems[iList],
722                                m_Directory[iList]->GetPath(),
723                                true, 16205, 16206));
724 }
725
726 void CGUIWindowFileManager::OnRename(int iList)
727 {
728   CStdString strFile;
729   for (int i = 0; i < m_vecItems[iList]->Size();++i)
730   {
731     CFileItemPtr pItem = m_vecItems[iList]->Get(i);
732     if (pItem->IsSelected())
733     {
734       strFile = pItem->GetPath();
735       break;
736     }
737   }
738
739   CFileUtils::RenameFile(strFile);
740
741   Refresh(iList);
742 }
743
744 void CGUIWindowFileManager::OnSelectAll(int iList)
745 {
746   for (int i = 0; i < m_vecItems[iList]->Size();++i)
747   {
748     CFileItemPtr pItem = m_vecItems[iList]->Get(i);
749     if (!pItem->IsParentFolder())
750     {
751       pItem->Select(true);
752     }
753   }
754 }
755
756 void CGUIWindowFileManager::OnNewFolder(int iList)
757 {
758   CStdString strNewFolder = "";
759   if (CGUIKeyboardFactory::ShowAndGetInput(strNewFolder, g_localizeStrings.Get(16014), false))
760   {
761     CStdString strNewPath = m_Directory[iList]->GetPath();
762     URIUtils::AddSlashAtEnd(strNewPath);
763     strNewPath += strNewFolder;
764     CDirectory::Create(strNewPath);
765     Refresh(iList);
766
767     //  select the new folder
768     for (int i=0; i<m_vecItems[iList]->Size(); ++i)
769     {
770       CFileItemPtr pItem=m_vecItems[iList]->Get(i);
771       CStdString strPath=pItem->GetPath();
772       URIUtils::RemoveSlashAtEnd(strPath);
773       if (strPath==strNewPath)
774       {
775         CONTROL_SELECT_ITEM(iList + CONTROL_LEFT_LIST, i);
776         break;
777       }
778     }
779   }
780 }
781
782 void CGUIWindowFileManager::Refresh(int iList)
783 {
784   int nSel = GetSelectedItem(iList);
785   // update the list views
786   Update(iList, m_Directory[iList]->GetPath());
787
788   while (nSel > m_vecItems[iList]->Size())
789     nSel--;
790
791   CONTROL_SELECT_ITEM(iList + CONTROL_LEFT_LIST, nSel);
792 }
793
794
795 void CGUIWindowFileManager::Refresh()
796 {
797   int iList = GetFocusedList();
798   int nSel = GetSelectedItem(iList);
799   // update the list views
800   Update(0, m_Directory[0]->GetPath());
801   Update(1, m_Directory[1]->GetPath());
802
803   while (nSel > (int)m_vecItems[iList]->Size())
804     nSel--;
805
806   CONTROL_SELECT_ITEM(iList + CONTROL_LEFT_LIST, nSel);
807 }
808
809 int CGUIWindowFileManager::GetSelectedItem(int iControl)
810 {
811   if (iControl < 0 || iControl > 1) return -1;
812   CGUIListContainer *pControl = (CGUIListContainer *)GetControl(iControl + CONTROL_LEFT_LIST);
813   if (!pControl || !m_vecItems[iControl]->Size()) return -1;
814   return pControl->GetSelectedItem();
815 }
816
817 void CGUIWindowFileManager::GoParentFolder(int iList)
818 {
819   CURL url(m_Directory[iList]->GetPath());
820   if ((url.GetProtocol() == "rar") || (url.GetProtocol() == "zip"))
821   {
822     // check for step-below, if, unmount rar
823     if (url.GetFileName().IsEmpty())
824       if (url.GetProtocol() == "zip")
825         g_ZipManager.release(m_Directory[iList]->GetPath()); // release resources
826   }
827
828   CStdString strPath(m_strParentPath[iList]), strOldPath(m_Directory[iList]->GetPath());
829   Update(iList, strPath);
830 }
831
832 /// \brief Build a directory history string
833 /// \param pItem Item to build the history string from
834 /// \param strHistoryString History string build as return value
835 void CGUIWindowFileManager::GetDirectoryHistoryString(const CFileItem* pItem, CStdString& strHistoryString)
836 {
837   if (pItem->m_bIsShareOrDrive)
838   {
839     // We are in the virtual directory
840
841     // History string of the DVD drive
842     // must be handel separately
843     if (pItem->m_iDriveType == CMediaSource::SOURCE_TYPE_DVD)
844     {
845       // Remove disc label from item label
846       // and use as history string, m_strPath
847       // can change for new discs
848       CStdString strLabel = pItem->GetLabel();
849       int nPosOpen = strLabel.Find('(');
850       int nPosClose = strLabel.ReverseFind(')');
851       if (nPosOpen > -1 && nPosClose > -1 && nPosClose > nPosOpen)
852       {
853         strLabel.Delete(nPosOpen + 1, (nPosClose) - (nPosOpen + 1));
854         strHistoryString = strLabel;
855       }
856       else
857         strHistoryString = strLabel;
858     }
859     else
860     {
861       // Other items in virtual directory
862       strHistoryString = pItem->GetLabel() + pItem->GetPath();
863       URIUtils::RemoveSlashAtEnd(strHistoryString);
864     }
865   }
866   else
867   {
868     // Normal directory items
869     strHistoryString = pItem->GetPath();
870     URIUtils::RemoveSlashAtEnd(strHistoryString);
871   }
872 }
873
874 bool CGUIWindowFileManager::GetDirectory(int iList, const CStdString &strDirectory, CFileItemList &items)
875 {
876   return m_rootDir.GetDirectory(strDirectory,items,false);
877 }
878
879 bool CGUIWindowFileManager::CanRename(int iList)
880 {
881   // TODO: Renaming of shares (requires writing to xboxmediacenter.xml)
882   // this might be able to be done via the webserver code stuff...
883   if (m_Directory[iList]->IsVirtualDirectoryRoot()) return false;
884   if (m_Directory[iList]->IsReadOnly()) return false;
885
886   return true;
887 }
888
889 bool CGUIWindowFileManager::CanCopy(int iList)
890 {
891   // can't copy if the destination is not writeable, or if the source is a share!
892   // TODO: Perhaps if the source is removeable media (DVD/CD etc.) we could
893   // put ripping/backup in here.
894   if (!CUtil::SupportsReadFileOperations(m_Directory[iList]->GetPath())) return false;
895   if (m_Directory[iList]->IsVirtualDirectoryRoot()) return false;
896   if (m_Directory[1 - iList]->IsVirtualDirectoryRoot()) return false;
897   if (m_Directory[iList]->IsVirtualDirectoryRoot()) return false;
898   if (m_Directory[1 -iList]->IsReadOnly()) return false;
899   return true;
900 }
901
902 bool CGUIWindowFileManager::CanMove(int iList)
903 {
904   // can't move if the destination is not writeable, or if the source is a share or not writeable!
905   if (m_Directory[0]->IsVirtualDirectoryRoot() || m_Directory[0]->IsReadOnly()) return false;
906   if (m_Directory[1]->IsVirtualDirectoryRoot() || m_Directory[1]->IsReadOnly()) return false;
907   return true;
908 }
909
910 bool CGUIWindowFileManager::CanDelete(int iList)
911 {
912   if (m_Directory[iList]->IsVirtualDirectoryRoot()) return false;
913   if (m_Directory[iList]->IsReadOnly()) return false;
914   return true;
915 }
916
917 bool CGUIWindowFileManager::CanNewFolder(int iList)
918 {
919   if (m_Directory[iList]->IsVirtualDirectoryRoot()) return false;
920   if (m_Directory[iList]->IsReadOnly()) return false;
921   return true;
922 }
923
924 int CGUIWindowFileManager::NumSelected(int iList)
925 {
926   int iSelectedItems = 0;
927   for (int iItem = 0; iItem < m_vecItems[iList]->Size(); ++iItem)
928   {
929     if (m_vecItems[iList]->Get(iItem)->IsSelected()) iSelectedItems++;
930   }
931   return iSelectedItems;
932 }
933
934 int CGUIWindowFileManager::GetFocusedList() const
935 {
936   return GetFocusedControlID() - CONTROL_LEFT_LIST;
937 }
938
939 void CGUIWindowFileManager::OnPopupMenu(int list, int item, bool bContextDriven /* = true */)
940 {
941   if (list < 0 || list >= 2) return ;
942   bool bDeselect = SelectItem(list, item);
943   // calculate the position for our menu
944   float posX = 200;
945   float posY = 100;
946   const CGUIControl *pList = GetControl(CONTROL_LEFT_LIST + list);
947   if (pList)
948   {
949     posX = pList->GetXPosition() + pList->GetWidth() / 2;
950     posY = pList->GetYPosition() + pList->GetHeight() / 2;
951   }
952
953   CFileItemPtr pItem = m_vecItems[list]->Get(item);
954   if (!pItem.get())
955     return;
956
957   if (m_Directory[list]->IsVirtualDirectoryRoot())
958   {
959     if (item < 0)
960     { // TODO: We should add the option here for shares to be added if there aren't any
961       return ;
962     }
963
964     // and do the popup menu
965     if (CGUIDialogContextMenu::SourcesMenu("files", pItem, posX, posY))
966     {
967       m_rootDir.SetSources(*CMediaSourceSettings::Get().GetSources("files"));
968       if (m_Directory[1 - list]->IsVirtualDirectoryRoot())
969         Refresh();
970       else
971         Refresh(list);
972       return ;
973     }
974     pItem->Select(false);
975     return ;
976   }
977   // popup the context menu
978
979   bool showEntry = false;
980   if (item >= m_vecItems[list]->Size()) item = -1;
981   if (item >= 0)
982     showEntry=(!pItem->IsParentFolder() || (pItem->IsParentFolder() && m_vecItems[list]->GetSelectedCount()>0));
983
984   // determine available players
985   VECPLAYERCORES vecCores;
986   CPlayerCoreFactory::Get().GetPlayers(*pItem, vecCores);
987
988   // add the needed buttons
989   CContextButtons choices;
990   if (item >= 0)
991   {
992     choices.Add(1, 188); // SelectAll
993     if (!pItem->IsParentFolder())
994       choices.Add(2,  XFILE::CFavouritesDirectory::IsFavourite(pItem.get(), GetID()) ? 14077 : 14076); // Add/Remove Favourite
995     if (vecCores.size() > 1)
996       choices.Add(3, 15213); // Play Using...
997     if (CanRename(list) && !pItem->IsParentFolder())
998       choices.Add(4, 118); // Rename
999     if (CanDelete(list) && showEntry)
1000       choices.Add(5, 117); // Delete
1001     if (CanCopy(list) && showEntry)
1002       choices.Add(6, 115); // Copy
1003     if (CanMove(list) && showEntry)
1004       choices.Add(7, 116); // Move
1005   }
1006   if (CanNewFolder(list))
1007     choices.Add(8, 20309); // New Folder
1008   if (item >= 0 && pItem->m_bIsFolder && !pItem->IsParentFolder())
1009     choices.Add(9, 13393); // Calculate Size
1010   choices.Add(10, 5);     // Settings
1011   choices.Add(11, 20128); // Go To Root
1012   choices.Add(12, 523);     // switch media
1013   if (CJobManager::GetInstance().IsProcessing("filemanager"))
1014     choices.Add(13, 167);
1015
1016   int btnid = CGUIDialogContextMenu::ShowAndGetChoice(choices);
1017   if (btnid == 1)
1018   {
1019     OnSelectAll(list);
1020     bDeselect=false;
1021   }
1022   if (btnid == 2)
1023   {
1024     XFILE::CFavouritesDirectory::AddOrRemove(pItem.get(), GetID());
1025     return;
1026   }
1027   if (btnid == 3)
1028   {
1029     VECPLAYERCORES vecCores;
1030     CPlayerCoreFactory::Get().GetPlayers(*pItem, vecCores);
1031     g_application.m_eForcedNextPlayer = CPlayerCoreFactory::Get().SelectPlayerDialog(vecCores);
1032     if (g_application.m_eForcedNextPlayer != EPC_NONE)
1033       OnStart(pItem.get());
1034   }
1035   if (btnid == 4)
1036     OnRename(list);
1037   if (btnid == 5)
1038     OnDelete(list);
1039   if (btnid == 6)
1040     OnCopy(list);
1041   if (btnid == 7)
1042     OnMove(list);
1043   if (btnid == 8)
1044     OnNewFolder(list);
1045   if (btnid == 9)
1046   {
1047     // setup the progress dialog, and show it
1048     CGUIDialogProgress *progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
1049     if (progress)
1050     {
1051       progress->SetHeading(13394);
1052       for (int i=0; i < 3; i++)
1053         progress->SetLine(i, "");
1054       progress->StartModal();
1055     }
1056
1057     //  Calculate folder size for each selected item
1058     for (int i=0; i<m_vecItems[list]->Size(); ++i)
1059     {
1060       CFileItemPtr pItem2=m_vecItems[list]->Get(i);
1061       if (pItem2->m_bIsFolder && pItem2->IsSelected())
1062       {
1063         int64_t folderSize = CalculateFolderSize(pItem2->GetPath(), progress);
1064         if (folderSize >= 0)
1065         {
1066           pItem2->m_dwSize = folderSize;
1067           if (folderSize == 0)
1068             pItem2->SetLabel2(StringUtils::SizeToString(folderSize));
1069           else
1070             pItem2->SetFileSizeLabel();
1071         }
1072       }
1073     }
1074     if (progress)
1075       progress->Close();
1076   }
1077   if (btnid == 10)
1078   {
1079     g_windowManager.ActivateWindow(WINDOW_SETTINGS_MENU);
1080     return;
1081   }
1082   if (btnid == 11)
1083   {
1084     Update(list,"");
1085     return;
1086   }
1087   if (btnid == 12)
1088   {
1089     CGUIDialogContextMenu::SwitchMedia("files", m_vecItems[list]->GetPath());
1090     return;
1091   }
1092   if (btnid == 13)
1093     CancelJobs();
1094
1095   if (bDeselect && item >= 0 && item < m_vecItems[list]->Size())
1096   { // deselect item as we didn't do anything
1097     pItem->Select(false);
1098   }
1099 }
1100
1101 // Highlights the item in the list under the cursor
1102 // returns true if we should deselect the item, false otherwise
1103 bool CGUIWindowFileManager::SelectItem(int list, int &item)
1104 {
1105   // get the currently selected item in the list
1106   item = GetSelectedItem(list);
1107
1108   // select the item if we need to
1109   if (item > -1 && !NumSelected(list) && !m_vecItems[list]->Get(item)->IsParentFolder())
1110   {
1111     m_vecItems[list]->Get(item)->Select(true);
1112     return true;
1113   }
1114   return false;
1115 }
1116
1117 // recursively calculates the selected folder size
1118 int64_t CGUIWindowFileManager::CalculateFolderSize(const CStdString &strDirectory, CGUIDialogProgress *pProgress)
1119 {
1120   if (pProgress)
1121   { // update our progress control
1122     pProgress->Progress();
1123     pProgress->SetLine(1, strDirectory);
1124     if (pProgress->IsCanceled())
1125       return -1;
1126   }
1127   // start by calculating the size of the files in this folder...
1128   int64_t totalSize = 0;
1129   CFileItemList items;
1130   CVirtualDirectory rootDir;
1131   rootDir.SetSources(*CMediaSourceSettings::Get().GetSources("files"));
1132   rootDir.GetDirectory(strDirectory, items, false);
1133   for (int i=0; i < items.Size(); i++)
1134   {
1135     if (items[i]->m_bIsFolder && !items[i]->IsParentFolder()) // folder
1136     {
1137       int64_t folderSize = CalculateFolderSize(items[i]->GetPath(), pProgress);
1138       if (folderSize < 0) return -1;
1139       totalSize += folderSize;
1140     }
1141     else // file
1142       totalSize += items[i]->m_dwSize;
1143   }
1144   return totalSize;
1145 }
1146
1147 void CGUIWindowFileManager::OnJobComplete(unsigned int jobID, bool success, CJob *job)
1148 {
1149   if(!success)
1150   {
1151     CFileOperationJob* fileJob = (CFileOperationJob*)job;
1152     CGUIDialogOK::ShowAndGetInput(fileJob->GetHeading(),
1153                                   fileJob->GetLine(), 16200, 0);
1154   }
1155
1156   if (IsActive())
1157   {
1158     CGUIMessage msg(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_UPDATE);
1159     CApplicationMessenger::Get().SendGUIMessage(msg, GetID(), false);
1160   }
1161
1162   CJobQueue::OnJobComplete(jobID, success, job);
1163 }
1164
1165 void CGUIWindowFileManager::ShowShareErrorMessage(CFileItem* pItem)
1166 {
1167   int idMessageText = 0;
1168   CURL url(pItem->GetPath());
1169   const CStdString& strHostName = url.GetHostName();
1170
1171   if (url.GetProtocol() == "smb" && strHostName.IsEmpty()) //  smb workgroup
1172     idMessageText = 15303; // Workgroup not found
1173   else if (pItem->m_iDriveType == CMediaSource::SOURCE_TYPE_REMOTE || URIUtils::IsRemote(pItem->GetPath()))
1174     idMessageText = 15301; // Could not connect to network server
1175   else
1176     idMessageText = 15300; // Path not found or invalid
1177
1178   CGUIDialogOK::ShowAndGetInput(220, idMessageText, 0, 0);
1179 }
1180
1181 void CGUIWindowFileManager::OnInitWindow()
1182 {
1183   bool bResult0 = Update(0, m_Directory[0]->GetPath());
1184   bool bResult1 = Update(1, m_Directory[1]->GetPath());
1185
1186   CGUIWindow::OnInitWindow();
1187
1188   if (!bCheckShareConnectivity)
1189   {
1190     bCheckShareConnectivity = true; //reset
1191     CFileItem pItem(strCheckSharePath, true);
1192     ShowShareErrorMessage(&pItem); //show the error message after window is loaded!
1193     Update(0,""); // reset view to root
1194   }
1195   else if (!bResult0)
1196   {
1197     ShowShareErrorMessage(m_Directory[0]); //show the error message after window is loaded!
1198   }
1199
1200   if (!bResult1)
1201   {
1202     ShowShareErrorMessage(m_Directory[1]); //show the error message after window is loaded!
1203   }
1204 }
1205
1206 void CGUIWindowFileManager::SetInitialPath(const CStdString &path)
1207 {
1208   // check for a passed destination path
1209   CStdString strDestination = path;
1210   m_rootDir.SetSources(*CMediaSourceSettings::Get().GetSources("files"));
1211   if (!strDestination.IsEmpty())
1212   {
1213     CLog::Log(LOGINFO, "Attempting to quickpath to: %s", strDestination.c_str());
1214   }
1215   // otherwise, is this the first time accessing this window?
1216   else if (m_Directory[0]->GetPath() == "?")
1217   {
1218     m_Directory[0]->SetPath(strDestination = CMediaSourceSettings::Get().GetDefaultSource("files"));
1219     CLog::Log(LOGINFO, "Attempting to default to: %s", strDestination.c_str());
1220   }
1221   // try to open the destination path
1222   if (!strDestination.IsEmpty())
1223   {
1224     // open root
1225     if (strDestination.Equals("$ROOT"))
1226     {
1227       m_Directory[0]->SetPath("");
1228       CLog::Log(LOGINFO, "  Success! Opening root listing.");
1229     }
1230     else
1231     {
1232       // default parameters if the jump fails
1233       m_Directory[0]->SetPath("");
1234
1235       bool bIsSourceName = false;
1236       VECSOURCES shares;
1237       m_rootDir.GetSources(shares);
1238       int iIndex = CUtil::GetMatchingSource(strDestination, shares, bIsSourceName);
1239       if (iIndex > -1)
1240       {
1241         // set current directory to matching share
1242         CStdString path;
1243         if (bIsSourceName && iIndex < (int)shares.size())
1244           path = shares[iIndex].strPath;
1245         else
1246           path = strDestination;
1247         URIUtils::RemoveSlashAtEnd(path);
1248         m_Directory[0]->SetPath(path);
1249         CLog::Log(LOGINFO, "  Success! Opened destination path: %s", strDestination.c_str());
1250
1251         // outside call: check the share for connectivity
1252         bCheckShareConnectivity = Update(0, m_Directory[0]->GetPath());
1253         if(!bCheckShareConnectivity)
1254           strCheckSharePath = m_Directory[0]->GetPath();
1255       }
1256       else
1257       {
1258         CLog::Log(LOGERROR, "  Failed! Destination parameter (%s) does not match a valid share!", strDestination.c_str());
1259       }
1260     }
1261   }
1262
1263   if (m_Directory[1]->GetPath() == "?") m_Directory[1]->SetPath("");
1264 }
1265
1266 const CFileItem& CGUIWindowFileManager::CurrentDirectory(int indx) const
1267 {
1268   return *m_Directory[indx];
1269 }