code cleanup in ChannelSelection,
[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         {
12                 m_list.insert(m_cursor, service);
13                 --m_cursor;
14         }
15         else
16                 m_list.push_back(service);
17         ++m_size;
18 }
19
20 void eListboxServiceContent::removeCurrent()
21 {
22         if (m_size && m_listbox)
23         {
24                 if (m_cursor_number == m_size-1)
25                 {
26                         m_list.erase(m_cursor--);
27                         --m_cursor_number;
28                 }
29                 else
30                         m_list.erase(m_cursor++);
31                 --m_size;
32                 m_listbox->entryRemoved(m_cursor_number);
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         m_visual_mode = mode;
199         
200         if (m_visual_mode == visModeSimple)
201         {
202                 m_element_position[celServiceName] = eRect(ePoint(0, 0), m_itemsize);
203                 m_element_font[celServiceName] = new gFont("Regular", 23);
204                 m_element_position[celServiceNumber] = eRect();
205                 m_element_font[celServiceNumber] = 0;
206                 m_element_position[celServiceInfo] = eRect();
207                 m_element_font[celServiceInfo] = 0;
208         }
209 }
210
211 void eListboxServiceContent::setElementPosition(int element, eRect where)
212 {
213         if ((element >= 0) && (element < celElements))
214                 m_element_position[element] = where;
215 }
216
217 void eListboxServiceContent::setElementFont(int element, gFont *font)
218 {
219         if ((element >= 0) && (element < celElements))
220                 m_element_font[element] = font;
221 }
222
223 void eListboxServiceContent::setPixmap(int type, ePtr<gPixmap> &pic)
224 {
225         if ((type >=0) && (type < picElements))
226                 m_pixmaps[type] = pic;
227 }
228
229 void eListboxServiceContent::sort()
230 {
231         if (!m_lst)
232                 m_service_center->list(m_root, m_lst);
233         if (m_lst)
234         {
235                 m_list.sort(iListableServiceCompare(m_lst));
236                         /* FIXME: is this really required or can we somehow keep the current entry? */
237                 cursorHome();
238                 if (m_listbox)
239                         m_listbox->entryReset();
240         }
241 }
242
243 DEFINE_REF(eListboxServiceContent);
244
245 eListboxServiceContent::eListboxServiceContent()
246         :m_visual_mode(visModeSimple), m_size(0), m_current_marked(false), m_numberoffset(0)
247 {
248         cursorHome();
249         eServiceCenter::getInstance(m_service_center);
250 }
251
252 void eListboxServiceContent::cursorHome()
253 {
254         if (m_current_marked && m_saved_cursor == m_list.end())
255         {
256                 if (m_cursor_number >= m_size)
257                 {
258                         m_cursor_number = m_size-1;
259                         --m_cursor;
260                 }
261                 while (m_cursor_number)
262                 {
263                         std::iter_swap(m_cursor--, m_cursor);
264                         --m_cursor_number;
265                         if (m_listbox && m_cursor_number)
266                                 m_listbox->entryChanged(m_cursor_number);
267                 }
268         }
269         else
270         {
271                 m_cursor = m_list.begin();
272                 m_cursor_number = 0;
273         }
274 }
275
276 void eListboxServiceContent::cursorEnd()
277 {
278         if (m_current_marked && m_saved_cursor == m_list.end())
279         {
280                 while (m_cursor != m_list.end())
281                 {
282                         list::iterator prev = m_cursor++;
283                         ++m_cursor_number;
284                         if ( prev != m_list.end() && m_cursor != m_list.end() )
285                         {
286                                 std::iter_swap(m_cursor, prev);
287                                 if ( m_listbox )
288                                         m_listbox->entryChanged(m_cursor_number);
289                         }
290                 }
291         }
292         else
293         {
294                 m_cursor = m_list.end();
295                 m_cursor_number = m_size;
296         }
297 }
298
299 int eListboxServiceContent::setCurrentMarked(bool state)
300 {
301         bool prev = m_current_marked;
302         m_current_marked = state;
303
304         if (state != prev && m_listbox)
305         {
306                 m_listbox->entryChanged(m_cursor_number);
307                 if (!state)
308                 {
309                         if (!m_lst)
310                                 m_service_center->list(m_root, m_lst);
311                         if (m_lst)
312                         {
313                                 ePtr<iMutableServiceList> list;
314                                 if (m_lst->startEdit(list))
315                                         eDebug("no editable list");
316                                 else
317                                 {
318                                         eServiceReference ref;
319                                         getCurrent(ref);
320                                         if(!ref)
321                                                 eDebug("no valid service selected");
322                                         else
323                                         {
324                                                 int pos = cursorGet();
325                                                 eDebugNoNewLine("move %s to %d ", ref.toString().c_str(), pos);
326                                                 if (list->moveService(ref, cursorGet()))
327                                                         eDebug("failed");
328                                                 else
329                                                         eDebug("ok");
330                                         }
331                                 }
332                         }
333                         else
334                                 eDebug("no list available!");
335                 }
336         }
337
338         return 0;
339 }
340
341 int eListboxServiceContent::cursorMove(int count)
342 {
343         int prev = m_cursor_number, last = m_cursor_number + count;
344         if (count > 0)
345         {
346                 while(count && m_cursor != m_list.end())
347                 {
348                         list::iterator prev_it = m_cursor++;
349                         if ( m_current_marked && m_cursor != m_list.end() && m_saved_cursor == m_list.end() )
350                         {
351                                 std::iter_swap(prev_it, m_cursor);
352                                 if ( m_listbox && prev != m_cursor_number && last != m_cursor_number )
353                                         m_listbox->entryChanged(m_cursor_number);
354                         }
355                         ++m_cursor_number;
356                         --count;
357         }
358         } else if (count < 0)
359         {
360                 while (count && m_cursor != m_list.begin())
361                 {
362                         list::iterator prev_it = m_cursor--;
363                         if ( m_current_marked && m_cursor != m_list.end() && prev_it != m_list.end() && m_saved_cursor == m_list.end() )
364                         {
365                                 std::iter_swap(prev_it, m_cursor);
366                                 if ( m_listbox && prev != m_cursor_number && last != m_cursor_number )
367                                         m_listbox->entryChanged(m_cursor_number);
368                         }
369                         --m_cursor_number;
370                         ++count;
371                 }
372         }
373         return 0;
374 }
375
376 int eListboxServiceContent::cursorValid()
377 {
378         return m_cursor != m_list.end();
379 }
380
381 int eListboxServiceContent::cursorSet(int n)
382 {
383         cursorHome();
384         cursorMove(n);
385         return 0;
386 }
387
388 int eListboxServiceContent::cursorGet()
389 {
390         return m_cursor_number;
391 }
392
393 void eListboxServiceContent::cursorSave()
394 {
395         m_saved_cursor = m_cursor;
396         m_saved_cursor_number = m_cursor_number;
397 }
398
399 void eListboxServiceContent::cursorRestore()
400 {
401         m_cursor = m_saved_cursor;
402         m_cursor_number = m_saved_cursor_number;
403         m_saved_cursor = m_list.end();
404 }
405
406 int eListboxServiceContent::size()
407 {
408         return m_size;
409 }
410         
411 void eListboxServiceContent::setSize(const eSize &size)
412 {
413         m_itemsize = size;
414         setVisualMode(m_visual_mode);
415 }
416
417 void eListboxServiceContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
418 {
419         painter.clip(eRect(offset, m_itemsize));
420
421         if (m_current_marked && selected)
422                 style.setStyle(painter, eWindowStyle::styleListboxMarked);
423         else if (cursorValid() && isMarked(*m_cursor))
424                 style.setStyle(painter, selected ? eWindowStyle::styleListboxMarkedAndSelected : eWindowStyle::styleListboxMarked);
425         else
426                 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
427         painter.clear();
428         
429         if (cursorValid())
430         {
431                         /* get service information */
432                 ePtr<iStaticServiceInformation> service_info;
433                 m_service_center->info(*m_cursor, service_info);
434
435                 if (m_is_playable_ignore.valid() && service_info && !service_info->isPlayable(*m_cursor, m_is_playable_ignore))
436                         painter.setForegroundColor(gRGB(0xbbbbbb));
437
438                 int xoffset=0;  // used as offset when painting the folder/marker symbol
439
440                 for (int e = 0; e < celElements; ++e)
441                 {
442                         if (m_element_font[e])
443                         {
444                                 int flags=gPainter::RT_VALIGN_CENTER,
445                                         yoffs = 0,
446                                         xoffs = xoffset;
447                                 eRect &area = m_element_position[e];
448                                 std::string text = "<n/a>";
449                                 xoffset=0;
450
451                                 switch (e)
452                                 {
453                                 case celServiceNumber:
454                                 {
455                                         if (m_cursor->flags & eServiceReference::isMarker)
456                                                 continue;
457                                         char bla[10];
458                                 /* how we can do this better? :) */
459                                         int markers_before=0;
460                                         {
461                                                 list::iterator tmp=m_cursor;
462                                                 while(tmp != m_list.begin())
463                                                 {
464                                                         --tmp;
465                                                         if (tmp->flags & eServiceReference::isMarker)
466                                                                 ++markers_before;
467                                                 }
468                                         }
469                                         sprintf(bla, "%d", m_numberoffset + m_cursor_number + 1 - markers_before);
470                                         text = bla;
471                                         flags|=gPainter::RT_HALIGN_RIGHT;
472                                         break;
473                                 }
474                                 case celServiceName:
475                                 {
476                                         if (service_info)
477                                                 service_info->getName(*m_cursor, text);
478                                         break;
479                                 }
480                                 case celServiceInfo:
481                                 {
482                                         ePtr<eServiceEvent> evt;
483                                         if ( !service_info->getEvent(*m_cursor, evt) )
484                                         {
485                                                 std::string name = evt->getEventName();
486                                                 if (!name.length())
487                                                         continue;
488                                                 text = '(' + evt->getEventName() + ')';
489                                         }
490                                         else
491                                                 continue;
492                                         break;
493                                 }
494                                 }
495
496                                 eRect tmp = area;
497                                 tmp.setWidth(tmp.width()-xoffs);
498
499                                 eTextPara *para = new eTextPara(tmp);
500                                 para->setFont(m_element_font[e]);
501                                 para->renderString(text.c_str());
502
503                                 if (e == celServiceName)
504                                 {
505                                         eRect bbox = para->getBoundBox();
506                                         int name_width = bbox.width()+8;
507                                         m_element_position[celServiceInfo].setLeft(area.left()+name_width);
508                                         m_element_position[celServiceInfo].setTop(area.top());
509                                         m_element_position[celServiceInfo].setWidth(area.width()-name_width);
510                                         m_element_position[celServiceInfo].setHeight(area.height());
511                                 }
512
513                                 if (flags & gPainter::RT_HALIGN_RIGHT)
514                                         para->realign(eTextPara::dirRight);
515                                 else if (flags & gPainter::RT_HALIGN_CENTER)
516                                         para->realign(eTextPara::dirCenter);
517                                 else if (flags & gPainter::RT_HALIGN_BLOCK)
518                                         para->realign(eTextPara::dirBlock);
519
520                                 if (flags & gPainter::RT_VALIGN_CENTER)
521                                 {
522                                         eRect bbox = para->getBoundBox();
523                                         int vcentered_top = (area.height() - bbox.height()) / 2;
524                                         yoffs = vcentered_top - bbox.top();
525                                 }
526
527                                 painter.renderPara(para, offset+ePoint(xoffs, yoffs));
528                         }
529                         else if (e == celServiceTypePixmap || e == celFolderPixmap || e == celMarkerPixmap)
530                         {
531                                 int orbpos = m_cursor->getUnsignedData(4) >> 16;
532                                 ePtr<gPixmap> &pixmap =
533                                         (e == celFolderPixmap) ? m_pixmaps[picFolder] :
534                                         (e == celMarkerPixmap) ? m_pixmaps[picMarker] :
535                                         (orbpos == 0xFFFF) ? m_pixmaps[picDVB_C] :
536                                         (orbpos == 0xEEEE) ? m_pixmaps[picDVB_T] : m_pixmaps[picDVB_S];
537                                 if (pixmap)
538                                 {
539                                         eSize pixmap_size = pixmap->size();
540                                         int p = celServiceInfo;
541                                         if (e == celFolderPixmap)
542                                                 p = celServiceName;
543                                         else if (e == celMarkerPixmap)
544                                                 p = celServiceNumber;
545                                         eRect area = m_element_position[p];
546                                         int correction = (area.height() - pixmap_size.height()) / 2;
547
548                                         if (m_cursor->flags & eServiceReference::flagDirectory)
549                                         {
550                                                 if (e != celFolderPixmap)
551                                                         continue;
552                                                 xoffset = pixmap_size.width() + 8;
553                                         }
554                                         else if (m_cursor->flags & eServiceReference::isMarker)
555                                         {
556                                                 if (e != celMarkerPixmap)
557                                                         continue;
558                                         }
559                                         else
560                                         {
561                                                 if (e != celServiceTypePixmap)
562                                                         continue;
563                                                 m_element_position[celServiceInfo] = area;
564                                                 m_element_position[celServiceInfo].setLeft(area.left() + pixmap_size.width() + 8);
565                                                 m_element_position[celServiceInfo].setWidth(area.width() - pixmap_size.width() - 8);
566                                         }
567
568                                         area.moveBy(offset);
569                                         painter.clip(area);
570                                         painter.blit(pixmap, offset+ePoint(area.left(), correction), area, gPainter::BT_ALPHATEST);
571                                         painter.clippop();
572                                 }
573                         }
574                 }
575                 
576                 if (selected)
577                         style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
578         }
579         
580         painter.clippop();
581 }
582
583 void eListboxServiceContent::setIgnoreService( const eServiceReference &service )
584 {
585         m_is_playable_ignore=service;
586 }