fixed: scroll bars didn't work.
[xbmc:xbmc-antiquated.git] / xbmc / GUIWindowVideoBase.cpp
1 /*
2  *      Copyright (C) 2005-2007 Team XboxMediaCenter
3  *      http://www.xboxmediacenter.com
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 GNU Make; 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 "GUIWindowVideoBase.h"
24 #include "Util.h"
25 #include "Utils/IMDB.h"
26 #include "Utils/HTTP.h"
27 #include "GUIWindowVideoInfo.h"
28 #include "PlayListFactory.h"
29 #include "Application.h"
30 #include "NFOFile.h"
31 #include "utils/fstrcmp.h"
32 #include "PlayListPlayer.h"
33 #ifdef PRE_SKIN_VERSION_2_1_COMPATIBILITY
34 #include "GUIFontManager.h"
35 #endif
36 #include "GUIPassword.h"
37 #include "FileSystem/ZipManager.h"
38 #include "FileSystem/StackDirectory.h"
39 #include "GUIDialogContextMenu.h"
40 #include "GUIDialogFileStacking.h"
41 #include "GUIDialogMediaSource.h"
42 #include "GUIWindowFileManager.h"
43 #include "FileSystem/VideoDatabaseDirectory.h"
44
45 #include "SkinInfo.h"
46
47 using namespace XFILE;
48 using namespace DIRECTORY;
49 using namespace PLAYLIST;
50 using namespace VIDEODATABASEDIRECTORY;
51
52 #define CONTROL_BTNVIEWASICONS     2
53 #define CONTROL_BTNSORTBY          3
54 #define CONTROL_BTNSORTASC         4
55 #define CONTROL_BTNTYPE            5
56 #define CONTROL_LIST              50
57 #define CONTROL_THUMBS            51
58 #define CONTROL_BIGLIST           52
59 #define CONTROL_LABELFILES        12
60 #define CONTROL_LABELEMPTY        13
61
62 #define CONTROL_PLAY_DVD          6
63 #define CONTROL_STACK             7
64 #define CONTROL_BTNSCAN           8
65 #define CONTROL_IMDB              9
66 #define CONTROL_BTNSHOWMODE       10
67
68 CGUIWindowVideoBase::CGUIWindowVideoBase(DWORD dwID, const CStdString &xmlFile)
69     : CGUIMediaWindow(dwID, xmlFile)
70 {
71   m_bDisplayEmptyDatabaseMessage = false;
72   m_thumbLoader.SetObserver(this);
73 }
74
75 CGUIWindowVideoBase::~CGUIWindowVideoBase()
76 {
77 }
78
79 bool CGUIWindowVideoBase::OnMessage(CGUIMessage& message)
80 {
81   switch ( message.GetMessage() )
82   {
83   case GUI_MSG_WINDOW_DEINIT:
84     if (m_thumbLoader.IsLoading())
85       m_thumbLoader.StopThread();
86     m_database.Close();
87     break;
88
89   case GUI_MSG_WINDOW_INIT:
90     {
91       m_database.Open();
92
93       m_dlgProgress = (CGUIDialogProgress*)m_gWindowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
94
95       // save current window, unless the current window is the video playlist window
96       if (GetID() != WINDOW_VIDEO_PLAYLIST)
97         g_stSettings.m_iVideoStartWindow = GetID();
98
99
100       return CGUIMediaWindow::OnMessage(message);
101     }
102     break;
103
104   case GUI_MSG_CLICKED:
105     {
106       int iControl = message.GetSenderId();
107       if (iControl == CONTROL_PLAY_DVD)
108       {
109         // play movie...
110         CUtil::PlayDVD();
111       }
112       else if (iControl == CONTROL_BTNTYPE)
113       {
114         CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_BTNTYPE);
115         m_gWindowManager.SendMessage(msg);
116
117         int nSelected = msg.GetParam1();
118         int nNewWindow = WINDOW_VIDEO_FILES;
119         switch (nSelected)
120         {
121         case 0:  // Movies
122           nNewWindow = WINDOW_VIDEO_FILES;
123           break;
124         case 1:  // Library
125           nNewWindow = WINDOW_VIDEO_NAV;
126           break;
127         }
128
129         if (nNewWindow != GetID())
130         {
131           g_stSettings.m_iVideoStartWindow = nNewWindow;
132           g_settings.Save();
133           m_gWindowManager.ChangeActiveWindow(nNewWindow);
134           CGUIMessage msg2(GUI_MSG_SETFOCUS, nNewWindow, CONTROL_BTNTYPE);
135           g_graphicsContext.SendMessage(msg2);
136         }
137
138         return true;
139       }
140       else if (iControl == CONTROL_BTNSHOWMODE)
141       {
142         g_stSettings.m_iMyVideoWatchMode++;
143         if (g_stSettings.m_iMyVideoWatchMode > VIDEO_SHOW_WATCHED)
144           g_stSettings.m_iMyVideoWatchMode = VIDEO_SHOW_ALL;
145         g_settings.Save();
146         Update(m_vecItems.m_strPath);
147         return true;
148       }
149       else if (m_viewControl.HasControl(iControl))  // list/thumb control
150       {
151         // get selected item
152         int iItem = m_viewControl.GetSelectedItem();
153         int iAction = message.GetParam1();
154
155         // iItem is checked for validity inside these routines
156         if (iAction == ACTION_QUEUE_ITEM || iAction == ACTION_MOUSE_MIDDLE_CLICK)
157         {
158           OnQueueItem(iItem);
159           return true;
160         }
161         else if (iAction == ACTION_SHOW_INFO)
162         {
163           SScraperInfo info;
164           CStdString strDir;
165           CUtil::GetDirectory(m_vecItems[iItem]->m_strPath,strDir);
166           m_database.GetScraperForPath(strDir,info.strPath,info.strContent);
167           OnInfo(iItem,info);
168           return true;
169         }
170         else if (iAction == ACTION_CONTEXT_MENU || iAction == ACTION_MOUSE_RIGHT_CLICK)
171         {
172           OnPopupMenu(iItem);
173           return true;
174         }
175         else if (iAction == ACTION_PLAYER_PLAY && !g_application.IsPlayingVideo())
176         {
177           OnResumeItem(iItem);
178           return true;
179         }
180         else if (iAction == ACTION_DELETE_ITEM)
181         {
182           // is delete allowed?
183           // must be at the title window
184           if (GetID() == WINDOW_VIDEO_NAV)
185             OnDeleteItem(iItem);
186
187           // or be at the files window and have file deletion enabled
188           else if (GetID() == WINDOW_VIDEO_FILES && g_guiSettings.GetBool("filelists.allowfiledeletion"))
189             OnDeleteItem(iItem);
190
191           // or be at the video playlists location
192           else if (m_vecItems.m_strPath.Equals("special://videoplaylists/"))
193             OnDeleteItem(iItem);
194           else
195             return false;
196           
197           return true;
198         }
199       }
200       else if (iControl == CONTROL_IMDB)
201       {
202         OnManualIMDB();
203       }
204     }
205     break;
206   }
207   return CGUIMediaWindow::OnMessage(message);
208 }
209
210 void CGUIWindowVideoBase::UpdateButtons()
211 {
212   // Remove labels from the window selection
213   CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), CONTROL_BTNTYPE);
214   g_graphicsContext.SendMessage(msg);
215
216   // Add labels to the window selection
217   CStdString strItem = g_localizeStrings.Get(744); // Files
218   CGUIMessage msg2(GUI_MSG_LABEL_ADD, GetID(), CONTROL_BTNTYPE);
219   msg2.SetLabel(strItem);
220   g_graphicsContext.SendMessage(msg2);
221
222   strItem = g_localizeStrings.Get(14022); // Library
223   msg2.SetLabel(strItem);
224   g_graphicsContext.SendMessage(msg2);
225
226   // Select the current window as default item
227   int nWindow = g_stSettings.m_iVideoStartWindow-WINDOW_VIDEO_FILES;
228   CONTROL_SELECT_ITEM(CONTROL_BTNTYPE, nWindow);
229
230   // disable scan and manual imdb controls if internet lookups are disabled
231   if (g_guiSettings.GetBool("network.enableinternet"))
232   {
233     CONTROL_ENABLE(CONTROL_BTNSCAN);
234     CONTROL_ENABLE(CONTROL_IMDB);
235   }
236   else
237   {
238     CONTROL_DISABLE(CONTROL_BTNSCAN);
239     CONTROL_DISABLE(CONTROL_IMDB);
240   }
241
242   SET_CONTROL_LABEL(CONTROL_BTNSHOWMODE, g_localizeStrings.Get(16100 + g_stSettings.m_iMyVideoWatchMode));
243   CGUIMediaWindow::UpdateButtons();
244 }
245
246 void CGUIWindowVideoBase::OnInfo(int iItem, const SScraperInfo& info)
247 {
248   if ( iItem < 0 || iItem >= m_vecItems.Size() ) return ;
249   CFileItem* pItem = m_vecItems[iItem];
250   CStdString strFile = CUtil::GetFileName(pItem->m_strPath);
251   // ShowIMDB can kill the item as this window can be closed while we do it,
252   // so take a copy of the item now
253   CFileItem item(*pItem);
254   ShowIMDB(&item, info);
255   Update(m_vecItems.m_strPath);
256 }
257
258 // ShowIMDB is called as follows:
259 // 1.  To lookup info on a file.
260 // 2.  To lookup info on a folder (which may or may not contain a file)
261 // 3.  To lookup info just for fun (no file or folder related)
262
263 // We just need the item object for this.
264 // A "blank" item object is sent for 3.
265 // If a folder is sent, currently it sets strFolder and bFolder
266 // this is only used for setting the folder thumb, however.
267
268 // Steps should be:
269
270 // 1.  Check database to see if we have this information already
271 // 2.  Else, check for a nfoFile to get the URL
272 // 3.  Run a loop to check for refresh
273 // 4.  If no URL is present do a search to get the URL
274 // 4.  Once we have the URL, download the details
275 // 5.  Once we have the details, add to the database if necessary (case 1,2)
276 //     and show the information.
277 // 6.  Check for a refresh, and if so, go to 3.
278
279 void CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const SScraperInfo& info)
280 {
281   /*
282   CLog::Log(LOGDEBUG,"CGUIWindowVideoBase::ShowIMDB");
283   CLog::Log(LOGDEBUG,"  strMovie  = [%s]", strMovie.c_str());
284   CLog::Log(LOGDEBUG,"  strFile   = [%s]", strFile.c_str());
285   CLog::Log(LOGDEBUG,"  strFolder = [%s]", strFolder.c_str());
286   CLog::Log(LOGDEBUG,"  bFolder   = [%s]", ((int)bFolder ? "true" : "false"));
287   */
288
289   CGUIDialogProgress* pDlgProgress = (CGUIDialogProgress*)m_gWindowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
290   CGUIDialogSelect* pDlgSelect = (CGUIDialogSelect*)m_gWindowManager.GetWindow(WINDOW_DIALOG_SELECT);
291   CGUIWindowVideoInfo* pDlgInfo = (CGUIWindowVideoInfo*)m_gWindowManager.GetWindow(WINDOW_VIDEO_INFO);
292
293   CIMDB IMDB;
294   IMDB.SetScraperInfo(info);
295
296   bool bUpdate = false;
297   bool bFound = false;
298
299   if (!pDlgProgress) return ;
300   if (!pDlgSelect) return ;
301   if (!pDlgInfo) return ;
302   CUtil::ClearCache();
303
304   // 1.  Check for already downloaded information, and if we have it, display our dialog
305   //     Return if no Refresh is needed.
306   if (m_database.HasMovieInfo(item->m_strPath))
307   {
308     CIMDBMovie movieDetails;
309     m_database.GetMovieInfo(item->m_strPath, movieDetails);
310     if (info.strContent.IsEmpty()) // disable refresh button
311       movieDetails.m_strIMDBNumber = "xx"+movieDetails.m_strIMDBNumber;
312     pDlgInfo->SetMovie(movieDetails, item);
313     pDlgInfo->DoModal();
314     item->SetThumbnailImage(pDlgInfo->GetThumbnail());
315     if ( !pDlgInfo->NeedRefresh() ) return ;
316     m_database.DeleteMovieInfo(item->m_strPath);
317   }
318
319   // quietly return if Internet lookups are disabled
320   if (!g_guiSettings.GetBool("network.enableinternet")) return ;
321   if (!g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].canWriteDatabases() && !g_passwordManager.bMasterUser)
322     return;
323
324   CIMDBUrl url;
325   CIMDBMovie movieDetails;
326
327   // 2. Look for a nfo File to get the search URL
328   CStdString nfoFile = GetnfoFile(item);
329   if ( !nfoFile.IsEmpty() && info.strContent.Equals("movies") )
330   {
331     CLog::Log(LOGDEBUG,"Found matching nfo file: %s", nfoFile.c_str());
332     if ( CFile::Cache(nfoFile, "Z:\\movie.nfo", NULL, NULL))
333     {
334       CNfoFile nfoReader;
335       if ( nfoReader.Create("Z:\\movie.nfo") == S_OK)
336       {
337                 url.m_strURL.push_back(nfoReader.m_strImDbUrl);
338         url.m_strURL.push_back(nfoReader.m_strImDbUrl+"/plotsummary");
339         url.m_strID = nfoReader.m_strImDbNr;
340         SScraperInfo info2(info);
341         info2.strPath = "imdb.xml"; // fallback to imdb scraper no matter what is configured
342         IMDB.SetScraperInfo(info2);
343         CLog::Log(LOGDEBUG,"-- imdb url: %s", url.m_strURL[0].c_str());
344       }
345       else
346         CLog::Log(LOGERROR,"Unable to find an imdb url in nfo file: %s", nfoFile.c_str());
347     }
348     else
349       CLog::Log(LOGERROR,"Unable to cache nfo file: %s", nfoFile.c_str());
350   }
351
352   CStdString movieName = item->GetLabel();
353   // 3. Run a loop so that if we Refresh we re-run this block
354   bool needsRefresh(false);
355   do
356   {
357     // 4. if we don't have a url, or need to refresh the search
358     //    then do the web search
359     if (url.m_strURL.size() == 0 || needsRefresh)
360     {
361       // 4a. show dialog that we're busy querying www.imdb.com
362       pDlgProgress->SetHeading(197);
363       pDlgProgress->SetLine(0, movieName);
364       pDlgProgress->SetLine(1, "");
365       pDlgProgress->SetLine(2, "");
366       pDlgProgress->StartModal();
367       pDlgProgress->Progress();
368
369       // 4b. do the websearch
370       IMDB_MOVIELIST movielist;
371       if (IMDB.FindMovie(movieName, movielist, pDlgProgress))
372       {
373         pDlgProgress->Close();
374         if (movielist.size() > 0)
375         {
376           // 4c. found movies - allow selection of the movie we found if several
377           if (movielist.size() == 1)
378           {
379             url = movielist[0];
380           }
381           else
382           {
383             pDlgSelect->SetHeading(196);
384             pDlgSelect->Reset();
385             for (unsigned int i = 0; i < movielist.size(); ++i)
386               pDlgSelect->Add(movielist[i].m_strTitle);
387             pDlgSelect->EnableButton(true);
388             pDlgSelect->SetButtonLabel(413); // manual
389             pDlgSelect->DoModal();
390
391             // and wait till user selects one
392             int iSelectedMovie = pDlgSelect->GetSelectedLabel();
393             if (iSelectedMovie >= 0)
394               url = movielist[iSelectedMovie];
395             else if (!pDlgSelect->IsButtonPressed())
396             {
397               return; // user backed out
398             }
399           }
400         }
401       }
402     }
403     // 4c. Check if url is still empty - occurs if user has selected to do a manual
404     //     lookup, or if the IMDb lookup failed or was cancelled.
405     if (url.m_strURL.size() == 0)
406     {
407       // Check for cancel of the progress dialog
408       pDlgProgress->Close();
409       if (pDlgProgress->IsCanceled())
410       {
411         return;
412       }
413
414       // Prompt the user to input the movieName
415       if (!CGUIDialogKeyboard::ShowAndGetInput(movieName, g_localizeStrings.Get(16009), false))
416       {
417         return; // user backed out
418       }
419
420       needsRefresh = true;
421     }
422     else
423     {
424       // 5. Download the movie information
425       // show dialog that we're downloading the movie info
426       pDlgProgress->SetHeading(198);
427       pDlgProgress->SetLine(0, movieName);
428       pDlgProgress->SetLine(1, url.m_strTitle);
429       pDlgProgress->SetLine(2, "");
430       pDlgProgress->StartModal();
431       pDlgProgress->Progress();
432
433       // get the movie info
434       if (IMDB.GetDetails(url, movieDetails, pDlgProgress))
435       {
436         // got all movie details :-)
437         OutputDebugString("got details\n");
438         pDlgProgress->Close();
439
440         // now show the imdb info
441         OutputDebugString("show info\n");
442
443         // Add to the database if applicable
444         if (item->m_strPath && (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].canWriteDatabases() || g_passwordManager.bMasterUser))
445         {
446           m_database.SetMovieInfo(item->m_strPath, movieDetails);
447           // remove directory caches
448           CFileItemList items;
449           CDirectory::GetDirectory("z:\\",items,".fi",false);
450           for (int i=0;i<items.Size();++i)
451           {
452             if (!items[i]->m_bIsFolder)
453             {
454               CFile::Delete(items[i]->m_strPath);
455             }
456           }
457         }
458
459         pDlgInfo->SetMovie(movieDetails, item);
460         pDlgInfo->DoModal();
461         item->SetThumbnailImage(pDlgInfo->GetThumbnail());
462         needsRefresh = pDlgInfo->NeedRefresh();
463       }
464       else
465       {
466         pDlgProgress->Close();
467         if (pDlgProgress->IsCanceled())
468         {
469           return; // user cancelled
470         }
471         OutputDebugString("failed to get details\n");
472         // show dialog...
473         CGUIDialogOK *pDlgOK = (CGUIDialogOK*)m_gWindowManager.GetWindow(WINDOW_DIALOG_OK);
474         if (pDlgOK)
475         {
476           pDlgOK->SetHeading(195);
477           pDlgOK->SetLine(0, movieName);
478           pDlgOK->SetLine(1, "");
479           pDlgOK->SetLine(2, "");
480           pDlgOK->SetLine(3, "");
481           pDlgOK->DoModal();
482         }
483         return;
484       }
485     }
486     // 6. Check for a refresh
487   } while (needsRefresh);
488 }
489
490 void CGUIWindowVideoBase::Render()
491 {
492   if (m_bDisplayEmptyDatabaseMessage)
493   {
494     SET_CONTROL_LABEL(CONTROL_LABELEMPTY,g_localizeStrings.Get(745)+'\n'+g_localizeStrings.Get(746))
495   }
496   else
497   {
498     SET_CONTROL_LABEL(CONTROL_LABELEMPTY,"")
499   }
500
501   CGUIMediaWindow::Render();
502 }
503
504 void CGUIWindowVideoBase::OnManualIMDB()
505 {
506   CStdString strInput;
507   if (!CGUIDialogKeyboard::ShowAndGetInput(strInput, g_localizeStrings.Get(16009), false)) return ;
508
509   CFileItem item(strInput);
510   item.m_strPath = "Z:\\";
511   ::DeleteFile(item.GetCachedVideoThumb().c_str());
512
513   SScraperInfo info;
514   info.strContent = "movies";
515   info.strPath = "imdb.xml";
516   ShowIMDB(&item,info);
517   
518   return ;
519 }
520
521 bool CGUIWindowVideoBase::IsCorrectDiskInDrive(const CStdString& strFileName, const CStdString& strDVDLabel)
522 {
523   CDetectDVDMedia::WaitMediaReady();
524   CCdInfo* pCdInfo = CDetectDVDMedia::GetCdInfo();
525   if (pCdInfo == NULL) return false;
526   if (!CFile::Exists(strFileName)) return false;
527   CStdString label = pCdInfo->GetDiscLabel().TrimRight(" ");
528   int iLabelCD = label.GetLength();
529   int iLabelDB = strDVDLabel.GetLength();
530   if (iLabelDB < iLabelCD) return false;
531   CStdString dbLabel = strDVDLabel.Left(iLabelCD);
532   return (dbLabel == label);
533 }
534
535 bool CGUIWindowVideoBase::CheckMovie(const CStdString& strFileName)
536 {
537   if (!m_database.HasMovieInfo(strFileName) ) return true;
538
539   CIMDBMovie movieDetails;
540   m_database.GetMovieInfo(strFileName, movieDetails);
541   CFileItem movieFile(movieDetails.m_strFileNameAndPath, false);
542   if ( !movieFile.IsOnDVD()) return true;
543   CGUIDialogOK *pDlgOK = (CGUIDialogOK*)m_gWindowManager.GetWindow(WINDOW_DIALOG_OK);
544   if (!pDlgOK) return true;
545   while (1)
546   {
547 //    if (IsCorrectDiskInDrive(strFileName, movieDetails.m_strDVDLabel))
548  //   {
549       return true;
550  //   }
551     pDlgOK->SetHeading( 428);
552     pDlgOK->SetLine( 0, 429 );
553 //    pDlgOK->SetLine( 1, movieDetails.m_strDVDLabel );
554     pDlgOK->SetLine( 2, "" );
555     pDlgOK->DoModal();
556     if (!pDlgOK->IsConfirmed())
557     {
558       break;
559     }
560   }
561   return false;
562 }
563
564 void CGUIWindowVideoBase::OnQueueItem(int iItem)
565 {
566   if ( iItem < 0 || iItem >= m_vecItems.Size() ) return ;
567
568   int iOldSize=g_playlistPlayer.GetPlaylist(PLAYLIST_VIDEO).size();
569
570   CFileItem item(*m_vecItems[iItem]);
571   if (item.IsRAR() || item.IsZIP())
572     return;
573
574   //  Allow queuing of unqueueable items
575   //  when we try to queue them directly
576   if (!item.CanQueue())
577     item.SetCanQueue(true);
578
579   CFileItemList queuedItems;
580   AddItemToPlayList(&item, queuedItems);
581   g_playlistPlayer.Add(PLAYLIST_VIDEO, queuedItems);
582   // video does not auto play on queue like music
583   m_viewControl.SetSelectedItem(iItem + 1);
584 }
585
586 void CGUIWindowVideoBase::AddItemToPlayList(const CFileItem* pItem, CFileItemList &queuedItems)
587 {
588   if (!pItem->CanQueue() || pItem->IsRAR() || pItem->IsZIP() || pItem->IsParentFolder()) // no zip/rar enques thank you!
589     return;
590
591   if (pItem->m_bIsFolder)
592   {
593     if (pItem->IsParentFolder()) return;
594
595     // Check if we add a locked share
596     if ( pItem->m_bIsShareOrDrive )
597     {
598       CFileItem item = *pItem;
599       if ( !g_passwordManager.IsItemUnlocked( &item, "video" ) )
600         return ;
601     }
602
603     // recursive
604     CFileItemList items;
605     GetDirectory(pItem->m_strPath, items);
606     SortItems(items);
607
608     for (int i = 0; i < items.Size(); ++i)
609     {
610       if (items[i]->m_bIsFolder)
611       {
612         CStdString strPath = items[i]->m_strPath;
613         if (CUtil::HasSlashAtEnd(strPath))
614           strPath.erase(strPath.size()-1);
615         strPath.ToLower();
616         if (strPath.size() > 6)
617         {
618           CStdString strSub = strPath.substr(strPath.size()-6);
619           if (strPath.substr(strPath.size()-6) == "sample") // skip sample folders
620             continue;
621         }
622       }
623       AddItemToPlayList(items[i], queuedItems);
624     }
625   }
626   else
627   {
628     // just an item
629     if (pItem->IsPlayList())
630     {
631       auto_ptr<CPlayList> pPlayList (CPlayListFactory::Create(*pItem));
632       if ( NULL != pPlayList.get())
633       {
634         // load it
635         if (!pPlayList->Load(pItem->m_strPath))
636         {
637           CGUIDialogOK::ShowAndGetInput(6, 0, 477, 0);
638           return; //hmmm unable to load playlist?
639         }
640
641         CPlayList playlist = *pPlayList;
642         for (int i = 0; i < (int)playlist.size(); ++i)
643           AddItemToPlayList(&playlist[i], queuedItems);
644         return;
645       }
646     }
647     else if(pItem->IsInternetStream())
648     { // just queue the internet stream, it will be expanded on play
649       queuedItems.Add(new CFileItem(*pItem));
650     }
651     else if (!pItem->IsNFO() && pItem->IsVideo())
652     {
653       queuedItems.Add(new CFileItem(*pItem));
654     }
655
656   }
657 }
658
659 void CGUIWindowVideoBase::DisplayEmptyDatabaseMessage(bool bDisplay)
660 {
661   m_bDisplayEmptyDatabaseMessage = bDisplay;
662 }
663
664 int  CGUIWindowVideoBase::GetResumeItemOffset(const CFileItem *item)
665 {
666   m_database.Open();
667   long startoffset = 0;
668
669   if (item->IsStack() && !g_guiSettings.GetBool("myvideos.treatstackasfile") )
670   {
671
672     CStdStringArray movies;
673     GetStackedFiles(item->m_strPath, movies);
674
675     /* check if any of the stacked files have a resume bookmark */
676     for(unsigned i = 0; i<movies.size();i++)
677     {
678       CBookmark bookmark;
679       if(m_database.GetResumeBookMark(movies[i], bookmark))
680       {
681         startoffset = (long)(bookmark.timeInSeconds*75);
682         startoffset += 0x10000000 * (i+1); /* store file number in here */
683         break;
684       }
685     }
686   }
687   else if (!item->IsNFO() && !item->IsPlayList())
688   {
689     CBookmark bookmark;
690     if(m_database.GetResumeBookMark(item->m_strPath, bookmark))
691       startoffset = (long)(bookmark.timeInSeconds*75);
692   }
693   m_database.Close();
694   return startoffset;
695 }
696
697 bool CGUIWindowVideoBase::OnClick(int iItem)
698 {
699   if (g_guiSettings.GetBool("myvideos.autoresume"))
700     OnResumeItem(iItem);
701   else
702     return CGUIMediaWindow::OnClick(iItem);
703
704   return true;
705 }
706
707 void CGUIWindowVideoBase::OnRestartItem(int iItem)
708 {
709   CGUIMediaWindow::OnClick(iItem);
710 }
711
712 void CGUIWindowVideoBase::OnResumeItem(int iItem)
713 {
714   m_vecItems[iItem]->m_lStartOffset = STARTOFFSET_RESUME;
715   CGUIMediaWindow::OnClick(iItem);
716 }
717
718 void CGUIWindowVideoBase::OnPopupMenu(int iItem, bool bContextDriven /* = true */)
719 {
720   // empty list in files view?
721   if (GetID() == WINDOW_VIDEO_FILES && m_vecItems.Size() == 0)
722     bContextDriven = false;
723   if (bContextDriven && (iItem < 0 || iItem >= m_vecItems.Size())) return;
724
725   // calculate our position
726   float posX = 200, posY = 100;
727   const CGUIControl *pList = GetControl(CONTROL_LIST);
728   if (pList)
729   {
730     posX = pList->GetXPosition() + pList->GetWidth() / 2;
731     posY = pList->GetYPosition() + pList->GetHeight() / 2;
732   }
733
734   // popup the context menu
735   CGUIDialogContextMenu *pMenu = (CGUIDialogContextMenu *)m_gWindowManager.GetWindow(WINDOW_DIALOG_CONTEXT_MENU);
736   if (!pMenu) return ;
737
738   // load our menu
739   pMenu->Initialize();
740
741   // contextual buttons
742   int btn_PlayPart = 0;       // For stacks
743   int btn_Queue = 0;                                    // Add to Playlist
744   int btn_PlayWith = 0;                         // Play
745   int btn_Restart = 0;                          // Restart Video from Beginning
746   int btn_Resume = 0;                                   // Resume Video
747   int btn_Show_Info = 0;                        // Show Video Information
748   int btn_AddToDatabase = 0;  // Manual add to Database
749   int btn_Assign = 0;         // Assign content to directory
750   int btn_Update = 0;         // Update content information
751   int btn_Mark_UnWatched = 0;   // Clear Watched Status (DB)
752   int btn_Mark_Watched = 0;             // Set Watched Status (DB)
753   int btn_Update_Title = 0;             // Change Title (DB)
754   int btn_Delete = 0;                                   // Delete
755   int btn_Rename = 0;                                   // Rename
756
757   bool bSelected = false;
758   VECPLAYERCORES vecCores;
759   int iFound = 0;
760   SScraperInfo info;
761
762   // contextual items only appear when the list is not empty
763   if (bContextDriven)
764   {
765     // mark the item
766     bSelected = m_vecItems[iItem]->IsSelected(); // item may already be selected (playlistitem)
767     m_vecItems[iItem]->Select(true);
768
769     // get players
770     CPlayerCoreFactory::GetPlayers(*m_vecItems[iItem], vecCores);
771
772     bool bIsGotoParent = m_vecItems[iItem]->IsParentFolder();
773     if (!bIsGotoParent)
774     {
775       // don't show the add to playlist button in playlist window
776       if (GetID() != WINDOW_VIDEO_PLAYLIST)
777       {
778         if (m_vecItems[iItem]->IsStack())
779         {
780           vector<long> times;
781           if (m_database.GetStackTimes(m_vecItems[iItem]->m_strPath,times))
782             btn_PlayPart = pMenu->AddButton(20324);
783         }
784         if (GetID() == WINDOW_VIDEO_NAV)
785         {
786           if (!m_vecItems.m_strPath.IsEmpty())
787             btn_Queue = pMenu->AddButton(13347);      // Add to Playlist
788         }
789         else
790           btn_Queue = pMenu->AddButton(13347);      // Add to Playlist
791
792         if (vecCores.size() >= 1)
793           btn_PlayWith = pMenu->AddButton(15213);
794         // allow a folder to be ad-hoc queued and played by the default player
795         else if (GetID() == WINDOW_VIDEO_FILES && (m_vecItems[iItem]->m_bIsFolder || m_vecItems[iItem]->IsPlayList()))
796           btn_PlayWith = pMenu->AddButton(208);
797
798         // if autoresume is enabled then add restart video button
799         // check to see if the Resume Video button is applicable
800         if (GetResumeItemOffset(m_vecItems[iItem]) > 0)
801           if (g_guiSettings.GetBool("myvideos.autoresume"))
802             btn_Restart = pMenu->AddButton(20132);    // Restart Video
803           else
804             btn_Resume = pMenu->AddButton(13381);     // Resume Video
805       }
806
807       if (GetID() == WINDOW_VIDEO_FILES && (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].canWriteDatabases() || g_passwordManager.bMasterUser))
808       {
809         m_database.GetScraperForPath(m_vecItems[iItem]->m_strPath,info.strPath,info.strContent,iFound);
810         if (m_vecItems[iItem]->m_bIsFolder)
811         {
812           if (iFound==0)
813           {
814             CStdString strPath(m_vecItems[iItem]->m_strPath);
815             CUtil::AddSlashAtEnd(strPath);
816             if (m_database.HasMovieInfo(strPath))
817               btn_Show_Info = pMenu->AddButton(13346);
818
819             btn_Assign = pMenu->AddButton(20333);
820           }
821           else
822           {
823             btn_Show_Info = pMenu->AddButton(13346);
824             btn_Update = pMenu->AddButton(13349);
825             btn_Assign = pMenu->AddButton(20333);
826           }
827         }
828         else
829         {
830           if (iFound > 0 || m_database.HasMovieInfo(m_vecItems[iItem]->m_strPath))
831             btn_Show_Info = pMenu->AddButton(13346);
832           else
833           {
834             m_database.Open();
835             if (!bIsGotoParent)
836             {
837               if (m_database.GetMovieInfo(m_vecItems[iItem]->m_strPath)<0)
838                 btn_AddToDatabase = pMenu->AddButton(527); // Add to Database
839             }
840             m_database.Close();
841           }
842         }
843       }
844     }
845     if (GetID() == WINDOW_VIDEO_NAV && !m_vecItems[iItem]->m_bIsFolder)
846       btn_Show_Info = pMenu->AddButton(13346);
847
848     // is the item a database movie?
849     if (GetID() == WINDOW_VIDEO_NAV && !m_vecItems[iItem]->m_musicInfoTag.GetURL().IsEmpty() && (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].canWriteDatabases() || g_passwordManager.bMasterUser))
850     {
851       // uses Loaded to hold Watched/UnWatched status
852       if (m_vecItems[iItem]->m_musicInfoTag.Loaded())
853         btn_Mark_UnWatched = pMenu->AddButton(16104); //Mark as UnWatched
854       else
855         btn_Mark_Watched = pMenu->AddButton(16103);   //Mark as Watched
856
857       if (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].canWriteDatabases() || g_passwordManager.bMasterUser)
858         btn_Update_Title = pMenu->AddButton(16105); //Edit Title
859     }
860     if (!bIsGotoParent)
861     {
862       // video playlists or file operations are allowed
863       if ((m_vecItems.m_strPath.Equals("special://videoplaylists/")) || (GetID() == WINDOW_VIDEO_FILES && g_guiSettings.GetBool("filelists.allowfiledeletion")))
864       {
865         if (!m_vecItems[iItem]->IsReadOnly())
866         { // enable only if writeable
867           btn_Delete = pMenu->AddButton(117);
868           btn_Rename = pMenu->AddButton(118);
869         }
870       }
871       // delete titles from database
872       if (GetID() == WINDOW_VIDEO_NAV && (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].canWriteDatabases() || g_passwordManager.bMasterUser))
873       {
874         CVideoDatabaseDirectory dir;
875         NODE_TYPE node = dir.GetDirectoryChildType(m_vecItems.m_strPath);
876         if (node == NODE_TYPE_TITLE)
877           btn_Delete = pMenu->AddButton(646);
878       }
879     }
880   } // if (bContextDriven)
881   // non-contextual buttons
882   int btn_Settings = pMenu->AddButton(5);                       // Settings
883   int btn_GoToRoot = 0;
884   if (!m_vecItems.m_strPath.IsEmpty())
885     btn_GoToRoot = pMenu->AddButton(20128);
886
887   int btn_Switch = 0;                                                                                                   // Switch Media
888   int btn_NowPlaying = 0;                                                                                       // Now Playing
889
890   // Switch Media is only visible in files window
891   if (GetID() == WINDOW_VIDEO_FILES)
892   {
893     btn_Switch = pMenu->AddButton(523); // switch media
894   }
895
896   // Now Playing... at the very bottom of the list for easy access
897   if (g_playlistPlayer.GetPlaylist(PLAYLIST_VIDEO).size() > 0)
898       btn_NowPlaying = pMenu->AddButton(13350);
899
900   // position it correctly
901   pMenu->SetPosition(posX - pMenu->GetWidth() / 2, posY - pMenu->GetHeight() / 2);
902   pMenu->DoModal();
903
904   int btnid = pMenu->GetButton();
905   if (btnid>0)
906   {
907     // play part
908     if (btnid == btn_PlayPart)
909     {
910       CFileItemList items;
911       CDirectory::GetDirectory(m_vecItems[iItem]->m_strPath,items);
912       CGUIDialogFileStacking* dlg = (CGUIDialogFileStacking*)m_gWindowManager.GetWindow(WINDOW_DIALOG_FILESTACKING);
913       if (!dlg)
914         return;
915       dlg->SetNumberOfFiles(items.Size());
916       dlg->DoModal();
917       int btn2 = dlg->GetSelectedFile();
918       if (btn2 > 0)
919       {
920         if (btn2 > 1)
921         {
922           vector<long> times;
923           if (!m_database.GetStackTimes(m_vecItems[iItem]->m_strPath, times)) // need to calculate them times
924             return;
925
926           m_vecItems[iItem]->m_lStartOffset = times[btn2-2]*75; // wtf?
927         }
928         else
929           m_vecItems[iItem]->m_lStartOffset = 0;
930
931         OnClick(iItem);
932       }
933     }
934     // queue
935     if (btnid == btn_Queue)
936     {
937       OnQueueItem(iItem);
938     }
939     // play
940     else if (btnid == btn_PlayWith)
941     {
942       // if folder, play with default player
943       if (m_vecItems[iItem]->m_bIsFolder)
944       {
945         PlayItem(iItem);
946       }
947       else
948       {
949         g_application.m_eForcedNextPlayer = CPlayerCoreFactory::SelectPlayerDialog(vecCores, posX, posY);
950         if( g_application.m_eForcedNextPlayer != EPC_NONE )
951           OnClick(iItem);
952       }
953     }
954     // restart
955     else if (btnid == btn_Restart)
956     {
957       OnRestartItem(iItem);
958     }
959     // resume
960     else if (btnid == btn_Resume)
961     {
962       OnResumeItem(iItem);
963     }
964     else if (btnid == btn_Assign)
965     {
966       OnAssignContent(iItem,iFound,info);
967     }
968     else if (btnid  == btn_Update) // update content 
969     {
970       OnScan(m_vecItems[iItem]->m_strPath,info);
971     }
972     // video info
973     else if (btnid == btn_Show_Info)
974     {
975       OnInfo(iItem,info);
976     }
977     // unwatched
978     else if (btnid == btn_Mark_UnWatched)
979     {
980       MarkUnWatched(iItem);
981     }
982     // watched
983     else if (btnid == btn_Mark_Watched)
984     {
985       MarkWatched(iItem);
986     }
987     // update title
988     else if (btnid == btn_Update_Title)
989     {
990       UpdateVideoTitle(iItem);
991     }
992     // delete
993     else if (btnid == btn_Delete)
994     {
995       OnDeleteItem(iItem);
996     }
997     // rename
998     else if (btnid == btn_Rename)
999     {
1000       OnRenameItem(iItem);
1001     }
1002     // settings
1003     else if (btnid == btn_Settings)
1004     {
1005       m_gWindowManager.ActivateWindow(WINDOW_SETTINGS_MYVIDEOS);
1006       return;
1007     }
1008     // go to root
1009     else if (btnid == btn_GoToRoot)
1010     {
1011       Update("");
1012       return;
1013     }
1014     // switch media
1015     else if (btnid == btn_Switch)
1016     {
1017       CGUIDialogContextMenu::SwitchMedia("video", m_vecItems.m_strPath, posX, posY);
1018       return;
1019     }
1020     // now playing
1021     else if (btnid ==  btn_NowPlaying)
1022     {
1023       m_gWindowManager.ActivateWindow(WINDOW_VIDEO_PLAYLIST);
1024       return;
1025     }
1026     else if (btnid == btn_AddToDatabase)
1027     {
1028       AddToDatabase(iItem);
1029     }
1030   }
1031   if (iItem < m_vecItems.Size())
1032     m_vecItems[iItem]->Select(bSelected);
1033 }
1034
1035 void CGUIWindowVideoBase::GetStackedFiles(const CStdString &strFilePath1, vector<CStdString> &movies)
1036 {
1037   CStdString strFilePath = strFilePath1;  // we're gonna be altering it
1038
1039   movies.clear();
1040
1041   CURL url(strFilePath);
1042   if (url.GetProtocol() == "stack")
1043   {
1044     CStackDirectory dir;
1045     CFileItemList items;
1046     dir.GetDirectory(strFilePath, items);
1047     for (int i = 0; i < items.Size(); ++i)
1048       movies.push_back(items[i]->m_strPath);
1049   }
1050   if (movies.empty())
1051     movies.push_back(strFilePath);
1052 }
1053
1054 bool CGUIWindowVideoBase::OnPlayMedia(int iItem)
1055 {
1056   // Reset Playlistplayer, playback started now does
1057   // not use the playlistplayer.
1058   g_playlistPlayer.Reset();
1059   g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_NONE);
1060
1061   if ( iItem < 0 || iItem >= (int)m_vecItems.Size() ) return false;
1062   CFileItem* pItem = m_vecItems[iItem];
1063
1064   if (pItem->m_strPath == "add" && pItem->GetLabel() == g_localizeStrings.Get(1026)) // 'add source button' in empty root
1065   {
1066     if (CGUIDialogMediaSource::ShowAndAddMediaSource("video"))
1067     {
1068       Update("");
1069       return true;
1070     }
1071     return false;
1072   }
1073
1074   PlayMovie(pItem);
1075
1076   return true;
1077 }
1078
1079 void CGUIWindowVideoBase::PlayMovie(const CFileItem *item)
1080 {
1081   CFileItemList movieList;
1082   int selectedFile = 1;
1083   long startoffset = item->m_lStartOffset;
1084
1085   if (item->IsStack() && !g_guiSettings.GetBool("myvideos.treatstackasfile"))
1086   {
1087     CStdStringArray movies;
1088     GetStackedFiles(item->m_strPath, movies);
1089
1090     if( item->m_lStartOffset == STARTOFFSET_RESUME )
1091     {
1092       startoffset = GetResumeItemOffset(item);
1093
1094       if( startoffset & 0xF0000000 ) /* file is specified as a flag */
1095       {
1096         selectedFile = (startoffset>>28);
1097         startoffset = startoffset & ~0xF0000000;
1098       }
1099       else
1100       {
1101         /* attempt to start on a specific time in a stack */
1102         /* if we are lucky, we might have stored timings for */
1103         /* this stack at some point */
1104
1105         m_database.Open();
1106
1107         /* figure out what file this time offset is */
1108         vector<long> times;
1109         m_database.GetStackTimes(item->m_strPath, times);
1110         long totaltime = 0;
1111         for(unsigned i = 0; i < times.size(); i++)
1112         {
1113           totaltime += times[i]*75;
1114           if( startoffset < totaltime )
1115           {
1116             selectedFile = i+1;
1117             startoffset -= totaltime - times[i]*75; /* rebase agains selected file */
1118             break;
1119           }
1120         }
1121         m_database.Close();
1122       }
1123     }
1124     else
1125     { // show file stacking dialog
1126       CGUIDialogFileStacking* dlg = (CGUIDialogFileStacking*)m_gWindowManager.GetWindow(WINDOW_DIALOG_FILESTACKING);
1127       if (dlg)
1128       {
1129         dlg->SetNumberOfFiles(movies.size());
1130         dlg->DoModal();
1131         selectedFile = dlg->GetSelectedFile();
1132         if (selectedFile < 1) return ;
1133       }
1134     }
1135     // add to our movie list
1136     for (unsigned int i = 0; i < movies.size(); i++)
1137     {
1138       movieList.Add(new CFileItem(movies[i], false));
1139     }
1140   }
1141   else
1142   {
1143     movieList.Add(new CFileItem(*item));
1144   }
1145
1146   g_playlistPlayer.Reset();
1147   g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_VIDEO);
1148   CPlayList& playlist = g_playlistPlayer.GetPlaylist(PLAYLIST_VIDEO);
1149   playlist.Clear();
1150   for (int i = selectedFile - 1; i < (int)movieList.Size(); ++i)
1151   {
1152     CPlayList::CPlayListItem playlistItem;
1153     CUtil::ConvertFileItemToPlayListItem(movieList[i], playlistItem);
1154     if (i == selectedFile - 1)
1155       playlistItem.m_lStartOffset = startoffset;
1156     playlist.Add(playlistItem);
1157   }
1158   // play movie...
1159   g_playlistPlayer.Play(0);
1160 }
1161
1162 void CGUIWindowVideoBase::OnDeleteItem(int iItem)
1163 {
1164   if ( iItem < 0 || iItem >= m_vecItems.Size()) return;
1165   // HACK: stacked files need to be treated as folders in order to be deleted
1166   if (m_vecItems[iItem]->IsStack())
1167     m_vecItems[iItem]->m_bIsFolder = true;
1168   if (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].getLockMode() != LOCK_MODE_EVERYONE && g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].filesLocked())
1169     if (!g_passwordManager.IsMasterLockUnlocked(true))
1170       return;
1171   if (!CGUIWindowFileManager::DeleteItem(m_vecItems[iItem]))
1172     return;
1173   Update(m_vecItems.m_strPath);
1174   m_viewControl.SetSelectedItem(iItem);
1175 }
1176
1177 void CGUIWindowVideoBase::MarkUnWatched(int iItem)
1178 {
1179   if ( iItem < 0 || iItem >= m_vecItems.Size() ) return ;
1180   CFileItem* pItem = m_vecItems[iItem];
1181   m_database.MarkAsUnWatched(atol(pItem->m_musicInfoTag.GetURL()));
1182   CUtil::DeleteVideoDatabaseDirectoryCache();
1183   m_viewControl.SetSelectedItem(iItem);
1184   Update(m_vecItems.m_strPath);
1185 }
1186
1187 //Add Mark a Title as watched
1188 void CGUIWindowVideoBase::MarkWatched(int iItem)
1189 {
1190   if ( iItem < 0 || iItem >= m_vecItems.Size() ) return ;
1191   CFileItem* pItem = m_vecItems[iItem];
1192   m_database.MarkAsWatched(atol(pItem->m_musicInfoTag.GetURL()));
1193   CUtil::DeleteVideoDatabaseDirectoryCache();
1194   m_viewControl.SetSelectedItem(iItem);
1195   Update(m_vecItems.m_strPath);
1196 }
1197
1198 //Add change a title's name
1199 void CGUIWindowVideoBase::UpdateVideoTitle(int iItem)
1200 {
1201   if ( iItem < 0 || iItem >= m_vecItems.Size() ) return ;
1202   CFileItem* pItem = m_vecItems[iItem];
1203
1204   //Get Current Name
1205   CIMDBMovie detail;
1206   m_database.GetMovieInfo("", detail, atol(pItem->m_musicInfoTag.GetURL()));
1207   CStdString strInput;
1208   strInput = detail.m_strTitle;
1209
1210   //Get the new title
1211   if (!CGUIDialogKeyboard::ShowAndGetInput(strInput, g_localizeStrings.Get(16105), false)) return ;
1212   m_database.UpdateMovieTitle(atol(pItem->m_musicInfoTag.GetURL()), strInput);
1213   CUtil::DeleteVideoDatabaseDirectoryCache();
1214   m_viewControl.SetSelectedItem(iItem);
1215   Update(m_vecItems.m_strPath);
1216 }
1217
1218 void CGUIWindowVideoBase::LoadPlayList(const CStdString& strPlayList, int iPlayList /* = PLAYLIST_VIDEO */)
1219 {
1220   // load a playlist like .m3u, .pls
1221   // first get correct factory to load playlist
1222   auto_ptr<CPlayList> pPlayList (CPlayListFactory::Create(strPlayList));
1223   if ( NULL != pPlayList.get())
1224   {
1225     // load it
1226     if (!pPlayList->Load(strPlayList))
1227     {
1228       CGUIDialogOK::ShowAndGetInput(6, 0, 477, 0);
1229       return ; //hmmm unable to load playlist?
1230     }
1231   }
1232
1233   if (g_application.ProcessAndStartPlaylist(strPlayList, *pPlayList, iPlayList))
1234   {
1235     if (m_guiState.get())
1236       m_guiState->SetPlaylistDirectory("playlistvideo://");
1237   }
1238 }
1239
1240 void CGUIWindowVideoBase::PlayItem(int iItem)
1241 {
1242   // restrictions should be placed in the appropiate window code
1243   // only call the base code if the item passes since this clears
1244   // the currently playing temp playlist
1245
1246   const CFileItem* pItem = m_vecItems[iItem];
1247   // if its a folder, build a temp playlist
1248   if (pItem->m_bIsFolder)
1249   {
1250     CFileItem item(*m_vecItems[iItem]);
1251
1252     //  Allow queuing of unqueueable items
1253     //  when we try to queue them directly
1254     if (!item.CanQueue())
1255       item.SetCanQueue(true);
1256
1257     // skip ".."
1258     if (item.IsParentFolder())
1259       return;
1260
1261     // recursively add items to list
1262     CFileItemList queuedItems;
1263     AddItemToPlayList(&item, queuedItems);
1264
1265     g_playlistPlayer.ClearPlaylist(PLAYLIST_VIDEO);
1266     g_playlistPlayer.Reset();
1267     g_playlistPlayer.Add(PLAYLIST_VIDEO, queuedItems);
1268     g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_VIDEO);
1269     g_playlistPlayer.Play();
1270   }
1271   else if (pItem->IsPlayList())
1272   {
1273     // load the playlist the old way
1274     LoadPlayList(pItem->m_strPath, PLAYLIST_VIDEO);
1275   }
1276   else
1277   {
1278     // single item, play it
1279     OnClick(iItem);
1280   }
1281 }
1282
1283 CStdString CGUIWindowVideoBase::GetnfoFile(CFileItem *item)
1284 {
1285   CStdString nfoFile;
1286   // Find a matching .nfo file
1287   if (item->m_bIsFolder)
1288   {
1289     // see if there is a unique nfo file in this folder, and if so, use that
1290     CFileItemList items;
1291     CDirectory dir;
1292     if (dir.GetDirectory(item->m_strPath, items, ".nfo") && items.Size())
1293     {
1294       int numNFO = -1;
1295       for (int i = 0; i < items.Size(); i++)
1296       {
1297         if (items[i]->IsNFO())
1298         {
1299           if (numNFO == -1)
1300             numNFO = i;
1301           else
1302           {
1303             numNFO = -1;
1304             break;
1305           }
1306         }
1307       }
1308       if (numNFO > -1)
1309         return items[numNFO]->m_strPath;
1310     }
1311   }
1312
1313   // file
1314   CStdString strExtension;
1315   CUtil::GetExtension(item->m_strPath, strExtension);
1316
1317   if (CUtil::IsInRAR(item->m_strPath)) // we have a rarred item - we want to check outside the rars
1318   {
1319     CFileItem item2(*item);
1320     CURL url(item->m_strPath);
1321     CStdString strPath;
1322     CUtil::GetDirectory(url.GetHostName(),strPath);
1323     CUtil::AddFileToFolder(strPath,CUtil::GetFileName(item->m_strPath),item2.m_strPath);
1324     return GetnfoFile(&item2);
1325   }
1326
1327   // already an .nfo file?
1328   if ( strcmpi(strExtension.c_str(), ".nfo") == 0 )
1329     nfoFile = item->m_strPath;
1330   // no, create .nfo file
1331   else
1332     CUtil::ReplaceExtension(item->m_strPath, ".nfo", nfoFile);
1333
1334   // test file existance
1335   if (!nfoFile.IsEmpty() && !CFile::Exists(nfoFile))
1336       nfoFile.Empty();
1337
1338   // try looking for .nfo file for a stacked item
1339   if (item->IsStack())
1340   {
1341     // first try .nfo file matching first file in stack
1342     CStackDirectory dir;
1343     CStdString firstFile = dir.GetFirstStackedFile(item->m_strPath);
1344     CFileItem item2;
1345     item2.m_strPath = firstFile;
1346     nfoFile = GetnfoFile(&item2);
1347     // else try .nfo file matching stacked title
1348     if (nfoFile.IsEmpty())
1349     {
1350       CStdString stackedTitlePath = dir.GetStackedTitlePath(item->m_strPath);
1351       item2.m_strPath = stackedTitlePath;
1352       nfoFile = GetnfoFile(&item2);
1353     }
1354   }
1355
1356   if (nfoFile.IsEmpty()) // final attempt - strip off any cd1 folders
1357   {
1358     CStdString strPath;
1359     CUtil::GetDirectory(item->m_strPath,strPath);
1360     CFileItem item2;
1361     if (strPath.Mid(strPath.size()-3).Equals("cd1"))
1362     {
1363       strPath = strPath.Mid(0,strPath.size()-3);
1364       CUtil::AddFileToFolder(strPath,CUtil::GetFileName(item->m_strPath),item2.m_strPath);
1365       return GetnfoFile(&item2);
1366     }
1367   }
1368
1369   return nfoFile;
1370 }
1371
1372 void CGUIWindowVideoBase::SetDatabaseDirectory(const VECMOVIES &movies, CFileItemList &items)
1373 {
1374   DWORD time = timeGetTime();
1375   for (int i = 0; i < (int)movies.size(); ++i)
1376   {
1377     CIMDBMovie movie = movies[i];
1378     {
1379       CStdString strTitle = movie.m_strTitle;
1380       if (g_settings.m_vecProfiles[0].getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser)
1381       {
1382         // check path
1383         CStdString strPath;
1384         CUtil::GetDirectory(movie.m_strFileNameAndPath,strPath);
1385         if (!g_passwordManager.IsDatabasePathUnlocked(strPath,g_settings.m_vecMyVideoShares))
1386           continue;
1387       }
1388
1389       CFileItem *pItem = new CFileItem(strTitle);
1390       pItem->m_strTitle=strTitle;
1391       pItem->m_strPath = movie.m_strFileNameAndPath;
1392       pItem->m_bIsFolder = false;
1393       pItem->m_bIsShareOrDrive = false;
1394
1395       pItem->m_fRating = movie.m_fRating;
1396       SYSTEMTIME time;
1397       time.wYear = movie.m_iYear;
1398       pItem->m_musicInfoTag.SetReleaseDate(time);
1399       pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED,movie.m_bWatched);
1400
1401       // Hack for extra info
1402       pItem->m_musicInfoTag.SetTitle(movie.m_strTitle);
1403       pItem->m_musicInfoTag.SetArtist(movie.m_strDirector);
1404       pItem->m_musicInfoTag.SetGenre(movie.m_strGenre);
1405       pItem->m_musicInfoTag.SetURL(movie.m_strSearchString);
1406       pItem->m_musicInfoTag.SetLoaded(movie.m_bWatched);
1407       // End hack for extra info
1408
1409       items.Add(pItem);
1410     }
1411   }
1412   CLog::Log(LOGDEBUG, "Time taken for SetDatabaseDirectory(): %i", timeGetTime() - time);
1413 }
1414
1415 void CGUIWindowVideoBase::ApplyIMDBThumbToFolder(const CStdString &folder, const CStdString &imdbThumb)
1416 {
1417   // copy icon to folder also;
1418   if (CFile::Exists(imdbThumb))
1419   {
1420     CFileItem folderItem(folder, true);
1421     CStdString strThumb(folderItem.GetCachedVideoThumb());
1422     CFile::Cache(imdbThumb.c_str(), strThumb.c_str(), NULL, NULL);
1423   }
1424 }
1425
1426 bool CGUIWindowVideoBase::Update(const CStdString &strDirectory)
1427 {
1428   if (m_thumbLoader.IsLoading())
1429     m_thumbLoader.StopThread();
1430
1431   if (!CGUIMediaWindow::Update(strDirectory))
1432     return false;
1433
1434   m_thumbLoader.Load(m_vecItems);
1435   return true;
1436 }
1437
1438 void CGUIWindowVideoBase::OnPrepareFileItems(CFileItemList &items)
1439 {
1440   items.SetCachedVideoThumbs();
1441 }
1442
1443 void CGUIWindowVideoBase::AddToDatabase(int iItem)
1444 {
1445   if (iItem < 0 || iItem >= m_vecItems.Size()) return;
1446   CFileItem* pItem;
1447   pItem = m_vecItems[iItem];
1448   if (pItem->IsParentFolder()) return;
1449   if (pItem->m_bIsFolder) return;
1450
1451   bool bGotXml = false;
1452   CFileItemList items;
1453   CIMDBMovie movie;
1454   movie.Reset();
1455
1456   // look for matching xml file first
1457   CStdString strXml = pItem->m_strPath + ".xml";
1458   if (pItem->IsStack())
1459   {
1460     // for a stack, use the first file in the stack
1461     CStackDirectory stack;
1462     strXml = stack.GetFirstStackedFile(pItem->m_strPath) + ".xml";
1463   }
1464   CStdString strCache = "Z:\\" + CUtil::GetFileName(strXml);
1465   if (CFile::Exists(strXml))
1466   {
1467     bGotXml = true;
1468     CLog::Log(LOGDEBUG,__FUNCTION__": found matching xml file:[%s]", strXml.c_str());
1469     CFile::Cache(strXml, strCache);
1470     CIMDB imdb;
1471     if (!imdb.LoadXML(strCache, movie, false))
1472     {
1473       CLog::Log(LOGERROR,__FUNCTION__": Could not parse info in file:[%s]", strXml.c_str());
1474       bGotXml = false;
1475     }
1476   }
1477
1478   // prompt for data
1479   if (!bGotXml)
1480   {
1481     // enter a new title
1482     CStdString strTitle = pItem->GetLabel();
1483     if (!CGUIDialogKeyboard::ShowAndGetInput(strTitle, g_localizeStrings.Get(528), false)) // Enter Title
1484       return;
1485
1486     // pick genre
1487     CGUIDialogSelect* pSelect = (CGUIDialogSelect*)m_gWindowManager.GetWindow(WINDOW_DIALOG_SELECT);
1488     if (!pSelect)
1489       return;
1490     pSelect->SetHeading(530); // Select Genre
1491     pSelect->Reset();
1492     items.ClearKeepPointer();
1493     if (!CDirectory::GetDirectory("videodb://1/", items))
1494       return;
1495     for (int i = 0; i < items.Size(); ++i)
1496       pSelect->Add(items[i]->GetLabel());
1497     pSelect->EnableButton(true);
1498     pSelect->SetButtonLabel(531); // New Genre
1499     pSelect->DoModal();
1500     CStdString strGenre;
1501     int iSelected = pSelect->GetSelectedLabel();
1502     if (iSelected >= 0)
1503       strGenre = items[iSelected]->GetLabel();
1504     else if (!pSelect->IsButtonPressed())
1505       return;
1506
1507     // enter new genre string
1508     if (strGenre.IsEmpty())
1509     {
1510       strGenre = g_localizeStrings.Get(532); // Manual Addition
1511       if (!CGUIDialogKeyboard::ShowAndGetInput(strGenre, g_localizeStrings.Get(533), false)) // Enter Genre
1512         return; // user backed out
1513       if (strGenre.IsEmpty())
1514         return; // no genre string
1515     }
1516
1517     // set movie info
1518     movie.m_strTitle = strTitle;
1519     movie.m_strGenre = strGenre;
1520   }
1521
1522   // double check title for uniqueness
1523   items.ClearKeepPointer();
1524   if (!CDirectory::GetDirectory("videodb://2/", items))
1525     return;
1526   for (int i = 0; i < items.Size(); ++i)
1527   {
1528     if (items[i]->m_strTitle.Equals(movie.m_strTitle))
1529     {
1530       // uh oh, duplicate title
1531       CGUIDialogOK *pDialog = (CGUIDialogOK*)m_gWindowManager.GetWindow(WINDOW_DIALOG_OK);
1532       if (pDialog)
1533       {
1534         pDialog->SetHeading(529); // Duplicate Title
1535         pDialog->SetLine(0, movie.m_strTitle);
1536         pDialog->SetLine(1, "");
1537         pDialog->SetLine(2, "");
1538         pDialog->SetLine(3, "");
1539         pDialog->DoModal();
1540       }
1541       return;
1542     }
1543   }
1544
1545   // everything is ok, so add to database
1546   m_database.Open();
1547   long lMovieId = m_database.AddMovie(pItem->m_strPath);
1548   movie.m_strIMDBNumber.Format("xx%08i", lMovieId);
1549   m_database.SetMovieInfo(pItem->m_strPath, movie);
1550   m_database.Close();
1551
1552   // done...
1553   CGUIDialogOK *pDialog = (CGUIDialogOK*)m_gWindowManager.GetWindow(WINDOW_DIALOG_OK);
1554   if (pDialog)
1555   {
1556     pDialog->SetHeading(20177); // Done
1557     pDialog->SetLine(0, movie.m_strTitle);
1558     pDialog->SetLine(1, movie.m_strGenre);
1559     pDialog->SetLine(2, movie.m_strIMDBNumber);
1560     pDialog->SetLine(3, "");
1561     pDialog->DoModal();
1562   }
1563
1564   // library view cache needs to be cleared
1565   CUtil::DeleteVideoDatabaseDirectoryCache();
1566 }