5eb15554275a91f55bcd6109a97282c8babb1db9
[vuplus_xbmc] / xbmc / video / dialogs / GUIDialogVideoBookmarks.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://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 "system.h"
22 #include "GUIDialogVideoBookmarks.h"
23 #include "video/VideoDatabase.h"
24 #include "Application.h"
25 #ifdef HAS_VIDEO_PLAYBACK
26 #include "cores/VideoRenderers/RenderManager.h"
27 #include "cores/VideoRenderers/RenderCapture.h"
28 #endif
29 #include "pictures/Picture.h"
30 #include "dialogs/GUIDialogContextMenu.h"
31 #include "view/ViewState.h"
32 #include "profiles/ProfilesManager.h"
33 #include "dialogs/GUIDialogKaiToast.h"
34 #include "settings/AdvancedSettings.h"
35 #include "FileItem.h"
36 #include "guilib/Texture.h"
37 #include "guilib/GUIWindowManager.h"
38 #include "utils/Crc32.h"
39 #include "guilib/Key.h"
40 #include "guilib/LocalizeStrings.h"
41 #include "utils/StringUtils.h"
42 #include "utils/URIUtils.h"
43 #include "threads/SingleLock.h"
44 #include "utils/log.h"
45 #include "utils/Variant.h"
46 #include "Util.h"
47 #include "cores/IPlayer.h"
48
49 using namespace std;
50
51 #define BOOKMARK_THUMB_WIDTH g_advancedSettings.GetThumbSize()
52
53 #define CONTROL_ADD_BOOKMARK           2
54 #define CONTROL_CLEAR_BOOKMARKS        3
55 #define CONTROL_ADD_EPISODE_BOOKMARK   4
56
57 #define CONTROL_LIST                  10
58 #define CONTROL_THUMBS                11
59
60 CGUIDialogVideoBookmarks::CGUIDialogVideoBookmarks()
61     : CGUIDialog(WINDOW_DIALOG_VIDEO_BOOKMARKS, "VideoOSDBookmarks.xml")
62 {
63   m_vecItems = new CFileItemList;
64   m_loadType = KEEP_IN_MEMORY;
65 }
66
67 CGUIDialogVideoBookmarks::~CGUIDialogVideoBookmarks()
68 {
69   delete m_vecItems;
70 }
71
72 bool CGUIDialogVideoBookmarks::OnMessage(CGUIMessage& message)
73 {
74   switch ( message.GetMessage() )
75   {
76   case GUI_MSG_WINDOW_DEINIT:
77     {
78       CUtil::DeleteVideoDatabaseDirectoryCache();
79       Clear();
80     }
81     break;
82
83   case GUI_MSG_WINDOW_INIT:
84     {
85       CGUIWindow::OnMessage(message);
86       Update();
87       return true;
88     }
89     break;
90
91   case GUI_MSG_CLICKED:
92     {
93       int iControl = message.GetSenderId();
94       if (iControl == CONTROL_ADD_BOOKMARK)
95       {
96         AddBookmark();
97         Update();
98       }
99       else if (iControl == CONTROL_CLEAR_BOOKMARKS)
100       {
101         ClearBookmarks();
102       }
103       else if (iControl == CONTROL_ADD_EPISODE_BOOKMARK)
104       {
105         AddEpisodeBookmark();
106         Update();
107       }
108       else if (m_viewControl.HasControl(iControl))  // list/thumb control
109       {
110         int iItem = m_viewControl.GetSelectedItem();
111         int iAction = message.GetParam1();
112         if (iAction == ACTION_DELETE_ITEM)
113         {
114           Delete(iItem);
115         }
116         else if (iAction == ACTION_SELECT_ITEM || iAction == ACTION_MOUSE_LEFT_CLICK)
117         {
118           GotoBookmark(iItem);
119         }
120       }
121     }
122     break;
123   case GUI_MSG_SETFOCUS:
124     {
125       if (m_viewControl.HasControl(message.GetControlId()) && m_viewControl.GetCurrentControl() != message.GetControlId())
126       {
127         m_viewControl.SetFocused();
128         return true;
129       }
130     }
131     break;
132   case GUI_MSG_REFRESH_LIST:
133     {
134       OnRefreshList();
135     }
136     break;
137   }
138
139   return CGUIDialog::OnMessage(message);
140 }
141
142 bool CGUIDialogVideoBookmarks::OnAction(const CAction &action)
143 {
144   switch(action.GetID())
145   {
146   case ACTION_CONTEXT_MENU:
147   case ACTION_MOUSE_RIGHT_CLICK:
148     {
149       OnPopupMenu(m_viewControl.GetSelectedItem());
150       return true;
151     }
152   }
153   return CGUIDialog::OnAction(action);
154 }
155
156
157 void CGUIDialogVideoBookmarks::OnPopupMenu(int item)
158 {
159   if (item < 0 || item >= m_vecItems->Size())
160     return;
161   
162     // highlight the item
163   (*m_vecItems)[item]->Select(true);
164   
165   CContextButtons choices;
166   
167   int langID = 20404; //"Remove bookmark"
168   if (m_bookmarks[item].type == CBookmark::EPISODE)
169     langID = 20405;   //"Remove episode bookmark"
170   choices.Add(1, langID); 
171
172   
173   int button = CGUIDialogContextMenu::ShowAndGetChoice(choices);
174   
175     // unhighlight the item
176   (*m_vecItems)[item]->Select(false);
177   
178   if (button == 1)
179     Delete(item);
180 }
181
182 void CGUIDialogVideoBookmarks::Delete(int item)
183 {
184   if ( item>=0 && (unsigned)item < m_bookmarks.size() )
185   {
186     CVideoDatabase videoDatabase;
187     videoDatabase.Open();
188     videoDatabase.ClearBookMarkOfFile(g_application.CurrentFile(),m_bookmarks[item],m_bookmarks[item].type);
189     videoDatabase.Close();
190     CUtil::DeleteVideoDatabaseDirectoryCache();
191   }
192   Update();
193 }
194
195 void CGUIDialogVideoBookmarks::OnRefreshList()
196 {
197   m_bookmarks.clear();
198   CBookmark resumemark;
199   
200     // open the d/b and retrieve the bookmarks for the current movie
201   CStdString path = g_application.CurrentFile();
202   if (g_application.CurrentFileItem().HasProperty("original_listitem_url") && 
203      !URIUtils::IsVideoDb(g_application.CurrentFileItem().GetProperty("original_listitem_url").asString()))
204     path = g_application.CurrentFileItem().GetProperty("original_listitem_url").asString();
205   CVideoDatabase videoDatabase;
206   videoDatabase.Open();
207   videoDatabase.GetBookMarksForFile(path, m_bookmarks);
208   videoDatabase.GetBookMarksForFile(path, m_bookmarks, CBookmark::EPISODE, true);
209   /* push in the resume mark first */
210   if( videoDatabase.GetResumeBookMark(path, resumemark) )
211     m_bookmarks.push_back(resumemark);
212   
213   videoDatabase.Close();
214   m_vecItems->Clear();
215     // cycle through each stored bookmark and add it to our list control
216   for (unsigned int i = 0; i < m_bookmarks.size(); ++i)
217   {
218     if (m_bookmarks[i].type == CBookmark::RESUME)
219       m_bookmarks[i].thumbNailImage = "bookmark-resume.png";
220     
221     CStdString bookmarkTime;
222     if (m_bookmarks[i].type == CBookmark::EPISODE)
223       bookmarkTime.Format("%s %i %s %i", g_localizeStrings.Get(20373), m_bookmarks[i].seasonNumber, g_localizeStrings.Get(20359).c_str(), m_bookmarks[i].episodeNumber);
224     else
225       bookmarkTime = StringUtils::SecondsToTimeString((long)m_bookmarks[i].timeInSeconds, TIME_FORMAT_HH_MM_SS);
226     
227     CFileItemPtr item(new CFileItem(bookmarkTime));
228     item->SetArt("thumb", m_bookmarks[i].thumbNailImage);
229     m_vecItems->Add(item);
230   }
231   m_viewControl.SetItems(*m_vecItems);
232 }
233
234 void CGUIDialogVideoBookmarks::Update()
235 {
236   CVideoDatabase videoDatabase;
237   videoDatabase.Open();
238
239   if (g_application.CurrentFileItem().HasVideoInfoTag() && g_application.CurrentFileItem().GetVideoInfoTag()->m_iEpisode > -1)
240   {
241     vector<CVideoInfoTag> episodes;
242     videoDatabase.GetEpisodesByFile(g_application.CurrentFile(),episodes);
243     if (episodes.size() > 1)
244     {
245       CONTROL_ENABLE(CONTROL_ADD_EPISODE_BOOKMARK);
246     }
247     else
248     {
249       CONTROL_DISABLE(CONTROL_ADD_EPISODE_BOOKMARK);
250     }
251   }
252   else
253   {
254     CONTROL_DISABLE(CONTROL_ADD_EPISODE_BOOKMARK);
255   }
256
257
258   // lock our display, as this window is rendered from the player thread
259   g_graphicsContext.Lock();
260   m_viewControl.SetCurrentView(DEFAULT_VIEW_ICONS);
261
262   // empty the list ready for population
263   Clear();
264
265   OnRefreshList();
266   
267   g_graphicsContext.Unlock();
268   
269   videoDatabase.Close();
270 }
271
272 void CGUIDialogVideoBookmarks::Clear()
273 {
274   m_viewControl.Clear();
275   m_vecItems->Clear();
276 }
277
278 void CGUIDialogVideoBookmarks::GotoBookmark(int item)
279 {
280   if (item < 0 || item >= (int)m_bookmarks.size()) return;
281   if (g_application.m_pPlayer->HasPlayer())
282   {
283     g_application.m_pPlayer->SetPlayerState(m_bookmarks[item].playerState);
284     g_application.SeekTime((double)m_bookmarks[item].timeInSeconds);
285   }
286 }
287
288 void CGUIDialogVideoBookmarks::ClearBookmarks()
289 {
290   CVideoDatabase videoDatabase;
291   videoDatabase.Open();
292   CStdString path = g_application.CurrentFile();
293   if (g_application.CurrentFileItem().HasProperty("original_listitem_url") && 
294      !URIUtils::IsVideoDb(g_application.CurrentFileItem().GetProperty("original_listitem_url").asString()))
295     path = g_application.CurrentFileItem().GetProperty("original_listitem_url").asString();
296   videoDatabase.ClearBookMarksOfFile(path, CBookmark::STANDARD);
297   videoDatabase.ClearBookMarksOfFile(path, CBookmark::RESUME);
298   videoDatabase.ClearBookMarksOfFile(path, CBookmark::EPISODE);
299   videoDatabase.Close();
300   Update();
301 }
302
303 bool CGUIDialogVideoBookmarks::AddBookmark(CVideoInfoTag* tag)
304 {
305   CVideoDatabase videoDatabase;
306   CBookmark bookmark;
307   bookmark.timeInSeconds = (int)g_application.GetTime();
308   bookmark.totalTimeInSeconds = (int)g_application.GetTotalTime();
309
310   if( g_application.m_pPlayer->HasPlayer() )
311     bookmark.playerState = g_application.m_pPlayer->GetPlayerState();
312   else
313     bookmark.playerState.Empty();
314
315   bookmark.player = CPlayerCoreFactory::Get().GetPlayerName(g_application.GetCurrentPlayer());
316
317   // create the thumbnail image
318 #ifdef HAS_VIDEO_PLAYBACK
319   float aspectRatio = g_renderManager.GetAspectRatio();
320 #else
321   float aspectRatio = 1.0f;
322 #endif
323   int width = BOOKMARK_THUMB_WIDTH;
324   int height = (int)(BOOKMARK_THUMB_WIDTH / aspectRatio);
325   if (height > (int)BOOKMARK_THUMB_WIDTH)
326   {
327     height = BOOKMARK_THUMB_WIDTH;
328     width = (int)(BOOKMARK_THUMB_WIDTH * aspectRatio);
329   }
330   {
331 #ifdef HAS_VIDEO_PLAYBACK
332     CRenderCapture* thumbnail = g_renderManager.AllocRenderCapture();
333
334     if (thumbnail)
335     {
336       g_renderManager.Capture(thumbnail, width, height, CAPTUREFLAG_IMMEDIATELY);
337
338       if (thumbnail->GetUserState() == CAPTURESTATE_DONE)
339       {
340         Crc32 crc;
341         crc.ComputeFromLowerCase(g_application.CurrentFile());
342         bookmark.thumbNailImage.Format("%08x_%i.jpg", (unsigned __int32) crc, (int)bookmark.timeInSeconds);
343         bookmark.thumbNailImage = URIUtils::AddFileToFolder(CProfilesManager::Get().GetBookmarksThumbFolder(), bookmark.thumbNailImage);
344         if (!CPicture::CreateThumbnailFromSurface(thumbnail->GetPixels(), width, height, thumbnail->GetWidth() * 4,
345                                             bookmark.thumbNailImage))
346           bookmark.thumbNailImage.Empty();
347       }
348       else
349         CLog::Log(LOGERROR,"CGUIDialogVideoBookmarks: failed to create thumbnail");
350
351       g_renderManager.ReleaseRenderCapture(thumbnail);
352     }
353 #endif
354   }
355   videoDatabase.Open();
356   if (tag)
357     videoDatabase.AddBookMarkForEpisode(*tag, bookmark);
358   else
359   {
360     CStdString path = g_application.CurrentFile();
361     if (g_application.CurrentFileItem().HasProperty("original_listitem_url") && 
362        !URIUtils::IsVideoDb(g_application.CurrentFileItem().GetProperty("original_listitem_url").asString()))
363       path = g_application.CurrentFileItem().GetProperty("original_listitem_url").asString();
364     videoDatabase.AddBookMarkToFile(path, bookmark, CBookmark::STANDARD);
365   }
366   videoDatabase.Close();
367   return true;
368 }
369
370 void CGUIDialogVideoBookmarks::OnWindowLoaded()
371 {
372   CGUIDialog::OnWindowLoaded();
373   m_viewControl.Reset();
374   m_viewControl.SetParentWindow(GetID());
375   m_viewControl.AddView(GetControl(CONTROL_THUMBS));
376 }
377
378 void CGUIDialogVideoBookmarks::OnWindowUnload()
379 {
380   CGUIDialog::OnWindowUnload();
381   m_viewControl.Reset();
382 }
383
384 CGUIControl *CGUIDialogVideoBookmarks::GetFirstFocusableControl(int id)
385 {
386   if (m_viewControl.HasControl(id))
387     id = m_viewControl.GetCurrentControl();
388   return CGUIWindow::GetFirstFocusableControl(id);
389 }
390
391 bool CGUIDialogVideoBookmarks::AddEpisodeBookmark()
392 {
393   vector<CVideoInfoTag> episodes;
394   CVideoDatabase videoDatabase;
395   videoDatabase.Open();
396   videoDatabase.GetEpisodesByFile(g_application.CurrentFile(), episodes);
397   videoDatabase.Close();
398   if(episodes.size() > 0)
399   {
400     CContextButtons choices;
401     for (unsigned int i=0; i < episodes.size(); ++i)
402     {
403       CStdString strButton;
404       strButton.Format("%s %i, %s %i", g_localizeStrings.Get(20373), episodes[i].m_iSeason, g_localizeStrings.Get(20359).c_str(), episodes[i].m_iEpisode);
405       choices.Add(i, strButton);
406     }
407
408     int pressed = CGUIDialogContextMenu::ShowAndGetChoice(choices);
409     if (pressed >= 0)
410     {
411       AddBookmark(&episodes[pressed]);
412       return true;
413     }
414   }
415   return false;
416 }
417
418
419
420 bool CGUIDialogVideoBookmarks::OnAddBookmark()
421 {
422   if (!g_application.CurrentFileItem().IsVideo())
423     return false;
424   
425   if (CGUIDialogVideoBookmarks::AddBookmark()) 
426   {
427     g_windowManager.SendMessage(GUI_MSG_REFRESH_LIST, 0, WINDOW_DIALOG_VIDEO_BOOKMARKS);
428     CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info,
429                                           g_localizeStrings.Get(298),   //"Bookmarks"
430                                           g_localizeStrings.Get(21362));//"Bookmark created"
431     return true;
432   }
433   return false;
434 }
435
436 bool CGUIDialogVideoBookmarks::OnAddEpisodeBookmark()
437 {
438   bool bReturn = false;
439   if (g_application.CurrentFileItem().HasVideoInfoTag() && g_application.CurrentFileItem().GetVideoInfoTag()->m_iEpisode > -1)
440   {
441     CVideoDatabase videoDatabase;
442     videoDatabase.Open();
443     vector<CVideoInfoTag> episodes;
444     videoDatabase.GetEpisodesByFile(g_application.CurrentFile(),episodes);
445     if (episodes.size() > 1)
446     {
447       bReturn = CGUIDialogVideoBookmarks::AddEpisodeBookmark();
448       if(bReturn)
449       {
450         g_windowManager.SendMessage(GUI_MSG_REFRESH_LIST, 0, WINDOW_DIALOG_VIDEO_BOOKMARKS);
451         CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, 
452                                               g_localizeStrings.Get(298),   //"Bookmarks"
453                                               g_localizeStrings.Get(21363));//"Episode Bookmark created"
454  
455       }
456     }
457     videoDatabase.Close();
458   }
459   return bReturn;
460 }
461
462