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