fixed: Position of context menu in bookmarks and favourites dialog.
[xbmc:xbmc-antiquated.git] / XBMC / xbmc / GUIDialogVideoBookmarks.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 "stdafx.h"
23 #include "GUIDialogVideoBookmarks.h"
24 #include "VideoDatabase.h"
25 #include "Application.h"
26 #include "Util.h"
27 #ifdef HAS_VIDEO_PLAYBACK
28 #include "cores/VideoRenderers/RenderManager.h"
29 #endif
30 #include "Picture.h"
31 #include "GUIDialogContextMenu.h"
32 #include "GUIWindowManager.h"
33 #include "ViewState.h"
34 #include "Settings.h"
35 #include "FileItem.h"
36 #include "Crc32.h"
37
38 using namespace std;
39
40 #define BOOKMARK_THUMB_WIDTH g_advancedSettings.m_thumbSize
41
42 #define CONTROL_ADD_BOOKMARK           2
43 #define CONTROL_CLEAR_BOOKMARKS        3
44 #define CONTROL_ADD_EPISODE_BOOKMARK   4
45
46 #define CONTROL_LIST                  10
47 #define CONTROL_THUMBS                11
48
49 CGUIDialogVideoBookmarks::CGUIDialogVideoBookmarks()
50     : CGUIDialog(WINDOW_DIALOG_VIDEO_BOOKMARKS, "VideoOSDBookmarks.xml")
51 {
52   m_vecItems = new CFileItemList;
53 }
54
55 CGUIDialogVideoBookmarks::~CGUIDialogVideoBookmarks()
56 {
57   delete m_vecItems;
58 }
59
60 bool CGUIDialogVideoBookmarks::OnMessage(CGUIMessage& message)
61 {
62   switch ( message.GetMessage() )
63   {
64   case GUI_MSG_WINDOW_DEINIT:
65     {
66       CUtil::DeleteVideoDatabaseDirectoryCache();
67       Clear();
68     }
69     break;
70
71   case GUI_MSG_WINDOW_INIT:
72     {
73       CGUIWindow::OnMessage(message);
74       Update();
75       return true;
76     }
77     break;
78
79   case GUI_MSG_CLICKED:
80     {
81       int iControl = message.GetSenderId();
82       if (iControl == CONTROL_ADD_BOOKMARK)
83       {
84         AddBookmark();
85       }
86       else if (iControl == CONTROL_CLEAR_BOOKMARKS)
87       {
88         ClearBookmarks();
89       }
90       else if (iControl == CONTROL_ADD_EPISODE_BOOKMARK)
91       {
92         AddEpisodeBookmark();
93       }
94       else if (m_viewControl.HasControl(iControl))  // list/thumb control
95       {
96         int iItem = m_viewControl.GetSelectedItem();
97         int iAction = message.GetParam1();
98         if (iAction == ACTION_DELETE_ITEM)
99         {
100           if( (unsigned)iItem < m_bookmarks.size() )
101           {
102             CVideoDatabase videoDatabase;
103             videoDatabase.Open();
104             videoDatabase.ClearBookMarkOfFile(g_application.CurrentFile(),m_bookmarks[iItem],m_bookmarks[iItem].type);
105             videoDatabase.Close();
106             CUtil::DeleteVideoDatabaseDirectoryCache();
107           }
108           Update();
109         }
110         else if (iAction == ACTION_SELECT_ITEM || iAction == ACTION_MOUSE_LEFT_CLICK)
111         {
112           GotoBookmark(iItem);
113         }
114       }
115     }
116     break;
117   case GUI_MSG_SETFOCUS:
118     {
119       if (m_viewControl.HasControl(message.GetControlId()) && (DWORD) m_viewControl.GetCurrentControl() != message.GetControlId())
120       {
121         m_viewControl.SetFocused();
122         return true;
123       }
124     }
125     break;
126   }
127
128   return CGUIDialog::OnMessage(message);
129 }
130
131 void CGUIDialogVideoBookmarks::Update()
132 {
133   m_bookmarks.clear();
134   CBookmark resumemark;
135
136   // open the d/b and retrieve the bookmarks for the current movie
137   CVideoDatabase videoDatabase;
138   videoDatabase.Open();
139   videoDatabase.GetBookMarksForFile(g_application.CurrentFile(), m_bookmarks);
140   videoDatabase.GetBookMarksForFile(g_application.CurrentFile(), m_bookmarks, CBookmark::EPISODE, true);
141   /* push in the resume mark first */
142   if( videoDatabase.GetResumeBookMark(g_application.CurrentFile(), resumemark) )
143     m_bookmarks.insert(m_bookmarks.begin(), resumemark);
144
145   if (g_application.CurrentFileItem().HasVideoInfoTag() && g_application.CurrentFileItem().GetVideoInfoTag()->m_iEpisode > -1)
146   {
147     vector<CVideoInfoTag> episodes;
148     videoDatabase.GetEpisodesByFile(g_application.CurrentFile(),episodes);
149     if (episodes.size() > 1)
150     {
151       CONTROL_ENABLE(CONTROL_ADD_EPISODE_BOOKMARK);
152     }
153     else
154     {
155       CONTROL_DISABLE(CONTROL_ADD_EPISODE_BOOKMARK);
156     }
157   }
158   else
159   {
160     CONTROL_DISABLE(CONTROL_ADD_EPISODE_BOOKMARK);
161   }
162
163   videoDatabase.Close();
164
165   // lock our display, as this window is rendered from the player thread
166   g_graphicsContext.Lock();
167   m_viewControl.SetCurrentView(DEFAULT_VIEW_ICONS);
168
169   // empty the list ready for population
170   Clear();
171
172   // cycle through each stored bookmark and add it to our list control
173   for (unsigned int i = 0; i < m_bookmarks.size(); ++i)
174   {
175     if (m_bookmarks[i].type == CBookmark::RESUME)
176       m_bookmarks[i].thumbNailImage = "bookmark-resume.png";
177
178     CStdString bookmarkTime;
179     if (m_bookmarks[i].type == CBookmark::EPISODE)
180       bookmarkTime.Format("%s %i %s %i", g_localizeStrings.Get(20373), m_bookmarks[i].seasonNumber, g_localizeStrings.Get(20359).c_str(), m_bookmarks[i].episodeNumber);
181     else
182       StringUtils::SecondsToTimeString((long)m_bookmarks[i].timeInSeconds, bookmarkTime, TIME_FORMAT_HH_MM_SS);
183
184     CFileItemPtr item(new CFileItem(bookmarkTime));
185     item->SetThumbnailImage(m_bookmarks[i].thumbNailImage);
186     m_vecItems->Add(item);
187   }
188   m_viewControl.SetItems(*m_vecItems);
189   g_graphicsContext.Unlock();
190 }
191
192 void CGUIDialogVideoBookmarks::Clear()
193 {
194   m_viewControl.Clear();
195   m_vecItems->Clear();
196 }
197
198 void CGUIDialogVideoBookmarks::GotoBookmark(int item)
199 {
200   if (item < 0 || item >= (int)m_bookmarks.size()) return;
201   if (g_application.m_pPlayer)
202   {
203     g_application.m_pPlayer->SetPlayerState(m_bookmarks[item].playerState);
204     g_application.SeekTime((double)m_bookmarks[item].timeInSeconds);
205   }
206 }
207
208 void CGUIDialogVideoBookmarks::ClearBookmarks()
209 {
210   CVideoDatabase videoDatabase;
211   videoDatabase.Open();
212   videoDatabase.ClearBookMarksOfFile(g_application.CurrentFile(), CBookmark::STANDARD);
213   videoDatabase.ClearBookMarksOfFile(g_application.CurrentFile(), CBookmark::RESUME);
214   videoDatabase.ClearBookMarksOfFile(g_application.CurrentFile(), CBookmark::EPISODE);
215   videoDatabase.Close();
216   Update();
217 }
218
219 void CGUIDialogVideoBookmarks::AddBookmark(CVideoInfoTag* tag)
220 {
221   CVideoDatabase videoDatabase;
222   CBookmark bookmark;
223   bookmark.timeInSeconds = (int)g_application.GetTime();
224
225   if( g_application.m_pPlayer )
226     bookmark.playerState = g_application.m_pPlayer->GetPlayerState();
227   else
228     bookmark.playerState.Empty();
229
230   bookmark.player = CPlayerCoreFactory::GetPlayerName(g_application.GetCurrentPlayer());
231
232   // create the thumbnail image
233 #ifdef HAS_VIDEO_PLAYBACK
234   float aspectRatio = g_renderManager.GetAspectRatio();
235 #else
236   float aspectRatio = 1.0f;
237 #endif
238   int width = BOOKMARK_THUMB_WIDTH;
239   int height = (int)(BOOKMARK_THUMB_WIDTH / aspectRatio);
240   if (height > BOOKMARK_THUMB_WIDTH)
241   {
242     height = BOOKMARK_THUMB_WIDTH;
243     width = (int)(BOOKMARK_THUMB_WIDTH * aspectRatio);
244   }
245   CSingleLock lock(g_graphicsContext);
246 #ifndef HAS_SDL
247   LPDIRECT3DTEXTURE8 texture = NULL;
248   if (D3D_OK == D3DXCreateTexture(g_graphicsContext.Get3DDevice(), width, height, 1, 0, D3DFMT_LIN_A8R8G8B8, D3DPOOL_MANAGED, &texture))
249   {
250     LPDIRECT3DSURFACE8 surface = NULL;
251     texture->GetSurfaceLevel(0, &surface);
252 #ifdef HAS_VIDEO_PLAYBACK
253     g_renderManager.CreateThumbnail(surface, width, height);
254 #endif
255     D3DLOCKED_RECT lockedRect;
256     surface->LockRect(&lockedRect, NULL, NULL);
257     // compute the thumb name + create the thumb image
258     Crc32 crc;
259     crc.ComputeFromLowerCase(g_application.CurrentFile());
260     bookmark.thumbNailImage.Format("%08x_%i.jpg", (unsigned __int32) crc, m_vecItems->Size() + 1);
261     bookmark.thumbNailImage = CUtil::AddFileToFolder(g_settings.GetBookmarksThumbFolder(), bookmark.thumbNailImage);
262     CPicture pic;
263     if (!pic.CreateThumbnailFromSurface((BYTE *)lockedRect.pBits, width, height, lockedRect.Pitch, bookmark.thumbNailImage))
264       bookmark.thumbNailImage.Empty();
265     surface->UnlockRect();
266     surface->Release();
267     texture->Release();
268   }
269 #elif defined(HAS_SDL)
270   SDL_Surface *texture = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32,
271                                               RMASK, GMASK, BMASK, AMASK);
272   if (texture)
273   {
274     SDL_LockSurface(texture);
275 #ifdef HAS_VIDEO_PLAYBACK
276     g_renderManager.CreateThumbnail(texture, width, height);
277 #endif
278     Crc32 crc;
279     crc.ComputeFromLowerCase(g_application.CurrentFile());
280     bookmark.thumbNailImage.Format("%08x_%i.jpg", (unsigned __int32) crc, m_vecItems->Size() + 1);
281     bookmark.thumbNailImage = CUtil::AddFileToFolder(g_settings.GetBookmarksThumbFolder(), bookmark.thumbNailImage);
282     CPicture pic;
283     if (!pic.CreateThumbnailFromSurface((BYTE *)texture->pixels, width, height, texture->pitch,
284                                         bookmark.thumbNailImage))
285       bookmark.thumbNailImage.Empty();
286     SDL_UnlockSurface(texture);
287     SDL_FreeSurface(texture);
288   }
289 #endif
290   lock.Leave();
291   videoDatabase.Open();
292   if (tag)
293     videoDatabase.AddBookMarkForEpisode(*tag, bookmark);
294   else
295     videoDatabase.AddBookMarkToFile(g_application.CurrentFile(), bookmark, CBookmark::STANDARD);
296   videoDatabase.Close();
297   Update();
298 }
299
300 void CGUIDialogVideoBookmarks::OnWindowLoaded()
301 {
302   CGUIDialog::OnWindowLoaded();
303   m_viewControl.Reset();
304   m_viewControl.SetParentWindow(GetID());
305   m_viewControl.AddView(GetControl(CONTROL_THUMBS));
306 }
307
308 void CGUIDialogVideoBookmarks::OnWindowUnload()
309 {
310   CGUIDialog::OnWindowUnload();
311   m_viewControl.Reset();
312 }
313
314 CGUIControl *CGUIDialogVideoBookmarks::GetFirstFocusableControl(int id)
315 {
316   if (m_viewControl.HasControl(id))
317     id = m_viewControl.GetCurrentControl();
318   return CGUIWindow::GetFirstFocusableControl(id);
319 }
320
321 void CGUIDialogVideoBookmarks::AddEpisodeBookmark()
322 {
323   vector<CVideoInfoTag> episodes;
324   CVideoDatabase videoDatabase;
325   CPoint pos;
326   videoDatabase.Open();
327   videoDatabase.GetEpisodesByFile(g_application.CurrentFile(), episodes);
328   videoDatabase.Close();
329   if(episodes.size() > 0)
330   {
331     CGUIDialogContextMenu *pMenu = (CGUIDialogContextMenu *)m_gWindowManager.GetWindow(WINDOW_DIALOG_CONTEXT_MENU);
332     map<int, CVideoInfoTag*> buttons;
333     const CGUIControl *pList = GetControl(CONTROL_ADD_EPISODE_BOOKMARK);
334     if (pList)
335       pos = pList->GetRenderPosition() + CPoint(pList->GetWidth() * 0.5f, pList->GetHeight() * 0.5f);
336     if (pMenu)
337     {
338       pMenu->Initialize();
339       for (unsigned int i=0; i < episodes.size(); ++i)
340       {
341         CStdString strButton;
342         strButton.Format("%s %i, %s %i", g_localizeStrings.Get(20373), episodes[i].m_iSeason, g_localizeStrings.Get(20359).c_str(), episodes[i].m_iEpisode);
343         buttons[pMenu->AddButton(strButton)] = &episodes[i];
344       }
345
346       pMenu->OffsetPosition(pos.x, pos.y);
347       pMenu->DoModal(GetID());
348
349       int pressed = pMenu->GetButton();
350       if (buttons.find(pressed) != buttons.end())
351         AddBookmark(buttons[pressed]);
352     }
353   }
354 }
355