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