[videodb] remove unused seasons table from episode_view
[xbmc.git] / xbmc / windows / GUIWindowFileManager.cpp
blob5c288c0209a3822b675c180724f04e48b9f94ddb
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "GUIWindowFileManager.h"
11 #include "Autorun.h"
12 #include "GUIPassword.h"
13 #include "GUIUserMessages.h"
14 #include "PlayListPlayer.h"
15 #include "ServiceBroker.h"
16 #include "URL.h"
17 #include "Util.h"
18 #include "application/Application.h"
19 #include "application/ApplicationComponents.h"
20 #include "application/ApplicationPlayer.h"
21 #include "cores/playercorefactory/PlayerCoreFactory.h"
22 #include "dialogs/GUIDialogBusy.h"
23 #include "dialogs/GUIDialogContextMenu.h"
24 #include "dialogs/GUIDialogMediaSource.h"
25 #include "dialogs/GUIDialogProgress.h"
26 #include "dialogs/GUIDialogTextViewer.h"
27 #include "dialogs/GUIDialogYesNo.h"
28 #include "favourites/FavouritesService.h"
29 #include "filesystem/Directory.h"
30 #include "filesystem/FileDirectoryFactory.h"
31 #include "filesystem/ZipManager.h"
32 #include "guilib/GUIComponent.h"
33 #include "guilib/GUIKeyboardFactory.h"
34 #include "guilib/GUIWindowManager.h"
35 #include "guilib/LocalizeStrings.h"
36 #include "input/InputManager.h"
37 #include "input/actions/Action.h"
38 #include "input/actions/ActionIDs.h"
39 #include "interfaces/generic/ScriptInvocationManager.h"
40 #include "messaging/ApplicationMessenger.h"
41 #include "messaging/helpers/DialogOKHelper.h"
42 #include "music/MusicFileItemClassify.h"
43 #include "network/Network.h"
44 #include "pictures/SlideShowDelegator.h"
45 #include "platform/Filesystem.h"
46 #include "playlists/PlayList.h"
47 #include "playlists/PlayListFactory.h"
48 #include "playlists/PlayListFileItemClassify.h"
49 #include "settings/MediaSourceSettings.h"
50 #include "settings/Settings.h"
51 #include "settings/SettingsComponent.h"
52 #include "storage/MediaManager.h"
53 #include "threads/IRunnable.h"
54 #include "utils/FileOperationJob.h"
55 #include "utils/FileUtils.h"
56 #include "utils/JobManager.h"
57 #include "utils/StringUtils.h"
58 #include "utils/URIUtils.h"
59 #include "utils/Variant.h"
60 #include "utils/log.h"
61 #include "video/VideoFileItemClassify.h"
63 using namespace XFILE;
64 using namespace KODI;
65 using namespace KODI::MESSAGING;
67 #define CONTROL_BTNSELECTALL 1
68 #define CONTROL_BTNFAVOURITES 2
69 #define CONTROL_BTNPLAYWITH 3
70 #define CONTROL_BTNRENAME 4
71 #define CONTROL_BTNDELETE 5
72 #define CONTROL_BTNCOPY 6
73 #define CONTROL_BTNMOVE 7
74 #define CONTROL_BTNNEWFOLDER 8
75 #define CONTROL_BTNCALCSIZE 9
76 #define CONTROL_BTNSWITCHMEDIA 11
77 #define CONTROL_BTNCANCELJOB 12
78 #define CONTROL_BTNVIEW 13
81 #define CONTROL_NUMFILES_LEFT 12
82 #define CONTROL_NUMFILES_RIGHT 13
84 #define CONTROL_LEFT_LIST 20
85 #define CONTROL_RIGHT_LIST 21
87 #define CONTROL_CURRENTDIRLABEL_LEFT 101
88 #define CONTROL_CURRENTDIRLABEL_RIGHT 102
90 namespace
92 class CGetDirectoryItems : public IRunnable
94 public:
95 CGetDirectoryItems(XFILE::CVirtualDirectory& dir, CURL& url, CFileItemList& items)
96 : m_dir(dir), m_url(url), m_items(items)
99 void Run() override
101 m_result = m_dir.GetDirectory(m_url, m_items, false, false);
103 void Cancel() override
105 m_dir.CancelDirectory();
107 bool m_result = false;
109 protected:
110 XFILE::CVirtualDirectory &m_dir;
111 CURL m_url;
112 CFileItemList &m_items;
116 CGUIWindowFileManager::CGUIWindowFileManager(void)
117 : CGUIWindow(WINDOW_FILES, "FileManager.xml"),
118 CJobQueue(false,2)
120 m_Directory[0] = new CFileItem;
121 m_Directory[1] = new CFileItem;
122 m_vecItems[0] = new CFileItemList;
123 m_vecItems[1] = new CFileItemList;
124 m_Directory[0]->SetPath("?");
125 m_Directory[1]->SetPath("?");
126 m_Directory[0]->m_bIsFolder = true;
127 m_Directory[1]->m_bIsFolder = true;
128 bCheckShareConnectivity = true;
129 m_loadType = KEEP_IN_MEMORY;
132 CGUIWindowFileManager::~CGUIWindowFileManager(void)
134 delete m_Directory[0];
135 delete m_Directory[1];
136 delete m_vecItems[0];
137 delete m_vecItems[1];
140 bool CGUIWindowFileManager::OnAction(const CAction &action)
142 int list = GetFocusedList();
143 if (list >= 0 && list <= 1)
145 int item;
147 // the non-contextual menu can be called at any time
148 if (action.GetID() == ACTION_CONTEXT_MENU && m_vecItems[list]->Size() == 0)
150 OnPopupMenu(list,-1, false);
151 return true;
153 if (action.GetID() == ACTION_DELETE_ITEM)
155 if (CanDelete(list))
157 bool bDeselect = SelectItem(list, item);
158 OnDelete(list);
159 if (bDeselect) m_vecItems[list]->Get(item)->Select(false);
161 return true;
163 if (action.GetID() == ACTION_COPY_ITEM)
165 if (CanCopy(list))
167 bool bDeselect = SelectItem(list, item);
168 OnCopy(list);
169 if (bDeselect) m_vecItems[list]->Get(item)->Select(false);
171 return true;
173 if (action.GetID() == ACTION_MOVE_ITEM)
175 if (CanMove(list))
177 bool bDeselect = SelectItem(list, item);
178 OnMove(list);
179 if (bDeselect) m_vecItems[list]->Get(item)->Select(false);
181 return true;
183 if (action.GetID() == ACTION_RENAME_ITEM)
185 if (CanRename(list))
187 bool bDeselect = SelectItem(list, item);
188 OnRename(list);
189 if (bDeselect) m_vecItems[list]->Get(item)->Select(false);
191 return true;
193 if (action.GetID() == ACTION_PARENT_DIR)
195 GoParentFolder(list);
196 return true;
198 if (action.GetID() == ACTION_PLAYER_PLAY)
200 #ifdef HAS_OPTICAL_DRIVE
201 if (m_vecItems[list]->Get(GetSelectedItem(list))->IsDVD())
202 return MEDIA_DETECT::CAutorun::PlayDiscAskResume(m_vecItems[list]->Get(GetSelectedItem(list))->GetPath());
203 #endif
206 return CGUIWindow::OnAction(action);
209 bool CGUIWindowFileManager::OnBack(int actionID)
211 int list = GetFocusedList();
212 if (list >= 0 && list <= 1 && actionID == ACTION_NAV_BACK && !m_vecItems[list]->IsVirtualDirectoryRoot())
214 GoParentFolder(list);
215 return true;
217 return CGUIWindow::OnBack(actionID);
220 bool CGUIWindowFileManager::OnMessage(CGUIMessage& message)
222 switch ( message.GetMessage() )
224 case GUI_MSG_NOTIFY_ALL:
225 { // Message is received even if window is inactive
226 if (message.GetParam1() == GUI_MSG_WINDOW_RESET)
228 m_Directory[0]->SetPath("?");
229 m_Directory[1]->SetPath("?");
230 m_Directory[0]->m_bIsFolder = true;
231 m_Directory[1]->m_bIsFolder = true;
232 return true;
235 // handle removable media
236 if (message.GetParam1() == GUI_MSG_REMOVED_MEDIA)
238 for (int i = 0; i < 2; i++)
240 if (m_Directory[i]->IsVirtualDirectoryRoot() && IsActive())
242 int iItem = GetSelectedItem(i);
243 Update(i, m_Directory[i]->GetPath());
244 CONTROL_SELECT_ITEM(CONTROL_LEFT_LIST + i, iItem);
246 else if (m_Directory[i]->IsRemovable() && !m_rootDir.IsInSource(m_Directory[i]->GetPath()))
247 { //
248 if (IsActive())
249 Update(i, "");
250 else
251 m_Directory[i]->SetPath("");
254 return true;
256 else if (message.GetParam1()==GUI_MSG_UPDATE_SOURCES)
257 { // State of the sources changed, so update our view
258 for (int i = 0; i < 2; i++)
260 if (m_Directory[i]->IsVirtualDirectoryRoot() && IsActive())
262 int iItem = GetSelectedItem(i);
263 Update(i, m_Directory[i]->GetPath());
264 CONTROL_SELECT_ITEM(CONTROL_LEFT_LIST + i, iItem);
267 return true;
269 else if (message.GetParam1()==GUI_MSG_UPDATE && IsActive())
271 Refresh();
272 return true;
275 break;
276 case GUI_MSG_PLAYBACK_STARTED:
277 case GUI_MSG_PLAYBACK_ENDED:
278 case GUI_MSG_PLAYBACK_STOPPED:
279 case GUI_MSG_PLAYLIST_CHANGED:
280 case GUI_MSG_PLAYLISTPLAYER_STOPPED:
281 case GUI_MSG_PLAYLISTPLAYER_STARTED:
282 case GUI_MSG_PLAYLISTPLAYER_CHANGED:
283 { // send a notify all to all controls on this window
284 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_REFRESH_LIST);
285 OnMessage(msg);
286 break;
288 case GUI_MSG_WINDOW_DEINIT:
290 CGUIWindow::OnMessage(message);
291 ClearFileItems(0);
292 ClearFileItems(1);
293 return true;
295 break;
297 case GUI_MSG_WINDOW_INIT:
299 SetInitialPath(message.GetStringParam());
300 message.SetStringParam("");
302 return CGUIWindow::OnMessage(message);
304 break;
305 case GUI_MSG_CLICKED:
307 int iControl = message.GetSenderId();
309 if (iControl == CONTROL_LEFT_LIST || iControl == CONTROL_RIGHT_LIST) // list/thumb control
311 // get selected item
312 int list = iControl - CONTROL_LEFT_LIST;
313 int iItem = GetSelectedItem(list);
314 int iAction = message.GetParam1();
316 // iItem is checked for validity inside these routines
317 if (iAction == ACTION_HIGHLIGHT_ITEM || iAction == ACTION_MOUSE_LEFT_CLICK)
319 OnMark(list, iItem);
320 if (!CServiceBroker::GetInputManager().IsMouseActive())
322 //move to next item
323 CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), iControl, iItem + 1);
324 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg);
327 else if (iAction == ACTION_SELECT_ITEM || iAction == ACTION_MOUSE_DOUBLE_CLICK)
329 OnClick(list, iItem);
331 else if (iAction == ACTION_CONTEXT_MENU || iAction == ACTION_MOUSE_RIGHT_CLICK)
333 OnPopupMenu(list, iItem);
337 break;
338 // prevent touch/gesture unfocussing ..
339 case GUI_MSG_GESTURE_NOTIFY:
340 case GUI_MSG_UNFOCUS_ALL:
341 return true;
343 return CGUIWindow::OnMessage(message);
346 void CGUIWindowFileManager::OnSort(int iList)
348 using namespace KODI::PLATFORM::FILESYSTEM;
349 // always sort the list by label in ascending order
350 for (int i = 0; i < m_vecItems[iList]->Size(); i++)
352 CFileItemPtr pItem = m_vecItems[iList]->Get(i);
353 if (pItem->m_bIsFolder && (!pItem->m_dwSize || pItem->IsPath("add")))
354 pItem->SetLabel2("");
355 else
356 pItem->SetFileSizeLabel();
358 // Set free space on disc
359 if (pItem->m_bIsShareOrDrive)
361 if (pItem->IsHD())
363 std::error_code ec;
364 auto freeSpace = space(pItem->GetPath(), ec);
365 if (ec.value() == 0)
367 pItem->m_dwSize = freeSpace.free;
368 pItem->SetFileSizeLabel();
371 else if (pItem->IsDVD() && CServiceBroker::GetMediaManager().IsDiscInDrive())
373 std::error_code ec;
374 auto freeSpace = space(pItem->GetPath(), ec);
375 if (ec.value() == 0)
377 pItem->m_dwSize = freeSpace.capacity;
378 pItem->SetFileSizeLabel();
381 } // if (pItem->m_bIsShareOrDrive)
385 m_vecItems[iList]->Sort(SortByLabel, SortOrderAscending);
388 void CGUIWindowFileManager::ClearFileItems(int iList)
390 CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), iList + CONTROL_LEFT_LIST);
391 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg);
393 m_vecItems[iList]->Clear(); // will clean up everything
396 void CGUIWindowFileManager::UpdateButtons()
398 // update our current directory labels
399 std::string strDir = CURL(m_Directory[0]->GetPath()).GetWithoutUserDetails();
400 if (strDir.empty())
402 SET_CONTROL_LABEL(CONTROL_CURRENTDIRLABEL_LEFT,g_localizeStrings.Get(20108));
404 else
406 SET_CONTROL_LABEL(CONTROL_CURRENTDIRLABEL_LEFT, strDir);
408 strDir = CURL(m_Directory[1]->GetPath()).GetWithoutUserDetails();
409 if (strDir.empty())
411 SET_CONTROL_LABEL(CONTROL_CURRENTDIRLABEL_RIGHT,g_localizeStrings.Get(20108));
413 else
415 SET_CONTROL_LABEL(CONTROL_CURRENTDIRLABEL_RIGHT, strDir);
418 // update the number of items in each list
419 UpdateItemCounts();
422 void CGUIWindowFileManager::UpdateItemCounts()
424 for (int i = 0; i < 2; i++)
426 unsigned int selectedCount = 0;
427 unsigned int totalCount = 0;
428 int64_t selectedSize = 0;
429 for (int j = 0; j < m_vecItems[i]->Size(); j++)
431 CFileItemPtr item = m_vecItems[i]->Get(j);
432 if (item->IsParentFolder()) continue;
433 if (item->IsSelected())
435 selectedCount++;
436 selectedSize += item->m_dwSize;
438 totalCount++;
440 std::string items;
441 if (selectedCount > 0)
442 items =
443 StringUtils::Format("{}/{} {} ({})", selectedCount, totalCount,
444 g_localizeStrings.Get(127), StringUtils::SizeToString(selectedSize));
445 else
446 items = StringUtils::Format("{} {}", totalCount, g_localizeStrings.Get(127));
447 SET_CONTROL_LABEL(CONTROL_NUMFILES_LEFT + i, items);
451 bool CGUIWindowFileManager::Update(int iList, const std::string &strDirectory)
453 if (m_updating)
455 CLog::Log(LOGWARNING, "CGUIWindowFileManager::Update - updating in progress");
456 return true;
458 CUpdateGuard ug(m_updating);
460 // get selected item
461 int iItem = GetSelectedItem(iList);
462 std::string strSelectedItem = "";
464 if (iItem >= 0 && iItem < m_vecItems[iList]->Size())
466 CFileItemPtr pItem = m_vecItems[iList]->Get(iItem);
467 if (!pItem->IsParentFolder())
469 GetDirectoryHistoryString(pItem.get(), strSelectedItem);
470 m_history[iList].SetSelectedItem(strSelectedItem, m_Directory[iList]->GetPath(), iItem);
474 std::string strOldDirectory=m_Directory[iList]->GetPath();
475 m_Directory[iList]->SetPath(strDirectory);
477 CFileItemList items;
478 if (!GetDirectory(iList, m_Directory[iList]->GetPath(), items))
480 if (strDirectory != strOldDirectory && GetDirectory(iList, strOldDirectory, items))
481 m_Directory[iList]->SetPath(strOldDirectory); // Fallback to old (previous) path)
482 else
483 Update(iList, ""); // Fallback to root
485 return false;
488 m_history[iList].SetSelectedItem(strSelectedItem, strOldDirectory);
490 ClearFileItems(iList);
492 m_vecItems[iList]->Append(items);
493 m_vecItems[iList]->SetPath(items.GetPath());
495 std::string strParentPath;
496 URIUtils::GetParentPath(strDirectory, strParentPath);
497 if (strDirectory.empty() && (m_vecItems[iList]->Size() == 0 || CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_FILELISTS_SHOWADDSOURCEBUTTONS)))
498 { // add 'add source button'
499 const std::string& strLabel = g_localizeStrings.Get(1026);
500 CFileItemPtr pItem(new CFileItem(strLabel));
501 pItem->SetPath("add");
502 pItem->SetArt("icon", "DefaultAddSource.png");
503 pItem->SetLabel(strLabel);
504 pItem->SetLabelPreformatted(true);
505 pItem->m_bIsFolder = true;
506 pItem->SetSpecialSort(SortSpecialOnBottom);
507 m_vecItems[iList]->Add(pItem);
509 else if (items.IsEmpty() || CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_FILELISTS_SHOWPARENTDIRITEMS))
511 CFileItemPtr pItem(new CFileItem(".."));
512 pItem->SetPath(m_rootDir.IsSource(strDirectory) ? "" : strParentPath);
513 pItem->m_bIsFolder = true;
514 pItem->m_bIsShareOrDrive = false;
515 m_vecItems[iList]->AddFront(pItem, 0);
518 m_strParentPath[iList] = (m_rootDir.IsSource(strDirectory) ? "" : strParentPath);
520 if (strDirectory.empty())
522 CFileItemPtr pItem(new CFileItem("special://profile/", true));
523 pItem->SetLabel(g_localizeStrings.Get(20070));
524 pItem->SetArt("thumb", "DefaultFolder.png");
525 pItem->SetLabelPreformatted(true);
526 m_vecItems[iList]->Add(pItem);
528 #ifdef TARGET_DARWIN_EMBEDDED
529 CFileItemPtr iItem(new CFileItem("special://envhome/Documents/Inbox", true));
530 iItem->SetLabel("Inbox");
531 iItem->SetArt("thumb", "DefaultFolder.png");
532 iItem->SetLabelPreformatted(true);
533 m_vecItems[iList]->Add(iItem);
534 #endif
535 #ifdef TARGET_ANDROID
536 CFileItemPtr iItem(new CFileItem("special://logpath", true));
537 iItem->SetLabel("Logs");
538 iItem->SetArt("thumb", "DefaultFolder.png");
539 iItem->SetLabelPreformatted(true);
540 m_vecItems[iList]->Add(iItem);
541 #endif
544 // if we have a .tbn file, use itself as the thumb
545 for (int i = 0; i < m_vecItems[iList]->Size(); i++)
547 CFileItemPtr pItem = m_vecItems[iList]->Get(i);
548 if (pItem->IsHD() &&
549 URIUtils::HasExtension(pItem->GetPath(), ".tbn"))
551 pItem->SetArt("thumb", pItem->GetPath());
554 m_vecItems[iList]->FillInDefaultIcons();
556 OnSort(iList);
557 UpdateButtons();
559 int item = 0;
560 strSelectedItem = m_history[iList].GetSelectedItem(m_Directory[iList]->GetPath());
561 for (int i = 0; i < m_vecItems[iList]->Size(); ++i)
563 CFileItemPtr pItem = m_vecItems[iList]->Get(i);
564 std::string strHistory;
565 GetDirectoryHistoryString(pItem.get(), strHistory);
566 if (strHistory == strSelectedItem)
568 item = i;
569 break;
572 UpdateControl(iList, item);
573 return true;
577 void CGUIWindowFileManager::OnClick(int iList, int iItem)
579 if ( iList < 0 || iList >= 2) return ;
580 if ( iItem < 0 || iItem >= m_vecItems[iList]->Size() ) return ;
582 CFileItemPtr pItem = m_vecItems[iList]->Get(iItem);
583 if (pItem->GetPath() == "add" && pItem->GetLabel() == g_localizeStrings.Get(1026)) // 'add source button' in empty root
585 if (CGUIDialogMediaSource::ShowAndAddMediaSource("files"))
587 m_rootDir.SetSources(*CMediaSourceSettings::GetInstance().GetSources("files"));
588 Update(0,m_Directory[0]->GetPath());
589 Update(1,m_Directory[1]->GetPath());
591 return;
594 if (!pItem->m_bIsFolder && pItem->IsFileFolder(EFILEFOLDER_MASK_ALL))
596 XFILE::IFileDirectory *pFileDirectory = NULL;
597 pFileDirectory = XFILE::CFileDirectoryFactory::Create(pItem->GetURL(), pItem.get(), "");
598 if(pFileDirectory)
599 pItem->m_bIsFolder = true;
600 else if(pItem->m_bIsFolder)
601 pItem->m_bIsFolder = false;
602 delete pFileDirectory;
605 if (pItem->m_bIsFolder)
607 // save path + drive type because of the possible refresh
608 std::string strPath = pItem->GetPath();
609 int iDriveType = pItem->m_iDriveType;
610 if ( pItem->m_bIsShareOrDrive )
612 if ( !g_passwordManager.IsItemUnlocked( pItem.get(), "files" ) )
614 Refresh();
615 return ;
618 if ( !HaveDiscOrConnection( strPath, iDriveType ) )
619 return ;
621 if (!Update(iList, strPath))
622 ShowShareErrorMessage(pItem.get());
624 else if (pItem->IsZIP() || pItem->IsCBZ()) // mount zip archive
626 CURL pathToUrl = URIUtils::CreateArchivePath("zip", pItem->GetURL(), "");
627 Update(iList, pathToUrl.Get());
629 else if (pItem->IsRAR() || pItem->IsCBR())
631 CURL pathToUrl = URIUtils::CreateArchivePath("rar", pItem->GetURL(), "");
632 Update(iList, pathToUrl.Get());
634 else
636 OnStart(pItem.get(), "");
637 return ;
639 // UpdateButtons();
642 //! @todo 2.0: Can this be removed, or should we run without the "special" file directories while
643 // in filemanager view.
644 void CGUIWindowFileManager::OnStart(CFileItem *pItem, const std::string &player)
646 // start playlists from file manager
647 if (PLAYLIST::IsPlayList(*pItem))
649 const std::string& strPlayList = pItem->GetPath();
650 std::unique_ptr<PLAYLIST::CPlayList> pPlayList(PLAYLIST::CPlayListFactory::Create(strPlayList));
651 if (nullptr != pPlayList)
653 if (!pPlayList->Load(strPlayList))
655 HELPERS::ShowOKDialogText(CVariant{6}, CVariant{477});
656 return;
659 g_application.ProcessAndStartPlaylist(strPlayList, *pPlayList, PLAYLIST::Id::TYPE_MUSIC);
660 return;
662 if (MUSIC::IsAudio(*pItem) || VIDEO::IsVideo(*pItem))
664 CServiceBroker::GetPlaylistPlayer().Play(std::make_shared<CFileItem>(*pItem), player);
665 return;
667 if (pItem->IsGame())
669 g_application.PlayFile(*pItem, player);
670 return ;
672 #ifdef HAS_PYTHON
673 if (pItem->IsPythonScript())
675 CScriptInvocationManager::GetInstance().ExecuteAsync(pItem->GetPath());
676 return ;
678 #endif
679 if (pItem->IsPicture())
681 const auto& components = CServiceBroker::GetAppComponents();
682 const auto appPlayer = components.GetComponent<CApplicationPlayer>();
683 if (appPlayer->IsPlayingVideo())
684 g_application.StopPlaying();
686 CSlideShowDelegator& slideShow = CServiceBroker::GetSlideShowDelegator();
687 slideShow.Reset();
688 slideShow.Add(pItem);
689 slideShow.Select(pItem->GetPath());
691 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_SLIDESHOW);
692 return;
694 if (pItem->IsType(".txt") || pItem->IsType(".xml"))
695 CGUIDialogTextViewer::ShowForFile(pItem->GetPath(), true);
698 bool CGUIWindowFileManager::HaveDiscOrConnection( std::string& strPath, int iDriveType )
700 if ( iDriveType == CMediaSource::SOURCE_TYPE_DVD )
702 if (!CServiceBroker::GetMediaManager().IsDiscInDrive(strPath))
704 HELPERS::ShowOKDialogText(CVariant{218}, CVariant{219});
705 int iList = GetFocusedList();
706 int iItem = GetSelectedItem(iList);
707 Update(iList, "");
708 CONTROL_SELECT_ITEM(iList + CONTROL_LEFT_LIST, iItem);
709 return false;
712 else if ( iDriveType == CMediaSource::SOURCE_TYPE_REMOTE )
714 //! @todo Handle not connected to a remote share
715 if (!CServiceBroker::GetNetwork().IsConnected())
717 HELPERS::ShowOKDialogText(CVariant{220}, CVariant{221});
718 return false;
721 else
722 return true;
723 return true;
726 void CGUIWindowFileManager::UpdateControl(int iList, int item)
728 CGUIMessage msg(GUI_MSG_LABEL_BIND, GetID(), iList + CONTROL_LEFT_LIST, item, 0, m_vecItems[iList]);
729 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg);
732 void CGUIWindowFileManager::OnMark(int iList, int iItem)
734 CFileItemPtr pItem = m_vecItems[iList]->Get(iItem);
736 if (!pItem->m_bIsShareOrDrive)
738 if (!pItem->IsParentFolder())
740 // MARK file
741 pItem->Select(!pItem->IsSelected());
745 UpdateItemCounts();
746 // UpdateButtons();
749 void CGUIWindowFileManager::OnCopy(int iList)
751 if (!CGUIDialogYesNo::ShowAndGetInput(CVariant{120}, CVariant{123}))
752 return;
754 AddJob(new CFileOperationJob(CFileOperationJob::ActionCopy,
755 *m_vecItems[iList],
756 m_Directory[1 - iList]->GetPath(),
757 true, 16201, 16202));
760 void CGUIWindowFileManager::OnMove(int iList)
762 if (!CGUIDialogYesNo::ShowAndGetInput(CVariant{121}, CVariant{124}))
763 return;
765 AddJob(new CFileOperationJob(CFileOperationJob::ActionMove,
766 *m_vecItems[iList],
767 m_Directory[1 - iList]->GetPath(),
768 true, 16203, 16204));
771 void CGUIWindowFileManager::OnDelete(int iList)
773 if (!CGUIDialogYesNo::ShowAndGetInput(CVariant{122}, CVariant{125}))
774 return;
776 AddJob(new CFileOperationJob(CFileOperationJob::ActionDelete,
777 *m_vecItems[iList],
778 m_Directory[iList]->GetPath(),
779 true, 16205, 16206));
782 void CGUIWindowFileManager::OnRename(int iList)
784 std::string strFile;
785 for (int i = 0; i < m_vecItems[iList]->Size();++i)
787 CFileItemPtr pItem = m_vecItems[iList]->Get(i);
788 if (pItem->IsSelected())
790 strFile = pItem->GetPath();
791 break;
795 CFileUtils::RenameFile(strFile);
797 Refresh(iList);
800 void CGUIWindowFileManager::OnSelectAll(int iList)
802 for (int i = 0; i < m_vecItems[iList]->Size();++i)
804 CFileItemPtr pItem = m_vecItems[iList]->Get(i);
805 if (!pItem->IsParentFolder())
807 pItem->Select(true);
812 void CGUIWindowFileManager::OnNewFolder(int iList)
814 std::string strNewFolder = "";
815 if (CGUIKeyboardFactory::ShowAndGetInput(strNewFolder, CVariant{g_localizeStrings.Get(16014)}, false))
817 std::string strNewPath = m_Directory[iList]->GetPath();
818 URIUtils::AddSlashAtEnd(strNewPath);
819 strNewPath += strNewFolder;
820 CDirectory::Create(strNewPath);
821 Refresh(iList);
823 // select the new folder
824 for (int i=0; i<m_vecItems[iList]->Size(); ++i)
826 CFileItemPtr pItem=m_vecItems[iList]->Get(i);
827 std::string strPath=pItem->GetPath();
828 URIUtils::RemoveSlashAtEnd(strPath);
829 if (strPath==strNewPath)
831 CONTROL_SELECT_ITEM(iList + CONTROL_LEFT_LIST, i);
832 break;
838 void CGUIWindowFileManager::Refresh(int iList)
840 int nSel = GetSelectedItem(iList);
841 // update the list views
842 Update(iList, m_Directory[iList]->GetPath());
844 while (nSel > m_vecItems[iList]->Size())
845 nSel--;
847 CONTROL_SELECT_ITEM(iList + CONTROL_LEFT_LIST, nSel);
851 void CGUIWindowFileManager::Refresh()
853 int iList = GetFocusedList();
854 int nSel = GetSelectedItem(iList);
855 // update the list views
856 Update(0, m_Directory[0]->GetPath());
857 Update(1, m_Directory[1]->GetPath());
859 while (nSel > m_vecItems[iList]->Size())
860 nSel--;
862 CONTROL_SELECT_ITEM(iList + CONTROL_LEFT_LIST, nSel);
865 int CGUIWindowFileManager::GetSelectedItem(int iControl)
867 if (iControl < 0 || iControl > 1 || m_vecItems[iControl]->IsEmpty())
868 return -1;
869 CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), iControl + CONTROL_LEFT_LIST);
870 if (OnMessage(msg))
871 return msg.GetParam1();
872 return -1;
875 void CGUIWindowFileManager::GoParentFolder(int iList)
877 CURL url(m_Directory[iList]->GetPath());
878 if (url.IsProtocol("rar") || url.IsProtocol("zip"))
880 // check for step-below, if, unmount rar
881 if (url.GetFileName().empty())
882 if (url.IsProtocol("zip"))
883 g_ZipManager.release(m_Directory[iList]->GetPath()); // release resources
886 std::string strPath(m_strParentPath[iList]), strOldPath(m_Directory[iList]->GetPath());
887 Update(iList, strPath);
890 /// \brief Build a directory history string
891 /// \param pItem Item to build the history string from
892 /// \param strHistoryString History string build as return value
893 void CGUIWindowFileManager::GetDirectoryHistoryString(const CFileItem* pItem, std::string& strHistoryString)
895 if (pItem->m_bIsShareOrDrive)
897 // We are in the virtual directory
899 // History string of the DVD drive
900 // must be handled separately
901 if (pItem->m_iDriveType == CMediaSource::SOURCE_TYPE_DVD)
903 // Remove disc label from item label
904 // and use as history string, m_strPath
905 // can change for new discs
906 std::string strLabel = pItem->GetLabel();
907 size_t nPosOpen = strLabel.find('(');
908 size_t nPosClose = strLabel.rfind(')');
909 if (nPosOpen != std::string::npos &&
910 nPosClose != std::string::npos &&
911 nPosClose > nPosOpen)
913 strLabel.erase(nPosOpen + 1, (nPosClose) - (nPosOpen + 1));
914 strHistoryString = strLabel;
916 else
917 strHistoryString = strLabel;
919 else
921 // Other items in virtual directory
922 strHistoryString = pItem->GetLabel() + pItem->GetPath();
923 URIUtils::RemoveSlashAtEnd(strHistoryString);
926 else
928 // Normal directory items
929 strHistoryString = pItem->GetPath();
930 URIUtils::RemoveSlashAtEnd(strHistoryString);
934 bool CGUIWindowFileManager::GetDirectory(int iList, const std::string &strDirectory, CFileItemList &items)
936 CURL pathToUrl(strDirectory);
938 CGetDirectoryItems getItems(m_rootDir, pathToUrl, items);
939 if (!CGUIDialogBusy::Wait(&getItems, 100, true))
941 return false;
943 return getItems.m_result;
946 bool CGUIWindowFileManager::CanRename(int iList)
948 //! @todo Renaming of shares (requires writing to sources.xml)
949 //! this might be able to be done via the webserver code stuff...
950 if (m_Directory[iList]->IsVirtualDirectoryRoot()) return false;
951 if (m_Directory[iList]->IsReadOnly()) return false;
953 return true;
956 bool CGUIWindowFileManager::CanCopy(int iList)
958 // can't copy if the destination is not writeable, or if the source is a share!
959 //! @todo Perhaps if the source is removeable media (DVD/CD etc.) we could
960 //! put ripping/backup in here.
961 if (!CUtil::SupportsReadFileOperations(m_Directory[iList]->GetPath())) return false;
962 if (m_Directory[iList]->IsVirtualDirectoryRoot()) return false;
963 if (m_Directory[1 - iList]->IsVirtualDirectoryRoot()) return false;
964 if (m_Directory[iList]->IsVirtualDirectoryRoot()) return false;
965 if (m_Directory[1 -iList]->IsReadOnly()) return false;
966 return true;
969 bool CGUIWindowFileManager::CanMove(int iList)
971 // can't move if the destination is not writeable, or if the source is a share or not writeable!
972 if (m_Directory[0]->IsVirtualDirectoryRoot() || m_Directory[0]->IsReadOnly()) return false;
973 if (m_Directory[1]->IsVirtualDirectoryRoot() || m_Directory[1]->IsReadOnly()) return false;
974 return true;
977 bool CGUIWindowFileManager::CanDelete(int iList)
979 if (m_Directory[iList]->IsVirtualDirectoryRoot()) return false;
980 if (m_Directory[iList]->IsReadOnly()) return false;
981 return true;
984 bool CGUIWindowFileManager::CanNewFolder(int iList)
986 if (m_Directory[iList]->IsVirtualDirectoryRoot()) return false;
987 if (m_Directory[iList]->IsReadOnly()) return false;
988 return true;
991 int CGUIWindowFileManager::NumSelected(int iList)
993 int iSelectedItems = 0;
994 for (int iItem = 0; iItem < m_vecItems[iList]->Size(); ++iItem)
996 if (m_vecItems[iList]->Get(iItem)->IsSelected()) iSelectedItems++;
998 return iSelectedItems;
1001 int CGUIWindowFileManager::GetFocusedList() const
1003 return GetFocusedControlID() - CONTROL_LEFT_LIST;
1006 void CGUIWindowFileManager::OnPopupMenu(int list, int item, bool bContextDriven /* = true */)
1008 if (list < 0 || list >= 2) return ;
1009 bool bDeselect = SelectItem(list, item);
1010 // calculate the position for our menu
1011 float posX = 200;
1012 float posY = 100;
1013 const CGUIControl *pList = GetControl(CONTROL_LEFT_LIST + list);
1014 if (pList)
1016 posX = pList->GetXPosition() + pList->GetWidth() / 2;
1017 posY = pList->GetYPosition() + pList->GetHeight() / 2;
1020 CFileItemPtr pItem = m_vecItems[list]->Get(item);
1021 if (!pItem.get())
1022 return;
1024 if (m_Directory[list]->IsVirtualDirectoryRoot())
1026 if (item < 0)
1027 { //! @todo We should add the option here for shares to be added if there aren't any
1028 return ;
1031 // and do the popup menu
1032 if (CGUIDialogContextMenu::SourcesMenu("files", pItem, posX, posY))
1034 m_rootDir.SetSources(*CMediaSourceSettings::GetInstance().GetSources("files"));
1035 if (m_Directory[1 - list]->IsVirtualDirectoryRoot())
1036 Refresh();
1037 else
1038 Refresh(list);
1039 return ;
1041 pItem->Select(false);
1042 return ;
1045 const CPlayerCoreFactory &playerCoreFactory = CServiceBroker::GetPlayerCoreFactory();
1047 // popup the context menu
1049 bool showEntry = false;
1050 if (item >= m_vecItems[list]->Size()) item = -1;
1051 if (item >= 0)
1052 showEntry=(!pItem->IsParentFolder() || (pItem->IsParentFolder() && m_vecItems[list]->GetSelectedCount()>0));
1054 // determine available players
1055 std::vector<std::string>players;
1056 playerCoreFactory.GetPlayers(*pItem, players);
1058 // add the needed buttons
1059 CContextButtons choices;
1060 if (item >= 0)
1062 //The ".." item is not selectable. Take that into account when figuring out if all items are selected
1063 int notSelectable = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_FILELISTS_SHOWPARENTDIRITEMS) ? 1 : 0;
1064 if (NumSelected(list) < m_vecItems[list]->Size() - notSelectable)
1065 choices.Add(CONTROL_BTNSELECTALL, 188); // SelectAll
1066 if (!pItem->IsParentFolder())
1067 choices.Add(CONTROL_BTNFAVOURITES, CServiceBroker::GetFavouritesService().IsFavourited(*pItem.get(), GetID()) ? 14077 : 14076); // Add/Remove Favourite
1068 if (players.size() > 1)
1069 choices.Add(CONTROL_BTNPLAYWITH, 15213);
1070 if (CanRename(list) && !pItem->IsParentFolder())
1071 choices.Add(CONTROL_BTNRENAME, 118);
1072 if (CanDelete(list) && showEntry)
1073 choices.Add(CONTROL_BTNDELETE, 117);
1074 if (CanCopy(list) && showEntry)
1075 choices.Add(CONTROL_BTNCOPY, 115);
1076 if (CanMove(list) && showEntry)
1077 choices.Add(CONTROL_BTNMOVE, 116);
1079 if (CanNewFolder(list))
1080 choices.Add(CONTROL_BTNNEWFOLDER, 20309);
1081 if (item >= 0 && pItem->m_bIsFolder && !pItem->IsParentFolder())
1082 choices.Add(CONTROL_BTNCALCSIZE, 13393);
1083 choices.Add(CONTROL_BTNSWITCHMEDIA, 523);
1084 if (CServiceBroker::GetJobManager()->IsProcessing("filemanager"))
1085 choices.Add(CONTROL_BTNCANCELJOB, 167);
1087 if (!pItem->m_bIsFolder)
1088 choices.Add(CONTROL_BTNVIEW, 39104);
1090 int btnid = CGUIDialogContextMenu::ShowAndGetChoice(choices);
1091 if (btnid == CONTROL_BTNSELECTALL)
1093 OnSelectAll(list);
1094 bDeselect=false;
1096 if (btnid == CONTROL_BTNFAVOURITES)
1098 CServiceBroker::GetFavouritesService().AddOrRemove(*pItem.get(), GetID());
1099 return;
1101 if (btnid == CONTROL_BTNPLAYWITH)
1103 std::vector<std::string>players;
1104 playerCoreFactory.GetPlayers(*pItem, players);
1105 std::string player = playerCoreFactory.SelectPlayerDialog(players);
1106 if (!player.empty())
1107 OnStart(pItem.get(), player);
1109 if (btnid == CONTROL_BTNRENAME)
1110 OnRename(list);
1111 if (btnid == CONTROL_BTNDELETE)
1112 OnDelete(list);
1113 if (btnid == CONTROL_BTNCOPY)
1114 OnCopy(list);
1115 if (btnid == CONTROL_BTNMOVE)
1116 OnMove(list);
1117 if (btnid == CONTROL_BTNNEWFOLDER)
1118 OnNewFolder(list);
1119 if (btnid == CONTROL_BTNCALCSIZE)
1121 // setup the progress dialog, and show it
1122 CGUIDialogProgress *progress = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogProgress>(WINDOW_DIALOG_PROGRESS);
1123 if (progress)
1125 progress->SetHeading(CVariant{13394});
1126 for (int i=0; i < 3; i++)
1127 progress->SetLine(i, CVariant{""});
1128 progress->Open();
1131 // Calculate folder size for each selected item
1132 for (int i=0; i<m_vecItems[list]->Size(); ++i)
1134 CFileItemPtr pItem2=m_vecItems[list]->Get(i);
1135 if (pItem2->m_bIsFolder && pItem2->IsSelected())
1137 int64_t folderSize = CalculateFolderSize(pItem2->GetPath(), progress);
1138 if (folderSize >= 0)
1140 pItem2->m_dwSize = folderSize;
1141 if (folderSize == 0)
1142 pItem2->SetLabel2(StringUtils::SizeToString(folderSize));
1143 else
1144 pItem2->SetFileSizeLabel();
1148 if (progress)
1149 progress->Close();
1151 if (btnid == CONTROL_BTNSWITCHMEDIA)
1153 CGUIDialogContextMenu::SwitchMedia("files", m_vecItems[list]->GetPath());
1154 return;
1156 if (btnid == CONTROL_BTNCANCELJOB)
1157 CancelJobs();
1158 if (btnid == CONTROL_BTNVIEW)
1159 CGUIDialogTextViewer::ShowForFile(pItem->GetPath(), true);
1161 if (bDeselect && item >= 0 && item < m_vecItems[list]->Size())
1162 { // deselect item as we didn't do anything
1163 pItem->Select(false);
1167 // Highlights the item in the list under the cursor
1168 // returns true if we should deselect the item, false otherwise
1169 bool CGUIWindowFileManager::SelectItem(int list, int &item)
1171 // get the currently selected item in the list
1172 item = GetSelectedItem(list);
1174 // select the item if we need to
1175 if (item > -1 && !NumSelected(list) && !m_vecItems[list]->Get(item)->IsParentFolder())
1177 m_vecItems[list]->Get(item)->Select(true);
1178 return true;
1180 return false;
1183 // recursively calculates the selected folder size
1184 int64_t CGUIWindowFileManager::CalculateFolderSize(const std::string &strDirectory, CGUIDialogProgress *pProgress)
1186 const CURL pathToUrl(strDirectory);
1187 if (pProgress)
1188 { // update our progress control
1189 pProgress->Progress();
1190 pProgress->SetLine(1, strDirectory);
1191 if (pProgress->IsCanceled())
1192 return -1;
1194 // start by calculating the size of the files in this folder...
1195 int64_t totalSize = 0;
1196 CFileItemList items;
1197 CVirtualDirectory rootDir;
1198 rootDir.SetSources(*CMediaSourceSettings::GetInstance().GetSources("files"));
1199 rootDir.GetDirectory(pathToUrl, items, false, false);
1200 for (int i=0; i < items.Size(); i++)
1202 if (items[i]->m_bIsFolder && !items[i]->IsParentFolder()) // folder
1204 int64_t folderSize = CalculateFolderSize(items[i]->GetPath(), pProgress);
1205 if (folderSize < 0) return -1;
1206 totalSize += folderSize;
1208 else // file
1209 totalSize += items[i]->m_dwSize;
1211 return totalSize;
1214 void CGUIWindowFileManager::OnJobComplete(unsigned int jobID, bool success, CJob *job)
1216 if(!success)
1218 CFileOperationJob* fileJob = static_cast<CFileOperationJob*>(job);
1219 HELPERS::ShowOKDialogLines(CVariant{fileJob->GetHeading()},
1220 CVariant{fileJob->GetLine()}, CVariant{16200}, CVariant{0});
1223 if (IsActive())
1225 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_UPDATE);
1226 CServiceBroker::GetAppMessenger()->SendGUIMessage(msg, GetID(), false);
1229 CJobQueue::OnJobComplete(jobID, success, job);
1232 void CGUIWindowFileManager::ShowShareErrorMessage(CFileItem* pItem)
1234 int idMessageText = 0;
1235 CURL url(pItem->GetPath());
1237 if (url.IsProtocol("smb") && url.GetHostName().empty()) // smb workgroup
1238 idMessageText = 15303; // Workgroup not found
1239 else if (pItem->m_iDriveType == CMediaSource::SOURCE_TYPE_REMOTE || URIUtils::IsRemote(pItem->GetPath()))
1240 idMessageText = 15301; // Could not connect to network server
1241 else
1242 idMessageText = 15300; // Path not found or invalid
1244 HELPERS::ShowOKDialogText(CVariant{220}, CVariant{idMessageText});
1247 void CGUIWindowFileManager::OnInitWindow()
1249 bool bResult0 = Update(0, m_Directory[0]->GetPath());
1250 bool bResult1 = Update(1, m_Directory[1]->GetPath());
1252 CGUIWindow::OnInitWindow();
1254 if (!bCheckShareConnectivity)
1256 bCheckShareConnectivity = true; //reset
1257 CFileItem pItem(strCheckSharePath, true);
1258 ShowShareErrorMessage(&pItem); //show the error message after window is loaded!
1259 Update(0,""); // reset view to root
1261 else if (!bResult0)
1263 ShowShareErrorMessage(m_Directory[0]); //show the error message after window is loaded!
1264 Update(0, ""); // reset view to root
1267 if (!bResult1)
1269 ShowShareErrorMessage(m_Directory[1]); //show the error message after window is loaded!
1270 Update(1, ""); // reset view to root
1274 void CGUIWindowFileManager::SetInitialPath(const std::string &path)
1276 // check for a passed destination path
1277 std::string strDestination = path;
1278 m_rootDir.SetSources(*CMediaSourceSettings::GetInstance().GetSources("files"));
1279 if (!strDestination.empty())
1281 CLog::Log(LOGINFO, "Attempting to quickpath to: {}", strDestination);
1283 // otherwise, is this the first time accessing this window?
1284 else if (m_Directory[0]->GetPath() == "?")
1286 m_Directory[0]->SetPath(strDestination = CMediaSourceSettings::GetInstance().GetDefaultSource("files"));
1287 CLog::Log(LOGINFO, "Attempting to default to: {}", strDestination);
1289 // try to open the destination path
1290 if (!strDestination.empty())
1292 // open root
1293 if (StringUtils::EqualsNoCase(strDestination, "$ROOT"))
1295 m_Directory[0]->SetPath("");
1296 CLog::Log(LOGINFO, " Success! Opening root listing.");
1298 else
1300 // default parameters if the jump fails
1301 m_Directory[0]->SetPath("");
1303 bool bIsSourceName = false;
1304 VECSOURCES shares;
1305 m_rootDir.GetSources(shares);
1306 int iIndex = CUtil::GetMatchingSource(strDestination, shares, bIsSourceName);
1307 if (iIndex > -1
1308 #if defined(TARGET_DARWIN_EMBEDDED)
1309 || URIUtils::PathHasParent(strDestination, "special://envhome/Documents/Inbox/")
1310 #endif
1311 || URIUtils::PathHasParent(strDestination, "special://profile/"))
1313 // set current directory to matching share
1314 std::string path;
1315 if (bIsSourceName && iIndex < (int)shares.size())
1316 path = shares[iIndex].strPath;
1317 else
1318 path = strDestination;
1319 URIUtils::RemoveSlashAtEnd(path);
1320 m_Directory[0]->SetPath(path);
1321 CLog::Log(LOGINFO, " Success! Opened destination path: {}", strDestination);
1323 // outside call: check the share for connectivity
1324 bCheckShareConnectivity = Update(0, m_Directory[0]->GetPath());
1325 if(!bCheckShareConnectivity)
1326 strCheckSharePath = m_Directory[0]->GetPath();
1328 else
1330 CLog::Log(LOGERROR, " Failed! Destination parameter ({}) does not match a valid share!",
1331 strDestination);
1336 if (m_Directory[1]->GetPath() == "?") m_Directory[1]->SetPath("");
1339 const CFileItem& CGUIWindowFileManager::CurrentDirectory(int indx) const
1341 return *m_Directory[indx];