small servicelist speedup
[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                 {
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         if (m_service_center->list(m_root, m_lst))
55                 eDebug("no list available!");
56         else if (m_lst->getContent(m_list))
57                 eDebug("getContent failed");
58
59         FillFinished();
60 }
61
62 void eListboxServiceContent::setCurrent(const eServiceReference &ref)
63 {
64         int index=0;
65         for (list::iterator i(m_list.begin()); i != m_list.end(); ++i, ++index)
66                 if ( *i == ref )
67                 {
68                         m_cursor = i;
69                         m_cursor_number = index;
70                         break;
71                 }
72         if (m_listbox)
73                 m_listbox->moveSelectionTo(index);
74 }
75
76 void eListboxServiceContent::getCurrent(eServiceReference &ref)
77 {
78         if (cursorValid())
79                 ref = *m_cursor;
80         else
81                 ref = eServiceReference();
82 }
83
84 int eListboxServiceContent::getNextBeginningWithChar(char c)
85 {
86 //      printf("Char: %c\n", c);
87         int index=0;
88         for (list::iterator i(m_list.begin()); i != m_list.end(); ++i, ++index)
89         {
90                 std::string text;
91                 ePtr<iStaticServiceInformation> service_info;
92                 m_service_center->info(*i, service_info);
93                 service_info->getName(*i, text);
94 //              printf("%c\n", text.c_str()[0]);
95                 int idx=0;
96                 int len=text.length();
97                 while ( idx <= len )
98                 {
99                         char cc = text[idx++];
100                         if ( cc >= 33 && cc < 127)
101                         {
102                                 if (cc == c)
103                                         return index;
104                                 break;
105                         }
106                 }
107         }
108         return 0;
109 }
110
111 int eListboxServiceContent::getPrevMarkerPos()
112 {
113         if (!m_listbox)
114                 return 0;
115         list::iterator i(m_cursor);
116         int index = m_cursor_number;
117         while (index)
118         {
119                 --i;
120                 --index;
121                 if (i->flags & eServiceReference::isMarker)
122                         break;
123         }
124         return index;
125 }
126
127 int eListboxServiceContent::getNextMarkerPos()
128 {
129         if (!m_listbox)
130                 return 0;
131         list::iterator i(m_cursor);
132         int index = m_cursor_number;
133         while (index < (m_size-1))
134         {
135                 ++i;
136                 ++index;
137                 if (i->flags & eServiceReference::isMarker)
138                         break;
139         }
140         return index;
141 }
142
143 void eListboxServiceContent::initMarked()
144 {
145         m_marked.clear();
146 }
147
148 void eListboxServiceContent::addMarked(const eServiceReference &ref)
149 {
150         m_marked.insert(ref);
151         if (m_listbox)
152                 m_listbox->entryChanged(lookupService(ref));
153 }
154
155 void eListboxServiceContent::removeMarked(const eServiceReference &ref)
156 {
157         m_marked.erase(ref);
158         if (m_listbox)
159                 m_listbox->entryChanged(lookupService(ref));
160 }
161
162 int eListboxServiceContent::isMarked(const eServiceReference &ref)
163 {
164         return m_marked.find(ref) != m_marked.end();
165 }
166
167 void eListboxServiceContent::markedQueryStart()
168 {
169         m_marked_iterator = m_marked.begin();
170 }
171
172 int eListboxServiceContent::markedQueryNext(eServiceReference &ref)
173 {
174         if (m_marked_iterator == m_marked.end())
175                 return -1;
176         ref = *m_marked_iterator++;
177         return 0;
178 }
179
180 int eListboxServiceContent::lookupService(const eServiceReference &ref)
181 {
182                 /* shortcut for cursor */
183         if (ref == *m_cursor)
184                 return m_cursor_number;
185                 /* otherwise, search in the list.. */
186         int index = 0;
187         for (list::const_iterator i(m_list.begin()); i != m_list.end(); ++i, ++index);
188         
189                 /* this is ok even when the index was not found. */
190         return index;
191 }
192
193 void eListboxServiceContent::setVisualMode(int mode)
194 {
195         m_visual_mode = mode;
196         
197         if (m_visual_mode == visModeSimple)
198         {
199                 m_element_position[celServiceName] = eRect(ePoint(0, 0), m_itemsize);
200                 m_element_font[celServiceName] = new gFont("Regular", 23);
201                 m_element_position[celServiceNumber] = eRect();
202                 m_element_font[celServiceNumber] = 0;
203                 m_element_position[celServiceInfo] = eRect();
204                 m_element_font[celServiceInfo] = 0;
205         }
206 }
207
208 void eListboxServiceContent::setElementPosition(int element, eRect where)
209 {
210         if ((element >= 0) && (element < celElements))
211                 m_element_position[element] = where;
212 }
213
214 void eListboxServiceContent::setElementFont(int element, gFont *font)
215 {
216         if ((element >= 0) && (element < celElements))
217                 m_element_font[element] = font;
218 }
219
220 void eListboxServiceContent::setPixmap(int type, ePtr<gPixmap> &pic)
221 {
222         if ((type >=0) && (type < picElements))
223                 m_pixmaps[type] = pic;
224 }
225
226 void eListboxServiceContent::sort()
227 {
228         if (!m_lst)
229                 m_service_center->list(m_root, m_lst);
230         if (m_lst)
231         {
232                 m_list.sort(iListableServiceCompare(m_lst));
233                         /* FIXME: is this really required or can we somehow keep the current entry? */
234                 cursorHome();
235                 if (m_listbox)
236                         m_listbox->entryReset();
237         }
238 }
239
240 DEFINE_REF(eListboxServiceContent);
241
242 eListboxServiceContent::eListboxServiceContent()
243         :m_visual_mode(visModeSimple), m_size(0), m_current_marked(false), m_numberoffset(0)
244 {
245         cursorHome();
246         eServiceCenter::getInstance(m_service_center);
247 }
248
249 void eListboxServiceContent::cursorHome()
250 {
251         if (m_current_marked && m_saved_cursor == m_list.end())
252         {
253                 if (m_cursor_number >= m_size)
254                 {
255                         m_cursor_number = m_size-1;
256                         --m_cursor;
257                 }
258                 while (m_cursor_number)
259                 {
260                         std::iter_swap(m_cursor--, m_cursor);
261                         --m_cursor_number;
262                         if (m_listbox && m_cursor_number)
263                                 m_listbox->entryChanged(m_cursor_number);
264                 }
265         }
266         else
267         {
268                 m_cursor = m_list.begin();
269                 m_cursor_number = 0;
270         }
271 }
272
273 void eListboxServiceContent::cursorEnd()
274 {
275         if (m_current_marked && m_saved_cursor == m_list.end())
276         {
277                 while (m_cursor != m_list.end())
278                 {
279                         list::iterator prev = m_cursor++;
280                         ++m_cursor_number;
281                         if ( prev != m_list.end() && m_cursor != m_list.end() )
282                         {
283                                 std::iter_swap(m_cursor, prev);
284                                 if ( m_listbox )
285                                         m_listbox->entryChanged(m_cursor_number);
286                         }
287                 }
288         }
289         else
290         {
291                 m_cursor = m_list.end();
292                 m_cursor_number = m_size;
293         }
294 }
295
296 int eListboxServiceContent::setCurrentMarked(bool state)
297 {
298         bool prev = m_current_marked;
299         m_current_marked = state;
300
301         if (state != prev && m_listbox)
302         {
303                 m_listbox->entryChanged(m_cursor_number);
304                 if (!state)
305                 {
306                         if (!m_lst)
307                                 m_service_center->list(m_root, m_lst);
308                         if (m_lst)
309                         {
310                                 ePtr<iMutableServiceList> list;
311                                 if (m_lst->startEdit(list))
312                                         eDebug("no editable list");
313                                 else
314                                 {
315                                         eServiceReference ref;
316                                         getCurrent(ref);
317                                         if(!ref)
318                                                 eDebug("no valid service selected");
319                                         else
320                                         {
321                                                 int pos = cursorGet();
322                                                 eDebugNoNewLine("move %s to %d ", ref.toString().c_str(), pos);
323                                                 if (list->moveService(ref, cursorGet()))
324                                                         eDebug("failed");
325                                                 else
326                                                         eDebug("ok");
327                                         }
328                                 }
329                         }
330                         else
331                                 eDebug("no list available!");
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 }