2 * Copyright (C) 2005-2012 Team XBMC
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)
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.
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/>.
21 #include "threads/SystemClock.h"
23 #include "GUIWindowPictures.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"
44 #include "interfaces/AnnouncementManager.h"
46 #define CONTROL_BTNVIEWASICONS 2
47 #define CONTROL_BTNSORTBY 3
48 #define CONTROL_BTNSORTASC 4
49 #define CONTROL_LABELFILES 12
52 using namespace XFILE;
53 using namespace PLAYLIST;
55 #define CONTROL_BTNSLIDESHOW 6
56 #define CONTROL_BTNSLIDESHOW_RECURSIVE 7
57 #define CONTROL_SHUFFLE 9
59 CGUIWindowPictures::CGUIWindowPictures(void)
60 : CGUIMediaWindow(WINDOW_PICTURES, "MyPics.xml")
62 m_thumbLoader.SetObserver(this);
63 m_slideShowStarted = false;
66 void CGUIWindowPictures::OnInitWindow()
68 CGUIMediaWindow::OnInitWindow();
69 if (m_slideShowStarted)
71 CGUIWindowSlideShow* wndw = (CGUIWindowSlideShow*)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
73 if (wndw && wndw->GetCurrentSlide())
74 URIUtils::GetDirectory(wndw->GetCurrentSlide()->GetPath(),path);
75 if (path.Equals(m_vecItems->GetPath()))
77 if (wndw && wndw->GetCurrentSlide())
78 m_viewControl.SetSelectedItem(wndw->GetCurrentSlide()->GetPath());
79 m_iSelectedItem = m_viewControl.GetSelectedItem();
81 m_slideShowStarted = false;
85 CGUIWindowPictures::~CGUIWindowPictures(void)
89 bool CGUIWindowPictures::OnMessage(CGUIMessage& message)
91 switch ( message.GetMessage() )
93 case GUI_MSG_WINDOW_DEINIT:
95 if (m_thumbLoader.IsLoading())
96 m_thumbLoader.StopThread();
98 if (message.GetParam1() != WINDOW_SLIDESHOW)
105 case GUI_MSG_WINDOW_INIT:
107 // is this the first time accessing this window?
108 if (m_vecItems->GetPath() == "?" && message.GetStringParam().IsEmpty())
109 message.SetStringParam(g_settings.m_defaultPictureSource);
111 m_dlgProgress = (CGUIDialogProgress*)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
113 if (message.GetParam1() != WINDOW_SLIDESHOW)
118 if (!CGUIMediaWindow::OnMessage(message))
125 case GUI_MSG_CLICKED:
127 int iControl = message.GetSenderId();
128 if (iControl == CONTROL_BTNSLIDESHOW) // Slide Show
132 else if (iControl == CONTROL_BTNSLIDESHOW_RECURSIVE) // Recursive Slide Show
134 OnSlideShowRecursive();
136 else if (iControl == CONTROL_SHUFFLE)
138 g_guiSettings.ToggleBool("slideshow.shuffle");
141 else if (m_viewControl.HasControl(iControl)) // list/thumb control
143 int iItem = m_viewControl.GetSelectedItem();
144 int iAction = message.GetParam1();
146 // iItem is checked for validity inside these routines
147 if (iAction == ACTION_DELETE_ITEM)
149 // is delete allowed?
150 if (g_guiSettings.GetBool("filelists.allowfiledeletion"))
155 else if (iAction == ACTION_PLAYER_PLAY)
157 ShowPicture(iItem, true);
160 else if (iAction == ACTION_SHOW_INFO)
169 return CGUIMediaWindow::OnMessage(message);
172 void CGUIWindowPictures::UpdateButtons()
174 CGUIMediaWindow::UpdateButtons();
176 // Update the shuffle button
177 if (g_guiSettings.GetBool("slideshow.shuffle"))
179 CGUIMessage msg2(GUI_MSG_SELECTED, GetID(), CONTROL_SHUFFLE);
180 g_windowManager.SendMessage(msg2);
184 CGUIMessage msg2(GUI_MSG_DESELECTED, GetID(), CONTROL_SHUFFLE);
185 g_windowManager.SendMessage(msg2);
188 // check we can slideshow or recursive slideshow
189 int nFolders = m_vecItems->GetFolderCount();
190 if (nFolders == m_vecItems->Size())
192 CONTROL_DISABLE(CONTROL_BTNSLIDESHOW);
196 CONTROL_ENABLE(CONTROL_BTNSLIDESHOW);
198 if (m_guiState.get() && !m_guiState->HideParentDirItems())
200 if (m_vecItems->Size() == 0 || nFolders == 0)
202 CONTROL_DISABLE(CONTROL_BTNSLIDESHOW_RECURSIVE);
206 CONTROL_ENABLE(CONTROL_BTNSLIDESHOW_RECURSIVE);
210 void CGUIWindowPictures::OnPrepareFileItems(CFileItemList& items)
212 for (int i=0;i<items.Size();++i )
213 if (items[i]->GetLabel().Equals("folder.jpg"))
216 if (items.GetFolderCount()==items.Size() || !g_guiSettings.GetBool("pictures.usetags"))
219 // Start the music info loader thread
220 CPictureInfoLoader loader;
221 loader.SetProgressCallback(m_dlgProgress);
224 bool bShowProgress=!g_windowManager.HasModalDialog();
225 bool bProgressVisible=false;
227 unsigned int tick=XbmcThreads::SystemClockMillis();
229 while (loader.IsLoading() && m_dlgProgress && !m_dlgProgress->IsCanceled())
232 { // Do we have to init a progress dialog?
233 unsigned int elapsed=XbmcThreads::SystemClockMillis()-tick;
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());
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;
248 if (bProgressVisible && m_dlgProgress)
250 m_dlgProgress->Progress();
252 } // if (bShowProgress)
254 } // while (loader.IsLoading())
256 if (bProgressVisible && m_dlgProgress)
257 m_dlgProgress->Close();
260 bool CGUIWindowPictures::Update(const CStdString &strDirectory, bool updateFilterPath /* = true */)
262 if (m_thumbLoader.IsLoading())
263 m_thumbLoader.StopThread();
265 if (!CGUIMediaWindow::Update(strDirectory, updateFilterPath))
268 m_vecItems->SetArt("thumb", "");
269 if (g_guiSettings.GetBool("pictures.generatethumbs"))
270 m_thumbLoader.Load(*m_vecItems);
271 m_vecItems->SetArt("thumb", CPictureThumbLoader::GetCachedImage(*m_vecItems, "thumb"));
276 bool CGUIWindowPictures::OnClick(int iItem)
278 if ( iItem < 0 || iItem >= (int)m_vecItems->Size() ) return true;
279 CFileItemPtr pItem = m_vecItems->Get(iItem);
281 if (pItem->IsCBZ() || pItem->IsCBR())
283 CStdString strComicPath;
285 URIUtils::CreateArchivePath(strComicPath, "zip", pItem->GetPath(), "");
287 URIUtils::CreateArchivePath(strComicPath, "rar", pItem->GetPath(), "");
289 OnShowPictureRecursive(strComicPath);
292 else if (CGUIMediaWindow::OnClick(iItem))
298 bool CGUIWindowPictures::GetDirectory(const CStdString &strDirectory, CFileItemList& items)
300 if (!CGUIMediaWindow::GetDirectory(strDirectory, items))
304 if (items.GetLabel().IsEmpty() && m_rootDir.IsSource(items.GetPath(), g_settings.GetSourcesFromType("pictures"), &label))
305 items.SetLabel(label);
310 bool CGUIWindowPictures::OnPlayMedia(int iItem)
312 if (m_vecItems->Get(iItem)->IsVideo())
313 return CGUIMediaWindow::OnPlayMedia(iItem);
315 return ShowPicture(iItem, false);
318 bool CGUIWindowPictures::ShowPicture(int iItem, bool startSlideShow)
320 if ( iItem < 0 || iItem >= (int)m_vecItems->Size() ) return false;
321 CFileItemPtr pItem = m_vecItems->Get(iItem);
322 CStdString strPicture = pItem->GetPath();
326 return MEDIA_DETECT::CAutorun::PlayDiscAskResume(m_vecItems->Get(iItem)->GetPath());
329 if (pItem->m_bIsShareOrDrive)
332 CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
335 if (g_application.IsPlayingVideo())
336 g_application.StopPlaying();
339 for (int i = 0; i < (int)m_vecItems->Size();++i)
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") &&
347 pSlideShow->Add(pItem.get());
351 if (pSlideShow->NumSlides() == 0)
354 pSlideShow->Select(strPicture);
357 pSlideShow->StartSlideShow(false);
361 param["player"]["speed"] = 1;
362 param["player"]["playerid"] = PLAYLIST_PICTURE;
363 ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Player, "xbmc", "OnPlay", pSlideShow->GetCurrentSlide(), param);
366 m_slideShowStarted = true;
367 g_windowManager.ActivateWindow(WINDOW_SLIDESHOW);
372 void CGUIWindowPictures::OnShowPictureRecursive(const CStdString& strPath)
374 CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
378 if (g_application.IsPlayingVideo())
379 g_application.StopPlaying();
380 pSlideShow->AddFromPath(strPath, true,
381 m_guiState->GetSortMethod(),
382 m_guiState->GetSortOrder());
383 if (pSlideShow->NumSlides())
385 m_slideShowStarted = true;
386 g_windowManager.ActivateWindow(WINDOW_SLIDESHOW);
391 void CGUIWindowPictures::OnSlideShowRecursive(const CStdString &strPicture)
393 CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
396 CStdString strExtensions;
398 CGUIViewState* viewState=CGUIViewState::GetViewState(GetID(), items);
401 strExtensions = viewState->GetExtensions();
404 m_slideShowStarted = true;
405 pSlideShow->RunSlideShow(strPicture, true,
406 g_guiSettings.GetBool("slideshow.shuffle"),false,
407 m_guiState->GetSortMethod(),
408 m_guiState->GetSortOrder(),
413 void CGUIWindowPictures::OnSlideShowRecursive()
415 CStdString strEmpty = "";
416 OnSlideShowRecursive(m_vecItems->GetPath());
419 void CGUIWindowPictures::OnSlideShow()
421 OnSlideShow(m_vecItems->GetPath());
424 void CGUIWindowPictures::OnSlideShow(const CStdString &strPicture)
426 CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
429 CStdString strExtensions;
431 CGUIViewState* viewState=CGUIViewState::GetViewState(GetID(), items);
434 strExtensions = viewState->GetExtensions();
437 m_slideShowStarted = true;
438 pSlideShow->RunSlideShow(strPicture, false ,false, false,
439 m_guiState->GetSortMethod(),
440 m_guiState->GetSortOrder(),
445 void CGUIWindowPictures::OnRegenerateThumbs()
447 if (m_thumbLoader.IsLoading()) return;
448 m_thumbLoader.SetRegenerateThumbs(true);
449 m_thumbLoader.Load(*m_vecItems);
452 void CGUIWindowPictures::GetContextButtons(int itemNumber, CContextButtons &buttons)
455 if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
456 item = m_vecItems->Get(itemNumber);
458 if (item && !item->GetProperty("pluginreplacecontextitems").asBoolean())
460 if ( m_vecItems->IsVirtualDirectoryRoot() && item)
462 CGUIDialogContextMenu::GetContextButtons("pictures", item, buttons);
466 if (item && !item->GetPath().Left(14).Equals("addons://more/"))
468 if (!m_vecItems->IsPlugin() && (item->IsPlugin() || item->IsScript()))
469 buttons.Add(CONTEXT_BUTTON_INFO, 24003); // Add-on info
470 if (!(item->m_bIsFolder || item->IsZIP() || item->IsRAR() || item->IsCBZ() || item->IsCBR() || item->IsScript()))
472 buttons.Add(CONTEXT_BUTTON_INFO, 13406); // picture info
473 buttons.Add(CONTEXT_BUTTON_VIEW_SLIDESHOW, item->m_bIsFolder ? 13317 : 13422); // View Slideshow
475 if (item->m_bIsFolder)
476 buttons.Add(CONTEXT_BUTTON_RECURSIVE_SLIDESHOW, 13318); // Recursive Slideshow
478 if (!m_thumbLoader.IsLoading())
479 buttons.Add(CONTEXT_BUTTON_REFRESH_THUMBS, 13315); // Create Thumbnails
480 if (g_guiSettings.GetBool("filelists.allowfiledeletion") && !item->IsReadOnly())
482 buttons.Add(CONTEXT_BUTTON_DELETE, 117);
483 buttons.Add(CONTEXT_BUTTON_RENAME, 118);
487 if (item->IsPlugin() || item->IsScript() || m_vecItems->IsPlugin())
488 buttons.Add(CONTEXT_BUTTON_PLUGIN_SETTINGS, 1045);
491 buttons.Add(CONTEXT_BUTTON_GOTO_ROOT, 20128);
492 buttons.Add(CONTEXT_BUTTON_SWITCH_MEDIA, 523);
496 CGUIMediaWindow::GetContextButtons(itemNumber, buttons);
497 if (item && !item->GetProperty("pluginreplacecontextitems").asBoolean())
498 buttons.Add(CONTEXT_BUTTON_SETTINGS, 5); // Settings
501 bool CGUIWindowPictures::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
503 CFileItemPtr item = (itemNumber >= 0 && itemNumber < m_vecItems->Size()) ? m_vecItems->Get(itemNumber) : CFileItemPtr();
504 if (m_vecItems->IsVirtualDirectoryRoot() && item)
506 if (CGUIDialogContextMenu::OnContextButton("pictures", item, button))
514 case CONTEXT_BUTTON_VIEW_SLIDESHOW:
515 if (item && item->m_bIsFolder)
516 OnSlideShow(item->GetPath());
518 ShowPicture(itemNumber, true);
520 case CONTEXT_BUTTON_RECURSIVE_SLIDESHOW:
522 OnSlideShowRecursive(item->GetPath());
524 case CONTEXT_BUTTON_INFO:
527 case CONTEXT_BUTTON_REFRESH_THUMBS:
528 OnRegenerateThumbs();
530 case CONTEXT_BUTTON_DELETE:
531 OnDeleteItem(itemNumber);
533 case CONTEXT_BUTTON_RENAME:
534 OnRenameItem(itemNumber);
536 case CONTEXT_BUTTON_SETTINGS:
537 g_windowManager.ActivateWindow(WINDOW_SETTINGS_MYPICTURES);
539 case CONTEXT_BUTTON_GOTO_ROOT:
542 case CONTEXT_BUTTON_SWITCH_MEDIA:
543 CGUIDialogContextMenu::SwitchMedia("pictures", m_vecItems->GetPath());
548 return CGUIMediaWindow::OnContextButton(itemNumber, button);
551 void CGUIWindowPictures::OnItemLoaded(CFileItem *pItem)
553 CPictureThumbLoader::ProcessFoldersAndArchives(pItem);
556 void CGUIWindowPictures::LoadPlayList(const CStdString& strPlayList)
558 CLog::Log(LOGDEBUG,"CGUIWindowPictures::LoadPlayList()... converting playlist into slideshow: %s", strPlayList.c_str());
559 auto_ptr<CPlayList> pPlayList (CPlayListFactory::Create(strPlayList));
560 if ( NULL != pPlayList.get())
562 if (!pPlayList->Load(strPlayList))
564 CGUIDialogOK::ShowAndGetInput(6, 0, 477, 0);
565 return ; //hmmm unable to load playlist?
569 CPlayList playlist = *pPlayList;
570 if (playlist.size() > 0)
573 CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
576 if (g_application.IsPlayingVideo())
577 g_application.StopPlaying();
579 // convert playlist items into slideshow items
581 for (int i = 0; i < (int)playlist.size(); ++i)
583 CFileItemPtr pItem = playlist[i];
584 //CLog::Log(LOGDEBUG,"-- playlist item: %s", pItem->GetPath().c_str());
585 if (pItem->IsPicture() && !(pItem->IsZIP() || pItem->IsRAR() || pItem->IsCBZ() || pItem->IsCBR()))
586 pSlideShow->Add(pItem.get());
589 // start slideshow if there are items
590 pSlideShow->StartSlideShow();
591 if (pSlideShow->NumSlides())
592 g_windowManager.ActivateWindow(WINDOW_SLIDESHOW);
596 void CGUIWindowPictures::OnInfo(int itemNumber)
598 CFileItemPtr item = (itemNumber >= 0 && itemNumber < m_vecItems->Size()) ? m_vecItems->Get(itemNumber) : CFileItemPtr();
601 if (!m_vecItems->IsPlugin() && (item->IsPlugin() || item->IsScript()))
603 CGUIDialogAddonInfo::ShowForItem(item);
606 if (item->m_bIsFolder || item->IsZIP() || item->IsRAR() || item->IsCBZ() || item->IsCBR() || !item->IsPicture())
608 CGUIDialogPictureInfo *pictureInfo = (CGUIDialogPictureInfo *)g_windowManager.GetWindow(WINDOW_DIALOG_PICTURE_INFO);
611 pictureInfo->SetPicture(item.get());
612 pictureInfo->DoModal();
616 CStdString CGUIWindowPictures::GetStartFolder(const CStdString &dir)
618 if (dir.Equals("Plugins") || dir.Equals("Addons"))
619 return "addons://sources/image/";
623 m_rootDir.GetSources(shares);
624 bool bIsSourceName = false;
625 int iIndex = CUtil::GetMatchingSource(dir, shares, bIsSourceName);
628 if (iIndex < (int)shares.size() && shares[iIndex].m_iHasLock == 2)
630 CFileItem item(shares[iIndex]);
631 if (!g_passwordManager.IsItemUnlocked(&item,"pictures"))
635 return shares[iIndex].strPath;
638 return CGUIMediaWindow::GetStartFolder(dir);