[videodb] remove unused seasons table from episode_view
[xbmc.git] / xbmc / dialogs / GUIDialogMediaSource.cpp
blob0afbc2d0609529228f77378fbd2016e4d4c5a44b
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 "GUIDialogMediaSource.h"
11 #include "FileItem.h"
12 #include "FileItemList.h"
13 #include "GUIDialogFileBrowser.h"
14 #include "GUIDialogYesNo.h"
15 #include "PasswordManager.h"
16 #include "ServiceBroker.h"
17 #include "URL.h"
18 #include "Util.h"
19 #include "filesystem/Directory.h"
20 #include "filesystem/PVRDirectory.h"
21 #include "guilib/GUIComponent.h"
22 #include "guilib/GUIKeyboardFactory.h"
23 #include "guilib/GUIWindowManager.h"
24 #include "guilib/LocalizeStrings.h"
25 #include "input/actions/ActionIDs.h"
26 #include "music/windows/GUIWindowMusicBase.h"
27 #include "pvr/recordings/PVRRecordingsPath.h"
28 #include "settings/MediaSourceSettings.h"
29 #include "settings/Settings.h"
30 #include "settings/SettingsComponent.h"
31 #include "utils/StringUtils.h"
32 #include "utils/URIUtils.h"
33 #include "utils/Variant.h"
34 #include "video/windows/GUIWindowVideoBase.h"
36 #if defined(TARGET_ANDROID)
37 #include "utils/FileUtils.h"
39 #include "platform/android/activity/XBMCApp.h"
40 #endif
42 #ifdef TARGET_WINDOWS_STORE
43 #include "platform/win10/filesystem/WinLibraryDirectory.h"
44 #endif
46 using namespace XFILE;
48 #define CONTROL_HEADING 2
49 #define CONTROL_PATH 10
50 #define CONTROL_PATH_BROWSE 11
51 #define CONTROL_NAME 12
52 #define CONTROL_PATH_ADD 13
53 #define CONTROL_PATH_REMOVE 14
54 #define CONTROL_OK 18
55 #define CONTROL_CANCEL 19
56 #define CONTROL_CONTENT 20
58 CGUIDialogMediaSource::CGUIDialogMediaSource(void)
59 : CGUIDialog(WINDOW_DIALOG_MEDIA_SOURCE, "DialogMediaSource.xml")
61 m_paths = new CFileItemList;
62 m_loadType = KEEP_IN_MEMORY;
65 CGUIDialogMediaSource::~CGUIDialogMediaSource()
67 delete m_paths;
70 bool CGUIDialogMediaSource::OnBack(int actionID)
72 m_confirmed = false;
73 return CGUIDialog::OnBack(actionID);
76 bool CGUIDialogMediaSource::OnMessage(CGUIMessage& message)
78 switch (message.GetMessage())
80 case GUI_MSG_CLICKED:
82 int iControl = message.GetSenderId();
83 int iAction = message.GetParam1();
84 if (iControl == CONTROL_PATH && (iAction == ACTION_SELECT_ITEM || iAction == ACTION_MOUSE_LEFT_CLICK))
85 OnPath(GetSelectedItem());
86 else if (iControl == CONTROL_PATH_BROWSE)
87 OnPathBrowse(GetSelectedItem());
88 else if (iControl == CONTROL_PATH_ADD)
89 OnPathAdd();
90 else if (iControl == CONTROL_PATH_REMOVE)
91 OnPathRemove(GetSelectedItem());
92 else if (iControl == CONTROL_NAME)
94 OnEditChanged(iControl, m_name);
95 UpdateButtons();
97 else if (iControl == CONTROL_OK)
98 OnOK();
99 else if (iControl == CONTROL_CANCEL)
100 OnCancel();
101 else
102 break;
103 return true;
105 break;
106 case GUI_MSG_WINDOW_INIT:
108 UpdateButtons();
110 break;
111 case GUI_MSG_SETFOCUS:
112 if (message.GetControlId() == CONTROL_PATH_BROWSE ||
113 message.GetControlId() == CONTROL_PATH_ADD ||
114 message.GetControlId() == CONTROL_PATH_REMOVE)
116 HighlightItem(GetSelectedItem());
118 else
119 HighlightItem(-1);
120 break;
122 return CGUIDialog::OnMessage(message);
125 // \brief Show CGUIDialogMediaSource dialog and prompt for a new media source.
126 // \return True if the media source is added, false otherwise.
127 bool CGUIDialogMediaSource::ShowAndAddMediaSource(const std::string &type)
129 CGUIDialogMediaSource *dialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogMediaSource>(WINDOW_DIALOG_MEDIA_SOURCE);
130 if (!dialog) return false;
131 dialog->Initialize();
132 dialog->SetShare(CMediaSource());
133 dialog->SetTypeOfMedia(type);
134 dialog->Open();
135 bool confirmed(dialog->IsConfirmed());
136 if (confirmed)
138 // Add this media source
139 // Get unique source name
140 std::string strName = dialog->GetUniqueMediaSourceName();
142 CMediaSource share;
143 share.FromNameAndPaths(type, strName, dialog->GetPaths());
144 if (dialog->m_paths->Size() > 0)
145 share.m_strThumbnailImage = dialog->m_paths->Get(0)->GetArt("thumb");
146 CMediaSourceSettings::GetInstance().AddShare(type, share);
147 OnMediaSourceChanged(type, "", share);
149 dialog->m_paths->Clear();
150 return confirmed;
153 bool CGUIDialogMediaSource::ShowAndEditMediaSource(const std::string &type, const std::string&share)
155 VECSOURCES* pShares = CMediaSourceSettings::GetInstance().GetSources(type);
156 if (pShares)
158 for (unsigned int i = 0;i<pShares->size();++i)
160 if (StringUtils::EqualsNoCase((*pShares)[i].strName, share))
161 return ShowAndEditMediaSource(type, (*pShares)[i]);
164 return false;
167 bool CGUIDialogMediaSource::ShowAndEditMediaSource(const std::string &type, const CMediaSource &share)
169 std::string strOldName = share.strName;
170 CGUIDialogMediaSource *dialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogMediaSource>(WINDOW_DIALOG_MEDIA_SOURCE);
171 if (!dialog) return false;
172 dialog->Initialize();
173 dialog->SetShare(share);
174 dialog->SetTypeOfMedia(type, true);
175 dialog->Open();
176 bool confirmed(dialog->IsConfirmed());
177 if (confirmed)
179 // Update media source
180 // Get unique new source name when changed
181 std::string strName(dialog->m_name);
182 if (!StringUtils::EqualsNoCase(dialog->m_name, strOldName))
183 strName = dialog->GetUniqueMediaSourceName();
185 CMediaSource newShare;
186 newShare.FromNameAndPaths(type, strName, dialog->GetPaths());
187 CMediaSourceSettings::GetInstance().UpdateShare(type, strOldName, newShare);
189 OnMediaSourceChanged(type, strOldName, newShare);
191 dialog->m_paths->Clear();
192 return confirmed;
195 std::string CGUIDialogMediaSource::GetUniqueMediaSourceName()
197 // Get unique source name for this media type
198 unsigned int i, j = 2;
199 bool bConfirmed = false;
200 VECSOURCES* pShares = CMediaSourceSettings::GetInstance().GetSources(m_type);
201 std::string strName = m_name;
202 while (!bConfirmed)
204 for (i = 0; i<pShares->size(); ++i)
206 if (StringUtils::EqualsNoCase((*pShares)[i].strName, strName))
207 break;
209 if (i < pShares->size())
210 // found a match - try next
211 strName = StringUtils::Format("{} ({})", m_name, j++);
212 else
213 bConfirmed = true;
215 return strName;
218 void CGUIDialogMediaSource::OnMediaSourceChanged(const std::string& type, const std::string& oldName, const CMediaSource& share)
220 // Processing once media source added/edited - library scraping and scanning
221 if (!StringUtils::StartsWithNoCase(share.strPath, "rss://") &&
222 !StringUtils::StartsWithNoCase(share.strPath, "rsss://") &&
223 !StringUtils::StartsWithNoCase(share.strPath, "upnp://"))
225 if (type == "video" && !URIUtils::IsLiveTV(share.strPath))
226 // Assign content to a path, refresh scraper information optionally start a scan
227 CGUIWindowVideoBase::OnAssignContent(share.strPath);
228 else if (type == "music")
229 CGUIWindowMusicBase::OnAssignContent(oldName, share);
233 void CGUIDialogMediaSource::OnPathBrowse(int item)
235 if (item < 0 || item >= m_paths->Size()) return;
236 // Browse is called. Open the filebrowser dialog.
237 // Ignore current path is best at this stage??
238 std::string path = m_paths->Get(item)->GetPath();
239 bool allowNetworkShares(m_type != "programs");
240 VECSOURCES extraShares;
242 if (m_name != CUtil::GetTitleFromPath(path))
243 m_bNameChanged = true;
244 path.clear();
246 if (m_type == "music")
248 CMediaSource share1;
249 #if defined(TARGET_ANDROID)
250 // add the default android music directory
251 std::string path;
252 if (CXBMCApp::GetExternalStorage(path, "music") && !path.empty() && CDirectory::Exists(path))
254 share1.strPath = path;
255 share1.strName = g_localizeStrings.Get(20240);
256 share1.m_ignore = true;
257 extraShares.push_back(share1);
259 #endif
261 #if defined(TARGET_WINDOWS_STORE)
262 // add the default UWP music directory
263 std::string path;
264 if (XFILE::CWinLibraryDirectory::GetStoragePath(m_type, path) && !path.empty() && CDirectory::Exists(path))
266 share1.strPath = path;
267 share1.strName = g_localizeStrings.Get(20245);
268 share1.m_ignore = true;
269 extraShares.push_back(share1);
271 #endif
273 // add the music playlist location
274 share1.strPath = "special://musicplaylists/";
275 share1.strName = g_localizeStrings.Get(20011);
276 share1.m_ignore = true;
277 extraShares.push_back(share1);
279 // add the recordings dir as needed
280 if (CPVRDirectory::HasRadioRecordings())
282 share1.strPath = PVR::CPVRRecordingsPath::PATH_ACTIVE_RADIO_RECORDINGS;
283 share1.strName = g_localizeStrings.Get(19017); // Recordings
284 extraShares.push_back(share1);
286 if (CPVRDirectory::HasDeletedRadioRecordings())
288 share1.strPath = PVR::CPVRRecordingsPath::PATH_DELETED_RADIO_RECORDINGS;
289 share1.strName = g_localizeStrings.Get(19184); // Deleted recordings
290 extraShares.push_back(share1);
293 if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_AUDIOCDS_RECORDINGPATH) != "")
295 share1.strPath = "special://recordings/";
296 share1.strName = g_localizeStrings.Get(21883);
297 extraShares.push_back(share1);
300 else if (m_type == "video")
302 CMediaSource share1;
303 #if defined(TARGET_ANDROID)
304 // add the default android video directory
305 std::string path;
306 if (CXBMCApp::GetExternalStorage(path, "videos") && !path.empty() && CFileUtils::Exists(path))
308 share1.strPath = path;
309 share1.strName = g_localizeStrings.Get(20241);
310 share1.m_ignore = true;
311 extraShares.push_back(share1);
313 #endif
314 #if defined(TARGET_WINDOWS_STORE)
315 // add the default UWP music directory
316 std::string path;
317 if (XFILE::CWinLibraryDirectory::GetStoragePath(m_type, path) && !path.empty() && CDirectory::Exists(path))
319 share1.strPath = path;
320 share1.strName = g_localizeStrings.Get(20246);
321 share1.m_ignore = true;
322 extraShares.push_back(share1);
324 #endif
326 // add the video playlist location
327 share1.m_ignore = true;
328 share1.strPath = "special://videoplaylists/";
329 share1.strName = g_localizeStrings.Get(20012);
330 extraShares.push_back(share1);
332 // add the recordings dir as needed
333 if (CPVRDirectory::HasTVRecordings())
335 share1.strPath = PVR::CPVRRecordingsPath::PATH_ACTIVE_TV_RECORDINGS;
336 share1.strName = g_localizeStrings.Get(19017); // Recordings
337 extraShares.push_back(share1);
339 if (CPVRDirectory::HasDeletedTVRecordings())
341 share1.strPath = PVR::CPVRRecordingsPath::PATH_DELETED_TV_RECORDINGS;
342 share1.strName = g_localizeStrings.Get(19184); // Deleted recordings
343 extraShares.push_back(share1);
346 else if (m_type == "pictures")
348 CMediaSource share1;
349 #if defined(TARGET_ANDROID)
350 // add the default android music directory
351 std::string path;
352 if (CXBMCApp::GetExternalStorage(path, "pictures") && !path.empty() && CFileUtils::Exists(path))
354 share1.strPath = path;
355 share1.strName = g_localizeStrings.Get(20242);
356 share1.m_ignore = true;
357 extraShares.push_back(share1);
360 path.clear();
361 if (CXBMCApp::GetExternalStorage(path, "photos") && !path.empty() && CFileUtils::Exists(path))
363 share1.strPath = path;
364 share1.strName = g_localizeStrings.Get(20243);
365 share1.m_ignore = true;
366 extraShares.push_back(share1);
368 #endif
369 #if defined(TARGET_WINDOWS_STORE)
370 // add the default UWP music directory
371 std::string path;
372 if (XFILE::CWinLibraryDirectory::GetStoragePath(m_type, path) && !path.empty() && CDirectory::Exists(path))
374 share1.strPath = path;
375 share1.strName = g_localizeStrings.Get(20247);
376 share1.m_ignore = true;
377 extraShares.push_back(share1);
379 path.clear();
380 if (XFILE::CWinLibraryDirectory::GetStoragePath("photos", path) && !path.empty() && CDirectory::Exists(path))
382 share1.strPath = path;
383 share1.strName = g_localizeStrings.Get(20248);
384 share1.m_ignore = true;
385 extraShares.push_back(share1);
387 #endif
389 share1.m_ignore = true;
390 if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_DEBUG_SCREENSHOTPATH) != "")
392 share1.strPath = "special://screenshots/";
393 share1.strName = g_localizeStrings.Get(20008);
394 extraShares.push_back(share1);
397 else if (m_type == "games")
399 // nothing to add
401 else if (m_type == "programs")
403 // nothing to add
405 if (CGUIDialogFileBrowser::ShowAndGetSource(path, allowNetworkShares, extraShares.size() == 0 ? NULL : &extraShares))
407 if (item < m_paths->Size()) // if the skin does funky things, m_paths may have been cleared
408 m_paths->Get(item)->SetPath(path);
409 if (!m_bNameChanged || m_name.empty())
411 CURL url(path);
412 m_name = url.GetWithoutUserDetails();
413 URIUtils::RemoveSlashAtEnd(m_name);
414 m_name = CUtil::GetTitleFromPath(m_name);
416 UpdateButtons();
420 void CGUIDialogMediaSource::OnPath(int item)
422 if (item < 0 || item >= m_paths->Size()) return;
424 std::string path(m_paths->Get(item)->GetPath());
425 if (m_name != CUtil::GetTitleFromPath(path))
426 m_bNameChanged = true;
428 CGUIKeyboardFactory::ShowAndGetInput(path, CVariant{ g_localizeStrings.Get(1021) }, false);
429 m_paths->Get(item)->SetPath(path);
431 if (!m_bNameChanged || m_name.empty())
433 CURL url(m_paths->Get(item)->GetPath());
434 m_name = url.GetWithoutUserDetails();
435 URIUtils::RemoveSlashAtEnd(m_name);
436 m_name = CUtil::GetTitleFromPath(m_name);
438 UpdateButtons();
441 void CGUIDialogMediaSource::OnOK()
443 // Verify the paths by doing a GetDirectory.
444 CFileItemList items;
446 // Create temp media source to encode path urls as multipath
447 // Name of actual source may need to be made unique when saved in sources
448 CMediaSource share;
449 share.FromNameAndPaths(m_type, m_name, GetPaths());
451 if (StringUtils::StartsWithNoCase(share.strPath, "plugin://") ||
452 CDirectory::GetDirectory(share.strPath, items, "", DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_ALLOW_PROMPT) ||
453 CGUIDialogYesNo::ShowAndGetInput(CVariant{ 1001 }, CVariant{ 1025 }))
455 m_confirmed = true;
456 Close();
460 void CGUIDialogMediaSource::OnCancel()
462 m_confirmed = false;
463 Close();
466 void CGUIDialogMediaSource::UpdateButtons()
468 if (!m_paths->Size()) // sanity
469 return;
471 CONTROL_ENABLE_ON_CONDITION(CONTROL_OK, !m_paths->Get(0)->GetPath().empty() && !m_name.empty());
472 CONTROL_ENABLE_ON_CONDITION(CONTROL_PATH_ADD, !m_paths->Get(0)->GetPath().empty());
473 CONTROL_ENABLE_ON_CONDITION(CONTROL_PATH_REMOVE, m_paths->Size() > 1);
474 // name
475 SET_CONTROL_LABEL2(CONTROL_NAME, m_name);
476 SendMessage(GUI_MSG_SET_TYPE, CONTROL_NAME, 0, 1022);
478 int currentItem = GetSelectedItem();
479 SendMessage(GUI_MSG_LABEL_RESET, CONTROL_PATH);
480 for (int i = 0; i < m_paths->Size(); i++)
482 CFileItemPtr item = m_paths->Get(i);
483 std::string path;
484 CURL url(item->GetPath());
485 path = url.GetWithoutUserDetails();
486 if (path.empty()) path = "<" + g_localizeStrings.Get(231) + ">"; // <None>
487 item->SetLabel(path);
489 CGUIMessage msg(GUI_MSG_LABEL_BIND, GetID(), CONTROL_PATH, 0, 0, m_paths);
490 OnMessage(msg);
491 SendMessage(GUI_MSG_ITEM_SELECT, CONTROL_PATH, currentItem);
493 SET_CONTROL_HIDDEN(CONTROL_CONTENT);
496 void CGUIDialogMediaSource::SetShare(const CMediaSource &share)
498 m_paths->Clear();
499 for (unsigned int i = 0; i < share.vecPaths.size(); i++)
501 CFileItemPtr item(new CFileItem(share.vecPaths[i], true));
502 m_paths->Add(item);
504 if (0 == share.vecPaths.size())
506 CFileItemPtr item(new CFileItem("", true));
507 m_paths->Add(item);
509 m_name = share.strName;
510 UpdateButtons();
513 void CGUIDialogMediaSource::SetTypeOfMedia(const std::string &type, bool editNotAdd)
515 m_type = type;
516 std::string heading;
517 if (editNotAdd)
519 if (type == "video")
520 heading = g_localizeStrings.Get(10053);
521 else if (type == "music")
522 heading = g_localizeStrings.Get(10054);
523 else if (type == "pictures")
524 heading = g_localizeStrings.Get(10055);
525 else if (type == "games")
526 heading = g_localizeStrings.Get(35252); // "Edit game source"
527 else if (type == "programs")
528 heading = g_localizeStrings.Get(10056);
529 else
530 heading = g_localizeStrings.Get(10057);
532 else
534 if (type == "video")
535 heading = g_localizeStrings.Get(10048);
536 else if (type == "music")
537 heading = g_localizeStrings.Get(10049);
538 else if (type == "pictures")
539 heading = g_localizeStrings.Get(13006);
540 else if (type == "games")
541 heading = g_localizeStrings.Get(35251); // "Add game source"
542 else if (type == "programs")
543 heading = g_localizeStrings.Get(10051);
544 else
545 heading = g_localizeStrings.Get(10052);
547 SET_CONTROL_LABEL(CONTROL_HEADING, heading);
550 int CGUIDialogMediaSource::GetSelectedItem()
552 CGUIMessage message(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_PATH);
553 OnMessage(message);
554 int value = message.GetParam1();
555 if (value < 0 || value >= m_paths->Size()) return 0;
556 return value;
559 void CGUIDialogMediaSource::HighlightItem(int item)
561 for (int i = 0; i < m_paths->Size(); i++)
562 m_paths->Get(i)->Select(false);
563 if (item >= 0 && item < m_paths->Size())
564 m_paths->Get(item)->Select(true);
565 CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), CONTROL_PATH, item);
566 OnMessage(msg);
569 void CGUIDialogMediaSource::OnPathRemove(int item)
571 m_paths->Remove(item);
572 UpdateButtons();
573 if (item >= m_paths->Size())
574 HighlightItem(m_paths->Size() - 1);
575 else
576 HighlightItem(item);
577 if (m_paths->Size() <= 1)
579 SET_CONTROL_FOCUS(CONTROL_PATH_ADD, 0);
583 void CGUIDialogMediaSource::OnPathAdd()
585 // add a new item and select it as well
586 CFileItemPtr item(new CFileItem("", true));
587 m_paths->Add(item);
588 UpdateButtons();
589 HighlightItem(m_paths->Size() - 1);
592 std::vector<std::string> CGUIDialogMediaSource::GetPaths() const
594 std::vector<std::string> paths;
595 for (int i = 0; i < m_paths->Size(); i++)
597 if (!m_paths->Get(i)->GetPath().empty())
598 { // strip off the user and password for supported paths (anything that the password manager can auth)
599 // and add the user/pass to the password manager - note, we haven't confirmed that it works
600 // at this point, but if it doesn't, the user will get prompted anyway in implementation.
601 CURL url(m_paths->Get(i)->GetPath());
602 if (CPasswordManager::GetInstance().IsURLSupported(url) && !url.GetUserName().empty())
604 CPasswordManager::GetInstance().SaveAuthenticatedURL(url);
605 url.SetPassword("");
606 url.SetUserName("");
607 url.SetDomain("");
609 paths.push_back(url.Get());
612 return paths;
615 void CGUIDialogMediaSource::OnDeinitWindow(int nextWindowID)
617 CGUIDialog::OnDeinitWindow(nextWindowID);
619 // clear paths container
620 CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), CONTROL_PATH, 0);
621 OnMessage(msg);