00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifndef _LISTWIDGET_H
00024 #define _LISTWIDGET_H
00025
00026 #ifdef HAVE_CONFIG_H
00027 # include <config.h>
00028 #endif
00029
00030 #ifdef HAVE_NCURSES_H
00031 # include <ncurses.h>
00032 #else // HAVE_NCURSES_H
00033 # ifdef HAVE_CURSES_H
00034 # include <curses.h>
00035 # else
00036 # error "Neither curses.h nor ncurses.h available"
00037 # endif // HAVE_CURSES_H
00038 #endif // HAVE_NCURSES_H
00039 #include "curswa.h"
00040
00041 #ifdef HAVE_FUNCTIONAL
00042 # include <functional>
00043 #endif
00044
00045 #ifdef HAVE_ITERATOR
00046 # include <iterator>
00047 #endif
00048
00049 #ifdef HAVE_LIST
00050 # include <list>
00051 #endif
00052
00053 #ifdef HAVE_ALGORITHM
00054 # include <algorithm>
00055 #endif
00056
00057 #ifdef HAVE_STRING_H
00058 # include <string.h>
00059 #endif
00060
00061 #include "../intl.h"
00062 #include "uiexception.h"
00063 #include "colors.h"
00064 #include "basewindow.h"
00065
00066 namespace YAPETUI {
00067
00082 template<class T>
00083 class ListWidget {
00084 public:
00091 enum SortOrder {
00092 ASCENDING,
00093 DESCENDING
00094 };
00095
00096 private:
00103 class ItemContains : public std::unary_function<T,bool> {
00104 private:
00105 const char* searchterm;
00106 public:
00107 explicit ItemContains(const char* t) :
00108 searchterm(t) {}
00109 bool operator()(const T& item) {
00110 const char* ptr;
00111 #ifdef HAVE_STRCASESTR
00112 ptr = strcasestr(item.c_str(), searchterm);
00113 #elif HAVE_STRSTR
00114 ptr = strstr(item.c_str(), searchterm);
00115 #else
00116 # error "Sorry, neither strcasestr() nor strstr() found"
00117 #endif
00118 if (ptr != NULL)
00119 return true;
00120
00121 return false;
00122 }
00123 };
00124
00125 WINDOW* window;
00126
00127 int width;
00128 int height;
00129
00136 bool hasfocus;
00137
00144 int start_pos;
00145
00154 int cur_pos;
00155
00162 SortOrder sortorder;
00163
00170 typename std::list<T> itemlist;
00171 typedef typename std::list<T>::size_type l_size_type;
00172
00173 typedef typename std::list<T>::iterator list_it;
00174 typedef typename std::list<T>::const_iterator c_list_it;
00175
00182 list_it cur_search_hit;
00183
00189 std::string last_search_term;
00190
00191 inline ListWidget(const ListWidget& lw) {}
00192 inline const ListWidget& operator=(const ListWidget& lw) {
00193 return *this; }
00194
00208 l_size_type validateIterator(list_it& it) {
00209 l_size_type pos;
00210 list_it itit = itemlist.begin();
00211
00212 for (pos = 0; itit != itemlist.end(); pos++, itit++ )
00213 if (itit == it)
00214 return pos;
00215
00216 return -1;
00217 }
00218
00219 l_size_type validateIterator(c_list_it& it) const {
00220 l_size_type pos;
00221 c_list_it itit = itemlist.begin();
00222
00223 for (pos = 0; itit != itemlist.end(); pos++, itit++ )
00224 if (itit == it)
00225 return pos;
00226
00227 return -1;
00228 }
00229
00230
00231 void highlightItemIter(list_it& it) {
00232 l_size_type pos = validateIterator(it);
00233
00234 if (pos < 0) return;
00235
00236 if ( (pos/pagesize()) > 0) {
00237 start_pos=pos;
00238 cur_pos=0;
00239 } else {
00240 start_pos = 0;
00241 cur_pos = pos;
00242 }
00243
00244 showListItems();
00245 showSelected(-1);
00246 }
00247
00256 int setBorder() const {
00257 if (hasfocus)
00258 return box(window,0,0);
00259 else
00260 return wborder(window, '|', '|', '-', '-', '+', '+', '+', '+');
00261 }
00262
00263 int pagesize() { return height-2; }
00264
00265 void clearWin() throw(UIException) {
00266 Colors::setcolor(window, LISTWIDGET);
00267 int retval = wclear(window);
00268 if (retval == ERR)
00269 throw UIException(_("Error clearing window"));
00270
00271 retval = setBorder();
00272 if (retval == ERR)
00273 throw UIException(_("Error drawing box around window"));
00274 }
00275
00276 void showScrollIndicators() throw(UIException) {
00277 if (start_pos > 0) {
00278 int retval = mvwaddch(window,
00279 1,
00280 width - 1,
00281 '^');
00282 if (retval == ERR)
00283 throw UIException(_("Unable to display scroll up indicator"));
00284 }
00285
00286 if ( (itemlist.size() - 1) > start_pos + cur_pos &&
00287 itemlist.size() > pagesize()) {
00288 int retval = mvwaddch(window,
00289 height - 2,
00290 width - 1,
00291 'v');
00292 if (retval == ERR)
00293 throw UIException(_("Unable to display scroll down indicator"));
00294 }
00295 }
00296
00297 void showListItems() throw(UIException) {
00298 int usable_width = width - 2;
00299
00300 clearWin();
00301
00302 typename std::list<T>::iterator itemlist_pos = itemlist.begin();
00303
00304 for(int i=0; i<start_pos; itemlist_pos++,i++);
00305
00306 for(int i=0; i<pagesize() && itemlist_pos != itemlist.end(); itemlist_pos++, i++) {
00307 int retval = mymvwaddnstr(window,
00308 1 + i,
00309 1,
00310 (*itemlist_pos).c_str(),
00311 usable_width);
00312 if (retval == ERR)
00313 throw UIException(_("Unable to display item"));
00314 }
00315
00316 showScrollIndicators();
00317 }
00318
00330 void showSelected(int old_pos) throw(UIException) {
00331 int retval = 0;
00332
00333 if (itemlist.size() > 0) {
00334 if (hasfocus)
00335 retval = mymvwchgat(window,
00336 cur_pos + 1,
00337 1,
00338 width-2,
00339 A_REVERSE,
00340 Colors::getcolor(LISTWIDGET),
00341 NULL);
00342 else
00343 retval = mymvwchgat(window,
00344 cur_pos + 1,
00345 1,
00346 width-2,
00347 A_NORMAL,
00348 Colors::getcolor(LISTWIDGET),
00349 NULL);
00350 if (retval == ERR)
00351 throw UIException(_("Error displaying cursor"));
00352
00353 }
00354
00355 if (old_pos > -1) {
00356
00357 retval = mymvwchgat(window,
00358 old_pos + 1,
00359 1,
00360 width-2,
00361 A_NORMAL,
00362 Colors::getcolor(LISTWIDGET),
00363 NULL);
00364 if (retval == ERR)
00365 throw UIException(_("Error move cursor"));
00366 }
00367
00368 retval = touchwin(window);
00369 if (retval == ERR)
00370 throw UIException(_("Error touching window"));
00371
00372 retval = wrefresh(window);
00373 if (retval == ERR)
00374 throw UIException(_("Error refreshing window"));
00375 }
00376
00377 void scrollUp() {
00378 if (itemlist.size() == 0) return;
00379
00380 if (cur_pos>0) {
00381 int old_pos = cur_pos--;
00382 showSelected(old_pos);
00383 } else {
00384 if (start_pos>0) {
00385 start_pos--;
00386 showListItems();
00387 showSelected(-1);
00388 }
00389 }
00390 }
00391
00392 void scrollDown() {
00393 if (itemlist.size() == 0) return;
00394
00395 if ( ((l_size_type)(cur_pos+start_pos))<itemlist.size()-1) {
00396 if (cur_pos < pagesize()-1 ) {
00397 int old_pos = cur_pos++;
00398 showSelected(old_pos);
00399 } else {
00400 if (((l_size_type)start_pos)<itemlist.size()-1) {
00401 start_pos++;
00402 showListItems();
00403 showSelected(-1);
00404 }
00405 }
00406 }
00407 }
00408
00409 void scrollPageUp() {
00410 if (itemlist.size() == 0) return;
00411
00412 int old_pos = cur_pos;
00413 cur_pos = 0;
00414 if ( start_pos - pagesize() > 0 ) {
00415 start_pos -= pagesize();
00416 }else {
00417 start_pos = 0;
00418 }
00419 showListItems();
00420 showSelected(old_pos);
00421 }
00422
00423 void scrollPageDown() {
00424 if (itemlist.size() == 0) return;
00425
00426 int old_pos = cur_pos;
00427 if ( ((l_size_type)pagesize()) > itemlist.size() - 1 ) {
00428 cur_pos = itemlist.size() - 1;
00429 start_pos = 0;
00430 } else {
00431 start_pos += pagesize() - 1;
00432 if ( ((l_size_type)start_pos) > itemlist.size() -1 ) {
00433 start_pos = itemlist.size() - pagesize() - 1;
00434 }
00435 cur_pos = 0;
00436 }
00437
00438 showListItems();
00439 showSelected(old_pos);
00440 }
00441
00442 void scrollHome() {
00443 if (itemlist.size() == 0) return;
00444
00445 start_pos = 0;
00446 int old_pos = cur_pos;
00447 cur_pos = 0;
00448 showListItems();
00449 showSelected(old_pos);
00450 }
00451
00452 void scrollEnd() {
00453 if (itemlist.size() == 0) return;
00454
00455 int old_pos = cur_pos;
00456 start_pos = itemlist.size() - pagesize();
00457 if (start_pos < 0) {
00458 start_pos = 0;
00459 cur_pos = itemlist.size()-1;
00460 } else {
00461 cur_pos = pagesize()-1;
00462 }
00463
00464 showListItems();
00465 showSelected(old_pos);
00466 }
00467
00468 void createWindow(int sx, int sy, int w, int h) throw(UIException) {
00469 window = newwin(h, w, sy, sx);
00470 if (window == NULL)
00471 throw UIException(_("Error creating list window"));
00472
00473 Colors::setcolor(window, LISTWIDGET);
00474
00475 int retval = keypad(window, true);
00476 if (retval == ERR)
00477 throw UIException(_("Error enabling keypad"));
00478
00479 retval = setBorder();
00480 if (retval == ERR)
00481 throw UIException(_("Error re-setting the border"));
00482
00483
00484 width = w;
00485 height = h;
00486 }
00487
00488 public:
00509 ListWidget(std::list<T> l, int sx, int sy, int w, int h)
00510 throw(UIException) : window(NULL),
00511 width(w),
00512 height(h),
00513 hasfocus(false),
00514 start_pos(0),
00515 cur_pos(0),
00516 itemlist(l),
00517 cur_search_hit(itemlist.end()),
00518 last_search_term("") {
00519 if ( sx == -1 ||
00520 sy == -1 ||
00521 width == -1 ||
00522 height == -1 )
00523 throw UIException(_("No idea of the dimension of the list"));
00524
00525 setSortOrder(ASCENDING);
00526
00527 createWindow(sx, sy, width, height);
00528 }
00529
00530 virtual ~ListWidget() {
00531 wclear(window);
00532 delwin(window);
00533 }
00534
00545 void setList(typename std::list<T>& l) {
00546 itemlist = l;
00547 start_pos = 0;
00548 cur_pos = 0;
00549 setSortOrder(this->sortorder);
00550 refresh();
00551 }
00552
00562 void replaceCurrentItem(T& item) {
00563 typename std::list<T>::iterator itemlist_pos = itemlist.begin();
00564 for (int i=0;
00565 i<(start_pos + cur_pos) && itemlist_pos != itemlist.end();
00566 itemlist_pos++, i++);
00567
00568 *itemlist_pos = item;
00569 setSortOrder(this->sortorder);
00570 }
00571
00572 void deleteSelectedItem() {
00573 if (itemlist.size()==0) return;
00574 typename std::list<T>::iterator itemlist_pos = itemlist.begin();
00575 for (int i=0;
00576 i<(start_pos + cur_pos) && itemlist_pos != itemlist.end();
00577 itemlist_pos++, i++);
00578
00579 if (itemlist_pos == itemlist.end()) return;
00580 itemlist.erase(itemlist_pos);
00581 scrollUp();
00582 }
00583
00584
00585 const std::list<T>& getList() const { return itemlist; }
00586 std::list<T>& getList() { return itemlist; }
00587
00610 virtual int focus() throw(UIException) {
00611 hasfocus = true;
00612
00613 int retval = setBorder();
00614 if (retval == ERR)
00615 throw UIException(_("Error setting the border of window"));
00616
00617 showScrollIndicators();
00618 showSelected(-1);
00619
00620 retval = wrefresh(window);
00621 if (retval == ERR)
00622 throw UIException(_("Error refreshing the list widget"));
00623
00624 int ch = 0;
00625 while (hasfocus) {
00626 ch = wgetch(window);
00627 switch (ch) {
00628 case KEY_UP:
00629 scrollUp();
00630 break;
00631 case KEY_DOWN:
00632 scrollDown();
00633 break;
00634 case KEY_HOME:
00635 case KEY_A1:
00636 scrollHome();
00637 break;
00638 case KEY_END:
00639 case KEY_C1:
00640 scrollEnd();
00641 break;
00642 case KEY_NPAGE:
00643 case KEY_C3:
00644 scrollPageDown();
00645 break;
00646 case KEY_PPAGE:
00647 case KEY_A3:
00648 scrollPageUp();
00649 break;
00650 case KEY_REFRESH:
00651 BaseWindow::refreshAll();
00652 break;
00653 default:
00654 hasfocus = false;
00655 break;
00656 }
00657 }
00658
00659 showSelected(-1);
00660
00661 retval = setBorder();
00662 if (retval == ERR)
00663 throw UIException(_("Error re-setting the border"));
00664 retval = wrefresh(window);
00665 if (retval == ERR)
00666 throw UIException(_("Error refreshing the list widget"));
00667
00668 return ch;
00669 }
00670
00671 void refresh() throw(UIException) {
00672 showListItems();
00673 showSelected(-1);
00674
00675 int retval = wrefresh(window);
00676 if (retval == ERR)
00677 throw UIException(_("Error refreshing list"));
00678 }
00679
00680 void resize(int sx, int sy, int w, int h) throw(UIException) {
00681 int retval = wclear(window);
00682 if (retval == ERR)
00683 throw UIException(_("Error clearing list"));
00684
00685 retval = wrefresh(window);
00686 if (retval == ERR)
00687 throw UIException(_("Error refreshing window"));
00688
00689 retval = delwin(window);
00690 if (retval == ERR)
00691 throw UIException(_("Error deleting window"));
00692
00693 createWindow(sx, sy, w, h);
00694 }
00695
00696 int getListPos() { return start_pos + cur_pos; }
00697
00698 T getSelectedItem() {
00699 typename std::list<T>::iterator itemlist_pos = itemlist.begin();
00700 for (int i=0;
00701 i<(start_pos + cur_pos) && itemlist_pos != itemlist.end();
00702 itemlist_pos++, i++);
00703 return *itemlist_pos;
00704 }
00705
00706 l_size_type size() { return itemlist.size(); }
00707
00715 SortOrder getSortOrder() const { return sortorder; }
00716
00725 void setSortOrder(SortOrder so) {
00726 itemlist.sort();
00727 sortorder = so;
00728 switch (sortorder) {
00729 case ASCENDING:
00730 break;
00731 case DESCENDING:
00732 std::reverse(itemlist.begin(),itemlist.end());
00733 break;
00734 }
00735 }
00736
00744 void setSortOrder() {
00745 setSortOrder(getSortOrder());
00746 }
00747
00757 bool searchTerm(const char* t) {
00758 last_search_term = t;
00759 cur_search_hit = std::find_if(itemlist.begin(),
00760 itemlist.end(),
00761 ItemContains(t));
00762
00763 if (cur_search_hit != itemlist.end()) {
00764 highlightItemIter(cur_search_hit);
00765 return true;
00766 }
00767
00768 return false;
00769 }
00770
00778 bool searchNext() {
00779 if (validateIterator(cur_search_hit) < 0 ||
00780 last_search_term.empty() )
00781 return false;
00782
00783
00784
00785 if (cur_search_hit == itemlist.end() ) {
00786 cur_search_hit = itemlist.begin();
00787 } else {
00788
00789
00790 cur_search_hit++;
00791 }
00792
00793
00794
00795
00796
00797 if (cur_search_hit == itemlist.end()) return false;
00798
00799 cur_search_hit = std::find_if(cur_search_hit,
00800 itemlist.end(),
00801 ItemContains(last_search_term.c_str()));
00802
00803 if (cur_search_hit != itemlist.end()) {
00804 highlightItemIter(cur_search_hit);
00805 return true;
00806 }
00807
00808 return false;
00809
00810 }
00811
00812 };
00813
00814 }
00815 #endif // _LISTWIDGET_H