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