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