[cosmetics] update date in GPL header
[vuplus_xbmc] / xbmc / view / GUIViewControl.cpp
1 /*
2  *      Copyright (C) 2005-2013 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, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "GUIViewControl.h"
22 #include "guilib/GUIWindowManager.h"
23 #include "utils/URIUtils.h"
24 #include "FileItem.h"
25 #include "guilib/LocalizeStrings.h"
26 #include "GUIInfoManager.h"
27 #include "guilib/Key.h"
28
29 CGUIViewControl::CGUIViewControl(void)
30 {
31   m_viewAsControl = -1;
32   m_parentWindow = WINDOW_INVALID;
33   m_fileItems = NULL;
34   Reset();
35 }
36
37 CGUIViewControl::~CGUIViewControl(void)
38 {
39 }
40
41 void CGUIViewControl::Reset()
42 {
43   m_currentView = -1;
44   m_visibleViews.clear();
45   m_allViews.clear();
46 }
47
48 void CGUIViewControl::AddView(const CGUIControl *control)
49 {
50   if (!control || !control->IsContainer()) return;
51   m_allViews.push_back((CGUIControl *)control);
52 }
53
54 void CGUIViewControl::SetViewControlID(int control)
55 {
56   m_viewAsControl = control;
57 }
58
59 void CGUIViewControl::SetParentWindow(int window)
60 {
61   m_parentWindow = window;
62 }
63
64 void CGUIViewControl::SetCurrentView(int viewMode, bool bRefresh /* = false */)
65 {
66   // grab the previous control
67   CGUIControl *previousView = NULL;
68   if (m_currentView >= 0 && m_currentView < (int)m_visibleViews.size())
69     previousView = m_visibleViews[m_currentView];
70
71   UpdateViewVisibility();
72
73   // viewMode is of the form TYPE << 16 | ID
74   VIEW_TYPE type = (VIEW_TYPE)(viewMode >> 16);
75   int id = viewMode & 0xffff;
76
77   // first find a view that matches this view, if possible...
78   int newView = GetView(type, id);
79   if (newView < 0) // no suitable view that matches both id and type, so try just type
80     newView = GetView(type, 0);
81   if (newView < 0 && type == VIEW_TYPE_BIG_ICON) // try icon view if they want big icon
82     newView = GetView(VIEW_TYPE_ICON, 0);
83   if (newView < 0 && type == VIEW_TYPE_BIG_INFO)
84     newView = GetView(VIEW_TYPE_INFO, 0);
85   if (newView < 0) // try a list view
86     newView = GetView(VIEW_TYPE_LIST, 0);
87   if (newView < 0) // try anything!
88     newView = GetView(VIEW_TYPE_NONE, 0);
89
90   if (newView < 0)
91     return;
92
93   m_currentView = newView;
94   CGUIControl *pNewView = m_visibleViews[m_currentView];
95
96   // make only current control visible...
97   for (ciViews view = m_allViews.begin(); view != m_allViews.end(); view++)
98     (*view)->SetVisible(false);
99   pNewView->SetVisible(true);
100
101   if (!bRefresh && pNewView == previousView)
102     return; // no need to actually update anything (other than visibility above)
103
104 //  CLog::Log(LOGDEBUG,"SetCurrentView: Oldview: %i, Newview :%i", m_currentView, viewMode);
105
106   bool hasFocus(false);
107   int item = -1;
108   if (previousView)
109   { // have an old view - let's clear it out and hide it.
110     hasFocus = previousView->HasFocus();
111     item = GetSelectedItem(previousView);
112     CGUIMessage msg(GUI_MSG_LABEL_RESET, m_parentWindow, previousView->GetID());
113     previousView->OnMessage(msg);
114   }
115
116   // Update it with the contents
117   UpdateContents(pNewView, item);
118
119   // and focus if necessary
120   if (hasFocus)
121   {
122     CGUIMessage msg(GUI_MSG_SETFOCUS, m_parentWindow, pNewView->GetID(), 0);
123     g_windowManager.SendMessage(msg);
124   }
125
126   // Update our view control only if we are not in the TV Window
127   if (m_parentWindow != WINDOW_PVR)
128     UpdateViewAsControl(((IGUIContainer *)pNewView)->GetLabel());
129 }
130
131 void CGUIViewControl::SetItems(CFileItemList &items)
132 {
133 //  CLog::Log(LOGDEBUG,"SetItems: %i", m_currentView);
134   m_fileItems = &items;
135   // update our current view control...
136   UpdateView();
137 }
138
139 void CGUIViewControl::UpdateContents(const CGUIControl *control, int currentItem)
140 {
141   if (!control || !m_fileItems) return;
142   CGUIMessage msg(GUI_MSG_LABEL_BIND, m_parentWindow, control->GetID(), currentItem, 0, m_fileItems);
143   g_windowManager.SendMessage(msg);
144 }
145
146 void CGUIViewControl::UpdateView()
147 {
148 //  CLog::Log(LOGDEBUG,"UpdateView: %i", m_currentView);
149   if (m_currentView < 0 || m_currentView >= (int)m_visibleViews.size())
150     return; // no valid current view!
151
152   CGUIControl *pControl = m_visibleViews[m_currentView];
153   // get the currently selected item
154   int item = GetSelectedItem(pControl);
155   UpdateContents(pControl, item < 0 ? 0 : item);
156 }
157
158 int CGUIViewControl::GetSelectedItem(const CGUIControl *control) const
159 {
160   if (!control || !m_fileItems) return -1;
161   CGUIMessage msg(GUI_MSG_ITEM_SELECTED, m_parentWindow, control->GetID());
162   g_windowManager.SendMessage(msg);
163
164   int iItem = msg.GetParam1();
165   if (iItem >= m_fileItems->Size())
166     return -1;
167   return iItem;
168 }
169
170 int CGUIViewControl::GetSelectedItem() const
171 {
172   if (m_currentView < 0 || m_currentView >= (int)m_visibleViews.size())
173     return -1; // no valid current view!
174
175   return GetSelectedItem(m_visibleViews[m_currentView]);
176 }
177
178 void CGUIViewControl::SetSelectedItem(int item)
179 {
180   if (!m_fileItems || item < 0 || item >= m_fileItems->Size())
181     return;
182
183   if (m_currentView < 0 || m_currentView >= (int)m_visibleViews.size())
184     return; // no valid current view!
185
186   CGUIMessage msg(GUI_MSG_ITEM_SELECT, m_parentWindow, m_visibleViews[m_currentView]->GetID(), item);
187   g_windowManager.SendMessage(msg);
188 }
189
190 void CGUIViewControl::SetSelectedItem(const CStdString &itemPath)
191 {
192   if (!m_fileItems || itemPath.IsEmpty())
193     return;
194
195   CStdString comparePath(itemPath);
196   URIUtils::RemoveSlashAtEnd(comparePath);
197
198   int item = -1;
199   for (int i = 0; i < m_fileItems->Size(); ++i)
200   {
201     CStdString strPath =(*m_fileItems)[i]->GetPath();
202     URIUtils::RemoveSlashAtEnd(strPath);
203     if (strPath.CompareNoCase(comparePath) == 0)
204     {
205       item = i;
206       break;
207     }
208   }
209   SetSelectedItem(item);
210 }
211
212 void CGUIViewControl::SetFocused()
213 {
214   if (m_currentView < 0 || m_currentView >= (int)m_visibleViews.size())
215     return; // no valid current view!
216
217   CGUIMessage msg(GUI_MSG_SETFOCUS, m_parentWindow, m_visibleViews[m_currentView]->GetID(), 0);
218   g_windowManager.SendMessage(msg);
219 }
220
221 bool CGUIViewControl::HasControl(int viewControlID) const
222 {
223   // run through our controls, checking for the id
224   for (ciViews it = m_allViews.begin(); it != m_allViews.end(); it++)
225   {
226     if ((*it)->GetID() == viewControlID)
227       return true;
228   }
229   return false;
230 }
231
232 int CGUIViewControl::GetCurrentControl() const
233 {
234   if (m_currentView < 0 || m_currentView >= (int)m_visibleViews.size())
235     return -1; // no valid current view!
236
237   return m_visibleViews[m_currentView]->GetID();
238 }
239
240 // returns the number-th view's viewmode (type and id)
241 int CGUIViewControl::GetViewModeNumber(int number) const
242 {
243   IGUIContainer *nextView = NULL;
244   if (number >= 0 && number < (int)m_visibleViews.size())
245     nextView = (IGUIContainer *)m_visibleViews[number];
246   else if (m_visibleViews.size())
247     nextView = (IGUIContainer *)m_visibleViews[0];
248   if (nextView)
249     return (nextView->GetType() << 16) | nextView->GetID();
250   return 0;  // no view modes :(
251 }
252
253 int CGUIViewControl::GetViewModeByID(int id) const
254 {
255   for (unsigned int i = 0; i < m_visibleViews.size(); ++i)
256   {
257     IGUIContainer *view = (IGUIContainer *)m_visibleViews[i];
258     if (view->GetID() == id)
259       return (view->GetType() << 16) | view->GetID();
260   }
261   return 0;  // no view modes :(
262 }
263
264 // returns the next viewmode in the cycle
265 int CGUIViewControl::GetNextViewMode(int direction) const
266 {
267   if (!m_visibleViews.size())
268     return 0; // no view modes :(
269
270   int viewNumber = (m_currentView + direction) % (int)m_visibleViews.size();
271   if (viewNumber < 0) viewNumber += m_visibleViews.size();
272   IGUIContainer *nextView = (IGUIContainer *)m_visibleViews[viewNumber];
273   return (nextView->GetType() << 16) | nextView->GetID();
274 }
275
276 void CGUIViewControl::Clear()
277 {
278   if (m_currentView < 0 || m_currentView >= (int)m_visibleViews.size())
279     return; // no valid current view!
280
281   CGUIMessage msg(GUI_MSG_LABEL_RESET, m_parentWindow, m_visibleViews[m_currentView]->GetID(), 0);
282   g_windowManager.SendMessage(msg);
283 }
284
285 int CGUIViewControl::GetView(VIEW_TYPE type, int id) const
286 {
287   for (int i = 0; i < (int)m_visibleViews.size(); i++)
288   {
289     IGUIContainer *view = (IGUIContainer *)m_visibleViews[i];
290     if ((type == VIEW_TYPE_NONE || type == view->GetType()) && (!id || view->GetID() == id))
291       return i;
292   }
293   return -1;
294 }
295
296 void CGUIViewControl::UpdateViewAsControl(const CStdString &viewLabel)
297 {
298   // the view as control could be a select/spin/dropdown button
299   CGUIMessage msg(GUI_MSG_LABEL_RESET, m_parentWindow, m_viewAsControl);
300   g_windowManager.SendMessage(msg);
301   for (unsigned int i = 0; i < m_visibleViews.size(); i++)
302   {
303     IGUIContainer *view = (IGUIContainer *)m_visibleViews[i];
304     CGUIMessage msg(GUI_MSG_LABEL_ADD, m_parentWindow, m_viewAsControl, i);
305     CStdString label;
306     label.Format(g_localizeStrings.Get(534).c_str(), view->GetLabel().c_str()); // View: %s
307     msg.SetLabel(label);
308     g_windowManager.SendMessage(msg);
309   }
310   CGUIMessage msgSelect(GUI_MSG_ITEM_SELECT, m_parentWindow, m_viewAsControl, m_currentView);
311   g_windowManager.SendMessage(msgSelect);
312
313   // otherwise it's just a normal button
314   CStdString label;
315   label.Format(g_localizeStrings.Get(534).c_str(), viewLabel.c_str()); // View: %s
316   CGUIMessage msgSet(GUI_MSG_LABEL_SET, m_parentWindow, m_viewAsControl);
317   msgSet.SetLabel(label);
318   g_windowManager.SendMessage(msgSet);
319 }
320
321 void CGUIViewControl::UpdateViewVisibility()
322 {
323   // first reset our infomanager cache, as it's likely that the vis conditions
324   // used for views (i.e. based on contenttype) may have changed
325   g_infoManager.ResetCache();
326   m_visibleViews.clear();
327   for (unsigned int i = 0; i < m_allViews.size(); i++)
328   {
329     CGUIControl *view = m_allViews[i];
330     if (view->GetVisibleCondition())
331     {
332       view->UpdateVisibility();
333       if (view->IsVisibleFromSkin())
334         m_visibleViews.push_back(view);
335     }
336     else
337       m_visibleViews.push_back(view);
338   }
339 }
340