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