PageRenderTime 51ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/xbmc/windows/GUIMediaWindow.cpp

https://github.com/weitao2012/android-1
C++ | 1602 lines | 1259 code | 185 blank | 158 comment | 360 complexity | 5cbd756115394bed00c283ad57350e03 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0
  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. #include "threads/SystemClock.h"
  22. #include "GUIMediaWindow.h"
  23. #include "GUIUserMessages.h"
  24. #include "Util.h"
  25. #include "PlayListPlayer.h"
  26. #include "addons/AddonManager.h"
  27. #include "addons/PluginSource.h"
  28. #include "filesystem/PluginDirectory.h"
  29. #include "filesystem/MultiPathDirectory.h"
  30. #include "GUIPassword.h"
  31. #include "Application.h"
  32. #include "ApplicationMessenger.h"
  33. #include "network/Network.h"
  34. #include "utils/RegExp.h"
  35. #include "PartyModeManager.h"
  36. #include "dialogs/GUIDialogMediaSource.h"
  37. #include "GUIWindowFileManager.h"
  38. #include "Favourites.h"
  39. #include "utils/LabelFormatter.h"
  40. #include "dialogs/GUIDialogProgress.h"
  41. #include "settings/AdvancedSettings.h"
  42. #include "settings/GUISettings.h"
  43. #include "URL.h"
  44. #include "dialogs/GUIDialogSmartPlaylistEditor.h"
  45. #include "addons/GUIDialogAddonSettings.h"
  46. #include "dialogs/GUIDialogYesNo.h"
  47. #include "guilib/GUIWindowManager.h"
  48. #include "dialogs/GUIDialogOK.h"
  49. #include "playlists/PlayList.h"
  50. #include "storage/MediaManager.h"
  51. #include "settings/Settings.h"
  52. #include "utils/StringUtils.h"
  53. #include "utils/URIUtils.h"
  54. #include "guilib/LocalizeStrings.h"
  55. #include "utils/TimeUtils.h"
  56. #include "filesystem/FileDirectoryFactory.h"
  57. #include "utils/log.h"
  58. #include "utils/FileUtils.h"
  59. #include "guilib/GUIEditControl.h"
  60. #include "guilib/GUIKeyboardFactory.h"
  61. #ifdef HAS_PYTHON
  62. #include "interfaces/python/XBPython.h"
  63. #endif
  64. #include "interfaces/Builtins.h"
  65. #if defined(TARGET_ANDROID)
  66. #include "xbmc/android/activity/XBMCApp.h"
  67. #endif
  68. #define CONTROL_BTNVIEWASICONS 2
  69. #define CONTROL_BTNSORTBY 3
  70. #define CONTROL_BTNSORTASC 4
  71. #define CONTROL_BTN_FILTER 19
  72. #define CONTROL_LABELFILES 12
  73. using namespace std;
  74. using namespace ADDON;
  75. CGUIMediaWindow::CGUIMediaWindow(int id, const char *xmlFile)
  76. : CGUIWindow(id, xmlFile)
  77. {
  78. m_vecItems = new CFileItemList;
  79. m_unfilteredItems = new CFileItemList;
  80. m_vecItems->SetPath("?");
  81. m_iLastControl = -1;
  82. m_iSelectedItem = -1;
  83. m_guiState.reset(CGUIViewState::GetViewState(GetID(), *m_vecItems));
  84. }
  85. CGUIMediaWindow::~CGUIMediaWindow()
  86. {
  87. delete m_vecItems;
  88. delete m_unfilteredItems;
  89. }
  90. #define CONTROL_VIEW_START 50
  91. #define CONTROL_VIEW_END 59
  92. void CGUIMediaWindow::LoadAdditionalTags(TiXmlElement *root)
  93. {
  94. CGUIWindow::LoadAdditionalTags(root);
  95. // configure our view control
  96. m_viewControl.Reset();
  97. m_viewControl.SetParentWindow(GetID());
  98. TiXmlElement *element = root->FirstChildElement("views");
  99. if (element && element->FirstChild())
  100. { // format is <views>50,29,51,95</views>
  101. CStdString allViews = element->FirstChild()->Value();
  102. CStdStringArray views;
  103. StringUtils::SplitString(allViews, ",", views);
  104. for (unsigned int i = 0; i < views.size(); i++)
  105. {
  106. int controlID = atol(views[i].c_str());
  107. CGUIControl *control = (CGUIControl *)GetControl(controlID);
  108. if (control && control->IsContainer())
  109. m_viewControl.AddView(control);
  110. }
  111. }
  112. else
  113. { // backward compatibility
  114. vector<CGUIControl *> controls;
  115. GetContainers(controls);
  116. for (ciControls it = controls.begin(); it != controls.end(); it++)
  117. {
  118. CGUIControl *control = *it;
  119. if (control->GetID() >= CONTROL_VIEW_START && control->GetID() <= CONTROL_VIEW_END)
  120. m_viewControl.AddView(control);
  121. }
  122. }
  123. m_viewControl.SetViewControlID(CONTROL_BTNVIEWASICONS);
  124. }
  125. void CGUIMediaWindow::OnWindowLoaded()
  126. {
  127. SendMessage(GUI_MSG_SET_TYPE, CONTROL_BTN_FILTER, CGUIEditControl::INPUT_TYPE_FILTER);
  128. CGUIWindow::OnWindowLoaded();
  129. SetupShares();
  130. }
  131. void CGUIMediaWindow::OnWindowUnload()
  132. {
  133. CGUIWindow::OnWindowUnload();
  134. m_viewControl.Reset();
  135. }
  136. CFileItemPtr CGUIMediaWindow::GetCurrentListItem(int offset)
  137. {
  138. int item = m_viewControl.GetSelectedItem();
  139. if (!m_vecItems->Size() || item < 0)
  140. return CFileItemPtr();
  141. item = (item + offset) % m_vecItems->Size();
  142. if (item < 0) item += m_vecItems->Size();
  143. return m_vecItems->Get(item);
  144. }
  145. bool CGUIMediaWindow::OnAction(const CAction &action)
  146. {
  147. if (action.GetID() == ACTION_PARENT_DIR)
  148. {
  149. GoParentFolder();
  150. return true;
  151. }
  152. // the non-contextual menu can be called at any time
  153. if (action.GetID() == ACTION_CONTEXT_MENU && !m_viewControl.HasControl(GetFocusedControlID()))
  154. {
  155. OnPopupMenu(-1);
  156. return true;
  157. }
  158. if (CGUIWindow::OnAction(action))
  159. return true;
  160. // live filtering
  161. if (action.GetID() == ACTION_FILTER_CLEAR)
  162. {
  163. CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS);
  164. message.SetStringParam("");
  165. OnMessage(message);
  166. return true;
  167. }
  168. if (action.GetID() == ACTION_BACKSPACE)
  169. {
  170. CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS, 2); // 2 for delete
  171. OnMessage(message);
  172. return true;
  173. }
  174. if (action.GetID() >= ACTION_FILTER_SMS2 && action.GetID() <= ACTION_FILTER_SMS9)
  175. {
  176. CStdString filter;
  177. filter.Format("%i", (int)(action.GetID() - ACTION_FILTER_SMS2 + 2));
  178. CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS, 1); // 1 for append
  179. message.SetStringParam(filter);
  180. OnMessage(message);
  181. return true;
  182. }
  183. return false;
  184. }
  185. bool CGUIMediaWindow::OnBack(int actionID)
  186. {
  187. if (actionID == ACTION_NAV_BACK && !(m_vecItems->IsVirtualDirectoryRoot() || m_vecItems->GetPath() == m_startDirectory))
  188. {
  189. GoParentFolder();
  190. return true;
  191. }
  192. return CGUIWindow::OnBack(actionID);
  193. }
  194. bool CGUIMediaWindow::OnMessage(CGUIMessage& message)
  195. {
  196. switch ( message.GetMessage() )
  197. {
  198. case GUI_MSG_WINDOW_DEINIT:
  199. {
  200. m_iSelectedItem = m_viewControl.GetSelectedItem();
  201. m_iLastControl = GetFocusedControlID();
  202. CGUIWindow::OnMessage(message);
  203. CGUIDialogContextMenu* pDlg = (CGUIDialogContextMenu*)g_windowManager.GetWindow(WINDOW_DIALOG_CONTEXT_MENU);
  204. if (pDlg && pDlg->IsActive())
  205. pDlg->Close();
  206. // Call ClearFileItems() after our window has finished doing any WindowClose
  207. // animations
  208. ClearFileItems();
  209. return true;
  210. }
  211. break;
  212. case GUI_MSG_CLICKED:
  213. {
  214. int iControl = message.GetSenderId();
  215. if (iControl == CONTROL_BTNVIEWASICONS)
  216. {
  217. // view as control could be a select button
  218. int viewMode = 0;
  219. const CGUIControl *control = GetControl(CONTROL_BTNVIEWASICONS);
  220. if (control && control->GetControlType() != CGUIControl::GUICONTROL_BUTTON)
  221. {
  222. CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_BTNVIEWASICONS);
  223. OnMessage(msg);
  224. viewMode = m_viewControl.GetViewModeNumber(msg.GetParam1());
  225. }
  226. else
  227. viewMode = m_viewControl.GetNextViewMode();
  228. if (m_guiState.get())
  229. m_guiState->SaveViewAsControl(viewMode);
  230. UpdateButtons();
  231. return true;
  232. }
  233. else if (iControl == CONTROL_BTNSORTASC) // sort asc
  234. {
  235. if (m_guiState.get())
  236. m_guiState->SetNextSortOrder();
  237. UpdateFileList();
  238. return true;
  239. }
  240. else if (iControl == CONTROL_BTNSORTBY) // sort by
  241. {
  242. if (m_guiState.get())
  243. m_guiState->SetNextSortMethod();
  244. UpdateFileList();
  245. return true;
  246. }
  247. else if (iControl == CONTROL_BTN_FILTER)
  248. {
  249. if (GetControl(iControl)->GetControlType() == CGUIControl::GUICONTROL_EDIT)
  250. { // filter updated
  251. CGUIMessage selected(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_BTN_FILTER);
  252. OnMessage(selected);
  253. OnFilterItems(selected.GetLabel());
  254. return true;
  255. }
  256. if (GetProperty("filter").empty())
  257. {
  258. CStdString filter = GetProperty("filter").asString();
  259. CGUIKeyboardFactory::ShowAndGetFilter(filter, false);
  260. SetProperty("filter", filter);
  261. }
  262. else
  263. OnFilterItems("");
  264. return true;
  265. }
  266. else if (m_viewControl.HasControl(iControl)) // list/thumb control
  267. {
  268. int iItem = m_viewControl.GetSelectedItem();
  269. int iAction = message.GetParam1();
  270. if (iItem < 0) break;
  271. if (iAction == ACTION_SELECT_ITEM || iAction == ACTION_MOUSE_LEFT_CLICK)
  272. {
  273. OnSelect(iItem);
  274. }
  275. else if (iAction == ACTION_CONTEXT_MENU || iAction == ACTION_MOUSE_RIGHT_CLICK)
  276. {
  277. OnPopupMenu(iItem);
  278. return true;
  279. }
  280. }
  281. }
  282. break;
  283. case GUI_MSG_SETFOCUS:
  284. {
  285. if (m_viewControl.HasControl(message.GetControlId()) && m_viewControl.GetCurrentControl() != message.GetControlId())
  286. {
  287. m_viewControl.SetFocused();
  288. return true;
  289. }
  290. }
  291. break;
  292. case GUI_MSG_NOTIFY_ALL:
  293. { // Message is received even if this window is inactive
  294. if (message.GetParam1() == GUI_MSG_WINDOW_RESET)
  295. {
  296. m_vecItems->SetPath("?");
  297. return true;
  298. }
  299. else if ( message.GetParam1() == GUI_MSG_REFRESH_THUMBS )
  300. {
  301. for (int i = 0; i < m_vecItems->Size(); i++)
  302. m_vecItems->Get(i)->FreeMemory(true);
  303. break; // the window will take care of any info images
  304. }
  305. else if (message.GetParam1() == GUI_MSG_REMOVED_MEDIA)
  306. {
  307. if ((m_vecItems->IsVirtualDirectoryRoot() ||
  308. m_vecItems->IsSourcesPath()) && IsActive())
  309. {
  310. int iItem = m_viewControl.GetSelectedItem();
  311. Update(m_vecItems->GetPath());
  312. m_viewControl.SetSelectedItem(iItem);
  313. }
  314. else if (m_vecItems->IsRemovable())
  315. { // check that we have this removable share still
  316. if (!m_rootDir.IsInSource(m_vecItems->GetPath()))
  317. { // don't have this share any more
  318. if (IsActive()) Update("");
  319. else
  320. {
  321. m_history.ClearPathHistory();
  322. m_vecItems->SetPath("");
  323. }
  324. }
  325. }
  326. return true;
  327. }
  328. else if (message.GetParam1()==GUI_MSG_UPDATE_SOURCES)
  329. { // State of the sources changed, so update our view
  330. if ((m_vecItems->IsVirtualDirectoryRoot() ||
  331. m_vecItems->IsSourcesPath()) && IsActive())
  332. {
  333. int iItem = m_viewControl.GetSelectedItem();
  334. Update(m_vecItems->GetPath());
  335. m_viewControl.SetSelectedItem(iItem);
  336. }
  337. return true;
  338. }
  339. else if (message.GetParam1()==GUI_MSG_UPDATE && IsActive())
  340. {
  341. if (message.GetNumStringParams())
  342. {
  343. if (message.GetParam2()) // param2 is used for resetting the history
  344. SetHistoryForPath(message.GetStringParam());
  345. CFileItemList list(message.GetStringParam());
  346. list.RemoveDiscCache(GetID());
  347. Update(message.GetStringParam());
  348. }
  349. else
  350. { // refresh the listing
  351. m_vecItems->RemoveDiscCache(GetID());
  352. Update(m_vecItems->GetPath());
  353. }
  354. }
  355. else if (message.GetParam1()==GUI_MSG_UPDATE_ITEM && message.GetItem())
  356. {
  357. CFileItemPtr newItem = boost::static_pointer_cast<CFileItem>(message.GetItem());
  358. if (IsActive())
  359. {
  360. if (m_vecItems->UpdateItem(newItem.get()) && message.GetParam2() == 1)
  361. { // need the list updated as well
  362. UpdateFileList();
  363. }
  364. }
  365. else if (newItem)
  366. { // need to remove the disc cache
  367. CFileItemList items;
  368. CStdString path;
  369. URIUtils::GetDirectory(newItem->GetPath(), path);
  370. items.SetPath(path);
  371. items.RemoveDiscCache(GetID());
  372. }
  373. }
  374. else if (message.GetParam1()==GUI_MSG_UPDATE_PATH)
  375. {
  376. if (IsActive())
  377. {
  378. if((message.GetStringParam() == m_vecItems->GetPath()) ||
  379. (m_vecItems->IsMultiPath() && XFILE::CMultiPathDirectory::HasPath(m_vecItems->GetPath(), message.GetStringParam())))
  380. {
  381. Update(m_vecItems->GetPath());
  382. }
  383. }
  384. }
  385. else if (message.GetParam1() == GUI_MSG_FILTER_ITEMS && IsActive())
  386. {
  387. CStdString filter(GetProperty("filter").asString());
  388. if (message.GetParam2() == 1) // append
  389. filter += message.GetStringParam();
  390. else if (message.GetParam2() == 2)
  391. { // delete
  392. if (filter.size())
  393. filter = filter.Left(filter.size() - 1);
  394. }
  395. else
  396. filter = message.GetStringParam();
  397. OnFilterItems(filter);
  398. return true;
  399. }
  400. else
  401. return CGUIWindow::OnMessage(message);
  402. return true;
  403. }
  404. break;
  405. case GUI_MSG_PLAYBACK_STARTED:
  406. case GUI_MSG_PLAYBACK_ENDED:
  407. case GUI_MSG_PLAYBACK_STOPPED:
  408. case GUI_MSG_PLAYLIST_CHANGED:
  409. case GUI_MSG_PLAYLISTPLAYER_STOPPED:
  410. case GUI_MSG_PLAYLISTPLAYER_STARTED:
  411. case GUI_MSG_PLAYLISTPLAYER_CHANGED:
  412. { // send a notify all to all controls on this window
  413. CGUIMessage msg(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_REFRESH_LIST);
  414. OnMessage(msg);
  415. break;
  416. }
  417. case GUI_MSG_CHANGE_VIEW_MODE:
  418. {
  419. int viewMode = 0;
  420. if (message.GetParam1()) // we have an id
  421. viewMode = m_viewControl.GetViewModeByID(message.GetParam1());
  422. else if (message.GetParam2())
  423. viewMode = m_viewControl.GetNextViewMode((int)message.GetParam2());
  424. if (m_guiState.get())
  425. m_guiState->SaveViewAsControl(viewMode);
  426. UpdateButtons();
  427. return true;
  428. }
  429. break;
  430. case GUI_MSG_CHANGE_SORT_METHOD:
  431. {
  432. if (m_guiState.get())
  433. {
  434. if (message.GetParam1())
  435. m_guiState->SetCurrentSortMethod((int)message.GetParam1());
  436. else if (message.GetParam2())
  437. m_guiState->SetNextSortMethod((int)message.GetParam2());
  438. }
  439. UpdateFileList();
  440. return true;
  441. }
  442. break;
  443. case GUI_MSG_CHANGE_SORT_DIRECTION:
  444. {
  445. if (m_guiState.get())
  446. m_guiState->SetNextSortOrder();
  447. UpdateFileList();
  448. return true;
  449. }
  450. break;
  451. case GUI_MSG_WINDOW_INIT:
  452. {
  453. if (m_vecItems->GetPath() == "?")
  454. m_vecItems->SetPath("");
  455. CStdString dir = message.GetStringParam(0);
  456. const CStdString &ret = message.GetStringParam(1);
  457. bool returning = ret.CompareNoCase("return") == 0;
  458. if (!dir.IsEmpty())
  459. {
  460. m_history.ClearPathHistory();
  461. // ensure our directory is valid
  462. dir = GetStartFolder(dir);
  463. if (!returning || m_vecItems->GetPath().Left(dir.GetLength()) != dir)
  464. { // we're not returning to the same path, so set our directory to the requested path
  465. m_vecItems->SetPath(dir);
  466. }
  467. // check for network up
  468. if (URIUtils::IsRemote(m_vecItems->GetPath()) && !WaitForNetwork())
  469. m_vecItems->SetPath("");
  470. SetHistoryForPath(m_vecItems->GetPath());
  471. }
  472. if (message.GetParam1() != WINDOW_INVALID)
  473. { // first time to this window - make sure we set the root path
  474. m_startDirectory = returning ? dir : "";
  475. }
  476. }
  477. break;
  478. }
  479. return CGUIWindow::OnMessage(message);
  480. }
  481. // \brief Updates the states (enable, disable, visible...)
  482. // of the controls defined by this window
  483. // Override this function in a derived class to add new controls
  484. void CGUIMediaWindow::UpdateButtons()
  485. {
  486. if (m_guiState.get())
  487. {
  488. // Update sorting controls
  489. if (m_guiState->GetDisplaySortOrder() == SortOrderNone)
  490. {
  491. CONTROL_DISABLE(CONTROL_BTNSORTASC);
  492. }
  493. else
  494. {
  495. CONTROL_ENABLE(CONTROL_BTNSORTASC);
  496. if (m_guiState->GetDisplaySortOrder() == SortOrderAscending)
  497. {
  498. CGUIMessage msg(GUI_MSG_DESELECTED, GetID(), CONTROL_BTNSORTASC);
  499. g_windowManager.SendMessage(msg);
  500. }
  501. else
  502. {
  503. CGUIMessage msg(GUI_MSG_SELECTED, GetID(), CONTROL_BTNSORTASC);
  504. g_windowManager.SendMessage(msg);
  505. }
  506. }
  507. // Update list/thumb control
  508. m_viewControl.SetCurrentView(m_guiState->GetViewAsControl());
  509. // Update sort by button
  510. if (m_guiState->GetSortMethod()==SORT_METHOD_NONE)
  511. {
  512. CONTROL_DISABLE(CONTROL_BTNSORTBY);
  513. }
  514. else
  515. {
  516. CONTROL_ENABLE(CONTROL_BTNSORTBY);
  517. }
  518. CStdString sortLabel;
  519. sortLabel.Format(g_localizeStrings.Get(550).c_str(), g_localizeStrings.Get(m_guiState->GetSortMethodLabel()).c_str());
  520. SET_CONTROL_LABEL(CONTROL_BTNSORTBY, sortLabel);
  521. }
  522. CStdString items;
  523. items.Format("%i %s", m_vecItems->GetObjectCount(), g_localizeStrings.Get(127).c_str());
  524. SET_CONTROL_LABEL(CONTROL_LABELFILES, items);
  525. //#ifdef PRE_SKIN_VERSION_3
  526. SET_CONTROL_SELECTED(GetID(),CONTROL_BTN_FILTER, !GetProperty("filter").empty());
  527. SET_CONTROL_LABEL2(CONTROL_BTN_FILTER, GetProperty("filter").asString());
  528. //#endif
  529. }
  530. void CGUIMediaWindow::ClearFileItems()
  531. {
  532. m_viewControl.Clear();
  533. m_vecItems->Clear(); // will clean up everything
  534. m_unfilteredItems->Clear();
  535. }
  536. // \brief Sorts Fileitems based on the sort method and sort oder provided by guiViewState
  537. void CGUIMediaWindow::SortItems(CFileItemList &items)
  538. {
  539. auto_ptr<CGUIViewState> guiState(CGUIViewState::GetViewState(GetID(), items));
  540. if (guiState.get())
  541. {
  542. items.Sort(guiState->GetSortMethod(), guiState->GetDisplaySortOrder());
  543. // Should these items be saved to the hdd
  544. if (items.CacheToDiscAlways())
  545. items.Save(GetID());
  546. }
  547. }
  548. // \brief Formats item labels based on the formatting provided by guiViewState
  549. void CGUIMediaWindow::FormatItemLabels(CFileItemList &items, const LABEL_MASKS &labelMasks)
  550. {
  551. CLabelFormatter fileFormatter(labelMasks.m_strLabelFile, labelMasks.m_strLabel2File);
  552. CLabelFormatter folderFormatter(labelMasks.m_strLabelFolder, labelMasks.m_strLabel2Folder);
  553. for (int i=0; i<items.Size(); ++i)
  554. {
  555. CFileItemPtr pItem=items[i];
  556. if (pItem->IsLabelPreformated())
  557. continue;
  558. if (pItem->m_bIsFolder)
  559. folderFormatter.FormatLabels(pItem.get());
  560. else
  561. fileFormatter.FormatLabels(pItem.get());
  562. }
  563. if(items.GetSortMethod() == SORT_METHOD_LABEL_IGNORE_THE
  564. || items.GetSortMethod() == SORT_METHOD_LABEL)
  565. items.ClearSortState();
  566. }
  567. // \brief Prepares and adds the fileitems list/thumb panel
  568. void CGUIMediaWindow::FormatAndSort(CFileItemList &items)
  569. {
  570. auto_ptr<CGUIViewState> viewState(CGUIViewState::GetViewState(GetID(), items));
  571. if (viewState.get())
  572. {
  573. LABEL_MASKS labelMasks;
  574. viewState->GetSortMethodLabelMasks(labelMasks);
  575. FormatItemLabels(items, labelMasks);
  576. }
  577. SortItems(items);
  578. }
  579. /*!
  580. \brief Overwrite to fill fileitems from a source
  581. \param strDirectory Path to read
  582. \param items Fill with items specified in \e strDirectory
  583. */
  584. bool CGUIMediaWindow::GetDirectory(const CStdString &strDirectory, CFileItemList &items)
  585. {
  586. // cleanup items
  587. if (items.Size())
  588. items.Clear();
  589. CStdString strParentPath=m_history.GetParentPath();
  590. CLog::Log(LOGDEBUG,"CGUIMediaWindow::GetDirectory (%s)", strDirectory.c_str());
  591. CLog::Log(LOGDEBUG," ParentPath = [%s]", strParentPath.c_str());
  592. // see if we can load a previously cached folder
  593. CFileItemList cachedItems(strDirectory);
  594. if (!strDirectory.IsEmpty() && cachedItems.Load(GetID()))
  595. {
  596. items.Assign(cachedItems);
  597. }
  598. else
  599. {
  600. unsigned int time = XbmcThreads::SystemClockMillis();
  601. if (strDirectory.IsEmpty())
  602. SetupShares();
  603. if (!m_rootDir.GetDirectory(strDirectory, items))
  604. return false;
  605. // took over a second, and not normally cached, so cache it
  606. if ((XbmcThreads::SystemClockMillis() - time) > 1000 && items.CacheToDiscIfSlow())
  607. items.Save(GetID());
  608. // if these items should replace the current listing, then pop it off the top
  609. if (items.GetReplaceListing())
  610. m_history.RemoveParentPath();
  611. }
  612. if (m_guiState.get() && !m_guiState->HideParentDirItems() && !items.GetPath().IsEmpty())
  613. {
  614. CFileItemPtr pItem(new CFileItem(".."));
  615. pItem->SetPath(strParentPath);
  616. pItem->m_bIsFolder = true;
  617. pItem->m_bIsShareOrDrive = false;
  618. items.AddFront(pItem, 0);
  619. }
  620. int iWindow = GetID();
  621. CStdStringArray regexps;
  622. // TODO: Do we want to limit the directories we apply the video ones to?
  623. if (iWindow == WINDOW_VIDEO_NAV)
  624. regexps = g_advancedSettings.m_videoExcludeFromListingRegExps;
  625. if (iWindow == WINDOW_MUSIC_FILES)
  626. regexps = g_advancedSettings.m_audioExcludeFromListingRegExps;
  627. if (iWindow == WINDOW_PICTURES)
  628. regexps = g_advancedSettings.m_pictureExcludeFromListingRegExps;
  629. if (regexps.size())
  630. {
  631. for (int i=0; i < items.Size();)
  632. {
  633. if (CUtil::ExcludeFileOrFolder(items[i]->GetPath(), regexps))
  634. items.Remove(i);
  635. else
  636. i++;
  637. }
  638. }
  639. // clear the filter
  640. SetProperty("filter", "");
  641. return true;
  642. }
  643. // \brief Set window to a specific directory
  644. // \param strDirectory The directory to be displayed in list/thumb control
  645. // This function calls OnPrepareFileItems() and OnFinalizeFileItems()
  646. bool CGUIMediaWindow::Update(const CStdString &strDirectory)
  647. {
  648. // TODO: OnInitWindow calls Update() before window path has been set properly.
  649. if (strDirectory == "?")
  650. return false;
  651. // get selected item
  652. int iItem = m_viewControl.GetSelectedItem();
  653. CStdString strSelectedItem = "";
  654. if (iItem >= 0 && iItem < m_vecItems->Size())
  655. {
  656. CFileItemPtr pItem = m_vecItems->Get(iItem);
  657. if (!pItem->IsParentFolder())
  658. {
  659. GetDirectoryHistoryString(pItem.get(), strSelectedItem);
  660. }
  661. }
  662. CStdString strOldDirectory = m_vecItems->GetPath();
  663. m_history.SetSelectedItem(strSelectedItem, strOldDirectory);
  664. CFileItemList items;
  665. if (!GetDirectory(strDirectory, items))
  666. {
  667. CLog::Log(LOGERROR,"CGUIMediaWindow::GetDirectory(%s) failed", strDirectory.c_str());
  668. // if the directory is the same as the old directory, then we'll return
  669. // false. Else, we assume we can get the previous directory
  670. if (strDirectory.Equals(strOldDirectory))
  671. return false;
  672. // We assume, we can get the parent
  673. // directory again, but we have to
  674. // return false to be able to eg. show
  675. // an error message.
  676. CStdString strParentPath = m_history.GetParentPath();
  677. m_history.RemoveParentPath();
  678. Update(strParentPath);
  679. return false;
  680. }
  681. if (items.GetLabel().IsEmpty())
  682. items.SetLabel(CUtil::GetTitleFromPath(items.GetPath(), true));
  683. ClearFileItems();
  684. m_vecItems->Copy(items);
  685. // if we're getting the root source listing
  686. // make sure the path history is clean
  687. if (strDirectory.IsEmpty())
  688. m_history.ClearPathHistory();
  689. int iWindow = GetID();
  690. int showLabel = 0;
  691. if (strDirectory.IsEmpty() && (iWindow == WINDOW_MUSIC_FILES ||
  692. iWindow == WINDOW_FILES ||
  693. iWindow == WINDOW_PICTURES ||
  694. iWindow == WINDOW_PROGRAMS))
  695. showLabel = 1026;
  696. if (strDirectory.Equals("sources://video/"))
  697. showLabel = 999;
  698. if (showLabel && (m_vecItems->Size() == 0 || !m_guiState->DisableAddSourceButtons())) // add 'add source button'
  699. {
  700. CStdString strLabel = g_localizeStrings.Get(showLabel);
  701. CFileItemPtr pItem(new CFileItem(strLabel));
  702. pItem->SetPath("add");
  703. pItem->SetIconImage("DefaultAddSource.png");
  704. pItem->SetLabel(strLabel);
  705. pItem->SetLabelPreformated(true);
  706. pItem->m_bIsFolder = true;
  707. pItem->SetSpecialSort(SortSpecialOnBottom);
  708. m_vecItems->Add(pItem);
  709. }
  710. m_iLastControl = GetFocusedControlID();
  711. // Ask the derived class if it wants to load additional info
  712. // for the fileitems like media info or additional
  713. // filtering on the items, setting thumbs.
  714. OnPrepareFileItems(*m_vecItems);
  715. // The idea here is to ensure we have something to focus if our file list
  716. // is empty. As such, this check MUST be last and ignore the hide parent
  717. // fileitems settings.
  718. if (m_vecItems->IsEmpty())
  719. {
  720. CFileItemPtr pItem(new CFileItem(".."));
  721. pItem->SetPath(m_history.GetParentPath());
  722. pItem->m_bIsFolder = true;
  723. pItem->m_bIsShareOrDrive = false;
  724. m_vecItems->AddFront(pItem, 0);
  725. }
  726. m_vecItems->FillInDefaultIcons();
  727. m_guiState.reset(CGUIViewState::GetViewState(GetID(), *m_vecItems));
  728. FormatAndSort(*m_vecItems);
  729. // Ask the devived class if it wants to do custom list operations,
  730. // eg. changing the label
  731. OnFinalizeFileItems(*m_vecItems);
  732. UpdateButtons();
  733. m_viewControl.SetItems(*m_vecItems);
  734. strSelectedItem = m_history.GetSelectedItem(m_vecItems->GetPath());
  735. bool bSelectedFound = false;
  736. //int iSongInDirectory = -1;
  737. for (int i = 0; i < m_vecItems->Size(); ++i)
  738. {
  739. CFileItemPtr pItem = m_vecItems->Get(i);
  740. // Update selected item
  741. if (!bSelectedFound)
  742. {
  743. CStdString strHistory;
  744. GetDirectoryHistoryString(pItem.get(), strHistory);
  745. if (strHistory == strSelectedItem)
  746. {
  747. m_viewControl.SetSelectedItem(i);
  748. bSelectedFound = true;
  749. }
  750. }
  751. }
  752. // if we haven't found the selected item, select the first item
  753. if (!bSelectedFound)
  754. m_viewControl.SetSelectedItem(0);
  755. m_history.AddPath(m_vecItems->GetPath());
  756. //m_history.DumpPathHistory();
  757. return true;
  758. }
  759. // \brief This function will be called by Update() before the
  760. // labels of the fileitems are formatted. Override this function
  761. // to set custom thumbs or load additional media info.
  762. // It's used to load tag info for music.
  763. void CGUIMediaWindow::OnPrepareFileItems(CFileItemList &items)
  764. {
  765. }
  766. // \brief This function will be called by Update() after the
  767. // labels of the fileitems are formatted. Override this function
  768. // to modify the fileitems. Eg. to modify the item label
  769. void CGUIMediaWindow::OnFinalizeFileItems(CFileItemList &items)
  770. {
  771. m_unfilteredItems->SetPath(items.GetPath()); // use the original path - it'll likely be relied on for other things later.
  772. m_unfilteredItems->Append(items);
  773. CStdString filter(GetProperty("filter").asString());
  774. GetFilteredItems(filter, items);
  775. }
  776. // \brief With this function you can react on a users click in the list/thumb panel.
  777. // It returns true, if the click is handled.
  778. // This function calls OnPlayMedia()
  779. bool CGUIMediaWindow::OnClick(int iItem)
  780. {
  781. if ( iItem < 0 || iItem >= (int)m_vecItems->Size() ) return true;
  782. CFileItemPtr pItem = m_vecItems->Get(iItem);
  783. if (pItem->IsParentFolder())
  784. {
  785. GoParentFolder();
  786. return true;
  787. }
  788. if (pItem->GetPath() == "add" || pItem->GetPath() == "sources://add/") // 'add source button' in empty root
  789. {
  790. OnContextButton(iItem, CONTEXT_BUTTON_ADD_SOURCE);
  791. return true;
  792. }
  793. if (!pItem->m_bIsFolder && pItem->IsFileFolder())
  794. {
  795. XFILE::IFileDirectory *pFileDirectory = NULL;
  796. pFileDirectory = XFILE::CFileDirectoryFactory::Create(pItem->GetPath(), pItem.get(), "");
  797. if(pFileDirectory)
  798. pItem->m_bIsFolder = true;
  799. else if(pItem->m_bIsFolder)
  800. pItem->m_bIsFolder = false;
  801. delete pFileDirectory;
  802. }
  803. if (pItem->IsScript())
  804. {
  805. // execute the script
  806. CURL url(pItem->GetPath());
  807. AddonPtr addon;
  808. if (CAddonMgr::Get().GetAddon(url.GetHostName(), addon))
  809. {
  810. #ifdef HAS_PYTHON
  811. if (!g_pythonParser.StopScript(addon->LibPath()))
  812. g_pythonParser.evalFile(addon->LibPath(),addon);
  813. #endif
  814. return true;
  815. }
  816. }
  817. if (pItem->m_bIsFolder)
  818. {
  819. if ( pItem->m_bIsShareOrDrive )
  820. {
  821. const CStdString& strLockType=m_guiState->GetLockType();
  822. if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE)
  823. if (!strLockType.IsEmpty() && !g_passwordManager.IsItemUnlocked(pItem.get(), strLockType))
  824. return true;
  825. if (!HaveDiscOrConnection(pItem->GetPath(), pItem->m_iDriveType))
  826. return true;
  827. }
  828. // check for the partymode playlist items - they may not exist yet
  829. if ((pItem->GetPath() == g_settings.GetUserDataItem("PartyMode.xsp")) ||
  830. (pItem->GetPath() == g_settings.GetUserDataItem("PartyMode-Video.xsp")))
  831. {
  832. // party mode playlist item - if it doesn't exist, prompt for user to define it
  833. if (!XFILE::CFile::Exists(pItem->GetPath()))
  834. {
  835. m_vecItems->RemoveDiscCache(GetID());
  836. if (CGUIDialogSmartPlaylistEditor::EditPlaylist(pItem->GetPath()))
  837. Update(m_vecItems->GetPath());
  838. return true;
  839. }
  840. }
  841. // remove the directory cache if the folder is not normally cached
  842. CFileItemList items(pItem->GetPath());
  843. if (!items.AlwaysCache())
  844. items.RemoveDiscCache(GetID());
  845. CFileItem directory(*pItem);
  846. if (!Update(directory.GetPath()))
  847. ShowShareErrorMessage(&directory);
  848. return true;
  849. }
  850. else if (pItem->IsPlugin() && !pItem->GetProperty("isplayable").asBoolean())
  851. {
  852. return XFILE::CPluginDirectory::RunScriptWithParams(pItem->GetPath());
  853. }
  854. #if defined(TARGET_ANDROID)
  855. else if (pItem->IsAndroidApp())
  856. {
  857. CStdString appName = URIUtils::GetFileName(pItem->GetPath());
  858. CLog::Log(LOGDEBUG, "CGUIMediaWindow::OnClick Trying to run: %s",appName.c_str());
  859. return CXBMCApp::StartActivity(appName);
  860. }
  861. #endif
  862. else
  863. {
  864. m_iSelectedItem = m_viewControl.GetSelectedItem();
  865. if (pItem->GetPath() == "newplaylist://")
  866. {
  867. m_vecItems->RemoveDiscCache(GetID());
  868. g_windowManager.ActivateWindow(WINDOW_MUSIC_PLAYLIST_EDITOR,"newplaylist://");
  869. return true;
  870. }
  871. else if (pItem->GetPath().Left(19).Equals("newsmartplaylist://"))
  872. {
  873. m_vecItems->RemoveDiscCache(GetID());
  874. if (CGUIDialogSmartPlaylistEditor::NewPlaylist(pItem->GetPath().Mid(19)))
  875. Update(m_vecItems->GetPath());
  876. return true;
  877. }
  878. else if (pItem->GetPath().Left(14).Equals("addons://more/"))
  879. {
  880. CBuiltins::Execute("ActivateWindow(AddonBrowser,addons://all/xbmc.addon." + pItem->GetPath().Mid(14) + ",return)");
  881. return true;
  882. }
  883. // If karaoke song is being played AND popup autoselector is enabled, the playlist should not be added
  884. bool do_not_add_karaoke = g_guiSettings.GetBool("karaoke.enabled") &&
  885. g_guiSettings.GetBool("karaoke.autopopupselector") && pItem->IsKaraoke();
  886. bool autoplay = m_guiState.get() && m_guiState->AutoPlayNextItem();
  887. if (m_vecItems->IsPlugin())
  888. {
  889. CURL url(m_vecItems->GetPath());
  890. AddonPtr addon;
  891. if (CAddonMgr::Get().GetAddon(url.GetHostName(),addon))
  892. {
  893. PluginPtr plugin = boost::dynamic_pointer_cast<CPluginSource>(addon);
  894. if (plugin && plugin->Provides(CPluginSource::AUDIO))
  895. {
  896. CFileItemList items;
  897. auto_ptr<CGUIViewState> state(CGUIViewState::GetViewState(GetID(), items));
  898. autoplay = state.get() && state->AutoPlayNextItem();
  899. }
  900. }
  901. }
  902. if (autoplay && !g_partyModeManager.IsEnabled() &&
  903. !pItem->IsPlayList() && !do_not_add_karaoke)
  904. {
  905. return OnPlayAndQueueMedia(pItem);
  906. }
  907. else
  908. {
  909. return OnPlayMedia(iItem);
  910. }
  911. }
  912. return false;
  913. }
  914. bool CGUIMediaWindow::OnSelect(int item)
  915. {
  916. return OnClick(item);
  917. }
  918. // \brief Checks if there is a disc in the dvd drive and whether the
  919. // network is connected or not.
  920. bool CGUIMediaWindow::HaveDiscOrConnection(const CStdString& strPath, int iDriveType)
  921. {
  922. if (iDriveType==CMediaSource::SOURCE_TYPE_DVD)
  923. {
  924. if (!g_mediaManager.IsDiscInDrive(strPath))
  925. {
  926. CGUIDialogOK::ShowAndGetInput(218, 219, 0, 0);
  927. return false;
  928. }
  929. }
  930. else if (iDriveType==CMediaSource::SOURCE_TYPE_REMOTE)
  931. {
  932. // TODO: Handle not connected to a remote share
  933. if ( !g_application.getNetwork().IsConnected() )
  934. {
  935. CGUIDialogOK::ShowAndGetInput(220, 221, 0, 0);
  936. return false;
  937. }
  938. }
  939. return true;
  940. }
  941. // \brief Shows a standard errormessage for a given pItem.
  942. void CGUIMediaWindow::ShowShareErrorMessage(CFileItem* pItem)
  943. {
  944. if (pItem->m_bIsShareOrDrive)
  945. {
  946. int idMessageText=0;
  947. const CURL& url=pItem->GetAsUrl();
  948. const CStdString& strHostName=url.GetHostName();
  949. if (pItem->m_iDriveType != CMediaSource::SOURCE_TYPE_REMOTE) // Local shares incl. dvd drive
  950. idMessageText=15300;
  951. else if (url.GetProtocol() == "smb" && strHostName.IsEmpty()) // smb workgroup
  952. idMessageText=15303;
  953. else // All other remote shares
  954. idMessageText=15301;
  955. CGUIDialogOK::ShowAndGetInput(220, idMessageText, 0, 0);
  956. }
  957. }
  958. // \brief The functon goes up one level in the directory tree
  959. void CGUIMediaWindow::GoParentFolder()
  960. {
  961. //m_history.DumpPathHistory();
  962. // remove current directory if its on the stack
  963. // there were some issues due some folders having a trailing slash and some not
  964. // so just add a trailing slash to all of them for comparison.
  965. CStdString strPath = m_vecItems->GetPath();
  966. URIUtils::AddSlashAtEnd(strPath);
  967. CStdString strParent = m_history.GetParentPath();
  968. // in case the path history is messed up and the current folder is on
  969. // the stack more than once, keep going until there's nothing left or they
  970. // dont match anymore.
  971. while (!strParent.IsEmpty())
  972. {
  973. URIUtils::AddSlashAtEnd(strParent);
  974. if (strParent.Equals(strPath))
  975. m_history.RemoveParentPath();
  976. else
  977. break;
  978. strParent = m_history.GetParentPath();
  979. }
  980. // if vector is not empty, pop parent
  981. // if vector is empty, parent is root source listing
  982. CStdString strOldPath(m_vecItems->GetPath());
  983. strParent = m_history.RemoveParentPath();
  984. Update(strParent);
  985. }
  986. // \brief Override the function to change the default behavior on how
  987. // a selected item history should look like
  988. void CGUIMediaWindow::GetDirectoryHistoryString(const CFileItem* pItem, CStdString& strHistoryString)
  989. {
  990. if (pItem->m_bIsShareOrDrive)
  991. {
  992. // We are in the virual directory
  993. // History string of the DVD drive
  994. // must be handel separately
  995. if (pItem->m_iDriveType == CMediaSource::SOURCE_TYPE_DVD)
  996. {
  997. // Remove disc label from item label
  998. // and use as history string, m_strPath
  999. // can change for new discs
  1000. CStdString strLabel = pItem->GetLabel();
  1001. int nPosOpen = strLabel.Find('(');
  1002. int nPosClose = strLabel.ReverseFind(')');
  1003. if (nPosOpen > -1 && nPosClose > -1 && nPosClose > nPosOpen)
  1004. {
  1005. strLabel.Delete(nPosOpen + 1, (nPosClose) - (nPosOpen + 1));
  1006. strHistoryString = strLabel;
  1007. }
  1008. else
  1009. strHistoryString = strLabel;
  1010. }
  1011. else
  1012. {
  1013. // Other items in virual directory
  1014. CStdString strPath = pItem->GetPath();
  1015. URIUtils::RemoveSlashAtEnd(strPath);
  1016. strHistoryString = pItem->GetLabel() + strPath;
  1017. }
  1018. }
  1019. else if (pItem->m_lEndOffset>pItem->m_lStartOffset && pItem->m_lStartOffset != -1)
  1020. {
  1021. // Could be a cue item, all items of a cue share the same filename
  1022. // so add the offsets to build the history string
  1023. strHistoryString.Format("%ld%ld", pItem->m_lStartOffset, pItem->m_lEndOffset);
  1024. strHistoryString += pItem->GetPath();
  1025. }
  1026. else
  1027. {
  1028. // Normal directory items
  1029. strHistoryString = pItem->GetPath();
  1030. }
  1031. URIUtils::RemoveSlashAtEnd(strHistoryString);
  1032. strHistoryString.ToLower();
  1033. }
  1034. // \brief Call this function to create a directory history for the
  1035. // path given by strDirectory.
  1036. void CGUIMediaWindow::SetHistoryForPath(const CStdString& strDirectory)
  1037. {
  1038. // Make sure our shares are configured
  1039. SetupShares();
  1040. if (!strDirectory.IsEmpty())
  1041. {
  1042. // Build the directory history for default path
  1043. CStdString strPath, strParentPath;
  1044. strPath = strDirectory;
  1045. URIUtils::RemoveSlashAtEnd(strPath);
  1046. CFileItemList items;
  1047. m_rootDir.GetDirectory("", items);
  1048. m_history.ClearPathHistory();
  1049. while (URIUtils::GetParentPath(strPath, strParentPath))
  1050. {
  1051. for (int i = 0; i < (int)items.Size(); ++i)
  1052. {
  1053. CFileItemPtr pItem = items[i];
  1054. CStdString path(pItem->GetPath());
  1055. URIUtils::RemoveSlashAtEnd(path);
  1056. if (path == strPath)
  1057. {
  1058. CStdString strHistory;
  1059. GetDirectoryHistoryString(pItem.get(), strHistory);
  1060. m_history.SetSelectedItem(strHistory, "");
  1061. URIUtils::AddSlashAtEnd(strPath);
  1062. m_history.AddPathFront(strPath);
  1063. m_history.AddPathFront("");
  1064. //m_history.DumpPathHistory();
  1065. return ;
  1066. }
  1067. }
  1068. URIUtils::AddSlashAtEnd(strPath);
  1069. m_history.AddPathFront(strPath);
  1070. m_history.SetSelectedItem(strPath, strParentPath);
  1071. strPath = strParentPath;
  1072. URIUtils::RemoveSlashAtEnd(strPath);
  1073. }
  1074. }
  1075. else
  1076. m_history.ClearPathHistory();
  1077. //m_history.DumpPathHistory();
  1078. }
  1079. // \brief Override if you want to change the default behavior, what is done
  1080. // when the user clicks on a file.
  1081. // This function is called by OnClick()
  1082. bool CGUIMediaWindow::OnPlayMedia(int iItem)
  1083. {
  1084. // Reset Playlistplayer, playback started now does
  1085. // not use the playlistplayer.
  1086. g_playlistPlayer.Reset();
  1087. g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_NONE);
  1088. CFileItemPtr pItem=m_vecItems->Get(iItem);
  1089. CLog::Log(LOGDEBUG, "%s %s", __FUNCTION__, pItem->GetPath().c_str());
  1090. bool bResult = false;
  1091. if (pItem->IsInternetStream() || pItem->IsPlayList())
  1092. bResult = g_application.PlayMedia(*pItem, m_guiState->GetPlaylist());
  1093. else
  1094. bResult = g_application.PlayFile(*pItem);
  1095. if (pItem->m_lStartOffset == STARTOFFSET_RESUME)
  1096. pItem->m_lStartOffset = 0;
  1097. return bResult;
  1098. }
  1099. // \brief Override if you want to change the default behavior of what is done
  1100. // when the user clicks on a file in a "folder" with similar files.
  1101. // This function is called by OnClick()
  1102. bool CGUIMediaWindow::OnPlayAndQueueMedia(const CFileItemPtr &item)
  1103. {
  1104. //play and add current directory to temporary playlist
  1105. int iPlaylist = m_guiState->GetPlaylist();
  1106. if (iPlaylist != PLAYLIST_NONE)
  1107. {
  1108. g_playlistPlayer.ClearPlaylist(iPlaylist);
  1109. g_playlistPlayer.Reset();
  1110. int mediaToPlay = 0;
  1111. CFileItemList queueItems;
  1112. for ( int i = 0; i < m_vecItems->Size(); i++ )
  1113. {
  1114. CFileItemPtr nItem = m_vecItems->Get(i);
  1115. if (nItem->m_bIsFolder)
  1116. continue;
  1117. if (!nItem->IsPlayList() && !nItem->IsZIP() && !nItem->IsRAR())
  1118. queueItems.Add(nItem);
  1119. if (nItem == item)
  1120. { // item that was clicked
  1121. mediaToPlay = queueItems.Size() - 1;
  1122. }
  1123. }
  1124. g_playlistPlayer.Add(iPlaylist, queueItems);
  1125. // Save current window and directory to know where the selected item was
  1126. if (m_guiState.get())
  1127. m_guiState->SetPlaylistDirectory(m_vecItems->GetPath());
  1128. // figure out where we start playback
  1129. if (g_playlistPlayer.IsShuffled(iPlaylist))
  1130. {
  1131. int iIndex = g_playlistPlayer.GetPlaylist(iPlaylist).FindOrder(mediaToPlay);
  1132. g_playlistPlayer.GetPlaylist(iPlaylist).Swap(0, iIndex);
  1133. mediaToPlay = 0;
  1134. }
  1135. // play
  1136. g_playlistPlayer.SetCurrentPlaylist(iPlaylist);
  1137. g_playlistPlayer.Play(mediaToPlay);
  1138. }
  1139. return true;
  1140. }
  1141. // \brief Synchonize the fileitems with the playlistplayer
  1142. // It recreated the playlist of the playlistplayer based
  1143. // on the fileitems of the window
  1144. void CGUIMediaWindow::UpdateFileList()
  1145. {
  1146. int nItem = m_viewControl.GetSelectedItem();
  1147. CStdString strSelected;
  1148. if (nItem >= 0)
  1149. strSelected = m_vecItems->Get(nItem)->GetPath();
  1150. FormatAndSort(*m_vecItems);
  1151. UpdateButtons();
  1152. m_viewControl.SetItems(*m_vecItems);
  1153. m_viewControl.SetSelectedItem(strSelected);
  1154. // set the currently playing item as selected, if its in this directory
  1155. if (m_guiState.get() && m_guiState->IsCurrentPlaylistDirectory(m_vecItems->GetPath()))
  1156. {
  1157. int iPlaylist=m_guiState->GetPlaylist();
  1158. int nSong = g_playlistPlayer.GetCurrentSong();
  1159. CFileItem playlistItem;
  1160. if (nSong > -1 && iPlaylist > -1)
  1161. playlistItem=*g_playlistPlayer.GetPlaylist(iPlaylist)[nSong];
  1162. g_playlistPlayer.ClearPlaylist(iPlaylist);
  1163. g_playlistPlayer.Reset();
  1164. for (int i = 0; i < m_vecItems->Size(); i++)
  1165. {
  1166. CFileItemPtr pItem = m_vecItems->Get(i);
  1167. if (pItem->m_bIsFolder)
  1168. continue;
  1169. if (!pItem->IsPlayList() && !pItem->IsZIP() && !pItem->IsRAR())
  1170. g_playlistPlayer.Add(iPlaylist, pItem);
  1171. if (pItem->GetPath() == playlistItem.GetPath() &&
  1172. pItem->m_lStartOffset == playlistItem.m_lStartOffset)
  1173. g_playlistPlayer.SetCurrentSong(g_playlistPlayer.GetPlaylist(iPlaylist).size() - 1);
  1174. }
  1175. }
  1176. }
  1177. void CGUIMediaWindow::OnDeleteItem(int iItem)
  1178. {
  1179. if ( iItem < 0 || iItem >= m_vecItems->Size()) return;
  1180. CFileItemPtr item = m_vecItems->Get(iItem);
  1181. if (item->IsPlayList())
  1182. item->m_bIsFolder = false;
  1183. if (g_settings.GetCurrentProfile().getLockMode() != LOCK_MODE_EVERYONE && g_settings.GetCurrentProfile().filesLocked())
  1184. if (!g_passwordManager.IsMasterLockUnlocked(true))
  1185. return;
  1186. if (!CFileUtils::DeleteItem(item))
  1187. return;
  1188. m_vecItems->RemoveDiscCache(GetID());
  1189. Update(m_vecItems->GetPath());
  1190. m_viewControl.SetSelectedItem(iItem);
  1191. }
  1192. void CGUIMediaWindow::OnRenameItem(int iItem)
  1193. {
  1194. if ( iItem < 0 || iItem >= m_vecItems->Size()) return;
  1195. if (g_settings.GetCurrentProfile().getLockMode() != LOCK_MODE_EVERYONE && g_settings.GetCurrentProfile().filesLocked())
  1196. if (!g_passwordManager.IsMasterLockUnlocked(true))
  1197. return;
  1198. if (!CFileUtils::RenameFile(m_vecItems->Get(iItem)->GetPath()))
  1199. return;
  1200. m_vecItems->RemoveDiscCache(GetID());
  1201. Update(m_vecItems->GetPath());
  1202. m_viewControl.SetSelectedItem(iItem);
  1203. }
  1204. void CGUIMediaWindow::OnInitWindow()
  1205. {
  1206. // initial fetch is done unthreaded to ensure the items are setup prior to skin animations kicking off
  1207. m_rootDir.SetAllowThreads(false);
  1208. Update(m_vecItems->GetPath());
  1209. m_rootDir.SetAllowThreads(true);
  1210. if (m_iSelectedItem > -1)
  1211. m_viewControl.SetSelectedItem(m_iSelectedItem);
  1212. CGUIWindow::OnInitWindow();
  1213. }
  1214. CGUIControl *CGUIMediaWindow::GetFirstFocusableControl(int id)
  1215. {
  1216. if (m_viewControl.HasControl(id))
  1217. id = m_viewControl.GetCurrentControl();
  1218. return CGUIWindow::GetFirstFocusableControl(id);
  1219. }
  1220. void CGUIMediaWindow::SetupShares()
  1221. {
  1222. // Setup shares and filemasks for this window
  1223. CFileItemList items;
  1224. CGUIViewState* viewState=CGUIViewState::GetViewState(GetID(), items);
  1225. if (viewState)
  1226. {
  1227. m_rootDir.SetMask(viewState->GetExtensions());
  1228. m_rootDir.SetSources(viewState->GetSources());
  1229. delete viewState;
  1230. }
  1231. }
  1232. bool CGUIMediaWindow::OnPopupMenu(int iItem)
  1233. {
  1234. // popup the context menu
  1235. // grab our context menu
  1236. CContextButtons buttons;
  1237. GetContextButtons(iItem, buttons);
  1238. if (buttons.size())
  1239. {
  1240. // mark the item
  1241. if (iItem >= 0 && iItem < m_vecItems->Size())
  1242. m_vecItems->Get(iItem)->Select(true);
  1243. int choice = CGUIDialogContextMenu::ShowAndGetChoice(buttons);
  1244. // deselect our item
  1245. if (iItem >= 0 && iItem < m_vecItems->Size())
  1246. m_vecItems->Get(iItem)->Select(false);
  1247. if (choice >= 0)
  1248. return OnContextButton(iItem, (CONTEXT_BUTTON)choice);
  1249. }
  1250. return false;
  1251. }
  1252. void CGUIMediaWindow::GetContextButtons(int itemNumber, CContextButtons &buttons)
  1253. {
  1254. CFileItemPtr item = (itemNumber >= 0 && itemNumber < m_vecItems->Size()) ? m_vecItems->Get(itemNumber) : CFileItemPtr();
  1255. if (!item)
  1256. return;
  1257. // user added buttons
  1258. CStdString label;
  1259. CStdString action;
  1260. for (int i = CONTEXT_BUTTON_USER1; i <= CONTEXT_BUTTON_USER10; i++)
  1261. {
  1262. label.Format("contextmenulabel(%i)", i - CONTEXT_BUTTON_USER1);
  1263. if (item->GetProperty(label).empty())
  1264. break;
  1265. action.Format("contextmenuaction(%i)", i - CONTEXT_BUTTON_USER1);
  1266. if (item->GetProperty(action).empty())
  1267. break;
  1268. buttons.Add((CONTEXT_BUTTON)i, item->GetProperty(label).asString());
  1269. }
  1270. if (item->GetProperty("pluginreplacecontextitems").asBoolean())
  1271. return;
  1272. // TODO: FAVOURITES Conditions on masterlock and localisation
  1273. if (!item->IsParentFolder() && !item->GetPath().Equals("add") && !item->GetPath().Equals("newplaylist://") &&
  1274. !item->GetPath().Left(19).Equals("newsmartplaylist://") && !item->GetPath().Left(9).Equals("newtag://"))
  1275. {
  1276. if (CFavourites::IsFavourite(item.get(), GetID()))
  1277. buttons.Add(CONTEXT_BUTTON_ADD_FAVOURITE, 14077); // Remove Favourite
  1278. else
  1279. buttons.Add(CONTEXT_BUTTON_ADD_FAVOURITE, 14076); // Add To Favourites;
  1280. }
  1281. }
  1282. bool CGUIMediaWindow::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
  1283. {
  1284. switch (button)
  1285. {
  1286. case CONTEXT_BUTTON_ADD_FAVOURITE:
  1287. {
  1288. CFileItemPtr item = m_vecItems->Get(itemNumber);
  1289. CFavourites::AddOrRemove(item.get(), GetID());
  1290. return true;
  1291. }
  1292. case CONTEXT_BUTTON_PLUGIN_SETTINGS:
  1293. {
  1294. CURL plugin(m_vecItems->Get(itemNumber)->GetPath());
  1295. ADDON::AddonPtr addon;
  1296. if (CAddonMgr::Get().GetAddon(plugin.GetHostName(), addon, ADDON_PLUGIN))
  1297. if (CGUIDialogAddonSettings::ShowAndGetInput(addon))
  1298. Update(m_vecItems->GetPath());
  1299. return true;
  1300. }
  1301. case CONTEXT_BUTTON_USER1:
  1302. case CONTEXT_BUTTON_USER2:
  1303. case CONTEXT_BUTTON_USER3:
  1304. case CONTEXT_BUTTON_USER4:
  1305. case CONTEXT_BUTTON_USER5:
  1306. case CONTEXT_BUTTON_USER6:
  1307. case CONTEXT_BUTTON_USER7:
  1308. case CONTEXT_BUTTON_USER8:
  1309. case CONTEXT_BUTTON_USER9:
  1310. case CONTEXT_BUTTON_USER10:
  1311. {
  1312. CStdString action;
  1313. action.Format("contextmenuaction(%i)", button - CONTEXT_BUTTON_USER1);
  1314. CApplicationMessenger::Get().ExecBuiltIn(m_vecItems->Get(itemNumber)->GetProperty(action).asString());
  1315. return true;
  1316. }
  1317. default:
  1318. break;
  1319. }
  1320. return false;
  1321. }
  1322. const CGUIViewState *CGUIMediaWindow::GetViewState() const
  1323. {
  1324. return m_guiState.get();
  1325. }
  1326. const CFileItemList& CGUIMediaWindow::CurrentDirectory() const
  1327. {
  1328. return *m_vecItems;
  1329. }
  1330. bool CGUIMediaWindow::WaitForNetwork() const
  1331. {
  1332. if (g_application.getNetwork().IsAvailable())
  1333. return true;
  1334. CGUIDialogProgress *progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
  1335. if (!progress)
  1336. return true;
  1337. CURL url(m_vecItems->GetPath());
  1338. progress->SetHeading(1040); // Loading Directory
  1339. progress->SetLine(1, url.GetWithoutUserDetails());
  1340. progress->ShowProgressBar(false);
  1341. progress->StartModal();
  1342. while (!g_application.getNetwork().IsAvailable())
  1343. {
  1344. progress->Progress();
  1345. if (progress->IsCanceled())
  1346. {
  1347. progress->Close();
  1348. return false;
  1349. }
  1350. }
  1351. progress->Close();
  1352. return true;
  1353. }
  1354. void CGUIMediaWindow::OnFilterItems(const CStdString &filter)
  1355. {
  1356. CStdString currentItem;
  1357. int item = m_viewControl.GetSelectedItem();
  1358. if (item >= 0)
  1359. currentItem = m_vecItems->Get(item)->GetPath();
  1360. m_viewControl.Clear();
  1361. CFileItemList items(m_unfilteredItems->GetPath()); // use the original path - it'll likely be relied on for other things later.
  1362. items.Append(*m_unfilteredItems);
  1363. if (GetFilteredItems(filter, items))
  1364. {
  1365. m_vecItems->ClearItems();
  1366. m_vecItems->Append(items);
  1367. SetProperty("filter", filter);
  1368. }
  1369. // and update our view control + buttons
  1370. m_viewControl.SetItems(*m_vecItems);
  1371. m_viewControl.SetSelectedItem(currentItem);
  1372. UpdateButtons();
  1373. }
  1374. bool CGUIMediaWindow::GetFilteredItems(const CStdString &filter, CFileItemList &items)
  1375. {
  1376. CStdString trimmedFilter(filter);
  1377. trimmedFilter.TrimLeft().ToLower();
  1378. if (trimmedFilter.IsEmpty())
  1379. return true;
  1380. CFileItemList filteredItems(items.GetPath()); // use the original path - it'll likely be relied on for other things later.
  1381. bool numericMatch = StringUtils::IsNaturalNumber(trimmedFilter);
  1382. for (int i = 0; i < items.Size(); i++)
  1383. {
  1384. CFileItemPtr item = items.Get(i);
  1385. if (item->IsParentFolder())
  1386. {
  1387. filteredItems.Add(item);
  1388. continue;
  1389. }
  1390. // TODO: Need to update this to get all labels, ideally out of the displayed info (ie from m_layout and m_focusedLayout)
  1391. // though that isn't practical. Perhaps a better idea would be to just grab the info that we should filter on based on
  1392. // where we are in the library tree.
  1393. // Another idea is tying the filter string to the current level of the tree, so that going deeper disables the filter,
  1394. // but it's re-enabled on the way back out.
  1395. CStdString match;
  1396. /* if (item->GetFocusedLayout())
  1397. match = item->GetFocusedLayout()->GetAllText();
  1398. else if (item->GetLayout())
  1399. match = item->GetLayout()->GetAllText();
  1400. else*/
  1401. match = item->GetLabel(); // Filter label only for now
  1402. if (numericMatch)
  1403. StringUtils::WordToDigits(match);
  1404. size_t pos = StringUtils::FindWords(match.c_str(), trimmedFilter.c_str());
  1405. if (pos != CStdString::npos)
  1406. filteredItems.Add(item);
  1407. }
  1408. items.ClearItems();
  1409. items.Append(filteredItems);
  1410. return (items.GetObjectCount() > 0);
  1411. }
  1412. CStdString CGUIMediaWindow::GetStartFolder(const CStdString &dir)
  1413. {
  1414. if (dir.Equals("$ROOT") || dir.Equals("Root"))
  1415. return "";
  1416. return dir;
  1417. }