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