work on service events
[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 #include <lib/dvb/pmt.h>
6 #include <lib/python/connections.h>
7
8 void eListboxServiceContent::addService(const eServiceReference &service, bool beforeCurrent)
9 {
10         if (beforeCurrent && m_size)
11                 m_list.insert(m_cursor, service);
12         else
13                 m_list.push_back(service);
14         ++m_size;
15         ++m_cursor_number;
16         if (m_listbox)
17                 m_listbox->entryAdded(m_cursor_number-1);
18 }
19
20 void eListboxServiceContent::removeCurrent()
21 {
22         if (m_size && m_listbox)
23         {
24                 --m_size;
25                 if (m_cursor_number == m_size-1)
26                 {
27                         m_list.erase(m_cursor--);
28                         --m_cursor_number;
29                 }
30                 else
31                         m_list.erase(m_cursor++);
32                 m_listbox->entryRemoved(m_cursor_number+1);
33         }
34 }
35
36 void eListboxServiceContent::FillFinished()
37 {
38         m_size = m_list.size();
39         cursorHome();
40
41         if (m_listbox)
42                 m_listbox->entryReset();
43 }
44
45 void eListboxServiceContent::setRoot(const eServiceReference &root, bool justSet)
46 {
47         m_list.clear();
48         m_root = root;
49
50         if (justSet)
51         {
52                 m_lst=0;
53                 return;
54         }
55         assert(m_service_center);
56         
57         if (m_service_center->list(m_root, m_lst))
58                 eDebug("no list available!");
59         else if (m_lst->getContent(m_list))
60                 eDebug("getContent failed");
61
62         FillFinished();
63 }
64
65 void eListboxServiceContent::setCurrent(const eServiceReference &ref)
66 {
67         int index=0;
68         for (list::iterator i(m_list.begin()); i != m_list.end(); ++i, ++index)
69                 if ( *i == ref )
70                 {
71                         m_cursor = i;
72                         m_cursor_number = index;
73                         break;
74                 }
75         if (m_listbox)
76                 m_listbox->moveSelectionTo(index);
77 }
78
79 void eListboxServiceContent::getCurrent(eServiceReference &ref)
80 {
81         if (cursorValid())
82                 ref = *m_cursor;
83         else
84                 ref = eServiceReference();
85 }
86
87 int eListboxServiceContent::getNextBeginningWithChar(char c)
88 {
89 //      printf("Char: %c\n", c);
90         int index=0;
91         for (list::iterator i(m_list.begin()); i != m_list.end(); ++i, ++index)
92         {
93                 std::string text;
94                 ePtr<iStaticServiceInformation> service_info;
95                 m_service_center->info(*i, service_info);
96                 service_info->getName(*i, text);
97 //              printf("%c\n", text.c_str()[0]);
98                 int idx=0;
99                 int len=text.length();
100                 while ( idx <= len )
101                 {
102                         char cc = text[idx++];
103                         if ( cc >= 33 && cc < 127)
104                         {
105                                 if (cc == c)
106                                         return index;
107                                 break;
108                         }
109                 }
110         }
111         return 0;
112 }
113
114 int eListboxServiceContent::getPrevMarkerPos()
115 {
116         if (!m_listbox)
117                 return 0;
118         list::iterator i(m_cursor);
119         int index = m_cursor_number;
120         while (index)
121         {
122                 --i;
123                 --index;
124                 if (i->flags & eServiceReference::isMarker)
125                         break;
126         }
127         return index;
128 }
129
130 int eListboxServiceContent::getNextMarkerPos()
131 {
132         if (!m_listbox)
133                 return 0;
134         list::iterator i(m_cursor);
135         int index = m_cursor_number;
136         while (index < (m_size-1))
137         {
138                 ++i;
139                 ++index;
140                 if (i->flags & eServiceReference::isMarker)
141                         break;
142         }
143         return index;
144 }
145
146 void eListboxServiceContent::initMarked()
147 {
148         m_marked.clear();
149 }
150
151 void eListboxServiceContent::addMarked(const eServiceReference &ref)
152 {
153         m_marked.insert(ref);
154         if (m_listbox)
155                 m_listbox->entryChanged(lookupService(ref));
156 }
157
158 void eListboxServiceContent::removeMarked(const eServiceReference &ref)
159 {
160         m_marked.erase(ref);
161         if (m_listbox)
162                 m_listbox->entryChanged(lookupService(ref));
163 }
164
165 int eListboxServiceContent::isMarked(const eServiceReference &ref)
166 {
167         return m_marked.find(ref) != m_marked.end();
168 }
169
170 void eListboxServiceContent::markedQueryStart()
171 {
172         m_marked_iterator = m_marked.begin();
173 }
174
175 int eListboxServiceContent::markedQueryNext(eServiceReference &ref)
176 {
177         if (m_marked_iterator == m_marked.end())
178                 return -1;
179         ref = *m_marked_iterator++;
180         return 0;
181 }
182
183 int eListboxServiceContent::lookupService(const eServiceReference &ref)
184 {
185                 /* shortcut for cursor */
186         if (ref == *m_cursor)
187                 return m_cursor_number;
188                 /* otherwise, search in the list.. */
189         int index = 0;
190         for (list::const_iterator i(m_list.begin()); i != m_list.end(); ++i, ++index);
191         
192                 /* this is ok even when the index was not found. */
193         return index;
194 }
195
196 void eListboxServiceContent::setVisualMode(int mode)
197 {
198         for (int i=0; i < celElements; ++i)
199         {
200                 m_element_position[i] = eRect();
201                 m_element_font[i] = 0;
202         }
203
204         m_visual_mode = mode;
205
206         if (m_visual_mode == visModeSimple)
207         {
208                 m_element_position[celServiceName] = eRect(ePoint(0, 0), m_itemsize);
209                 m_element_font[celServiceName] = new gFont("Regular", 23);
210         }
211 }
212
213 void eListboxServiceContent::setElementPosition(int element, eRect where)
214 {
215         if ((element >= 0) && (element < celElements))
216                 m_element_position[element] = where;
217 }
218
219 void eListboxServiceContent::setElementFont(int element, gFont *font)
220 {
221         if ((element >= 0) && (element < celElements))
222                 m_element_font[element] = font;
223 }
224
225 void eListboxServiceContent::setPixmap(int type, ePtr<gPixmap> &pic)
226 {
227         if ((type >=0) && (type < picElements))
228                 m_pixmaps[type] = pic;
229 }
230
231 void eListboxServiceContent::sort()
232 {
233         if (!m_lst)
234                 m_service_center->list(m_root, m_lst);
235         if (m_lst)
236         {
237                 m_list.sort(iListableServiceCompare(m_lst));
238                         /* FIXME: is this really required or can we somehow keep the current entry? */
239                 cursorHome();
240                 if (m_listbox)
241                         m_listbox->entryReset();
242         }
243 }
244
245 DEFINE_REF(eListboxServiceContent);
246
247 eListboxServiceContent::eListboxServiceContent()
248         :m_visual_mode(visModeSimple), m_size(0), m_current_marked(false), m_numberoffset(0)
249 {
250         cursorHome();
251         eServiceCenter::getInstance(m_service_center);
252 }
253
254 void eListboxServiceContent::cursorHome()
255 {
256         if (m_current_marked && m_saved_cursor == m_list.end())
257         {
258                 if (m_cursor_number >= m_size)
259                 {
260                         m_cursor_number = m_size-1;
261                         --m_cursor;
262                 }
263                 while (m_cursor_number)
264                 {
265                         std::iter_swap(m_cursor--, m_cursor);
266                         --m_cursor_number;
267                         if (m_listbox && m_cursor_number)
268                                 m_listbox->entryChanged(m_cursor_number);
269                 }
270         }
271         else
272         {
273                 m_cursor = m_list.begin();
274                 m_cursor_number = 0;
275         }
276 }
277
278 void eListboxServiceContent::cursorEnd()
279 {
280         if (m_current_marked && m_saved_cursor == m_list.end())
281         {
282                 while (m_cursor != m_list.end())
283                 {
284                         list::iterator prev = m_cursor++;
285                         ++m_cursor_number;
286                         if ( prev != m_list.end() && m_cursor != m_list.end() )
287                         {
288                                 std::iter_swap(m_cursor, prev);
289                                 if ( m_listbox )
290                                         m_listbox->entryChanged(m_cursor_number);
291                         }
292                 }
293         }
294         else
295         {
296                 m_cursor = m_list.end();
297                 m_cursor_number = m_size;
298         }
299 }
300
301 int eListboxServiceContent::setCurrentMarked(bool state)
302 {
303         bool prev = m_current_marked;
304         m_current_marked = state;
305
306         if (state != prev && m_listbox)
307         {
308                 m_listbox->entryChanged(m_cursor_number);
309                 if (!state)
310                 {
311                         if (!m_lst)
312                                 m_service_center->list(m_root, m_lst);
313                         if (m_lst)
314                         {
315                                 ePtr<iMutableServiceList> list;
316                                 if (m_lst->startEdit(list))
317                                         eDebug("no editable list");
318                                 else
319                                 {
320                                         eServiceReference ref;
321                                         getCurrent(ref);
322                                         if(!ref)
323                                                 eDebug("no valid service selected");
324                                         else
325                                         {
326                                                 int pos = cursorGet();
327                                                 eDebugNoNewLine("move %s to %d ", ref.toString().c_str(), pos);
328                                                 if (list->moveService(ref, cursorGet()))
329                                                         eDebug("failed");
330                                                 else
331                                                         eDebug("ok");
332                                         }
333                                 }
334                         }
335                         else
336                                 eDebug("no list available!");
337                 }
338         }
339
340         return 0;
341 }
342
343 int eListboxServiceContent::cursorMove(int count)
344 {
345         int prev = m_cursor_number, last = m_cursor_number + count;
346         if (count > 0)
347         {
348                 while(count && m_cursor != m_list.end())
349                 {
350                         list::iterator prev_it = m_cursor++;
351                         if ( m_current_marked && m_cursor != m_list.end() && m_saved_cursor == m_list.end() )
352                         {
353                                 std::iter_swap(prev_it, m_cursor);
354                                 if ( m_listbox && prev != m_cursor_number && last != m_cursor_number )
355                                         m_listbox->entryChanged(m_cursor_number);
356                         }
357                         ++m_cursor_number;
358                         --count;
359         }
360         } else if (count < 0)
361         {
362                 while (count && m_cursor != m_list.begin())
363                 {
364                         list::iterator prev_it = m_cursor--;
365                         if ( m_current_marked && m_cursor != m_list.end() && prev_it != m_list.end() && m_saved_cursor == m_list.end() )
366                         {
367                                 std::iter_swap(prev_it, m_cursor);
368                                 if ( m_listbox && prev != m_cursor_number && last != m_cursor_number )
369                                         m_listbox->entryChanged(m_cursor_number);
370                         }
371                         --m_cursor_number;
372                         ++count;
373                 }
374         }
375         return 0;
376 }
377
378 int eListboxServiceContent::cursorValid()
379 {
380         return m_cursor != m_list.end();
381 }
382
383 int eListboxServiceContent::cursorSet(int n)
384 {
385         cursorHome();
386         cursorMove(n);
387         return 0;
388 }
389
390 int eListboxServiceContent::cursorGet()
391 {
392         return m_cursor_number;
393 }
394
395 void eListboxServiceContent::cursorSave()
396 {
397         m_saved_cursor = m_cursor;
398         m_saved_cursor_number = m_cursor_number;
399 }
400
401 void eListboxServiceContent::cursorRestore()
402 {
403         m_cursor = m_saved_cursor;
404         m_cursor_number = m_saved_cursor_number;
405         m_saved_cursor = m_list.end();
406 }
407
408 int eListboxServiceContent::size()
409 {
410         return m_size;
411 }
412         
413 void eListboxServiceContent::setSize(const eSize &size)
414 {
415         m_itemsize = size;
416         if (m_visual_mode == visModeSimple)
417                 setVisualMode(m_visual_mode);
418 }
419
420 void eListboxServiceContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
421 {
422         painter.clip(eRect(offset, m_itemsize));
423
424         if (m_current_marked && selected)
425                 style.setStyle(painter, eWindowStyle::styleListboxMarked);
426         else if (cursorValid() && isMarked(*m_cursor))
427                 style.setStyle(painter, selected ? eWindowStyle::styleListboxMarkedAndSelected : eWindowStyle::styleListboxMarked);
428         else
429                 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
430         painter.clear();
431         
432         if (cursorValid())
433         {
434                         /* get service information */
435                 ePtr<iStaticServiceInformation> service_info;
436                 m_service_center->info(*m_cursor, service_info);
437                 eServiceReference ref = *m_cursor;
438                 bool isPlayable = !(ref.flags & eServiceReference::isDirectory || ref.flags & eServiceReference::isMarker);
439
440                 if (isPlayable && m_is_playable_ignore.valid() && service_info && !service_info->isPlayable(*m_cursor, m_is_playable_ignore))
441                         painter.setForegroundColor(gRGB(0xbbbbbb));
442
443                 int xoffset=0;  // used as offset when painting the folder/marker symbol
444
445                 for (int e = 0; e < celElements; ++e)
446                 {
447                         if (m_element_font[e])
448                         {
449                                 int flags=gPainter::RT_VALIGN_CENTER,
450                                         yoffs = 0,
451                                         xoffs = xoffset;
452                                 eRect &area = m_element_position[e];
453                                 std::string text = "<n/a>";
454                                 xoffset=0;
455
456                                 switch (e)
457                                 {
458                                 case celServiceNumber:
459                                 {
460                                         if (m_cursor->flags & eServiceReference::isMarker)
461                                                 continue;
462                                         char bla[10];
463                                 /* how we can do this better? :) */
464                                         int markers_before=0;
465                                         {
466                                                 list::iterator tmp=m_cursor;
467                                                 while(tmp != m_list.begin())
468                                                 {
469                                                         --tmp;
470                                                         if (tmp->flags & eServiceReference::isMarker)
471                                                                 ++markers_before;
472                                                 }
473                                         }
474                                         sprintf(bla, "%d", m_numberoffset + m_cursor_number + 1 - markers_before);
475                                         text = bla;
476                                         flags|=gPainter::RT_HALIGN_RIGHT;
477                                         break;
478                                 }
479                                 case celServiceName:
480                                 {
481                                         if (service_info)
482                                                 service_info->getName(*m_cursor, text);
483                                         break;
484                                 }
485                                 case celServiceInfo:
486                                 {
487                                         ePtr<eServiceEvent> evt;
488                                         if ( service_info && !service_info->getEvent(*m_cursor, evt) )
489                                         {
490                                                 std::string name = evt->getEventName();
491                                                 if (!name.length())
492                                                         continue;
493                                                 text = '(' + evt->getEventName() + ')';
494                                         }
495                                         else
496                                                 continue;
497                                         break;
498                                 }
499                                 }
500
501                                 eRect tmp = area;
502                                 tmp.setWidth(tmp.width()-xoffs);
503
504                                 eTextPara *para = new eTextPara(tmp);
505                                 para->setFont(m_element_font[e]);
506                                 para->renderString(text.c_str());
507
508                                 if (e == celServiceName)
509                                 {
510                                         eRect bbox = para->getBoundBox();
511                                         int name_width = bbox.width()+8;
512                                         m_element_position[celServiceInfo].setLeft(area.left()+name_width);
513                                         m_element_position[celServiceInfo].setTop(area.top());
514                                         m_element_position[celServiceInfo].setWidth(area.width()-name_width);
515                                         m_element_position[celServiceInfo].setHeight(area.height());
516                                 }
517
518                                 if (flags & gPainter::RT_HALIGN_RIGHT)
519                                         para->realign(eTextPara::dirRight);
520                                 else if (flags & gPainter::RT_HALIGN_CENTER)
521                                         para->realign(eTextPara::dirCenter);
522                                 else if (flags & gPainter::RT_HALIGN_BLOCK)
523                                         para->realign(eTextPara::dirBlock);
524
525                                 if (flags & gPainter::RT_VALIGN_CENTER)
526                                 {
527                                         eRect bbox = para->getBoundBox();
528                                         int vcentered_top = (area.height() - bbox.height()) / 2;
529                                         yoffs = vcentered_top - bbox.top();
530                                 }
531
532                                 painter.renderPara(para, offset+ePoint(xoffs, yoffs));
533                         }
534                         else if (e == celServiceTypePixmap || e == celFolderPixmap || e == celMarkerPixmap)
535                         {
536                                 int orbpos = m_cursor->getUnsignedData(4) >> 16;
537                                 ePtr<gPixmap> &pixmap =
538                                         (e == celFolderPixmap) ? m_pixmaps[picFolder] :
539                                         (e == celMarkerPixmap) ? m_pixmaps[picMarker] :
540                                         (orbpos == 0xFFFF) ? m_pixmaps[picDVB_C] :
541                                         (orbpos == 0xEEEE) ? m_pixmaps[picDVB_T] : m_pixmaps[picDVB_S];
542                                 if (pixmap)
543                                 {
544                                         eSize pixmap_size = pixmap->size();
545                                         int p = celServiceInfo;
546                                         if (e == celFolderPixmap)
547                                                 p = celServiceName;
548                                         else if (e == celMarkerPixmap)
549                                                 p = celServiceNumber;
550                                         eRect area = m_element_position[p];
551                                         int correction = (area.height() - pixmap_size.height()) / 2;
552
553                                         if (isPlayable)
554                                         {
555                                                 if (e != celServiceTypePixmap)
556                                                         continue;
557                                                 m_element_position[celServiceInfo] = area;
558                                                 m_element_position[celServiceInfo].setLeft(area.left() + pixmap_size.width() + 8);
559                                                 m_element_position[celServiceInfo].setWidth(area.width() - pixmap_size.width() - 8);
560                                         }
561                                         else if (m_cursor->flags & eServiceReference::isDirectory)
562                                         {
563                                                 if (e != celFolderPixmap)
564                                                         continue;
565                                                 xoffset = pixmap_size.width() + 8;
566                                         }
567                                         else if (m_cursor->flags & eServiceReference::isMarker)
568                                         {
569                                                 if (e != celMarkerPixmap)
570                                                         continue;
571                                         }
572                                         else
573                                                 eFatal("unknown service type in listboxservice");
574
575                                         area.moveBy(offset);
576                                         painter.clip(area);
577                                         painter.blit(pixmap, offset+ePoint(area.left(), correction), area, gPainter::BT_ALPHATEST);
578                                         painter.clippop();
579                                 }
580                         }
581                 }
582                 
583                 if (selected)
584                         style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
585         }
586         
587         painter.clippop();
588 }
589
590 void eListboxServiceContent::setIgnoreService( const eServiceReference &service )
591 {
592         m_is_playable_ignore=service;
593 }