2 * Copyright (C) 2005-2013 Team XBMC
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)
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.
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/>.
22 #include "GUIWindowFileManager.h"
23 #include "Application.h"
24 #include "ApplicationMessenger.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"
57 #include "utils/JobManager.h"
58 #include "utils/FileOperationJob.h"
59 #include "utils/FileUtils.h"
60 #include "utils/URIUtils.h"
65 using namespace XFILE;
66 using namespace PLAYLIST;
70 #define ACTION_DELETE 3
71 #define ACTION_CREATEFOLDER 4
72 #define ACTION_DELETEFOLDER 5
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
84 #define CONTROL_NUMFILES_LEFT 12
85 #define CONTROL_NUMFILES_RIGHT 13
87 #define CONTROL_LEFT_LIST 20
88 #define CONTROL_RIGHT_LIST 21
90 #define CONTROL_CURRENTDIRLABEL_LEFT 101
91 #define CONTROL_CURRENTDIRLABEL_RIGHT 102
93 CGUIWindowFileManager::CGUIWindowFileManager(void)
94 : CGUIWindow(WINDOW_FILES, "FileManager.xml"),
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;
109 CGUIWindowFileManager::~CGUIWindowFileManager(void)
111 delete m_Directory[0];
112 delete m_Directory[1];
113 delete m_vecItems[0];
114 delete m_vecItems[1];
117 bool CGUIWindowFileManager::OnAction(const CAction &action)
119 int list = GetFocusedList();
120 if (list >= 0 && list <= 1)
124 // the non-contextual menu can be called at any time
125 if (action.GetID() == ACTION_CONTEXT_MENU && m_vecItems[list]->Size() == 0)
127 OnPopupMenu(list,-1, false);
130 if (action.GetID() == ACTION_DELETE_ITEM)
134 bool bDeselect = SelectItem(list, item);
136 if (bDeselect) m_vecItems[list]->Get(item)->Select(false);
140 if (action.GetID() == ACTION_COPY_ITEM)
144 bool bDeselect = SelectItem(list, item);
146 if (bDeselect) m_vecItems[list]->Get(item)->Select(false);
150 if (action.GetID() == ACTION_MOVE_ITEM)
154 bool bDeselect = SelectItem(list, item);
156 if (bDeselect) m_vecItems[list]->Get(item)->Select(false);
160 if (action.GetID() == ACTION_RENAME_ITEM)
164 bool bDeselect = SelectItem(list, item);
166 if (bDeselect) m_vecItems[list]->Get(item)->Select(false);
170 if (action.GetID() == ACTION_PARENT_DIR)
172 GoParentFolder(list);
175 if (action.GetID() == ACTION_PLAYER_PLAY)
178 if (m_vecItems[list]->Get(GetSelectedItem(list))->IsDVD())
179 return MEDIA_DETECT::CAutorun::PlayDiscAskResume(m_vecItems[list]->Get(GetSelectedItem(list))->GetPath());
183 return CGUIWindow::OnAction(action);
186 bool CGUIWindowFileManager::OnBack(int actionID)
188 int list = GetFocusedList();
189 if (list >= 0 && list <= 1 && actionID == ACTION_NAV_BACK && !m_vecItems[list]->IsVirtualDirectoryRoot())
191 GoParentFolder(list);
194 return CGUIWindow::OnBack(actionID);
197 bool CGUIWindowFileManager::OnMessage(CGUIMessage& message)
199 switch ( message.GetMessage() )
201 case GUI_MSG_NOTIFY_ALL:
202 { // Message is received even if window is inactive
203 if (message.GetParam1() == GUI_MSG_WINDOW_RESET)
205 m_Directory[0]->SetPath("?");
206 m_Directory[1]->SetPath("?");
207 m_Directory[0]->m_bIsFolder = true;
208 m_Directory[1]->m_bIsFolder = true;
212 // handle removable media
213 if (message.GetParam1() == GUI_MSG_REMOVED_MEDIA)
215 for (int i = 0; i < 2; i++)
217 if (m_Directory[i]->IsVirtualDirectoryRoot() && IsActive())
219 int iItem = GetSelectedItem(i);
220 Update(i, m_Directory[i]->GetPath());
221 CONTROL_SELECT_ITEM(CONTROL_LEFT_LIST + i, iItem);
223 else if (m_Directory[i]->IsRemovable() && !m_rootDir.IsInSource(m_Directory[i]->GetPath()))
228 m_Directory[i]->SetPath("");
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++)
237 if (m_Directory[i]->IsVirtualDirectoryRoot() && IsActive())
239 int iItem = GetSelectedItem(i);
240 Update(i, m_Directory[i]->GetPath());
241 CONTROL_SELECT_ITEM(CONTROL_LEFT_LIST + i, iItem);
246 else if (message.GetParam1()==GUI_MSG_UPDATE && IsActive())
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);
265 case GUI_MSG_WINDOW_DEINIT:
267 CGUIWindow::OnMessage(message);
274 case GUI_MSG_WINDOW_INIT:
276 SetInitialPath(message.GetStringParam());
277 message.SetStringParam("");
279 return CGUIWindow::OnMessage(message);
282 case GUI_MSG_CLICKED:
284 int iControl = message.GetSenderId();
286 if (iControl == CONTROL_LEFT_LIST || iControl == CONTROL_RIGHT_LIST) // list/thumb control
289 int list = iControl - CONTROL_LEFT_LIST;
290 int iItem = GetSelectedItem(list);
291 int iAction = message.GetParam1();
293 // iItem is checked for validity inside these routines
294 if (iAction == ACTION_HIGHLIGHT_ITEM || iAction == ACTION_MOUSE_LEFT_CLICK)
297 if (!g_Mouse.IsActive())
300 CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), iControl, iItem + 1);
301 g_windowManager.SendMessage(msg);
304 else if (iAction == ACTION_SELECT_ITEM || iAction == ACTION_MOUSE_DOUBLE_CLICK)
306 OnClick(list, iItem);
308 else if (iAction == ACTION_CONTEXT_MENU || iAction == ACTION_MOUSE_RIGHT_CLICK)
310 OnPopupMenu(list, iItem);
316 return CGUIWindow::OnMessage(message);
319 void CGUIWindowFileManager::OnSort(int iList)
321 // always sort the list by label in ascending order
322 for (int i = 0; i < m_vecItems[iList]->Size(); i++)
324 CFileItemPtr pItem = m_vecItems[iList]->Get(i);
325 if (pItem->m_bIsFolder && (!pItem->m_dwSize || pItem->GetPath().Equals("add")))
326 pItem->SetLabel2("");
328 pItem->SetFileSizeLabel();
330 // Set free space on disc
331 if (pItem->m_bIsShareOrDrive)
335 ULARGE_INTEGER ulBytesFree;
336 if (GetDiskFreeSpaceEx(pItem->GetPath().c_str(), &ulBytesFree, NULL, NULL))
338 pItem->m_dwSize = ulBytesFree.QuadPart;
339 pItem->SetFileSizeLabel();
342 else if (pItem->IsDVD() && g_mediaManager.IsDiscInDrive())
344 ULARGE_INTEGER ulBytesTotal;
345 if (GetDiskFreeSpaceEx(pItem->GetPath().c_str(), NULL, &ulBytesTotal, NULL))
347 pItem->m_dwSize = ulBytesTotal.QuadPart;
348 pItem->SetFileSizeLabel();
351 } // if (pItem->m_bIsShareOrDrive)
355 m_vecItems[iList]->Sort(SortByLabel, SortOrderAscending);
358 void CGUIWindowFileManager::ClearFileItems(int iList)
360 CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), iList + CONTROL_LEFT_LIST);
361 g_windowManager.SendMessage(msg);
363 m_vecItems[iList]->Clear(); // will clean up everything
366 void CGUIWindowFileManager::UpdateButtons()
368 // update our current directory labels
369 CStdString strDir = CURL(m_Directory[0]->GetPath()).GetWithoutUserDetails();
370 if (strDir.IsEmpty())
372 SET_CONTROL_LABEL(CONTROL_CURRENTDIRLABEL_LEFT,g_localizeStrings.Get(20108));
376 SET_CONTROL_LABEL(CONTROL_CURRENTDIRLABEL_LEFT, strDir);
378 strDir = CURL(m_Directory[1]->GetPath()).GetWithoutUserDetails();
379 if (strDir.IsEmpty())
381 SET_CONTROL_LABEL(CONTROL_CURRENTDIRLABEL_RIGHT,g_localizeStrings.Get(20108));
385 SET_CONTROL_LABEL(CONTROL_CURRENTDIRLABEL_RIGHT, strDir);
388 // update the number of items in each list
392 void CGUIWindowFileManager::UpdateItemCounts()
394 for (int i = 0; i < 2; i++)
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++)
402 CFileItemPtr item = m_vecItems[i]->Get(j);
403 if (item->IsParentFolder()) continue;
404 if (item->IsSelected())
407 selectedSize += item->m_dwSize;
410 totalSize += item->m_dwSize;
413 if (selectedCount > 0)
414 items.Format("%i/%i %s (%s)", selectedCount, totalCount, g_localizeStrings.Get(127).c_str(), StringUtils::SizeToString(selectedSize).c_str());
416 items.Format("%i %s", totalCount, g_localizeStrings.Get(127).c_str());
417 SET_CONTROL_LABEL(CONTROL_NUMFILES_LEFT + i, items);
421 bool CGUIWindowFileManager::Update(int iList, const CStdString &strDirectory)
424 int iItem = GetSelectedItem(iList);
425 CStdString strSelectedItem = "";
427 if (iItem >= 0 && iItem < (int)m_vecItems[iList]->Size())
429 CFileItemPtr pItem = m_vecItems[iList]->Get(iItem);
430 if (!pItem->IsParentFolder())
432 GetDirectoryHistoryString(pItem.get(), strSelectedItem);
433 m_history[iList].SetSelectedItem(strSelectedItem, m_Directory[iList]->GetPath());
437 CStdString strOldDirectory=m_Directory[iList]->GetPath();
438 m_Directory[iList]->SetPath(strDirectory);
441 if (!GetDirectory(iList, m_Directory[iList]->GetPath(), items))
443 if (strDirectory != strOldDirectory && GetDirectory(iList, strOldDirectory, items))
444 m_Directory[iList]->SetPath(strOldDirectory); // Fallback to old (previous) path)
446 Update(iList, ""); // Fallback to root
451 m_history[iList].SetSelectedItem(strSelectedItem, strOldDirectory);
453 ClearFileItems(iList);
455 m_vecItems[iList]->Append(items);
456 m_vecItems[iList]->SetPath(items.GetPath());
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);
472 else if (items.IsEmpty() || CSettings::Get().GetBool("filelists.showparentdiritems"))
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);
481 m_strParentPath[iList] = (m_rootDir.IsSource(strDirectory) ? "" : strParentPath);
483 if (strDirectory.IsEmpty())
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);
492 // if we have a .tbn file, use itself as the thumb
493 for (int i = 0; i < (int)m_vecItems[iList]->Size(); i++)
495 CFileItemPtr pItem = m_vecItems[iList]->Get(i);
497 URIUtils::HasExtension(pItem->GetPath(), ".tbn"))
499 pItem->SetArt("thumb", pItem->GetPath());
502 m_vecItems[iList]->FillInDefaultIcons();
508 strSelectedItem = m_history[iList].GetSelectedItem(m_Directory[iList]->GetPath());
509 for (int i = 0; i < m_vecItems[iList]->Size(); ++i)
511 CFileItemPtr pItem = m_vecItems[iList]->Get(i);
512 CStdString strHistory;
513 GetDirectoryHistoryString(pItem.get(), strHistory);
514 if (strHistory == strSelectedItem)
520 UpdateControl(iList, item);
525 void CGUIWindowFileManager::OnClick(int iList, int iItem)
527 if ( iList < 0 || iList >= 2) return ;
528 if ( iItem < 0 || iItem >= m_vecItems[iList]->Size() ) return ;
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
533 if (CGUIDialogMediaSource::ShowAndAddMediaSource("files"))
535 m_rootDir.SetSources(*CMediaSourceSettings::Get().GetSources("files"));
536 Update(0,m_Directory[0]->GetPath());
537 Update(1,m_Directory[1]->GetPath());
542 if (!pItem->m_bIsFolder && pItem->IsFileFolder(EFILEFOLDER_MASK_ALL))
544 XFILE::IFileDirectory *pFileDirectory = NULL;
545 pFileDirectory = XFILE::CFileDirectoryFactory::Create(pItem->GetPath(), pItem.get(), "");
547 pItem->m_bIsFolder = true;
548 else if(pItem->m_bIsFolder)
549 pItem->m_bIsFolder = false;
550 delete pFileDirectory;
553 if (pItem->m_bIsFolder)
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 )
560 if ( !g_passwordManager.IsItemUnlocked( pItem.get(), "files" ) )
566 if ( !HaveDiscOrConnection( strPath, iDriveType ) )
569 if (!Update(iList, strPath))
570 ShowShareErrorMessage(pItem.get());
572 else if (pItem->IsZIP() || pItem->IsCBZ()) // mount zip archive
574 CStdString strArcivedPath;
575 URIUtils::CreateArchivePath(strArcivedPath, "zip", pItem->GetPath(), "");
576 Update(iList, strArcivedPath);
578 else if (pItem->IsRAR() || pItem->IsCBR())
580 CStdString strArcivedPath;
581 URIUtils::CreateArchivePath(strArcivedPath, "rar", pItem->GetPath(), "");
582 Update(iList, strArcivedPath);
586 OnStart(pItem.get());
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)
596 // start playlists from file manager
597 if (pItem->IsPlayList())
599 CStdString strPlayList = pItem->GetPath();
600 auto_ptr<CPlayList> pPlayList (CPlayListFactory::Create(strPlayList));
601 if (NULL != pPlayList.get())
603 if (!pPlayList->Load(strPlayList))
605 CGUIDialogOK::ShowAndGetInput(6, 0, 477, 0);
609 g_application.ProcessAndStartPlaylist(strPlayList, *pPlayList, PLAYLIST_MUSIC);
612 if (pItem->IsAudio() || pItem->IsVideo())
614 g_application.PlayFile(*pItem);
618 if (pItem->IsPythonScript())
620 CScriptInvocationManager::Get().Execute(pItem->GetPath());
624 if (pItem->IsPicture())
626 CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
629 if (g_application.m_pPlayer->IsPlayingVideo())
630 g_application.StopPlaying();
633 pSlideShow->Add(pItem);
634 pSlideShow->Select(pItem->GetPath());
636 g_windowManager.ActivateWindow(WINDOW_SLIDESHOW);
640 bool CGUIWindowFileManager::HaveDiscOrConnection( CStdString& strPath, int iDriveType )
642 if ( iDriveType == CMediaSource::SOURCE_TYPE_DVD )
644 if ( !g_mediaManager.IsDiscInDrive(strPath) )
646 CGUIDialogOK::ShowAndGetInput(218, 219, 0, 0);
647 int iList = GetFocusedList();
648 int iItem = GetSelectedItem(iList);
650 CONTROL_SELECT_ITEM(iList + CONTROL_LEFT_LIST, iItem);
654 else if ( iDriveType == CMediaSource::SOURCE_TYPE_REMOTE )
656 // TODO: Handle not connected to a remote share
657 if ( !g_application.getNetwork().IsConnected() )
659 CGUIDialogOK::ShowAndGetInput(220, 221, 0, 0);
668 void CGUIWindowFileManager::UpdateControl(int iList, int item)
670 CGUIMessage msg(GUI_MSG_LABEL_BIND, GetID(), iList + CONTROL_LEFT_LIST, item, 0, m_vecItems[iList]);
671 g_windowManager.SendMessage(msg);
674 void CGUIWindowFileManager::OnMark(int iList, int iItem)
676 CFileItemPtr pItem = m_vecItems[iList]->Get(iItem);
678 if (!pItem->m_bIsShareOrDrive)
680 if (!pItem->IsParentFolder())
683 pItem->Select(!pItem->IsSelected());
691 void CGUIWindowFileManager::OnCopy(int iList)
693 if (!CGUIDialogYesNo::ShowAndGetInput(120, 123, 0, 0))
696 AddJob(new CFileOperationJob(CFileOperationJob::ActionCopy,
698 m_Directory[1 - iList]->GetPath(),
699 true, 16201, 16202));
702 void CGUIWindowFileManager::OnMove(int iList)
704 if (!CGUIDialogYesNo::ShowAndGetInput(121, 124, 0, 0))
707 AddJob(new CFileOperationJob(CFileOperationJob::ActionMove,
709 m_Directory[1 - iList]->GetPath(),
710 true, 16203, 16204));
713 void CGUIWindowFileManager::OnDelete(int iList)
715 if (!CGUIDialogYesNo::ShowAndGetInput(122, 125, 0, 0))
718 AddJob(new CFileOperationJob(CFileOperationJob::ActionDelete,
720 m_Directory[iList]->GetPath(),
721 true, 16205, 16206));
724 void CGUIWindowFileManager::OnRename(int iList)
727 for (int i = 0; i < m_vecItems[iList]->Size();++i)
729 CFileItemPtr pItem = m_vecItems[iList]->Get(i);
730 if (pItem->IsSelected())
732 strFile = pItem->GetPath();
737 CFileUtils::RenameFile(strFile);
742 void CGUIWindowFileManager::OnSelectAll(int iList)
744 for (int i = 0; i < m_vecItems[iList]->Size();++i)
746 CFileItemPtr pItem = m_vecItems[iList]->Get(i);
747 if (!pItem->IsParentFolder())
754 void CGUIWindowFileManager::OnNewFolder(int iList)
756 CStdString strNewFolder = "";
757 if (CGUIKeyboardFactory::ShowAndGetInput(strNewFolder, g_localizeStrings.Get(16014), false))
759 CStdString strNewPath = m_Directory[iList]->GetPath();
760 URIUtils::AddSlashAtEnd(strNewPath);
761 strNewPath += strNewFolder;
762 CDirectory::Create(strNewPath);
765 // select the new folder
766 for (int i=0; i<m_vecItems[iList]->Size(); ++i)
768 CFileItemPtr pItem=m_vecItems[iList]->Get(i);
769 CStdString strPath=pItem->GetPath();
770 URIUtils::RemoveSlashAtEnd(strPath);
771 if (strPath==strNewPath)
773 CONTROL_SELECT_ITEM(iList + CONTROL_LEFT_LIST, i);
780 void CGUIWindowFileManager::Refresh(int iList)
782 int nSel = GetSelectedItem(iList);
783 // update the list views
784 Update(iList, m_Directory[iList]->GetPath());
786 while (nSel > m_vecItems[iList]->Size())
789 CONTROL_SELECT_ITEM(iList + CONTROL_LEFT_LIST, nSel);
793 void CGUIWindowFileManager::Refresh()
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());
801 while (nSel > (int)m_vecItems[iList]->Size())
804 CONTROL_SELECT_ITEM(iList + CONTROL_LEFT_LIST, nSel);
807 int CGUIWindowFileManager::GetSelectedItem(int iControl)
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();
815 void CGUIWindowFileManager::GoParentFolder(int iList)
817 CURL url(m_Directory[iList]->GetPath());
818 if ((url.GetProtocol() == "rar") || (url.GetProtocol() == "zip"))
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
826 CStdString strPath(m_strParentPath[iList]), strOldPath(m_Directory[iList]->GetPath());
827 Update(iList, strPath);
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)
835 if (pItem->m_bIsShareOrDrive)
837 // We are in the virtual directory
839 // History string of the DVD drive
840 // must be handel separately
841 if (pItem->m_iDriveType == CMediaSource::SOURCE_TYPE_DVD)
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)
851 strLabel.Delete(nPosOpen + 1, (nPosClose) - (nPosOpen + 1));
852 strHistoryString = strLabel;
855 strHistoryString = strLabel;
859 // Other items in virtual directory
860 strHistoryString = pItem->GetLabel() + pItem->GetPath();
861 URIUtils::RemoveSlashAtEnd(strHistoryString);
866 // Normal directory items
867 strHistoryString = pItem->GetPath();
868 URIUtils::RemoveSlashAtEnd(strHistoryString);
872 bool CGUIWindowFileManager::GetDirectory(int iList, const CStdString &strDirectory, CFileItemList &items)
874 return m_rootDir.GetDirectory(strDirectory,items,false);
877 bool CGUIWindowFileManager::CanRename(int iList)
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;
887 bool CGUIWindowFileManager::CanCopy(int iList)
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;
900 bool CGUIWindowFileManager::CanMove(int iList)
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;
908 bool CGUIWindowFileManager::CanDelete(int iList)
910 if (m_Directory[iList]->IsVirtualDirectoryRoot()) return false;
911 if (m_Directory[iList]->IsReadOnly()) return false;
915 bool CGUIWindowFileManager::CanNewFolder(int iList)
917 if (m_Directory[iList]->IsVirtualDirectoryRoot()) return false;
918 if (m_Directory[iList]->IsReadOnly()) return false;
922 int CGUIWindowFileManager::NumSelected(int iList)
924 int iSelectedItems = 0;
925 for (int iItem = 0; iItem < m_vecItems[iList]->Size(); ++iItem)
927 if (m_vecItems[iList]->Get(iItem)->IsSelected()) iSelectedItems++;
929 return iSelectedItems;
932 int CGUIWindowFileManager::GetFocusedList() const
934 return GetFocusedControlID() - CONTROL_LEFT_LIST;
937 void CGUIWindowFileManager::OnPopupMenu(int list, int item, bool bContextDriven /* = true */)
939 if (list < 0 || list >= 2) return ;
940 bool bDeselect = SelectItem(list, item);
941 // calculate the position for our menu
944 const CGUIControl *pList = GetControl(CONTROL_LEFT_LIST + list);
947 posX = pList->GetXPosition() + pList->GetWidth() / 2;
948 posY = pList->GetYPosition() + pList->GetHeight() / 2;
951 CFileItemPtr pItem = m_vecItems[list]->Get(item);
955 if (m_Directory[list]->IsVirtualDirectoryRoot())
958 { // TODO: We should add the option here for shares to be added if there aren't any
962 // and do the popup menu
963 if (CGUIDialogContextMenu::SourcesMenu("files", pItem, posX, posY))
965 m_rootDir.SetSources(*CMediaSourceSettings::Get().GetSources("files"));
966 if (m_Directory[1 - list]->IsVirtualDirectoryRoot())
972 pItem->Select(false);
975 // popup the context menu
977 bool showEntry = false;
978 if (item >= m_vecItems[list]->Size()) item = -1;
980 showEntry=(!pItem->IsParentFolder() || (pItem->IsParentFolder() && m_vecItems[list]->GetSelectedCount()>0));
982 // determine available players
983 VECPLAYERCORES vecCores;
984 CPlayerCoreFactory::Get().GetPlayers(*pItem, vecCores);
986 // add the needed buttons
987 CContextButtons choices;
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
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);
1016 int btnid = CGUIDialogContextMenu::ShowAndGetChoice(choices);
1024 XFILE::CFavouritesDirectory::AddOrRemove(pItem.get(), GetID());
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());
1047 // setup the progress dialog, and show it
1048 CGUIDialogProgress *progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
1051 progress->SetHeading(13394);
1052 for (int i=0; i < 3; i++)
1053 progress->SetLine(i, "");
1054 progress->StartModal();
1057 // Calculate folder size for each selected item
1058 for (int i=0; i<m_vecItems[list]->Size(); ++i)
1060 CFileItemPtr pItem2=m_vecItems[list]->Get(i);
1061 if (pItem2->m_bIsFolder && pItem2->IsSelected())
1063 int64_t folderSize = CalculateFolderSize(pItem2->GetPath(), progress);
1064 if (folderSize >= 0)
1066 pItem2->m_dwSize = folderSize;
1067 if (folderSize == 0)
1068 pItem2->SetLabel2(StringUtils::SizeToString(folderSize));
1070 pItem2->SetFileSizeLabel();
1084 CGUIDialogContextMenu::SwitchMedia("files", m_vecItems[list]->GetPath());
1090 if (bDeselect && item >= 0 && item < m_vecItems[list]->Size())
1091 { // deselect item as we didn't do anything
1092 pItem->Select(false);
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)
1100 // get the currently selected item in the list
1101 item = GetSelectedItem(list);
1103 // select the item if we need to
1104 if (item > -1 && !NumSelected(list) && !m_vecItems[list]->Get(item)->IsParentFolder())
1106 m_vecItems[list]->Get(item)->Select(true);
1112 // recursively calculates the selected folder size
1113 int64_t CGUIWindowFileManager::CalculateFolderSize(const CStdString &strDirectory, CGUIDialogProgress *pProgress)
1116 { // update our progress control
1117 pProgress->Progress();
1118 pProgress->SetLine(1, strDirectory);
1119 if (pProgress->IsCanceled())
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++)
1130 if (items[i]->m_bIsFolder && !items[i]->IsParentFolder()) // folder
1132 int64_t folderSize = CalculateFolderSize(items[i]->GetPath(), pProgress);
1133 if (folderSize < 0) return -1;
1134 totalSize += folderSize;
1137 totalSize += items[i]->m_dwSize;
1142 void CGUIWindowFileManager::OnJobComplete(unsigned int jobID, bool success, CJob *job)
1146 CFileOperationJob* fileJob = (CFileOperationJob*)job;
1147 CGUIDialogOK::ShowAndGetInput(fileJob->GetHeading(),
1148 fileJob->GetLine(), 16200, 0);
1153 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_UPDATE);
1154 CApplicationMessenger::Get().SendGUIMessage(msg, GetID(), false);
1157 CJobQueue::OnJobComplete(jobID, success, job);
1160 void CGUIWindowFileManager::ShowShareErrorMessage(CFileItem* pItem)
1162 int idMessageText = 0;
1163 CURL url(pItem->GetPath());
1164 const CStdString& strHostName = url.GetHostName();
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
1171 idMessageText = 15300; // Path not found or invalid
1173 CGUIDialogOK::ShowAndGetInput(220, idMessageText, 0, 0);
1176 void CGUIWindowFileManager::OnInitWindow()
1178 bool bResult0 = Update(0, m_Directory[0]->GetPath());
1179 bool bResult1 = Update(1, m_Directory[1]->GetPath());
1181 CGUIWindow::OnInitWindow();
1183 if (!bCheckShareConnectivity)
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
1192 ShowShareErrorMessage(m_Directory[0]); //show the error message after window is loaded!
1197 ShowShareErrorMessage(m_Directory[1]); //show the error message after window is loaded!
1201 void CGUIWindowFileManager::SetInitialPath(const CStdString &path)
1203 // check for a passed destination path
1204 CStdString strDestination = path;
1205 m_rootDir.SetSources(*CMediaSourceSettings::Get().GetSources("files"));
1206 if (!strDestination.IsEmpty())
1208 CLog::Log(LOGINFO, "Attempting to quickpath to: %s", strDestination.c_str());
1210 // otherwise, is this the first time accessing this window?
1211 else if (m_Directory[0]->GetPath() == "?")
1213 m_Directory[0]->SetPath(strDestination = CMediaSourceSettings::Get().GetDefaultSource("files"));
1214 CLog::Log(LOGINFO, "Attempting to default to: %s", strDestination.c_str());
1216 // try to open the destination path
1217 if (!strDestination.IsEmpty())
1220 if (strDestination.Equals("$ROOT"))
1222 m_Directory[0]->SetPath("");
1223 CLog::Log(LOGINFO, " Success! Opening root listing.");
1227 // default parameters if the jump fails
1228 m_Directory[0]->SetPath("");
1230 bool bIsSourceName = false;
1232 m_rootDir.GetSources(shares);
1233 int iIndex = CUtil::GetMatchingSource(strDestination, shares, bIsSourceName);
1236 // set current directory to matching share
1238 if (bIsSourceName && iIndex < (int)shares.size())
1239 path = shares[iIndex].strPath;
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());
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();
1253 CLog::Log(LOGERROR, " Failed! Destination parameter (%s) does not match a valid share!", strDestination.c_str());
1258 if (m_Directory[1]->GetPath() == "?") m_Directory[1]->SetPath("");
1261 const CFileItem& CGUIWindowFileManager::CurrentDirectory(int indx) const
1263 return *m_Directory[indx];