[videodb] Remove nested transaction when saving state after stopping PVR playback
[xbmc.git] / xbmc / view / GUIViewControl.cpp
blob6ce4516b5227c1cd54d68ee3cf561ad46482b951
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "GUIViewControl.h"
11 #include "FileItem.h"
12 #include "FileItemList.h"
13 #include "GUIInfoManager.h"
14 #include "ServiceBroker.h"
15 #include "guilib/GUIComponent.h"
16 #include "guilib/GUIWindowManager.h"
17 #include "guilib/IGUIContainer.h"
18 #include "guilib/LocalizeStrings.h"
19 #include "guilib/WindowIDs.h"
20 #include "utils/StringUtils.h"
21 #include "utils/URIUtils.h"
23 #include <utility>
25 CGUIViewControl::CGUIViewControl(void)
27 m_viewAsControl = -1;
28 m_parentWindow = WINDOW_INVALID;
29 m_fileItems = nullptr;
30 Reset();
33 CGUIViewControl::~CGUIViewControl(void) = default;
35 void CGUIViewControl::Reset()
37 m_currentView = -1;
38 m_visibleViews.clear();
39 m_allViews.clear();
42 void CGUIViewControl::AddView(const CGUIControl *control)
44 if (!control || !control->IsContainer()) return;
45 m_allViews.push_back(const_cast<CGUIControl*>(control));
48 void CGUIViewControl::SetViewControlID(int control)
50 m_viewAsControl = control;
53 void CGUIViewControl::SetParentWindow(int window)
55 m_parentWindow = window;
58 void CGUIViewControl::SetCurrentView(int viewMode, bool bRefresh /* = false */)
60 // grab the previous control
61 CGUIControl *previousView = nullptr;
62 if (m_currentView >= 0 && m_currentView < (int)m_visibleViews.size())
63 previousView = m_visibleViews[m_currentView];
65 UpdateViewVisibility();
67 // viewMode is of the form TYPE << 16 | ID
68 VIEW_TYPE type = (VIEW_TYPE)(viewMode >> 16);
69 int id = viewMode & 0xffff;
71 // first find a view that matches this view, if possible...
72 int newView = GetView(type, id);
73 if (newView < 0) // no suitable view that matches both id and type, so try just type
74 newView = GetView(type, 0);
75 if (newView < 0 && type == VIEW_TYPE_BIG_ICON) // try icon view if they want big icon
76 newView = GetView(VIEW_TYPE_ICON, 0);
77 if (newView < 0 && type == VIEW_TYPE_BIG_INFO)
78 newView = GetView(VIEW_TYPE_INFO, 0);
79 if (newView < 0) // try a list view
80 newView = GetView(VIEW_TYPE_LIST, 0);
81 if (newView < 0) // try anything!
82 newView = GetView(VIEW_TYPE_NONE, 0);
84 if (newView < 0)
85 return;
87 m_currentView = newView;
88 CGUIControl *pNewView = m_visibleViews[m_currentView];
90 // make only current control visible...
91 for (ciViews view = m_allViews.begin(); view != m_allViews.end(); ++view)
92 (*view)->SetVisible(false);
93 pNewView->SetVisible(true);
95 if (!bRefresh && pNewView == previousView)
96 return; // no need to actually update anything (other than visibility above)
98 // CLog::Log(LOGDEBUG,"SetCurrentView: Oldview: {}, Newview :{}", m_currentView, viewMode);
100 bool hasFocus(false);
101 int item = -1;
102 if (previousView)
103 { // have an old view - let's clear it out and hide it.
104 hasFocus = previousView->HasFocus();
105 item = GetSelectedItem(previousView);
106 CGUIMessage msg(GUI_MSG_LABEL_RESET, m_parentWindow, previousView->GetID());
107 previousView->OnMessage(msg);
110 // Update it with the contents
111 UpdateContents(pNewView, item);
113 // and focus if necessary
114 if (hasFocus)
116 CGUIMessage msg(GUI_MSG_SETFOCUS, m_parentWindow, pNewView->GetID(), 0);
117 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg, m_parentWindow);
120 UpdateViewAsControl(static_cast<IGUIContainer*>(pNewView)->GetLabel());
123 void CGUIViewControl::SetItems(CFileItemList &items)
125 // CLog::Log(LOGDEBUG,"SetItems: {}", m_currentView);
126 m_fileItems = &items;
127 // update our current view control...
128 UpdateView();
131 void CGUIViewControl::UpdateContents(const CGUIControl *control, int currentItem) const
133 if (!control || !m_fileItems) return;
134 CGUIMessage msg(GUI_MSG_LABEL_BIND, m_parentWindow, control->GetID(), currentItem, 0, m_fileItems);
135 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg, m_parentWindow);
138 void CGUIViewControl::UpdateView()
140 // CLog::Log(LOGDEBUG,"UpdateView: {}", m_currentView);
141 if (m_currentView < 0 || m_currentView >= (int)m_visibleViews.size())
142 return; // no valid current view!
144 CGUIControl *pControl = m_visibleViews[m_currentView];
145 // get the currently selected item
146 int item = GetSelectedItem(pControl);
147 UpdateContents(pControl, item < 0 ? 0 : item);
150 int CGUIViewControl::GetSelectedItem(const CGUIControl *control) const
152 if (!control || !m_fileItems)
153 return -1;
155 CGUIMessage msg(GUI_MSG_ITEM_SELECTED, m_parentWindow, control->GetID());
156 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg, m_parentWindow);
158 int iItem = msg.GetParam1();
159 if (iItem >= m_fileItems->Size())
160 return -1;
162 return iItem;
165 int CGUIViewControl::GetSelectedItem() const
167 if (m_currentView < 0 || m_currentView >= (int)m_visibleViews.size())
168 return -1; // no valid current view!
170 return GetSelectedItem(m_visibleViews[m_currentView]);
173 std::string CGUIViewControl::GetSelectedItemPath() const
175 if (m_currentView < 0 || (size_t)m_currentView >= m_visibleViews.size())
176 return "";
178 int selectedItem = GetSelectedItem(m_visibleViews[m_currentView]);
179 if (selectedItem > -1)
181 CFileItemPtr fileItem = m_fileItems->Get(selectedItem);
182 if (fileItem)
183 return fileItem->GetPath();
186 return "";
189 void CGUIViewControl::SetSelectedItem(int item)
191 if (!m_fileItems || item < 0 || item >= m_fileItems->Size())
192 return;
194 if (m_currentView < 0 || m_currentView >= (int)m_visibleViews.size())
195 return; // no valid current view!
197 CGUIMessage msg(GUI_MSG_ITEM_SELECT, m_parentWindow, m_visibleViews[m_currentView]->GetID(), item);
198 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg, m_parentWindow);
201 void CGUIViewControl::SetSelectedItem(const std::string &itemPath)
203 if (!m_fileItems || itemPath.empty())
204 return;
206 std::string comparePath(itemPath);
207 URIUtils::RemoveSlashAtEnd(comparePath);
209 int item = -1;
210 for (int i = 0; i < m_fileItems->Size(); ++i)
212 std::string strPath =(*m_fileItems)[i]->GetPath();
213 URIUtils::RemoveSlashAtEnd(strPath);
214 if (strPath == comparePath)
216 item = i;
217 break;
220 SetSelectedItem(item);
223 void CGUIViewControl::SetFocused()
225 if (m_currentView < 0 || m_currentView >= (int)m_visibleViews.size())
226 return; // no valid current view!
228 CGUIMessage msg(GUI_MSG_SETFOCUS, m_parentWindow, m_visibleViews[m_currentView]->GetID(), 0);
229 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg, m_parentWindow);
232 bool CGUIViewControl::HasControl(int viewControlID) const
234 // run through our controls, checking for the id
235 for (ciViews it = m_allViews.begin(); it != m_allViews.end(); ++it)
237 if ((*it)->GetID() == viewControlID)
238 return true;
240 return false;
243 int CGUIViewControl::GetCurrentControl() const
245 if (m_currentView < 0 || m_currentView >= (int)m_visibleViews.size())
246 return -1; // no valid current view!
248 return m_visibleViews[m_currentView]->GetID();
251 // returns the number-th view's viewmode (type and id)
252 int CGUIViewControl::GetViewModeNumber(int number) const
254 IGUIContainer *nextView = nullptr;
255 if (number >= 0 && number < (int)m_visibleViews.size())
256 nextView = static_cast<IGUIContainer*>(m_visibleViews[number]);
257 else if (m_visibleViews.size())
258 nextView = static_cast<IGUIContainer*>(m_visibleViews[0]);
259 if (nextView)
260 return (nextView->GetType() << 16) | nextView->GetID();
261 return 0; // no view modes :(
264 // returns the amount of visible views
265 int CGUIViewControl::GetViewModeCount() const
267 return static_cast<int>(m_visibleViews.size());
270 int CGUIViewControl::GetViewModeByID(int id) const
272 for (unsigned int i = 0; i < m_visibleViews.size(); ++i)
274 IGUIContainer *view = static_cast<IGUIContainer*>(m_visibleViews[i]);
275 if (view->GetID() == id)
276 return (view->GetType() << 16) | view->GetID();
278 return 0; // no view modes :(
281 // returns the next viewmode in the cycle
282 int CGUIViewControl::GetNextViewMode(int direction) const
284 if (!m_visibleViews.size())
285 return 0; // no view modes :(
287 int viewNumber = (m_currentView + direction) % (int)m_visibleViews.size();
288 if (viewNumber < 0) viewNumber += m_visibleViews.size();
289 IGUIContainer *nextView = static_cast<IGUIContainer*>(m_visibleViews[viewNumber]);
290 return (nextView->GetType() << 16) | nextView->GetID();
293 void CGUIViewControl::Clear()
295 if (m_currentView < 0 || m_currentView >= (int)m_visibleViews.size())
296 return; // no valid current view!
298 CGUIMessage msg(GUI_MSG_LABEL_RESET, m_parentWindow, m_visibleViews[m_currentView]->GetID(), 0);
299 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg, m_parentWindow);
302 int CGUIViewControl::GetView(VIEW_TYPE type, int id) const
304 for (int i = 0; i < (int)m_visibleViews.size(); i++)
306 IGUIContainer *view = static_cast<IGUIContainer*>(m_visibleViews[i]);
307 if ((type == VIEW_TYPE_NONE || type == view->GetType()) && (!id || view->GetID() == id))
308 return i;
310 return -1;
313 void CGUIViewControl::UpdateViewAsControl(const std::string &viewLabel)
315 // the view as control could be a select/spin/dropdown button
316 std::vector< std::pair<std::string, int> > labels;
317 for (unsigned int i = 0; i < m_visibleViews.size(); i++)
319 IGUIContainer *view = static_cast<IGUIContainer*>(m_visibleViews[i]);
320 std::string label = StringUtils::Format(g_localizeStrings.Get(534),
321 view->GetLabel()); // View: {}
322 labels.emplace_back(std::move(label), i);
324 CGUIMessage msg(GUI_MSG_SET_LABELS, m_parentWindow, m_viewAsControl, m_currentView);
325 msg.SetPointer(&labels);
326 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg, m_parentWindow);
328 // otherwise it's just a normal button
329 std::string label = StringUtils::Format(g_localizeStrings.Get(534), viewLabel); // View: {}
330 CGUIMessage msgSet(GUI_MSG_LABEL_SET, m_parentWindow, m_viewAsControl);
331 msgSet.SetLabel(label);
332 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msgSet, m_parentWindow);
335 void CGUIViewControl::UpdateViewVisibility()
337 // first reset our infomanager cache, as it's likely that the vis conditions
338 // used for views (i.e. based on contenttype) may have changed
339 CGUIInfoManager& infoMgr = CServiceBroker::GetGUI()->GetInfoManager();
340 infoMgr.ResetCache();
341 infoMgr.GetInfoProviders().GetGUIControlsInfoProvider().ResetContainerMovingCache();
342 m_visibleViews.clear();
343 for (unsigned int i = 0; i < m_allViews.size(); i++)
345 CGUIControl *view = m_allViews[i];
346 if (view->HasVisibleCondition())
348 view->UpdateVisibility(nullptr);
349 if (view->IsVisibleFromSkin())
350 m_visibleViews.push_back(view);
352 else
353 m_visibleViews.push_back(view);