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