Merge pull request #1580 from asylumfunk/js-house-cleaning
[vuplus_xbmc] / xbmc / pictures / GUIWindowPictures.cpp
1 /*
2  *      Copyright (C) 2005-2012 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 "threads/SystemClock.h"
22 #include "system.h"
23 #include "GUIWindowPictures.h"
24 #include "URL.h"
25 #include "Util.h"
26 #include "Application.h"
27 #include "GUIPassword.h"
28 #include "dialogs/GUIDialogMediaSource.h"
29 #include "GUIDialogPictureInfo.h"
30 #include "addons/GUIDialogAddonInfo.h"
31 #include "dialogs/GUIDialogProgress.h"
32 #include "playlists/PlayListFactory.h"
33 #include "PictureInfoLoader.h"
34 #include "guilib/GUIWindowManager.h"
35 #include "dialogs/GUIDialogOK.h"
36 #include "dialogs/GUIDialogYesNo.h"
37 #include "playlists/PlayList.h"
38 #include "settings/Settings.h"
39 #include "settings/GUISettings.h"
40 #include "utils/TimeUtils.h"
41 #include "utils/log.h"
42 #include "utils/URIUtils.h"
43 #include "Autorun.h"
44
45 #define CONTROL_BTNVIEWASICONS      2
46 #define CONTROL_BTNSORTBY           3
47 #define CONTROL_BTNSORTASC          4
48 #define CONTROL_LABELFILES         12
49
50 using namespace std;
51 using namespace XFILE;
52 using namespace PLAYLIST;
53
54 #define CONTROL_BTNSLIDESHOW   6
55 #define CONTROL_BTNSLIDESHOW_RECURSIVE   7
56 #define CONTROL_SHUFFLE      9
57
58 CGUIWindowPictures::CGUIWindowPictures(void)
59     : CGUIMediaWindow(WINDOW_PICTURES, "MyPics.xml")
60 {
61   m_thumbLoader.SetObserver(this);
62   m_slideShowStarted = false;
63 }
64
65 void CGUIWindowPictures::OnInitWindow()
66 {
67   CGUIMediaWindow::OnInitWindow();
68   if (m_slideShowStarted)
69   {
70     CGUIWindowSlideShow* wndw = (CGUIWindowSlideShow*)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
71     CStdString path;
72     if (wndw && wndw->GetCurrentSlide())
73       URIUtils::GetDirectory(wndw->GetCurrentSlide()->GetPath(),path);
74     if (path.Equals(m_vecItems->GetPath()))
75     {
76       if (wndw && wndw->GetCurrentSlide())
77         m_viewControl.SetSelectedItem(wndw->GetCurrentSlide()->GetPath());
78       m_iSelectedItem = m_viewControl.GetSelectedItem();
79     }
80     m_slideShowStarted = false;
81   }
82 }
83
84 CGUIWindowPictures::~CGUIWindowPictures(void)
85 {
86 }
87
88 bool CGUIWindowPictures::OnMessage(CGUIMessage& message)
89 {
90   switch ( message.GetMessage() )
91   {
92   case GUI_MSG_WINDOW_DEINIT:
93     {
94       if (m_thumbLoader.IsLoading())
95         m_thumbLoader.StopThread();
96
97       if (message.GetParam1() != WINDOW_SLIDESHOW)
98       {
99         m_ImageLib.Unload();
100       }
101     }
102     break;
103
104   case GUI_MSG_WINDOW_INIT:
105     {
106       // is this the first time accessing this window?
107       if (m_vecItems->GetPath() == "?" && message.GetStringParam().IsEmpty())
108         message.SetStringParam(g_settings.m_defaultPictureSource);
109
110       m_dlgProgress = (CGUIDialogProgress*)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
111
112       if (message.GetParam1() != WINDOW_SLIDESHOW)
113       {
114         m_ImageLib.Load();
115       }
116
117       if (!CGUIMediaWindow::OnMessage(message))
118         return false;
119
120       return true;
121     }
122     break;
123
124   case GUI_MSG_CLICKED:
125     {
126       int iControl = message.GetSenderId();
127       if (iControl == CONTROL_BTNSLIDESHOW) // Slide Show
128       {
129         OnSlideShow();
130       }
131       else if (iControl == CONTROL_BTNSLIDESHOW_RECURSIVE) // Recursive Slide Show
132       {
133         OnSlideShowRecursive();
134       }
135       else if (iControl == CONTROL_SHUFFLE)
136       {
137         g_guiSettings.ToggleBool("slideshow.shuffle");
138         g_settings.Save();
139       }
140       else if (m_viewControl.HasControl(iControl))  // list/thumb control
141       {
142         int iItem = m_viewControl.GetSelectedItem();
143         int iAction = message.GetParam1();
144
145         // iItem is checked for validity inside these routines
146         if (iAction == ACTION_DELETE_ITEM)
147         {
148           // is delete allowed?
149           if (g_guiSettings.GetBool("filelists.allowfiledeletion"))
150             OnDeleteItem(iItem);
151           else
152             return false;
153         }
154         else if (iAction == ACTION_PLAYER_PLAY)
155         {
156           ShowPicture(iItem, true);
157           return true;
158         }
159         else if (iAction == ACTION_SHOW_INFO)
160         {
161           OnInfo(iItem);
162           return true;
163         }
164       }
165     }
166     break;
167   }
168   return CGUIMediaWindow::OnMessage(message);
169 }
170
171 void CGUIWindowPictures::UpdateButtons()
172 {
173   CGUIMediaWindow::UpdateButtons();
174
175   // Update the shuffle button
176   if (g_guiSettings.GetBool("slideshow.shuffle"))
177   {
178     CGUIMessage msg2(GUI_MSG_SELECTED, GetID(), CONTROL_SHUFFLE);
179     g_windowManager.SendMessage(msg2);
180   }
181   else
182   {
183     CGUIMessage msg2(GUI_MSG_DESELECTED, GetID(), CONTROL_SHUFFLE);
184     g_windowManager.SendMessage(msg2);
185   }
186
187   // check we can slideshow or recursive slideshow
188   int nFolders = m_vecItems->GetFolderCount();
189   if (nFolders == m_vecItems->Size())
190   {
191     CONTROL_DISABLE(CONTROL_BTNSLIDESHOW);
192   }
193   else
194   {
195     CONTROL_ENABLE(CONTROL_BTNSLIDESHOW);
196   }
197   if (m_guiState.get() && !m_guiState->HideParentDirItems())
198     nFolders--;
199   if (m_vecItems->Size() == 0 || nFolders == 0)
200   {
201     CONTROL_DISABLE(CONTROL_BTNSLIDESHOW_RECURSIVE);
202   }
203   else
204   {
205     CONTROL_ENABLE(CONTROL_BTNSLIDESHOW_RECURSIVE);
206   }
207 }
208
209 void CGUIWindowPictures::OnPrepareFileItems(CFileItemList& items)
210 {
211   for (int i=0;i<items.Size();++i )
212     if (items[i]->GetLabel().Equals("folder.jpg"))
213       items.Remove(i);
214
215   if (items.GetFolderCount()==items.Size() || !g_guiSettings.GetBool("pictures.usetags"))
216     return;
217
218   // Start the music info loader thread
219   CPictureInfoLoader loader;
220   loader.SetProgressCallback(m_dlgProgress);
221   loader.Load(items);
222
223   bool bShowProgress=!g_windowManager.HasModalDialog();
224   bool bProgressVisible=false;
225
226   unsigned int tick=XbmcThreads::SystemClockMillis();
227
228   while (loader.IsLoading() && m_dlgProgress && !m_dlgProgress->IsCanceled())
229   {
230     if (bShowProgress)
231     { // Do we have to init a progress dialog?
232       unsigned int elapsed=XbmcThreads::SystemClockMillis()-tick;
233
234       if (!bProgressVisible && elapsed>1500 && m_dlgProgress)
235       { // tag loading takes more then 1.5 secs, show a progress dialog
236         CURL url(items.GetPath());
237
238         m_dlgProgress->SetHeading(189);
239         m_dlgProgress->SetLine(0, 505);
240         m_dlgProgress->SetLine(1, "");
241         m_dlgProgress->SetLine(2, url.GetWithoutUserDetails());
242         m_dlgProgress->StartModal();
243         m_dlgProgress->ShowProgressBar(true);
244         bProgressVisible = true;
245       }
246
247       if (bProgressVisible && m_dlgProgress)
248       { // keep GUI alive
249         m_dlgProgress->Progress();
250       }
251     } // if (bShowProgress)
252     Sleep(1);
253   } // while (loader.IsLoading())
254
255   if (bProgressVisible && m_dlgProgress)
256     m_dlgProgress->Close();
257 }
258
259 bool CGUIWindowPictures::Update(const CStdString &strDirectory)
260 {
261   if (m_thumbLoader.IsLoading())
262     m_thumbLoader.StopThread();
263
264   if (!CGUIMediaWindow::Update(strDirectory))
265     return false;
266
267   m_vecItems->SetThumbnailImage("");
268   if (g_guiSettings.GetBool("pictures.generatethumbs"))
269     m_thumbLoader.Load(*m_vecItems);
270   m_vecItems->SetThumbnailImage(CPictureThumbLoader::GetCachedImage(*m_vecItems, "thumb"));
271
272   return true;
273 }
274
275 bool CGUIWindowPictures::OnClick(int iItem)
276 {
277   if ( iItem < 0 || iItem >= (int)m_vecItems->Size() ) return true;
278   CFileItemPtr pItem = m_vecItems->Get(iItem);
279
280   if (pItem->IsCBZ() || pItem->IsCBR())
281   {
282     CStdString strComicPath;
283     if (pItem->IsCBZ())
284       URIUtils::CreateArchivePath(strComicPath, "zip", pItem->GetPath(), "");
285     else
286       URIUtils::CreateArchivePath(strComicPath, "rar", pItem->GetPath(), "");
287
288     OnShowPictureRecursive(strComicPath);
289     return true;
290   }
291   else if (CGUIMediaWindow::OnClick(iItem))
292     return true;
293
294   return false;
295 }
296
297 bool CGUIWindowPictures::GetDirectory(const CStdString &strDirectory, CFileItemList& items)
298 {
299   if (!CGUIMediaWindow::GetDirectory(strDirectory, items))
300     return false;
301
302   CStdString label;
303   if (items.GetLabel().IsEmpty() && m_rootDir.IsSource(items.GetPath(), g_settings.GetSourcesFromType("pictures"), &label)) 
304     items.SetLabel(label);
305
306   return true;
307 }
308
309 bool CGUIWindowPictures::OnPlayMedia(int iItem)
310 {
311   if (m_vecItems->Get(iItem)->IsVideo())
312     return CGUIMediaWindow::OnPlayMedia(iItem);
313
314   return ShowPicture(iItem, false);
315 }
316
317 bool CGUIWindowPictures::ShowPicture(int iItem, bool startSlideShow)
318 {
319   if ( iItem < 0 || iItem >= (int)m_vecItems->Size() ) return false;
320   CFileItemPtr pItem = m_vecItems->Get(iItem);
321   CStdString strPicture = pItem->GetPath();
322
323 #ifdef HAS_DVD_DRIVE
324   if (pItem->IsDVD())
325     return MEDIA_DETECT::CAutorun::PlayDiscAskResume(m_vecItems->Get(iItem)->GetPath());
326 #endif
327
328   if (pItem->m_bIsShareOrDrive)
329     return false;
330
331   CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
332   if (!pSlideShow)
333     return false;
334   if (g_application.IsPlayingVideo())
335     g_application.StopPlaying();
336
337   pSlideShow->Reset();
338   for (int i = 0; i < (int)m_vecItems->Size();++i)
339   {
340     CFileItemPtr pItem = m_vecItems->Get(i);
341     if (!pItem->m_bIsFolder && !(URIUtils::IsRAR(pItem->GetPath()) || 
342           URIUtils::IsZIP(pItem->GetPath())) && (pItem->IsPicture() || (
343                                 g_guiSettings.GetBool("pictures.showvideos") &&
344                                 pItem->IsVideo())))
345     {
346       pSlideShow->Add(pItem.get());
347     }
348   }
349
350   if (pSlideShow->NumSlides() == 0)
351     return false;
352
353   pSlideShow->Select(strPicture);
354
355   if (startSlideShow)
356     pSlideShow->StartSlideShow(false);
357
358   m_slideShowStarted = true;
359   g_windowManager.ActivateWindow(WINDOW_SLIDESHOW);
360
361   return true;
362 }
363
364 void CGUIWindowPictures::OnShowPictureRecursive(const CStdString& strPath)
365 {
366   CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
367   if (pSlideShow)
368   {
369     // stop any video
370     if (g_application.IsPlayingVideo())
371       g_application.StopPlaying();
372     pSlideShow->AddFromPath(strPath, true,
373                             m_guiState->GetSortMethod(),
374                             m_guiState->GetSortOrder());
375     if (pSlideShow->NumSlides())
376     {
377       m_slideShowStarted = true;
378       g_windowManager.ActivateWindow(WINDOW_SLIDESHOW);
379     }
380   }
381 }
382
383 void CGUIWindowPictures::OnSlideShowRecursive(const CStdString &strPicture)
384 {
385   CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
386   if (pSlideShow)
387   {   
388     CStdString strExtensions;
389     CFileItemList items;
390     CGUIViewState* viewState=CGUIViewState::GetViewState(GetID(), items);
391     if (viewState)
392     {
393       strExtensions = viewState->GetExtensions();
394       delete viewState;
395     }
396     m_slideShowStarted = true;
397     pSlideShow->RunSlideShow(strPicture, true,
398                              g_guiSettings.GetBool("slideshow.shuffle"),false,
399                              m_guiState->GetSortMethod(),
400                              m_guiState->GetSortOrder(),
401                              strExtensions);
402   }
403 }
404
405 void CGUIWindowPictures::OnSlideShowRecursive()
406 {
407   CStdString strEmpty = "";
408   OnSlideShowRecursive(m_vecItems->GetPath());
409 }
410
411 void CGUIWindowPictures::OnSlideShow()
412 {
413   OnSlideShow(m_vecItems->GetPath());
414 }
415
416 void CGUIWindowPictures::OnSlideShow(const CStdString &strPicture)
417 {
418   CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
419   if (pSlideShow)
420   {    
421     CStdString strExtensions;
422     CFileItemList items;
423     CGUIViewState* viewState=CGUIViewState::GetViewState(GetID(), items);
424     if (viewState)
425     {
426       strExtensions = viewState->GetExtensions();
427       delete viewState;
428     }
429     m_slideShowStarted = true;
430     pSlideShow->RunSlideShow(strPicture, false ,false, false,
431                              m_guiState->GetSortMethod(),
432                              m_guiState->GetSortOrder(),
433                              strExtensions);
434   }
435 }
436
437 void CGUIWindowPictures::OnRegenerateThumbs()
438 {
439   if (m_thumbLoader.IsLoading()) return;
440   m_thumbLoader.SetRegenerateThumbs(true);
441   m_thumbLoader.Load(*m_vecItems);
442 }
443
444 void CGUIWindowPictures::GetContextButtons(int itemNumber, CContextButtons &buttons)
445 {
446   CFileItemPtr item;
447   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
448     item = m_vecItems->Get(itemNumber);
449
450   if (item && !item->GetProperty("pluginreplacecontextitems").asBoolean())
451   {
452     if ( m_vecItems->IsVirtualDirectoryRoot() && item)
453     {
454       CGUIDialogContextMenu::GetContextButtons("pictures", item, buttons);
455     }
456     else
457     {
458       if (item && !item->GetPath().Left(14).Equals("addons://more/"))
459       {
460         if (!m_vecItems->IsPlugin() && (item->IsPlugin() || item->IsScript()))
461           buttons.Add(CONTEXT_BUTTON_INFO, 24003); // Add-on info
462         if (!(item->m_bIsFolder || item->IsZIP() || item->IsRAR() || item->IsCBZ() || item->IsCBR() || item->IsScript()))
463         {
464           buttons.Add(CONTEXT_BUTTON_INFO, 13406); // picture info
465           buttons.Add(CONTEXT_BUTTON_VIEW_SLIDESHOW, item->m_bIsFolder ? 13317 : 13422);      // View Slideshow
466         }
467         if (item->m_bIsFolder)
468           buttons.Add(CONTEXT_BUTTON_RECURSIVE_SLIDESHOW, 13318);     // Recursive Slideshow
469
470         if (!m_thumbLoader.IsLoading())
471           buttons.Add(CONTEXT_BUTTON_REFRESH_THUMBS, 13315);         // Create Thumbnails
472         if (g_guiSettings.GetBool("filelists.allowfiledeletion") && !item->IsReadOnly())
473         {
474           buttons.Add(CONTEXT_BUTTON_DELETE, 117);
475           buttons.Add(CONTEXT_BUTTON_RENAME, 118);
476         }
477       }
478
479       if (item->IsPlugin() || item->IsScript() || m_vecItems->IsPlugin())
480         buttons.Add(CONTEXT_BUTTON_PLUGIN_SETTINGS, 1045);
481       else
482       {
483         buttons.Add(CONTEXT_BUTTON_GOTO_ROOT, 20128);
484         buttons.Add(CONTEXT_BUTTON_SWITCH_MEDIA, 523);
485       }
486     }
487   }
488   CGUIMediaWindow::GetContextButtons(itemNumber, buttons);
489   if (item && !item->GetProperty("pluginreplacecontextitems").asBoolean())
490     buttons.Add(CONTEXT_BUTTON_SETTINGS, 5);                  // Settings
491 }
492
493 bool CGUIWindowPictures::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
494 {
495   CFileItemPtr item = (itemNumber >= 0 && itemNumber < m_vecItems->Size()) ? m_vecItems->Get(itemNumber) : CFileItemPtr();
496   if (m_vecItems->IsVirtualDirectoryRoot() && item)
497   {
498     if (CGUIDialogContextMenu::OnContextButton("pictures", item, button))
499     {
500       Update("");
501       return true;
502     }
503   }
504   switch (button)
505   {
506   case CONTEXT_BUTTON_VIEW_SLIDESHOW:
507     if (item && item->m_bIsFolder)
508       OnSlideShow(item->GetPath());
509     else
510       ShowPicture(itemNumber, true);
511     return true;
512   case CONTEXT_BUTTON_RECURSIVE_SLIDESHOW:
513     if (item)
514       OnSlideShowRecursive(item->GetPath());
515     return true;
516   case CONTEXT_BUTTON_INFO:
517     OnInfo(itemNumber);
518     return true;
519   case CONTEXT_BUTTON_REFRESH_THUMBS:
520     OnRegenerateThumbs();
521     return true;
522   case CONTEXT_BUTTON_DELETE:
523     OnDeleteItem(itemNumber);
524     return true;
525   case CONTEXT_BUTTON_RENAME:
526     OnRenameItem(itemNumber);
527     return true;
528   case CONTEXT_BUTTON_SETTINGS:
529     g_windowManager.ActivateWindow(WINDOW_SETTINGS_MYPICTURES);
530     return true;
531   case CONTEXT_BUTTON_GOTO_ROOT:
532     Update("");
533     return true;
534   case CONTEXT_BUTTON_SWITCH_MEDIA:
535     CGUIDialogContextMenu::SwitchMedia("pictures", m_vecItems->GetPath());
536     return true;
537   default:
538     break;
539   }
540   return CGUIMediaWindow::OnContextButton(itemNumber, button);
541 }
542
543 void CGUIWindowPictures::OnItemLoaded(CFileItem *pItem)
544 {
545   CPictureThumbLoader::ProcessFoldersAndArchives(pItem);
546 }
547
548 void CGUIWindowPictures::LoadPlayList(const CStdString& strPlayList)
549 {
550   CLog::Log(LOGDEBUG,"CGUIWindowPictures::LoadPlayList()... converting playlist into slideshow: %s", strPlayList.c_str());
551   auto_ptr<CPlayList> pPlayList (CPlayListFactory::Create(strPlayList));
552   if ( NULL != pPlayList.get())
553   {
554     if (!pPlayList->Load(strPlayList))
555     {
556       CGUIDialogOK::ShowAndGetInput(6, 0, 477, 0);
557       return ; //hmmm unable to load playlist?
558     }
559   }
560
561   CPlayList playlist = *pPlayList;
562   if (playlist.size() > 0)
563   {
564     // set up slideshow
565     CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
566     if (!pSlideShow)
567       return;
568     if (g_application.IsPlayingVideo())
569       g_application.StopPlaying();
570
571     // convert playlist items into slideshow items
572     pSlideShow->Reset();
573     for (int i = 0; i < (int)playlist.size(); ++i)
574     {
575       CFileItemPtr pItem = playlist[i];
576       //CLog::Log(LOGDEBUG,"-- playlist item: %s", pItem->GetPath().c_str());
577       if (pItem->IsPicture() && !(pItem->IsZIP() || pItem->IsRAR() || pItem->IsCBZ() || pItem->IsCBR()))
578         pSlideShow->Add(pItem.get());
579     }
580
581     // start slideshow if there are items
582     pSlideShow->StartSlideShow();
583     if (pSlideShow->NumSlides())
584       g_windowManager.ActivateWindow(WINDOW_SLIDESHOW);
585   }
586 }
587
588 void CGUIWindowPictures::OnInfo(int itemNumber)
589 {
590   CFileItemPtr item = (itemNumber >= 0 && itemNumber < m_vecItems->Size()) ? m_vecItems->Get(itemNumber) : CFileItemPtr();
591   if (!item)
592     return;
593   if (!m_vecItems->IsPlugin() && (item->IsPlugin() || item->IsScript()))
594   {
595     CGUIDialogAddonInfo::ShowForItem(item);
596     return;
597   }
598   if (item->m_bIsFolder || item->IsZIP() || item->IsRAR() || item->IsCBZ() || item->IsCBR() || !item->IsPicture())
599     return;
600   CGUIDialogPictureInfo *pictureInfo = (CGUIDialogPictureInfo *)g_windowManager.GetWindow(WINDOW_DIALOG_PICTURE_INFO);
601   if (pictureInfo)
602   {
603     pictureInfo->SetPicture(item.get());
604     pictureInfo->DoModal();
605   }
606 }
607
608 CStdString CGUIWindowPictures::GetStartFolder(const CStdString &dir)
609 {
610   if (dir.Equals("Plugins") || dir.Equals("Addons"))
611     return "addons://sources/image/";
612
613   SetupShares();
614   VECSOURCES shares;
615   m_rootDir.GetSources(shares);
616   bool bIsSourceName = false;
617   int iIndex = CUtil::GetMatchingSource(dir, shares, bIsSourceName);
618   if (iIndex > -1)
619   {
620     if (iIndex < (int)shares.size() && shares[iIndex].m_iHasLock == 2)
621     {
622       CFileItem item(shares[iIndex]);
623       if (!g_passwordManager.IsItemUnlocked(&item,"pictures"))
624         return "";
625     }
626     if (bIsSourceName)
627       return shares[iIndex].strPath;
628     return dir;
629   }
630   return CGUIMediaWindow::GetStartFolder(dir);
631 }