fix wrap around with enabled movemode
[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)
9 {
10         m_list.push_back(service);
11 }
12
13 void eListboxServiceContent::FillFinished()
14 {
15         m_size = m_list.size();
16         cursorHome();
17
18         if (m_listbox)
19                 m_listbox->entryReset();
20 }
21
22 void eListboxServiceContent::setRoot(const eServiceReference &root, bool justSet)
23 {
24         m_list.clear();
25         m_root = root;
26
27         if (justSet)
28                 return;
29         assert(m_service_center);
30         
31         ePtr<iListableService> lst;
32         if (m_service_center->list(m_root, lst))
33                 eDebug("no list available!");
34         else
35                 if (lst->getContent(m_list))
36                         eDebug("getContent failed");
37
38         FillFinished();
39 }
40
41 void eListboxServiceContent::setCurrent(const eServiceReference &ref)
42 {
43         int index=0;
44         for (list::iterator i(m_list.begin()); i != m_list.end(); ++i, ++index)
45                 if ( *i == ref )
46                 {
47                         m_cursor = i;
48                         m_cursor_number = index;
49                         break;
50                 }
51         if (m_listbox)
52                 m_listbox->moveSelectionTo(index);
53 }
54
55 void eListboxServiceContent::getCurrent(eServiceReference &ref)
56 {
57         if (cursorValid())
58                 ref = *m_cursor;
59         else
60                 ref = eServiceReference();
61 }
62
63 int eListboxServiceContent::getNextBeginningWithChar(char c)
64 {
65 //      printf("Char: %c\n", c);
66         int index=0;
67         for (list::iterator i(m_list.begin()); i != m_list.end(); ++i, ++index)
68         {
69                 std::string text;
70                 ePtr<iStaticServiceInformation> service_info;
71                 m_service_center->info(*i, service_info);
72                 service_info->getName(*i, text);
73 //              printf("%c\n", text.c_str()[0]);
74                 int idx=0;
75                 int len=text.length();
76                 while ( idx <= len )
77                 {
78                         char cc = text[idx++];
79                         if ( cc >= 33 && cc < 127)
80                         {
81                                 if (cc == c)
82                                         return index;
83                                 break;
84                         }
85                 }
86         }
87         return 0;
88 }
89
90 void eListboxServiceContent::initMarked()
91 {
92         m_marked.clear();
93 }
94
95 void eListboxServiceContent::addMarked(const eServiceReference &ref)
96 {
97         m_marked.insert(ref);
98         if (m_listbox)
99                 m_listbox->entryChanged(lookupService(ref));
100 }
101
102 void eListboxServiceContent::removeMarked(const eServiceReference &ref)
103 {
104         m_marked.erase(ref);
105         if (m_listbox)
106                 m_listbox->entryChanged(lookupService(ref));
107 }
108
109 int eListboxServiceContent::isMarked(const eServiceReference &ref)
110 {
111         return m_marked.find(ref) != m_marked.end();
112 }
113
114 void eListboxServiceContent::markedQueryStart()
115 {
116         m_marked_iterator = m_marked.begin();
117 }
118
119 int eListboxServiceContent::markedQueryNext(eServiceReference &ref)
120 {
121         if (m_marked_iterator == m_marked.end())
122                 return -1;
123         ref = *m_marked_iterator++;
124         return 0;
125 }
126
127 int eListboxServiceContent::lookupService(const eServiceReference &ref)
128 {
129                 /* shortcut for cursor */
130         if (ref == *m_cursor)
131                 return m_cursor_number;
132                 /* otherwise, search in the list.. */
133         int index = 0;
134         for (list::const_iterator i(m_list.begin()); i != m_list.end(); ++i, ++index);
135         
136                 /* this is ok even when the index was not found. */
137         return index;
138 }
139
140 void eListboxServiceContent::setVisualMode(int mode)
141 {
142         m_visual_mode = mode;
143         
144         if (m_visual_mode == visModeSimple)
145         {
146                 m_element_position[celServiceName] = eRect(ePoint(0, 0), m_itemsize);
147                 m_element_font[celServiceName] = new gFont("Regular", 23);
148                 m_element_position[celServiceNumber] = eRect();
149                 m_element_font[celServiceNumber] = 0;
150                 m_element_position[celIcon] = eRect();
151                 m_element_position[celServiceInfo] = eRect();
152                 m_element_font[celServiceInfo] = 0;
153         }
154 }
155
156 void eListboxServiceContent::setElementPosition(int element, eRect where)
157 {
158         if ((element >= 0) && (element < celElements))
159                 m_element_position[element] = where;
160 }
161
162 void eListboxServiceContent::setElementFont(int element, gFont *font)
163 {
164         if ((element >= 0) && (element < celElements))
165                 m_element_font[element] = font;
166 }
167
168 void eListboxServiceContent::sort()
169 {
170         ePtr<iListableService> lst;
171         if (!m_service_center->list(m_root, lst))
172         {
173                 m_list.sort(iListableServiceCompare(lst));
174                         /* FIXME: is this really required or can we somehow keep the current entry? */
175                 cursorHome();
176                 if (m_listbox)
177                         m_listbox->entryReset();
178         }
179 }
180
181 DEFINE_REF(eListboxServiceContent);
182
183 eListboxServiceContent::eListboxServiceContent()
184         :m_visual_mode(visModeSimple), m_size(0), m_current_marked(false), m_numberoffset(0)
185 {
186         cursorHome();
187         eServiceCenter::getInstance(m_service_center);
188 }
189
190 void eListboxServiceContent::cursorHome()
191 {
192         if (m_current_marked && m_saved_cursor == m_list.end())
193         {
194                 if (m_cursor_number >= m_size)
195                 {
196                         m_cursor_number = m_size-1;
197                         --m_cursor;
198                 }
199                 while (m_cursor_number)
200                 {
201                         std::iter_swap(m_cursor--, m_cursor);
202                         --m_cursor_number;
203                         if (m_listbox && m_cursor_number)
204                                 m_listbox->entryChanged(m_cursor_number);
205                 }
206         }
207         else
208         {
209                 m_cursor = m_list.begin();
210                 m_cursor_number = 0;
211         }
212 }
213
214 void eListboxServiceContent::cursorEnd()
215 {
216         if (m_current_marked && m_saved_cursor == m_list.end())
217         {
218                 while (m_cursor != m_list.end())
219                 {
220                         list::iterator prev = m_cursor++;
221                         ++m_cursor_number;
222                         if ( prev != m_list.end() && m_cursor != m_list.end() )
223                         {
224                                 std::iter_swap(m_cursor, prev);
225                                 if ( m_listbox )
226                                         m_listbox->entryChanged(m_cursor_number);
227                         }
228                 }
229         }
230         else
231         {
232                 m_cursor = m_list.end();
233                 m_cursor_number = m_size;
234         }
235 }
236
237 int eListboxServiceContent::setCurrentMarked(bool state)
238 {
239         bool prev = m_current_marked;
240         m_current_marked = state;
241
242         if (state != prev && m_listbox)
243         {
244                 m_listbox->entryChanged(m_cursor_number);
245                 if (!state)
246                 {
247                         ePtr<iListableService> lst;
248                         if (m_service_center->list(m_root, lst))
249                                 eDebug("no list available!");
250                         else
251                         {
252                                 ePtr<iMutableServiceList> list;
253                                 if (lst->startEdit(list))
254                                         eDebug("no editable list");
255                                 else
256                                 {
257                                         eServiceReference ref;
258                                         getCurrent(ref);
259                                         if(!ref)
260                                                 eDebug("no valid service selected");
261                                         else
262                                         {
263                                                 int pos = cursorGet();
264                                                 eDebugNoNewLine("move %s to %d ", ref.toString().c_str(), pos);
265                                                 if (list->moveService(ref, cursorGet()))
266                                                         eDebug("failed");
267                                                 else
268                                                         eDebug("ok");
269                                         }
270                                 }
271                         }
272                 }
273         }
274
275         return 0;
276 }
277
278 int eListboxServiceContent::cursorMove(int count)
279 {
280         int prev = m_cursor_number, last = m_cursor_number + count;
281         if (count > 0)
282         {
283                 while(count && m_cursor != m_list.end())
284                 {
285                         list::iterator prev_it = m_cursor++;
286                         if ( m_current_marked && m_cursor != m_list.end() && m_saved_cursor == m_list.end() )
287                         {
288                                 std::iter_swap(prev_it, m_cursor);
289                                 if ( m_listbox && prev != m_cursor_number && last != m_cursor_number )
290                                         m_listbox->entryChanged(m_cursor_number);
291                         }
292                         ++m_cursor_number;
293                         --count;
294         }
295         } else if (count < 0)
296         {
297                 while (count && m_cursor != m_list.begin())
298                 {
299                         list::iterator prev_it = m_cursor--;
300                         if ( m_current_marked && m_cursor != m_list.end() && prev_it != m_list.end() && m_saved_cursor == m_list.end() )
301                         {
302                                 std::iter_swap(prev_it, m_cursor);
303                                 if ( m_listbox && prev != m_cursor_number && last != m_cursor_number )
304                                         m_listbox->entryChanged(m_cursor_number);
305                         }
306                         --m_cursor_number;
307                         ++count;
308                 }
309         }
310         return 0;
311 }
312
313 int eListboxServiceContent::cursorValid()
314 {
315         return m_cursor != m_list.end();
316 }
317
318 int eListboxServiceContent::cursorSet(int n)
319 {
320         cursorHome();
321         cursorMove(n);
322         return 0;
323 }
324
325 int eListboxServiceContent::cursorGet()
326 {
327         return m_cursor_number;
328 }
329
330 void eListboxServiceContent::cursorSave()
331 {
332         m_saved_cursor = m_cursor;
333         m_saved_cursor_number = m_cursor_number;
334 }
335
336 void eListboxServiceContent::cursorRestore()
337 {
338         m_cursor = m_saved_cursor;
339         m_cursor_number = m_saved_cursor_number;
340         m_saved_cursor = m_list.end();
341 }
342
343 int eListboxServiceContent::size()
344 {
345         return m_size;
346 }
347         
348 void eListboxServiceContent::setSize(const eSize &size)
349 {
350         m_itemsize = size;
351         setVisualMode(m_visual_mode);
352 }
353
354 void eListboxServiceContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
355 {
356         painter.clip(eRect(offset, m_itemsize));
357
358         if (m_current_marked && selected)
359                 style.setStyle(painter, eWindowStyle::styleListboxMarked);
360         else if (cursorValid() && isMarked(*m_cursor))
361                 style.setStyle(painter, eWindowStyle::styleListboxMarked);
362         else
363                 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
364         painter.clear();
365         
366         if (cursorValid())
367         {
368                         /* get service information */
369                 ePtr<iStaticServiceInformation> service_info;
370                 m_service_center->info(*m_cursor, service_info);
371
372                 if (m_is_playable_ignore.valid() && !service_info->isPlayable(*m_cursor, m_is_playable_ignore))
373                         painter.setForegroundColor(gRGB(0xbbbbbb));
374
375                 for (int e = 0; e < celElements; ++e)
376                 {
377                         if (!m_element_font[e])
378                                 continue;
379                         int flags=gPainter::RT_VALIGN_CENTER;
380
381                         eRect area = m_element_position[e];
382
383                         std::string text = "<n/a>";
384
385                         switch (e)
386                         {
387                         case celIcon:
388                                 // render icon here...
389                                 continue;
390                         case celServiceNumber:
391                         {
392                                 char bla[10];
393                                 sprintf(bla, "%d", m_numberoffset + m_cursor_number + 1);
394                                 text = bla;
395                                 flags|=gPainter::RT_HALIGN_RIGHT;
396                                 break;
397                         }
398                         case celServiceName:
399                         {
400                                 if (service_info)
401                                         service_info->getName(*m_cursor, text);
402                                 break;
403                         }
404                         case celServiceInfo:
405                         {
406                                 ePtr<eServiceEvent> evt;
407                                 if ( !service_info->getEvent(*m_cursor, evt) )
408                                         text = '(' + evt->getEventName() + ')';
409                                 else
410                                         continue;
411                                 break;
412                         }
413                         }
414
415                         eTextPara *para = new eTextPara(area);
416
417                         para->setFont(m_element_font[e]);
418                         para->renderString(text);
419
420                         if (e == celServiceName)
421                         {
422                                 eRect bbox = para->getBoundBox();
423                                 int name_width = bbox.width()+10;
424                                 m_element_position[celServiceInfo].setLeft(area.left()+name_width);
425                                 m_element_position[celServiceInfo].setTop(area.top());
426                                 m_element_position[celServiceInfo].setWidth(area.width()-name_width);
427                                 m_element_position[celServiceInfo].setHeight(area.height());
428                         }
429
430                         if (flags & gPainter::RT_HALIGN_RIGHT)
431                                 para->realign(eTextPara::dirRight);
432                         else if (flags & gPainter::RT_HALIGN_CENTER)
433                                 para->realign(eTextPara::dirCenter);
434                         else if (flags & gPainter::RT_HALIGN_BLOCK)
435                                 para->realign(eTextPara::dirBlock);
436
437                         ePoint offs = offset;
438
439                         if (flags & gPainter::RT_VALIGN_CENTER)
440                         {
441                                 eRect bbox = para->getBoundBox();
442                                 int vcentered_top = (area.height() - bbox.height()) / 2;
443                                 int correction = vcentered_top - bbox.top();
444                                 offs += ePoint(0, correction);
445                         }
446
447                         painter.renderPara(para, offs);
448                 }
449                 
450                 if (selected)
451                         style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
452         }
453         
454         painter.clippop();
455 }
456
457 void eListboxServiceContent::setIgnoreService( const eServiceReference &service )
458 {
459         m_is_playable_ignore=service;
460 }