/*
* Copyright (C) 2005-2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, see
* .
*
*/
#include "system.h"
#include "GUIDialogVideoBookmarks.h"
#include "video/VideoDatabase.h"
#include "Application.h"
#ifdef HAS_VIDEO_PLAYBACK
#include "cores/VideoRenderers/RenderManager.h"
#include "cores/VideoRenderers/RenderCapture.h"
#endif
#include "pictures/Picture.h"
#include "dialogs/GUIDialogContextMenu.h"
#include "view/ViewState.h"
#include "profiles/ProfilesManager.h"
#include "dialogs/GUIDialogKaiToast.h"
#include "settings/AdvancedSettings.h"
#include "FileItem.h"
#include "guilib/Texture.h"
#include "guilib/GUIWindowManager.h"
#include "utils/Crc32.h"
#include "guilib/Key.h"
#include "guilib/LocalizeStrings.h"
#include "utils/StringUtils.h"
#include "utils/URIUtils.h"
#include "threads/SingleLock.h"
#include "utils/log.h"
#include "utils/Variant.h"
#include "Util.h"
#include "cores/IPlayer.h"
using namespace std;
#define BOOKMARK_THUMB_WIDTH g_advancedSettings.GetThumbSize()
#define CONTROL_ADD_BOOKMARK 2
#define CONTROL_CLEAR_BOOKMARKS 3
#define CONTROL_ADD_EPISODE_BOOKMARK 4
#define CONTROL_LIST 10
#define CONTROL_THUMBS 11
CGUIDialogVideoBookmarks::CGUIDialogVideoBookmarks()
: CGUIDialog(WINDOW_DIALOG_VIDEO_BOOKMARKS, "VideoOSDBookmarks.xml")
{
m_vecItems = new CFileItemList;
m_loadType = KEEP_IN_MEMORY;
}
CGUIDialogVideoBookmarks::~CGUIDialogVideoBookmarks()
{
delete m_vecItems;
}
bool CGUIDialogVideoBookmarks::OnMessage(CGUIMessage& message)
{
switch ( message.GetMessage() )
{
case GUI_MSG_WINDOW_DEINIT:
{
CUtil::DeleteVideoDatabaseDirectoryCache();
Clear();
}
break;
case GUI_MSG_WINDOW_INIT:
{
CGUIWindow::OnMessage(message);
Update();
return true;
}
break;
case GUI_MSG_CLICKED:
{
int iControl = message.GetSenderId();
if (iControl == CONTROL_ADD_BOOKMARK)
{
AddBookmark();
Update();
}
else if (iControl == CONTROL_CLEAR_BOOKMARKS)
{
ClearBookmarks();
}
else if (iControl == CONTROL_ADD_EPISODE_BOOKMARK)
{
AddEpisodeBookmark();
Update();
}
else if (m_viewControl.HasControl(iControl)) // list/thumb control
{
int iItem = m_viewControl.GetSelectedItem();
int iAction = message.GetParam1();
if (iAction == ACTION_DELETE_ITEM)
{
Delete(iItem);
}
else if (iAction == ACTION_SELECT_ITEM || iAction == ACTION_MOUSE_LEFT_CLICK)
{
GotoBookmark(iItem);
}
}
}
break;
case GUI_MSG_SETFOCUS:
{
if (m_viewControl.HasControl(message.GetControlId()) && m_viewControl.GetCurrentControl() != message.GetControlId())
{
m_viewControl.SetFocused();
return true;
}
}
break;
case GUI_MSG_REFRESH_LIST:
{
OnRefreshList();
}
break;
}
return CGUIDialog::OnMessage(message);
}
bool CGUIDialogVideoBookmarks::OnAction(const CAction &action)
{
switch(action.GetID())
{
case ACTION_CONTEXT_MENU:
case ACTION_MOUSE_RIGHT_CLICK:
{
OnPopupMenu(m_viewControl.GetSelectedItem());
return true;
}
}
return CGUIDialog::OnAction(action);
}
void CGUIDialogVideoBookmarks::OnPopupMenu(int item)
{
if (item < 0 || item >= m_vecItems->Size())
return;
// highlight the item
(*m_vecItems)[item]->Select(true);
CContextButtons choices;
int langID = 20404; //"Remove bookmark"
if (m_bookmarks[item].type == CBookmark::EPISODE)
langID = 20405; //"Remove episode bookmark"
choices.Add(1, langID);
int button = CGUIDialogContextMenu::ShowAndGetChoice(choices);
// unhighlight the item
(*m_vecItems)[item]->Select(false);
if (button == 1)
Delete(item);
}
void CGUIDialogVideoBookmarks::Delete(int item)
{
if ( item>=0 && (unsigned)item < m_bookmarks.size() )
{
CVideoDatabase videoDatabase;
videoDatabase.Open();
std::string path(g_application.CurrentFile());
if (g_application.CurrentFileItem().HasProperty("original_listitem_url") &&
!URIUtils::IsVideoDb(g_application.CurrentFileItem().GetProperty("original_listitem_url").asString()))
path = g_application.CurrentFileItem().GetProperty("original_listitem_url").asString();
videoDatabase.ClearBookMarkOfFile(path, m_bookmarks[item], m_bookmarks[item].type);
videoDatabase.Close();
CUtil::DeleteVideoDatabaseDirectoryCache();
}
Update();
}
void CGUIDialogVideoBookmarks::OnRefreshList()
{
m_bookmarks.clear();
CBookmark resumemark;
// open the d/b and retrieve the bookmarks for the current movie
CStdString path = g_application.CurrentFile();
if (g_application.CurrentFileItem().HasProperty("original_listitem_url") &&
!URIUtils::IsVideoDb(g_application.CurrentFileItem().GetProperty("original_listitem_url").asString()))
path = g_application.CurrentFileItem().GetProperty("original_listitem_url").asString();
CVideoDatabase videoDatabase;
videoDatabase.Open();
videoDatabase.GetBookMarksForFile(path, m_bookmarks);
videoDatabase.GetBookMarksForFile(path, m_bookmarks, CBookmark::EPISODE, true);
/* push in the resume mark first */
if( videoDatabase.GetResumeBookMark(path, resumemark) )
m_bookmarks.push_back(resumemark);
videoDatabase.Close();
m_vecItems->Clear();
// cycle through each stored bookmark and add it to our list control
for (unsigned int i = 0; i < m_bookmarks.size(); ++i)
{
if (m_bookmarks[i].type == CBookmark::RESUME)
m_bookmarks[i].thumbNailImage = "bookmark-resume.png";
CStdString bookmarkTime;
if (m_bookmarks[i].type == CBookmark::EPISODE)
bookmarkTime = StringUtils::Format("%s %li %s %li", g_localizeStrings.Get(20373).c_str(), m_bookmarks[i].seasonNumber, g_localizeStrings.Get(20359).c_str(), m_bookmarks[i].episodeNumber);
else
bookmarkTime = StringUtils::SecondsToTimeString((long)m_bookmarks[i].timeInSeconds, TIME_FORMAT_HH_MM_SS);
CFileItemPtr item(new CFileItem(bookmarkTime));
item->SetArt("thumb", m_bookmarks[i].thumbNailImage);
m_vecItems->Add(item);
}
m_viewControl.SetItems(*m_vecItems);
}
void CGUIDialogVideoBookmarks::Update()
{
CVideoDatabase videoDatabase;
videoDatabase.Open();
if (g_application.CurrentFileItem().HasVideoInfoTag() && g_application.CurrentFileItem().GetVideoInfoTag()->m_iEpisode > -1)
{
vector episodes;
videoDatabase.GetEpisodesByFile(g_application.CurrentFile(),episodes);
if (episodes.size() > 1)
{
CONTROL_ENABLE(CONTROL_ADD_EPISODE_BOOKMARK);
}
else
{
CONTROL_DISABLE(CONTROL_ADD_EPISODE_BOOKMARK);
}
}
else
{
CONTROL_DISABLE(CONTROL_ADD_EPISODE_BOOKMARK);
}
// lock our display, as this window is rendered from the player thread
g_graphicsContext.Lock();
m_viewControl.SetCurrentView(DEFAULT_VIEW_ICONS);
// empty the list ready for population
Clear();
OnRefreshList();
g_graphicsContext.Unlock();
videoDatabase.Close();
}
void CGUIDialogVideoBookmarks::Clear()
{
m_viewControl.Clear();
m_vecItems->Clear();
}
void CGUIDialogVideoBookmarks::GotoBookmark(int item)
{
if (item < 0 || item >= (int)m_bookmarks.size()) return;
if (g_application.m_pPlayer->HasPlayer())
{
g_application.m_pPlayer->SetPlayerState(m_bookmarks[item].playerState);
g_application.SeekTime((double)m_bookmarks[item].timeInSeconds);
}
}
void CGUIDialogVideoBookmarks::ClearBookmarks()
{
CVideoDatabase videoDatabase;
videoDatabase.Open();
CStdString path = g_application.CurrentFile();
if (g_application.CurrentFileItem().HasProperty("original_listitem_url") &&
!URIUtils::IsVideoDb(g_application.CurrentFileItem().GetProperty("original_listitem_url").asString()))
path = g_application.CurrentFileItem().GetProperty("original_listitem_url").asString();
videoDatabase.ClearBookMarksOfFile(path, CBookmark::STANDARD);
videoDatabase.ClearBookMarksOfFile(path, CBookmark::RESUME);
videoDatabase.ClearBookMarksOfFile(path, CBookmark::EPISODE);
videoDatabase.Close();
Update();
}
bool CGUIDialogVideoBookmarks::AddBookmark(CVideoInfoTag* tag)
{
CVideoDatabase videoDatabase;
CBookmark bookmark;
bookmark.timeInSeconds = (int)g_application.GetTime();
bookmark.totalTimeInSeconds = (int)g_application.GetTotalTime();
if( g_application.m_pPlayer->HasPlayer() )
bookmark.playerState = g_application.m_pPlayer->GetPlayerState();
else
bookmark.playerState.clear();
bookmark.player = CPlayerCoreFactory::Get().GetPlayerName(g_application.GetCurrentPlayer());
// create the thumbnail image
#ifdef HAS_VIDEO_PLAYBACK
float aspectRatio = g_renderManager.GetAspectRatio();
#else
float aspectRatio = 1.0f;
#endif
int width = BOOKMARK_THUMB_WIDTH;
int height = (int)(BOOKMARK_THUMB_WIDTH / aspectRatio);
if (height > (int)BOOKMARK_THUMB_WIDTH)
{
height = BOOKMARK_THUMB_WIDTH;
width = (int)(BOOKMARK_THUMB_WIDTH * aspectRatio);
}
{
#ifdef HAS_VIDEO_PLAYBACK
CRenderCapture* thumbnail = g_renderManager.AllocRenderCapture();
if (thumbnail)
{
g_renderManager.Capture(thumbnail, width, height, CAPTUREFLAG_IMMEDIATELY);
if (thumbnail->GetUserState() == CAPTURESTATE_DONE)
{
Crc32 crc;
crc.ComputeFromLowerCase(g_application.CurrentFile());
bookmark.thumbNailImage = StringUtils::Format("%08x_%i.jpg", (unsigned __int32) crc, (int)bookmark.timeInSeconds);
bookmark.thumbNailImage = URIUtils::AddFileToFolder(CProfilesManager::Get().GetBookmarksThumbFolder(), bookmark.thumbNailImage);
if (!CPicture::CreateThumbnailFromSurface(thumbnail->GetPixels(), width, height, thumbnail->GetWidth() * 4,
bookmark.thumbNailImage))
bookmark.thumbNailImage.clear();
}
else
CLog::Log(LOGERROR,"CGUIDialogVideoBookmarks: failed to create thumbnail");
g_renderManager.ReleaseRenderCapture(thumbnail);
}
#endif
}
videoDatabase.Open();
if (tag)
videoDatabase.AddBookMarkForEpisode(*tag, bookmark);
else
{
CStdString path = g_application.CurrentFile();
if (g_application.CurrentFileItem().HasProperty("original_listitem_url") &&
!URIUtils::IsVideoDb(g_application.CurrentFileItem().GetProperty("original_listitem_url").asString()))
path = g_application.CurrentFileItem().GetProperty("original_listitem_url").asString();
videoDatabase.AddBookMarkToFile(path, bookmark, CBookmark::STANDARD);
}
videoDatabase.Close();
return true;
}
void CGUIDialogVideoBookmarks::OnWindowLoaded()
{
CGUIDialog::OnWindowLoaded();
m_viewControl.Reset();
m_viewControl.SetParentWindow(GetID());
m_viewControl.AddView(GetControl(CONTROL_THUMBS));
}
void CGUIDialogVideoBookmarks::OnWindowUnload()
{
CGUIDialog::OnWindowUnload();
m_viewControl.Reset();
}
CGUIControl *CGUIDialogVideoBookmarks::GetFirstFocusableControl(int id)
{
if (m_viewControl.HasControl(id))
id = m_viewControl.GetCurrentControl();
return CGUIWindow::GetFirstFocusableControl(id);
}
bool CGUIDialogVideoBookmarks::AddEpisodeBookmark()
{
vector episodes;
CVideoDatabase videoDatabase;
videoDatabase.Open();
videoDatabase.GetEpisodesByFile(g_application.CurrentFile(), episodes);
videoDatabase.Close();
if(episodes.size() > 0)
{
CContextButtons choices;
for (unsigned int i=0; i < episodes.size(); ++i)
{
CStdString strButton = StringUtils::Format("%s %i, %s %i",
g_localizeStrings.Get(20373).c_str(), episodes[i].m_iSeason,
g_localizeStrings.Get(20359).c_str(), episodes[i].m_iEpisode);
choices.Add(i, strButton);
}
int pressed = CGUIDialogContextMenu::ShowAndGetChoice(choices);
if (pressed >= 0)
{
AddBookmark(&episodes[pressed]);
return true;
}
}
return false;
}
bool CGUIDialogVideoBookmarks::OnAddBookmark()
{
if (!g_application.CurrentFileItem().IsVideo())
return false;
if (CGUIDialogVideoBookmarks::AddBookmark())
{
g_windowManager.SendMessage(GUI_MSG_REFRESH_LIST, 0, WINDOW_DIALOG_VIDEO_BOOKMARKS);
CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info,
g_localizeStrings.Get(298), //"Bookmarks"
g_localizeStrings.Get(21362));//"Bookmark created"
return true;
}
return false;
}
bool CGUIDialogVideoBookmarks::OnAddEpisodeBookmark()
{
bool bReturn = false;
if (g_application.CurrentFileItem().HasVideoInfoTag() && g_application.CurrentFileItem().GetVideoInfoTag()->m_iEpisode > -1)
{
CVideoDatabase videoDatabase;
videoDatabase.Open();
vector episodes;
videoDatabase.GetEpisodesByFile(g_application.CurrentFile(),episodes);
if (episodes.size() > 1)
{
bReturn = CGUIDialogVideoBookmarks::AddEpisodeBookmark();
if(bReturn)
{
g_windowManager.SendMessage(GUI_MSG_REFRESH_LIST, 0, WINDOW_DIALOG_VIDEO_BOOKMARKS);
CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info,
g_localizeStrings.Get(298), //"Bookmarks"
g_localizeStrings.Get(21363));//"Episode Bookmark created"
}
}
videoDatabase.Close();
}
return bReturn;
}