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