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