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