fix linked tuners (i hope)
[enigma2.git] / lib / service / listboxservice.cpp
1 #include <lib/service/listboxservice.h>
2 #include <lib/service/service.h>
3 #include <lib/gdi/font.h>
4 #include <lib/dvb/epgcache.h>
5
6 void eListboxServiceContent::setRoot(const eServiceReference &root)
7 {
8         m_list.clear();
9         m_root = root;
10         
11         assert(m_service_center);
12         
13         ePtr<iListableService> lst;
14         if (m_service_center->list(m_root, lst))
15                 eDebug("no list available!");
16         else
17                 if (lst->getContent(m_list))
18                         eDebug("getContent failed");
19
20         m_size = m_list.size();
21         cursorHome();
22         
23         if (m_listbox)
24                 m_listbox->entryReset();
25 }
26
27 void eListboxServiceContent::setCurrent(const eServiceReference &ref)
28 {
29         int index=0;
30         for (list::iterator i(m_list.begin()); i != m_list.end(); ++i, ++index)
31                 if ( *i == ref )
32                 {
33                         m_cursor = i;
34                         m_cursor_number = index;
35                         break;
36                 }
37 }
38
39 void eListboxServiceContent::getCurrent(eServiceReference &ref)
40 {
41         if (cursorValid())
42                 ref = *m_cursor;
43         else
44                 ref = eServiceReference();
45 }
46
47 void eListboxServiceContent::initMarked()
48 {
49         m_marked.clear();
50 }
51
52 void eListboxServiceContent::addMarked(const eServiceReference &ref)
53 {
54         m_marked.insert(ref);
55         if (m_listbox)
56                 m_listbox->entryChanged(lookupService(ref));
57 }
58
59 void eListboxServiceContent::removeMarked(const eServiceReference &ref)
60 {
61         m_marked.erase(ref);
62         if (m_listbox)
63                 m_listbox->entryChanged(lookupService(ref));
64 }
65
66 int eListboxServiceContent::isMarked(const eServiceReference &ref)
67 {
68         return m_marked.find(ref) != m_marked.end();
69 }
70
71 void eListboxServiceContent::markedQueryStart()
72 {
73         m_marked_iterator = m_marked.begin();
74 }
75
76 int eListboxServiceContent::markedQueryNext(eServiceReference &ref)
77 {
78         if (m_marked_iterator == m_marked.end())
79                 return -1;
80         ref = *m_marked_iterator++;
81         return 0;
82 }
83
84 int eListboxServiceContent::lookupService(const eServiceReference &ref)
85 {
86                 /* shortcut for cursor */
87         if (ref == *m_cursor)
88                 return m_cursor_number;
89                 /* otherwise, search in the list.. */
90         int index = 0;
91         for (list::const_iterator i(m_list.begin()); i != m_list.end(); ++i, ++index);
92         
93                 /* this is ok even when the index was not found. */
94         return index;
95 }
96
97 void eListboxServiceContent::setVisualMode(int mode)
98 {
99         m_visual_mode = mode;
100         
101         if (m_visual_mode == visModeSimple)
102         {
103                 m_element_position[celServiceName] = eRect(ePoint(0, 0), m_itemsize);
104                 m_element_font[celServiceName] = new gFont("Arial", 23);
105                 m_element_position[celServiceNumber] = eRect();
106                 m_element_font[celServiceNumber] = 0;
107                 m_element_position[celIcon] = eRect();
108                 m_element_position[celServiceInfo] = eRect();
109                 m_element_font[celServiceInfo] = 0;
110         }
111 }
112
113 void eListboxServiceContent::setElementPosition(int element, eRect where)
114 {
115         if ((element >= 0) && (element < celElements))
116                 m_element_position[element] = where;
117 }
118
119 void eListboxServiceContent::setElementFont(int element, gFont *font)
120 {
121         if ((element >= 0) && (element < celElements))
122                 m_element_font[element] = font;
123 }
124
125 void eListboxServiceContent::sort()
126 {
127         ePtr<iListableService> lst;
128   if (!m_service_center->list(m_root, lst))
129   {
130                 m_list.sort(iListableServiceCompare(lst));
131                         /* FIXME: is this really required or can we somehow keep the current entry? */
132                 cursorHome();
133                 if (m_listbox)
134                         m_listbox->entryReset();
135         }
136 }
137
138 DEFINE_REF(eListboxServiceContent);
139
140 eListboxServiceContent::eListboxServiceContent()
141         :epgcache(eEPGCache::getInstance()), m_visual_mode(visModeSimple), m_size(0), m_current_marked(false), m_numberoffset(0)
142 {
143         cursorHome();
144         eServiceCenter::getInstance(m_service_center);
145 }
146
147 void eListboxServiceContent::cursorHome()
148 {
149         if (m_current_marked && m_saved_cursor == m_list.end())
150         {
151                 while (m_cursor_number)
152                 {
153                         std::iter_swap(m_cursor--, m_cursor);
154                         --m_cursor_number;
155                         if (m_listbox && m_cursor_number)
156                                 m_listbox->entryChanged(m_cursor_number);
157                 }
158         }
159         else
160         {
161                 m_cursor = m_list.begin();
162                 m_cursor_number = 0;
163         }
164 }
165
166 void eListboxServiceContent::cursorEnd()
167 {
168         if (m_current_marked && m_saved_cursor == m_list.end())
169         {
170                 while (m_cursor != m_list.end())
171                 {
172                         list::iterator prev = m_cursor++;
173                         ++m_cursor_number;
174                         if ( prev != m_list.end() && m_cursor != m_list.end() )
175                         {
176                                 std::iter_swap(m_cursor, prev);
177                                 if ( m_listbox )
178                                         m_listbox->entryChanged(m_cursor_number);
179                         }
180                 }
181         }
182         else
183         {
184                 m_cursor = m_list.end();
185                 m_cursor_number = m_size;
186         }
187 }
188
189 int eListboxServiceContent::setCurrentMarked(bool state)
190 {
191         bool prev = m_current_marked;
192         m_current_marked = state;
193
194         if (state != prev && m_listbox)
195         {
196                 m_listbox->entryChanged(m_cursor_number);
197                 if (!state)
198                 {
199                         ePtr<iListableService> lst;
200                         if (m_service_center->list(m_root, lst))
201                                 eDebug("no list available!");
202                         else
203                         {
204                                 ePtr<iMutableServiceList> list;
205                                 if (lst->startEdit(list))
206                                         eDebug("no editable list");
207                                 else
208                                 {
209                                         eServiceReference ref;
210                                         getCurrent(ref);
211                                         if(!ref)
212                                                 eDebug("no valid service selected");
213                                         else
214                                         {
215                                                 int pos = cursorGet();
216                                                 eDebugNoNewLine("move %s to %d ", ref.toString().c_str(), pos);
217                                                 if (list->moveService(ref, cursorGet()))
218                                                         eDebug("failed");
219                                                 else
220                                                         eDebug("ok");
221                                         }
222                                 }
223                         }
224                 }
225         }
226
227         return 0;
228 }
229
230 int eListboxServiceContent::cursorMove(int count)
231 {
232         int prev = m_cursor_number, last = m_cursor_number + count;
233         if (count > 0)
234         {
235                 while(count && m_cursor != m_list.end())
236                 {
237                         list::iterator prev_it = m_cursor++;
238                         if ( m_current_marked && m_cursor != m_list.end() && m_saved_cursor == m_list.end() )
239                         {
240                                 std::iter_swap(prev_it, m_cursor);
241                                 if ( m_listbox && prev != m_cursor_number && last != m_cursor_number )
242                                         m_listbox->entryChanged(m_cursor_number);
243                         }
244                         ++m_cursor_number;
245                         --count;
246         }
247         } else if (count < 0)
248         {
249                 while (count && m_cursor != m_list.begin())
250                 {
251                         list::iterator prev_it = m_cursor--;
252                         if ( m_current_marked && m_cursor != m_list.end() && prev_it != m_list.end() && m_saved_cursor == m_list.end() )
253                         {
254                                 std::iter_swap(prev_it, m_cursor);
255                                 if ( m_listbox && prev != m_cursor_number && last != m_cursor_number )
256                                         m_listbox->entryChanged(m_cursor_number);
257                         }
258                         --m_cursor_number;
259                         ++count;
260                 }
261         }
262         return 0;
263 }
264
265 int eListboxServiceContent::cursorValid()
266 {
267         return m_cursor != m_list.end();
268 }
269
270 int eListboxServiceContent::cursorSet(int n)
271 {
272         cursorHome();
273         cursorMove(n);
274         
275         return 0;
276 }
277
278 int eListboxServiceContent::cursorGet()
279 {
280         return m_cursor_number;
281 }
282
283 void eListboxServiceContent::cursorSave()
284 {
285         m_saved_cursor = m_cursor;
286         m_saved_cursor_number = m_cursor_number;
287 }
288
289 void eListboxServiceContent::cursorRestore()
290 {
291         m_cursor = m_saved_cursor;
292         m_cursor_number = m_saved_cursor_number;
293         m_saved_cursor = m_list.end();
294 }
295
296 int eListboxServiceContent::size()
297 {
298         return m_size;
299 }
300         
301 void eListboxServiceContent::setSize(const eSize &size)
302 {
303         m_itemsize = size;
304         setVisualMode(m_visual_mode);
305 }
306
307 void eListboxServiceContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
308 {
309         painter.clip(eRect(offset, m_itemsize));
310
311         if (m_current_marked && selected)
312                 style.setStyle(painter, eWindowStyle::styleListboxMarked);
313         else if (cursorValid() && isMarked(*m_cursor))
314                 style.setStyle(painter, eWindowStyle::styleListboxMarked);
315         else
316                 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
317         painter.clear();
318         
319         if (cursorValid())
320         {
321                         /* get service information */
322                 ePtr<iStaticServiceInformation> service_info;
323                 m_service_center->info(*m_cursor, service_info);
324                 
325                 for (int e = 0; e < celElements; ++e)
326                 {
327                         if (!m_element_font[e])
328                                 continue;
329                         int flags=gPainter::RT_VALIGN_CENTER;
330
331                         eRect area = m_element_position[e];
332
333                         std::string text = "<n/a>";
334
335                         switch (e)
336                         {
337                         case celIcon:
338                                 // render icon here...
339                                 continue;
340                         case celServiceNumber:
341                         {
342                                 char bla[10];
343                                 sprintf(bla, "%d", m_numberoffset + m_cursor_number + 1);
344                                 text = bla;
345                                 flags|=gPainter::RT_HALIGN_RIGHT;
346                                 break;
347                         }
348                         case celServiceName:
349                         {
350                                 if (service_info)
351                                         service_info->getName(*m_cursor, text);
352                                 break;
353                         }
354                         case celServiceInfo:
355                         {
356                                 ePtr<eServiceEvent> evt;
357                                 time_t t=-1;
358                                 if ( !epgcache->lookupEventTime(*m_cursor, t, evt) )
359                                         text = '(' + evt->getEventName() + ')';
360                                 else
361                                         continue;
362                                 break;
363                         }
364                         }
365
366                         eTextPara *para = new eTextPara(area);
367
368                         para->setFont(m_element_font[e]);
369                         para->renderString(text);
370
371                         if (e == celServiceName)
372                         {
373                                 eRect bbox = para->getBoundBox();
374                                 int name_width = bbox.width()+10;
375                                 m_element_position[celServiceInfo].setLeft(area.left()+name_width);
376                                 m_element_position[celServiceInfo].setTop(area.top());
377                                 m_element_position[celServiceInfo].setWidth(area.width()-name_width);
378                                 m_element_position[celServiceInfo].setHeight(area.height());
379                         }
380
381                         if (flags & gPainter::RT_HALIGN_RIGHT)
382                                 para->realign(eTextPara::dirRight);
383                         else if (flags & gPainter::RT_HALIGN_CENTER)
384                                 para->realign(eTextPara::dirCenter);
385                         else if (flags & gPainter::RT_HALIGN_BLOCK)
386                                 para->realign(eTextPara::dirBlock);
387
388                         ePoint offs = offset;
389
390                         if (flags & gPainter::RT_VALIGN_CENTER)
391                         {
392                                 eRect bbox = para->getBoundBox();
393                                 int vcentered_top = (area.height() - bbox.height()) / 2;
394                                 int correction = vcentered_top - bbox.top();
395                                 offs += ePoint(0, correction);
396                         }
397
398                         painter.renderPara(para, offs);
399                 }
400                 
401                 if (selected)
402                         style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
403         }
404         
405         painter.clippop();
406 }
407