1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9 #include "GUIDialogFileBrowser.h"
10
11 #include "AutoSwitch.h"
12 #include "FileItem.h"
13 #include "GUIDialogContextMenu.h"
14 #include "GUIDialogMediaSource.h"
15 #include "GUIDialogYesNo.h"
16 #include "GUIPassword.h"
17 #include "GUIUserMessages.h"
18 #include "ServiceBroker.h"
19 #include "URL.h"
20 #include "Util.h"
21 #include "filesystem/Directory.h"
22 #include "filesystem/File.h"
23 #include "filesystem/MultiPathDirectory.h"
24 #include "guilib/GUIComponent.h"
25 #include "guilib/GUIKeyboardFactory.h"
26 #include "guilib/GUIWindowManager.h"
27 #include "guilib/LocalizeStrings.h"
28 #include "input/Key.h"
29 #include "messaging/helpers/DialogOKHelper.h"
30 #include "network/GUIDialogNetworkSetup.h"
31 #include "network/Network.h"
32 #include "profiles/ProfileManager.h"
33 #include "settings/MediaSourceSettings.h"
34 #include "settings/SettingsComponent.h"
35 #include "storage/MediaManager.h"
36 #include "utils/FileExtensionProvider.h"
37 #include "utils/StringUtils.h"
38 #include "utils/URIUtils.h"
39 #include "utils/Variant.h"
40 #include "utils/log.h"
41
42 using namespace KODI::MESSAGING;
43 using namespace XFILE;
44
45 #define CONTROL_LIST 450
46 #define CONTROL_THUMBS 451
47 #define CONTROL_HEADING_LABEL 411
48 #define CONTROL_LABEL_PATH 412
49 #define CONTROL_OK 413
50 #define CONTROL_CANCEL 414
51 #define CONTROL_NEWFOLDER 415
52 #define CONTROL_FLIP 416
53
CGUIDialogFileBrowser()54 CGUIDialogFileBrowser::CGUIDialogFileBrowser()
55 : CGUIDialog(WINDOW_DIALOG_FILE_BROWSER, "FileBrowser.xml")
56 {
57 m_Directory = new CFileItem;
58 m_vecItems = new CFileItemList;
59 m_bConfirmed = false;
60 m_Directory->m_bIsFolder = true;
61 m_browsingForFolders = 0;
62 m_browsingForImages = false;
63 m_useFileDirectories = false;
64 m_addNetworkShareEnabled = false;
65 m_singleList = false;
66 m_thumbLoader.SetObserver(this);
67 m_flipEnabled = false;
68 m_bFlip = false;
69 m_multipleSelection = false;
70 m_loadType = KEEP_IN_MEMORY;
71 }
72
~CGUIDialogFileBrowser()73 CGUIDialogFileBrowser::~CGUIDialogFileBrowser()
74 {
75 delete m_Directory;
76 delete m_vecItems;
77 }
78
OnAction(const CAction & action)79 bool CGUIDialogFileBrowser::OnAction(const CAction &action)
80 {
81 if (action.GetID() == ACTION_PARENT_DIR)
82 {
83 GoParentFolder();
84 return true;
85 }
86 if ((action.GetID() == ACTION_CONTEXT_MENU || action.GetID() == ACTION_MOUSE_RIGHT_CLICK) && m_Directory->GetPath().empty())
87 {
88 int iItem = m_viewControl.GetSelectedItem();
89 if ((!m_addSourceType.empty() && iItem != m_vecItems->Size()-1))
90 return OnPopupMenu(iItem);
91 if (m_addNetworkShareEnabled && CServiceBroker::GetMediaManager().HasLocation(m_selectedPath))
92 {
93 // need to make sure this source is not an auto added location
94 // as users locations might have the same paths
95 CFileItemPtr pItem = (*m_vecItems)[iItem];
96 for (unsigned int i=0;i<m_shares.size();++i)
97 {
98 if (StringUtils::EqualsNoCase(m_shares[i].strName, pItem->GetLabel()) && m_shares[i].m_ignore)
99 return false;
100 }
101
102 return OnPopupMenu(iItem);
103 }
104
105 return false;
106 }
107
108 return CGUIDialog::OnAction(action);
109 }
110
OnBack(int actionID)111 bool CGUIDialogFileBrowser::OnBack(int actionID)
112 {
113 if (actionID == ACTION_NAV_BACK && !m_vecItems->IsVirtualDirectoryRoot())
114 {
115 GoParentFolder();
116 return true;
117 }
118 return CGUIDialog::OnBack(actionID);
119 }
120
OnMessage(CGUIMessage & message)121 bool CGUIDialogFileBrowser::OnMessage(CGUIMessage& message)
122 {
123 switch ( message.GetMessage() )
124 {
125 case GUI_MSG_WINDOW_DEINIT:
126 {
127 if (m_thumbLoader.IsLoading())
128 m_thumbLoader.StopThread();
129 CGUIDialog::OnMessage(message);
130 ClearFileItems();
131 m_addNetworkShareEnabled = false;
132 return true;
133 }
134 break;
135
136 case GUI_MSG_WINDOW_INIT:
137 {
138 m_bConfirmed = false;
139 m_bFlip = false;
140 bool bIsDir = false;
141 // this code allows two different selection modes for directories
142 // end the path with a slash to start inside the directory
143 if (URIUtils::HasSlashAtEnd(m_selectedPath))
144 {
145 bIsDir = true;
146 bool bFool;
147 int iSource = CUtil::GetMatchingSource(m_selectedPath,m_shares,bFool);
148 bFool = true;
149 if (iSource > -1 && iSource < (int)m_shares.size())
150 {
151 if (URIUtils::PathEquals(m_shares[iSource].strPath, m_selectedPath))
152 bFool = false;
153 }
154
155 if (bFool && !CDirectory::Exists(m_selectedPath))
156 m_selectedPath.clear();
157 }
158 else
159 {
160 if (!CFile::Exists(m_selectedPath) && !CDirectory::Exists(m_selectedPath))
161 m_selectedPath.clear();
162 }
163
164 // find the parent folder if we are a file browser (don't do this for folders)
165 m_Directory->SetPath(m_selectedPath);
166 if (!m_browsingForFolders && !bIsDir)
167 m_Directory->SetPath(URIUtils::GetParentPath(m_selectedPath));
168 Update(m_Directory->GetPath());
169 m_viewControl.SetSelectedItem(m_selectedPath);
170 return CGUIDialog::OnMessage(message);
171 }
172 break;
173
174 case GUI_MSG_CLICKED:
175 {
176 if (m_viewControl.HasControl(message.GetSenderId())) // list control
177 {
178 int iItem = m_viewControl.GetSelectedItem();
179 int iAction = message.GetParam1();
180 if (iItem < 0) break;
181 CFileItemPtr pItem = (*m_vecItems)[iItem];
182 if ((iAction == ACTION_SELECT_ITEM || iAction == ACTION_MOUSE_LEFT_CLICK) &&
183 (!m_multipleSelection || pItem->m_bIsShareOrDrive || pItem->m_bIsFolder))
184 {
185 OnClick(iItem);
186 return true;
187 }
188 else if ((iAction == ACTION_HIGHLIGHT_ITEM || iAction == ACTION_MOUSE_LEFT_CLICK || iAction == ACTION_SELECT_ITEM) &&
189 (m_multipleSelection && !pItem->m_bIsShareOrDrive && !pItem->m_bIsFolder))
190 {
191 pItem->Select(!pItem->IsSelected());
192 CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), message.GetSenderId(), iItem + 1);
193 OnMessage(msg);
194 }
195 }
196 else if (message.GetSenderId() == CONTROL_OK)
197 {
198 if (m_browsingForFolders == 2)
199 {
200 int iItem = m_viewControl.GetSelectedItem();
201
202 std::string strPath;
203 if (iItem == 0)
204 strPath = m_selectedPath;
205 else
206 strPath = (*m_vecItems)[iItem]->GetPath();
207
208 std::string strTest = URIUtils::AddFileToFolder(strPath, "1");
209 CFile file;
210 if (file.OpenForWrite(strTest,true))
211 {
212 file.Close();
213 CFile::Delete(strTest);
214 m_bConfirmed = true;
215 Close();
216 }
217 else
218 HELPERS::ShowOKDialogText(CVariant{257}, CVariant{20072});
219 }
220 else
221 {
222 if (m_multipleSelection)
223 {
224 for (int iItem = 0; iItem < m_vecItems->Size(); ++iItem)
225 {
226 CFileItemPtr pItem = (*m_vecItems)[iItem];
227 if (pItem->IsSelected())
228 m_markedPath.push_back(pItem->GetPath());
229 }
230 }
231 m_bConfirmed = true;
232 Close();
233 }
234 return true;
235 }
236 else if (message.GetSenderId() == CONTROL_CANCEL)
237 {
238 Close();
239 return true;
240 }
241 else if (message.GetSenderId() == CONTROL_NEWFOLDER)
242 {
243 std::string strInput;
244 if (CGUIKeyboardFactory::ShowAndGetInput(strInput, CVariant{g_localizeStrings.Get(119)}, false))
245 {
246 std::string strPath = URIUtils::AddFileToFolder(m_vecItems->GetPath(), strInput);
247 if (CDirectory::Create(strPath))
248 Update(m_vecItems->GetPath());
249 else
250 HELPERS::ShowOKDialogText(CVariant{20069}, CVariant{20072});
251 }
252 }
253 else if (message.GetSenderId() == CONTROL_FLIP)
254 m_bFlip = !m_bFlip;
255 }
256 break;
257 case GUI_MSG_SETFOCUS:
258 {
259 if (m_viewControl.HasControl(message.GetControlId()) && m_viewControl.GetCurrentControl() != message.GetControlId())
260 {
261 m_viewControl.SetFocused();
262 return true;
263 }
264 }
265 break;
266 case GUI_MSG_NOTIFY_ALL:
267 { // Message is received only if this window is active
268 if (message.GetParam1() == GUI_MSG_REMOVED_MEDIA)
269 {
270 if (m_Directory->IsVirtualDirectoryRoot() && IsActive())
271 {
272 int iItem = m_viewControl.GetSelectedItem();
273 Update(m_Directory->GetPath());
274 m_viewControl.SetSelectedItem(iItem);
275 }
276 else if (m_Directory->IsRemovable())
277 { // check that we have this removable share still
278 if (!m_rootDir.IsInSource(m_Directory->GetPath()))
279 { // don't have this share any more
280 if (IsActive()) Update("");
281 else
282 {
283 m_history.ClearPathHistory();
284 m_Directory->SetPath("");
285 }
286 }
287 }
288 return true;
289 }
290 else if (message.GetParam1()==GUI_MSG_UPDATE_SOURCES)
291 { // State of the sources changed, so update our view
292 if (m_Directory->IsVirtualDirectoryRoot() && IsActive())
293 {
294 int iItem = m_viewControl.GetSelectedItem();
295 Update(m_Directory->GetPath());
296 m_viewControl.SetSelectedItem(iItem);
297 }
298 return true;
299 }
300 else if (message.GetParam1()==GUI_MSG_UPDATE_PATH)
301 {
302 if (IsActive())
303 {
304 if((message.GetStringParam() == m_Directory->GetPath()) ||
305 (m_Directory->IsMultiPath() && XFILE::CMultiPathDirectory::HasPath(m_Directory->GetPath(), message.GetStringParam())))
306 {
307 int iItem = m_viewControl.GetSelectedItem();
308 Update(m_Directory->GetPath());
309 m_viewControl.SetSelectedItem(iItem);
310 }
311 }
312 }
313 }
314 break;
315
316 }
317 return CGUIDialog::OnMessage(message);
318 }
319
ClearFileItems()320 void CGUIDialogFileBrowser::ClearFileItems()
321 {
322 m_viewControl.Clear();
323 m_vecItems->Clear(); // will clean up everything
324 }
325
OnSort()326 void CGUIDialogFileBrowser::OnSort()
327 {
328 if (!m_singleList)
329 m_vecItems->Sort(SortByLabel, SortOrderAscending);
330 }
331
Update(const std::string & strDirectory)332 void CGUIDialogFileBrowser::Update(const std::string &strDirectory)
333 {
334 const CURL pathToUrl(strDirectory);
335
336 if (m_browsingForImages && m_thumbLoader.IsLoading())
337 m_thumbLoader.StopThread();
338 // get selected item
339 int iItem = m_viewControl.GetSelectedItem();
340 std::string strSelectedItem;
341 if (iItem >= 0 && iItem < m_vecItems->Size())
342 {
343 CFileItemPtr pItem = (*m_vecItems)[iItem];
344 if (!pItem->IsParentFolder())
345 {
346 strSelectedItem = pItem->GetPath();
347 URIUtils::RemoveSlashAtEnd(strSelectedItem);
348 m_history.SetSelectedItem(strSelectedItem, m_Directory->GetPath().empty()?"empty":m_Directory->GetPath());
349 }
350 }
351
352 if (!m_singleList)
353 {
354 CFileItemList items;
355 std::string strParentPath;
356
357 if (!m_rootDir.GetDirectory(pathToUrl, items, m_useFileDirectories, false))
358 {
359 CLog::Log(LOGERROR,"CGUIDialogFileBrowser::GetDirectory(%s) failed", pathToUrl.GetRedacted().c_str());
360
361 // We assume, we can get the parent
362 // directory again
363 std::string strParentPath = m_history.GetParentPath();
364 m_history.RemoveParentPath();
365 Update(strParentPath);
366 return;
367 }
368
369 // check if current directory is a root share
370 if (!m_rootDir.IsSource(strDirectory))
371 {
372 if (URIUtils::GetParentPath(strDirectory, strParentPath))
373 {
374 CFileItemPtr pItem(new CFileItem(".."));
375 pItem->SetPath(strParentPath);
376 pItem->m_bIsFolder = true;
377 pItem->m_bIsShareOrDrive = false;
378 items.AddFront(pItem, 0);
379 }
380 }
381 else
382 {
383 // yes, this is the root of a share
384 // add parent path to the virtual directory
385 CFileItemPtr pItem(new CFileItem(".."));
386 pItem->SetPath("");
387 pItem->m_bIsShareOrDrive = false;
388 pItem->m_bIsFolder = true;
389 items.AddFront(pItem, 0);
390 strParentPath = "";
391 }
392
393 ClearFileItems();
394 m_vecItems->Copy(items);
395 m_Directory->SetPath(strDirectory);
396 m_strParentPath = strParentPath;
397 }
398
399 // if we're getting the root source listing
400 // make sure the path history is clean
401 if (strDirectory.empty())
402 m_history.ClearPathHistory();
403
404 // some evil stuff don't work with the '/' mask, e.g. shoutcast directory - make sure no files are in there
405 if (m_browsingForFolders)
406 {
407 for (int i=0;i<m_vecItems->Size();++i)
408 if (!(*m_vecItems)[i]->m_bIsFolder)
409 {
410 m_vecItems->Remove(i);
411 i--;
412 }
413 }
414
415 // No need to set thumbs
416
417 m_vecItems->FillInDefaultIcons();
418
419 OnSort();
420
421 if (m_Directory->GetPath().empty() && m_addNetworkShareEnabled &&
422 (CServiceBroker::GetSettingsComponent()->GetProfileManager()->GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE ||
423 CServiceBroker::GetSettingsComponent()->GetProfileManager()->IsMasterProfile() || g_passwordManager.bMasterUser))
424 { // we are in the virtual directory - add the "Add Network Location" item
425 CFileItemPtr pItem(new CFileItem(g_localizeStrings.Get(1032)));
426 pItem->SetPath("net://");
427 pItem->m_bIsFolder = true;
428 m_vecItems->Add(pItem);
429 }
430 if (m_Directory->GetPath().empty() && !m_addSourceType.empty())
431 {
432 CFileItemPtr pItem(new CFileItem(g_localizeStrings.Get(21359)));
433 pItem->SetPath("source://");
434 pItem->m_bIsFolder = true;
435 m_vecItems->Add(pItem);
436 }
437
438 m_viewControl.SetItems(*m_vecItems);
439 m_viewControl.SetCurrentView((m_browsingForImages && CAutoSwitch::ByFileCount(*m_vecItems)) ? CONTROL_THUMBS : CONTROL_LIST);
440
441 std::string strPath2 = m_Directory->GetPath();
442 URIUtils::RemoveSlashAtEnd(strPath2);
443 strSelectedItem = m_history.GetSelectedItem(strPath2==""?"empty":strPath2);
444
445 bool bSelectedFound = false;
446 for (int i = 0; i < m_vecItems->Size(); ++i)
447 {
448 CFileItemPtr pItem = (*m_vecItems)[i];
449 strPath2 = pItem->GetPath();
450 URIUtils::RemoveSlashAtEnd(strPath2);
451 if (strPath2 == strSelectedItem)
452 {
453 m_viewControl.SetSelectedItem(i);
454 bSelectedFound = true;
455 break;
456 }
457 }
458
459 // if we haven't found the selected item, select the first item
460 if (!bSelectedFound)
461 m_viewControl.SetSelectedItem(0);
462
463 m_history.AddPath(m_Directory->GetPath());
464
465 if (m_browsingForImages)
466 m_thumbLoader.Load(*m_vecItems);
467 }
468
FrameMove()469 void CGUIDialogFileBrowser::FrameMove()
470 {
471 int item = m_viewControl.GetSelectedItem();
472 if (item >= 0)
473 {
474 // if we are browsing for folders, and not in the root directory, then we use the parent path,
475 // else we use the current file's path
476 if (m_browsingForFolders && !m_Directory->IsVirtualDirectoryRoot())
477 m_selectedPath = m_Directory->GetPath();
478 else
479 m_selectedPath = (*m_vecItems)[item]->GetPath();
480 if (m_selectedPath == "net://")
481 {
482 SET_CONTROL_LABEL(CONTROL_LABEL_PATH, g_localizeStrings.Get(1032)); // "Add Network Location..."
483 }
484 else
485 {
486 // Update the current path label
487 CURL url(m_selectedPath);
488 std::string safePath = url.GetWithoutUserDetails();
489 SET_CONTROL_LABEL(CONTROL_LABEL_PATH, safePath);
490 }
491 if ((!m_browsingForFolders && (*m_vecItems)[item]->m_bIsFolder) || ((*m_vecItems)[item]->GetPath() == "image://Browse"))
492 {
493 CONTROL_DISABLE(CONTROL_OK);
494 }
495 else
496 {
497 CONTROL_ENABLE(CONTROL_OK);
498 }
499 if (m_browsingForFolders == 2)
500 {
501 CONTROL_ENABLE(CONTROL_NEWFOLDER);
502 }
503 else
504 {
505 CONTROL_DISABLE(CONTROL_NEWFOLDER);
506 }
507 if (m_flipEnabled)
508 {
509 CONTROL_ENABLE(CONTROL_FLIP);
510 }
511 else
512 {
513 CONTROL_DISABLE(CONTROL_FLIP);
514 }
515 }
516 CGUIDialog::FrameMove();
517 }
518
OnClick(int iItem)519 void CGUIDialogFileBrowser::OnClick(int iItem)
520 {
521 if ( iItem < 0 || iItem >= m_vecItems->Size() ) return ;
522 CFileItemPtr pItem = (*m_vecItems)[iItem];
523 std::string strPath = pItem->GetPath();
524
525 if (pItem->m_bIsFolder)
526 {
527 if (pItem->GetPath() == "net://")
528 { // special "Add Network Location" item
529 OnAddNetworkLocation();
530 return;
531 }
532 if (pItem->GetPath() == "source://")
533 { // special "Add Source" item
534 OnAddMediaSource();
535 return;
536 }
537 if (!m_addSourceType.empty())
538 {
539 OnEditMediaSource(pItem.get());
540 return;
541 }
542 if ( pItem->m_bIsShareOrDrive )
543 {
544 if ( !HaveDiscOrConnection( pItem->m_iDriveType ) )
545 return ;
546 }
547 Update(strPath);
548 }
549 else if (!m_browsingForFolders)
550 {
551 m_selectedPath = pItem->GetPath();
552 m_bConfirmed = true;
553 Close();
554 }
555 }
556
HaveDiscOrConnection(int iDriveType)557 bool CGUIDialogFileBrowser::HaveDiscOrConnection( int iDriveType )
558 {
559 if ( iDriveType == CMediaSource::SOURCE_TYPE_DVD )
560 {
561 if (!CServiceBroker::GetMediaManager().IsDiscInDrive())
562 {
563 HELPERS::ShowOKDialogText(CVariant{218}, CVariant{219});
564 return false;
565 }
566 }
567 else if ( iDriveType == CMediaSource::SOURCE_TYPE_REMOTE )
568 {
569 //! @todo Handle not connected to a remote share
570 if ( !CServiceBroker::GetNetwork().IsConnected() )
571 {
572 HELPERS::ShowOKDialogText(CVariant{220}, CVariant{221});
573 return false;
574 }
575 }
576
577 return true;
578 }
579
GoParentFolder()580 void CGUIDialogFileBrowser::GoParentFolder()
581 {
582 std::string strPath(m_strParentPath);
583 if (strPath.size() == 2)
584 if (strPath[1] == ':')
585 URIUtils::AddSlashAtEnd(strPath);
586 Update(strPath);
587 }
588
OnWindowLoaded()589 void CGUIDialogFileBrowser::OnWindowLoaded()
590 {
591 CGUIDialog::OnWindowLoaded();
592 m_viewControl.Reset();
593 m_viewControl.SetParentWindow(GetID());
594 m_viewControl.AddView(GetControl(CONTROL_LIST));
595 m_viewControl.AddView(GetControl(CONTROL_THUMBS));
596 }
597
OnWindowUnload()598 void CGUIDialogFileBrowser::OnWindowUnload()
599 {
600 CGUIDialog::OnWindowUnload();
601 m_viewControl.Reset();
602 }
603
ShowAndGetImage(const CFileItemList & items,const VECSOURCES & shares,const std::string & heading,std::string & result,bool * flip,int label)604 bool CGUIDialogFileBrowser::ShowAndGetImage(const CFileItemList &items, const VECSOURCES &shares, const std::string &heading, std::string &result, bool* flip, int label)
605 {
606 CGUIDialogFileBrowser *browser = new CGUIDialogFileBrowser();
607 if (!browser)
608 return false;
609 CServiceBroker::GetGUI()->GetWindowManager().AddUniqueInstance(browser);
610
611 browser->m_browsingForImages = true;
612 browser->m_singleList = true;
613 browser->m_vecItems->Clear();
614 browser->m_vecItems->Append(items);
615 if (true)
616 {
617 CFileItemPtr item(new CFileItem("image://Browse", false));
618 item->SetLabel(g_localizeStrings.Get(20153));
619 item->SetArt("icon", "DefaultFolder.png");
620 browser->m_vecItems->Add(item);
621 }
622 browser->SetHeading(heading);
623 browser->m_flipEnabled = flip?true:false;
624 browser->Open();
625 bool confirmed(browser->IsConfirmed());
626 if (confirmed)
627 {
628 result = browser->m_selectedPath;
629 if (result == "image://Browse")
630 { // "Browse for thumb"
631 CServiceBroker::GetGUI()->GetWindowManager().Remove(browser->GetID());
632 delete browser;
633 return ShowAndGetImage(shares, g_localizeStrings.Get(label), result);
634 }
635 }
636
637 if (flip)
638 *flip = browser->m_bFlip != 0;
639
640 CServiceBroker::GetGUI()->GetWindowManager().Remove(browser->GetID());
641 delete browser;
642
643 return confirmed;
644 }
645
ShowAndGetImage(const VECSOURCES & shares,const std::string & heading,std::string & path)646 bool CGUIDialogFileBrowser::ShowAndGetImage(const VECSOURCES &shares, const std::string &heading, std::string &path)
647 {
648 return ShowAndGetFile(shares, CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(), heading, path, true); // true for use thumbs
649 }
650
ShowAndGetImageList(const VECSOURCES & shares,const std::string & heading,std::vector<std::string> & path)651 bool CGUIDialogFileBrowser::ShowAndGetImageList(const VECSOURCES &shares, const std::string &heading, std::vector<std::string> &path)
652 {
653 return ShowAndGetFileList(shares, CServiceBroker::GetFileExtensionProvider().GetPictureExtensions(), heading, path, true); // true for use thumbs
654 }
655
ShowAndGetDirectory(const VECSOURCES & shares,const std::string & heading,std::string & path,bool bWriteOnly)656 bool CGUIDialogFileBrowser::ShowAndGetDirectory(const VECSOURCES &shares, const std::string &heading, std::string &path, bool bWriteOnly)
657 {
658 // an extension mask of "/" ensures that no files are shown
659 if (bWriteOnly)
660 {
661 VECSOURCES shareWritable;
662 for (unsigned int i=0;i<shares.size();++i)
663 {
664 if (shares[i].IsWritable())
665 shareWritable.push_back(shares[i]);
666 }
667
668 return ShowAndGetFile(shareWritable, "/w", heading, path);
669 }
670
671 return ShowAndGetFile(shares, "/", heading, path);
672 }
673
ShowAndGetFile(const VECSOURCES & shares,const std::string & mask,const std::string & heading,std::string & path,bool useThumbs,bool useFileDirectories)674 bool CGUIDialogFileBrowser::ShowAndGetFile(const VECSOURCES &shares, const std::string &mask, const std::string &heading, std::string &path, bool useThumbs /* = false */, bool useFileDirectories /* = false */)
675 {
676 CGUIDialogFileBrowser *browser = new CGUIDialogFileBrowser();
677 if (!browser)
678 return false;
679 CServiceBroker::GetGUI()->GetWindowManager().AddUniqueInstance(browser);
680
681 browser->m_useFileDirectories = useFileDirectories;
682
683 browser->m_browsingForImages = useThumbs;
684 browser->SetHeading(heading);
685 browser->SetSources(shares);
686 std::string strMask = mask;
687 if (mask == "/")
688 browser->m_browsingForFolders=1;
689 else
690 if (mask == "/w")
691 {
692 browser->m_browsingForFolders=2;
693 strMask = "/";
694 }
695 else
696 browser->m_browsingForFolders = 0;
697
698 browser->m_rootDir.SetMask(strMask);
699 browser->m_selectedPath = path;
700 browser->m_addNetworkShareEnabled = false;
701 browser->Open();
702 bool confirmed(browser->IsConfirmed());
703 if (confirmed)
704 path = browser->m_selectedPath;
705 CServiceBroker::GetGUI()->GetWindowManager().Remove(browser->GetID());
706 delete browser;
707 return confirmed;
708 }
709
710 // same as above, starting in a single directory
ShowAndGetFile(const std::string & directory,const std::string & mask,const std::string & heading,std::string & path,bool useThumbs,bool useFileDirectories,bool singleList)711 bool CGUIDialogFileBrowser::ShowAndGetFile(const std::string &directory, const std::string &mask, const std::string &heading, std::string &path, bool useThumbs /* = false */, bool useFileDirectories /* = false */, bool singleList /* = false */)
712 {
713 CGUIDialogFileBrowser *browser = new CGUIDialogFileBrowser();
714 if (!browser)
715 return false;
716 CServiceBroker::GetGUI()->GetWindowManager().AddUniqueInstance(browser);
717
718 browser->m_useFileDirectories = useFileDirectories;
719 browser->m_browsingForImages = useThumbs;
720 browser->SetHeading(heading);
721
722 // add a single share for this directory
723 if (!singleList)
724 {
725 VECSOURCES shares;
726 CMediaSource share;
727 share.strPath = directory;
728 URIUtils::RemoveSlashAtEnd(share.strPath); // this is needed for the dodgy code in WINDOW_INIT
729 shares.push_back(share);
730 browser->SetSources(shares);
731 }
732 else
733 {
734 browser->m_vecItems->Clear();
735 CDirectory::GetDirectory(directory,*browser->m_vecItems, "", DIR_FLAG_DEFAULTS);
736 CFileItemPtr item(new CFileItem("file://Browse", false));
737 item->SetLabel(g_localizeStrings.Get(20153));
738 item->SetArt("icon", "DefaultFolder.png");
739 browser->m_vecItems->Add(item);
740 browser->m_singleList = true;
741 }
742 std::string strMask = mask;
743 if (mask == "/")
744 browser->m_browsingForFolders=1;
745 else
746 if (mask == "/w")
747 {
748 browser->m_browsingForFolders=2;
749 strMask = "/";
750 }
751 else
752 browser->m_browsingForFolders = 0;
753
754 browser->m_rootDir.SetMask(strMask);
755 browser->m_selectedPath = directory;
756 browser->m_addNetworkShareEnabled = false;
757 browser->Open();
758 bool confirmed(browser->IsConfirmed());
759 if (confirmed)
760 path = browser->m_selectedPath;
761 if (path == "file://Browse")
762 { // "Browse for thumb"
763 CServiceBroker::GetGUI()->GetWindowManager().Remove(browser->GetID());
764 delete browser;
765 VECSOURCES shares;
766 CServiceBroker::GetMediaManager().GetLocalDrives(shares);
767
768 return ShowAndGetFile(shares, mask, heading, path, useThumbs,useFileDirectories);
769 }
770 CServiceBroker::GetGUI()->GetWindowManager().Remove(browser->GetID());
771 delete browser;
772 return confirmed;
773 }
774
ShowAndGetFileList(const VECSOURCES & shares,const std::string & mask,const std::string & heading,std::vector<std::string> & path,bool useThumbs,bool useFileDirectories)775 bool CGUIDialogFileBrowser::ShowAndGetFileList(const VECSOURCES &shares, const std::string &mask, const std::string &heading, std::vector<std::string> &path, bool useThumbs /* = false */, bool useFileDirectories /* = false */)
776 {
777 CGUIDialogFileBrowser *browser = new CGUIDialogFileBrowser();
778 if (!browser)
779 return false;
780 CServiceBroker::GetGUI()->GetWindowManager().AddUniqueInstance(browser);
781
782 browser->m_useFileDirectories = useFileDirectories;
783 browser->m_multipleSelection = true;
784 browser->m_browsingForImages = useThumbs;
785 browser->SetHeading(heading);
786 browser->SetSources(shares);
787 browser->m_browsingForFolders = 0;
788 browser->m_rootDir.SetMask(mask);
789 browser->m_addNetworkShareEnabled = false;
790 browser->Open();
791 bool confirmed(browser->IsConfirmed());
792 if (confirmed)
793 {
794 if (browser->m_markedPath.size())
795 path = browser->m_markedPath;
796 else
797 path.push_back(browser->m_selectedPath);
798 }
799 CServiceBroker::GetGUI()->GetWindowManager().Remove(browser->GetID());
800 delete browser;
801 return confirmed;
802 }
803
SetHeading(const std::string & heading)804 void CGUIDialogFileBrowser::SetHeading(const std::string &heading)
805 {
806 Initialize();
807 SET_CONTROL_LABEL(CONTROL_HEADING_LABEL, heading);
808 }
809
ShowAndGetSource(std::string & path,bool allowNetworkShares,VECSOURCES * additionalShare,const std::string & strType)810 bool CGUIDialogFileBrowser::ShowAndGetSource(std::string &path, bool allowNetworkShares, VECSOURCES* additionalShare /* = NULL */, const std::string& strType /* = "" */)
811 {
812 // Technique is
813 // 1. Show Filebrowser with currently defined local, and optionally the network locations.
814 // 2. Have the "Add Network Location" option in addition.
815 // 3a. If the "Add Network Location" is pressed, then:
816 // a) Fire up the network location dialog to grab the new location
817 // b) Check the location by doing a GetDirectory() - if it fails, prompt the user
818 // to allow them to add currently disconnected network shares.
819 // c) Save this location to our xml file (network.xml)
820 // d) Return to 1.
821 // 3b. If the "Add Source" is pressed, then:
822 // a) Fire up the media source dialog to add the new location
823 // 4. Optionally allow user to browse the local and network locations for their share.
824 // 5. On OK, return.
825
826 // Create a new filebrowser window
827 CGUIDialogFileBrowser *browser = new CGUIDialogFileBrowser();
828 if (!browser) return false;
829
830 // Add it to our window manager
831 CServiceBroker::GetGUI()->GetWindowManager().AddUniqueInstance(browser);
832
833 VECSOURCES shares;
834 if (!strType.empty())
835 {
836 if (additionalShare)
837 shares = *additionalShare;
838 browser->m_addSourceType = strType;
839 }
840 else
841 {
842 browser->SetHeading(g_localizeStrings.Get(1023));
843
844 CServiceBroker::GetMediaManager().GetLocalDrives(shares);
845
846 // Now the additional share if appropriate
847 if (additionalShare)
848 {
849 shares.insert(shares.end(),additionalShare->begin(),additionalShare->end());
850 }
851
852 // Now add the network shares...
853 if (allowNetworkShares)
854 {
855 CServiceBroker::GetMediaManager().GetNetworkLocations(shares);
856 }
857 }
858
859 browser->SetSources(shares);
860 browser->m_rootDir.SetMask("/");
861 browser->m_rootDir.AllowNonLocalSources(false); // don't allow plug n play shares
862 browser->m_browsingForFolders = 1;
863 browser->m_addNetworkShareEnabled = allowNetworkShares;
864 browser->m_selectedPath = "";
865 browser->Open();
866 bool confirmed = browser->IsConfirmed();
867 if (confirmed)
868 path = browser->m_selectedPath;
869
870 CServiceBroker::GetGUI()->GetWindowManager().Remove(browser->GetID());
871 delete browser;
872 return confirmed;
873 }
874
SetSources(const VECSOURCES & shares)875 void CGUIDialogFileBrowser::SetSources(const VECSOURCES &shares)
876 {
877 m_shares = shares;
878 if (!m_shares.size() && m_addSourceType.empty())
879 CServiceBroker::GetMediaManager().GetLocalDrives(m_shares);
880 m_rootDir.SetSources(m_shares);
881 }
882
OnAddNetworkLocation()883 void CGUIDialogFileBrowser::OnAddNetworkLocation()
884 {
885 // ok, fire up the network location dialog
886 std::string path;
887 if (CGUIDialogNetworkSetup::ShowAndGetNetworkAddress(path))
888 {
889 // verify the path by doing a GetDirectory.
890 CFileItemList items;
891 if (CDirectory::GetDirectory(path, items, "", DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_ALLOW_PROMPT) || CGUIDialogYesNo::ShowAndGetInput(CVariant{1001}, CVariant{1002}))
892 { // add the network location to the shares list
893 CMediaSource share;
894 share.strPath = path; //setPath(path);
895 CURL url(path);
896 share.strName = url.GetWithoutUserDetails();
897 URIUtils::RemoveSlashAtEnd(share.strName);
898 m_shares.push_back(share);
899 // add to our location manager...
900 CServiceBroker::GetMediaManager().AddNetworkLocation(path);
901 }
902 }
903 m_rootDir.SetSources(m_shares);
904 Update(m_vecItems->GetPath());
905 }
906
OnAddMediaSource()907 void CGUIDialogFileBrowser::OnAddMediaSource()
908 {
909 if (CGUIDialogMediaSource::ShowAndAddMediaSource(m_addSourceType))
910 {
911 SetSources(*CMediaSourceSettings::GetInstance().GetSources(m_addSourceType));
912 Update("");
913 }
914 }
915
OnEditMediaSource(CFileItem * pItem)916 void CGUIDialogFileBrowser::OnEditMediaSource(CFileItem* pItem)
917 {
918 if (CGUIDialogMediaSource::ShowAndEditMediaSource(m_addSourceType,pItem->GetLabel()))
919 {
920 SetSources(*CMediaSourceSettings::GetInstance().GetSources(m_addSourceType));
921 Update("");
922 }
923 }
924
OnPopupMenu(int iItem)925 bool CGUIDialogFileBrowser::OnPopupMenu(int iItem)
926 {
927 CContextButtons choices;
928 choices.Add(1, m_addSourceType.empty() ? 20133 : 21364);
929 choices.Add(2, m_addSourceType.empty() ? 20134 : 21365);
930
931 int btnid = CGUIDialogContextMenu::ShowAndGetChoice(choices);
932 if (btnid == 1)
933 {
934 if (m_addNetworkShareEnabled)
935 {
936 std::string strOldPath=m_selectedPath,newPath=m_selectedPath;
937 VECSOURCES shares=m_shares;
938 if (CGUIDialogNetworkSetup::ShowAndGetNetworkAddress(newPath))
939 {
940 CServiceBroker::GetMediaManager().SetLocationPath(strOldPath, newPath);
941 CURL url(newPath);
942 for (unsigned int i=0;i<shares.size();++i)
943 {
944 if (URIUtils::CompareWithoutSlashAtEnd(shares[i].strPath, strOldPath))//getPath().Equals(strOldPath))
945 {
946 shares[i].strName = url.GetWithoutUserDetails();
947 shares[i].strPath = newPath;
948 URIUtils::RemoveSlashAtEnd(shares[i].strName);
949 break;
950 }
951 }
952 // refresh dialog content
953 SetSources(shares);
954 m_rootDir.SetMask("/");
955 m_browsingForFolders = 1;
956 m_addNetworkShareEnabled = true;
957 m_selectedPath = url.GetWithoutUserDetails();
958 Update(m_Directory->GetPath());
959 m_viewControl.SetSelectedItem(iItem);
960 }
961 }
962 else
963 {
964 CFileItemPtr item = m_vecItems->Get(iItem);
965 OnEditMediaSource(item.get());
966 }
967 }
968 if (btnid == 2)
969 {
970 if (m_addNetworkShareEnabled)
971 {
972 CServiceBroker::GetMediaManager().RemoveLocation(m_selectedPath);
973
974 for (unsigned int i=0;i<m_shares.size();++i)
975 {
976 if (URIUtils::CompareWithoutSlashAtEnd(m_shares[i].strPath, m_selectedPath) && !m_shares[i].m_ignore) // getPath().Equals(m_selectedPath))
977 {
978 m_shares.erase(m_shares.begin()+i);
979 break;
980 }
981 }
982 m_rootDir.SetSources(m_shares);
983 m_rootDir.SetMask("/");
984
985 m_browsingForFolders = 1;
986 m_addNetworkShareEnabled = true;
987 m_selectedPath = "";
988
989 Update(m_Directory->GetPath());
990 }
991 else
992 {
993 CMediaSourceSettings::GetInstance().DeleteSource(m_addSourceType,(*m_vecItems)[iItem]->GetLabel(),(*m_vecItems)[iItem]->GetPath());
994 SetSources(*CMediaSourceSettings::GetInstance().GetSources(m_addSourceType));
995 Update("");
996 }
997 }
998
999 return true;
1000 }
1001
GetCurrentListItem(int offset)1002 CFileItemPtr CGUIDialogFileBrowser::GetCurrentListItem(int offset)
1003 {
1004 int item = m_viewControl.GetSelectedItem();
1005 if (item < 0 || !m_vecItems->Size()) return CFileItemPtr();
1006
1007 item = (item + offset) % m_vecItems->Size();
1008 if (item < 0) item += m_vecItems->Size();
1009 return (*m_vecItems)[item];
1010 }
1011
GetFirstFocusableControl(int id)1012 CGUIControl *CGUIDialogFileBrowser::GetFirstFocusableControl(int id)
1013 {
1014 if (m_viewControl.HasControl(id))
1015 id = m_viewControl.GetCurrentControl();
1016 return CGUIWindow::GetFirstFocusableControl(id);
1017 }
1018
1019
1020