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.
9 #include "GUIViewControl.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"
25 CGUIViewControl::CGUIViewControl(void)
28 m_parentWindow
= WINDOW_INVALID
;
29 m_fileItems
= nullptr;
33 CGUIViewControl::~CGUIViewControl(void) = default;
35 void CGUIViewControl::Reset()
38 m_visibleViews
.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);
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);
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
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...
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
)
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())
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())
178 int selectedItem
= GetSelectedItem(m_visibleViews
[m_currentView
]);
179 if (selectedItem
> -1)
181 CFileItemPtr fileItem
= m_fileItems
->Get(selectedItem
);
183 return fileItem
->GetPath();
189 void CGUIViewControl::SetSelectedItem(int item
)
191 if (!m_fileItems
|| item
< 0 || item
>= m_fileItems
->Size())
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())
206 std::string
comparePath(itemPath
);
207 URIUtils::RemoveSlashAtEnd(comparePath
);
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
)
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
)
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]);
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
))
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
);
353 m_visibleViews
.push_back(view
);