boinctui-2.7.1/src/0000775000175000017500000000000014536642777012007 5ustar ssssboinctui-2.7.1/src/nstatictext.cpp0000664000175000017500000000403014536642777015062 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include "nstatictext.h" #include "kclog.h" void NStaticText::appendstring(int attr, const char* fmt, ...) { va_list args; va_start(args, fmt); content->vappend(attr, fmt, args); va_end(args); needrefresh = true; this->refresh(); } void NStaticText::setstring(int attr, const char* fmt, ...) { va_list args; va_start(args, fmt); delete content; content = new NColorString(attr,fmt,args); va_end(args); needrefresh = true; this->refresh(); } void NStaticText::refresh() { wbkgd(win,bgcolor); std::list::iterator it; werase(win); wmove(win,0,0); if (align == 1) //центрирование { wmove(win,0,(getwidth()/2)-(content->getlen()+1)/2); } if (align == 2) //правое { wmove(win,0,getwidth()-content->getlen()/*+1*/); } for (it = content->parts.begin(); it != content->parts.end(); it++) //цикл по частям тек строки { NColorStringPart* part = *it; //kLogPrintf("[%d] %s\n", part->attr, part->s.c_str()); wattrset(win,part->attr); wprintw(win,"%s",part->s.c_str()); //wattrset(win,0); } wbkgdset(win,bgcolor); wclrtoeol(win); //очищаем до конца строки NView::refresh(); } boinctui-2.7.1/src/resultparse.cpp0000664000175000017500000001201314536642777015061 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include #include #include #include "resultparse.h" #include "kclog.h" std::stack curitem; //на верху стека указатель на текущий заполняемый эл-т а голова это вершина дерева void callbackStartElement(void* userdata, const char* name, const char** atts); //колбэк начала эл-та void callbackEndElement(void* userdata, const char* name); //коллбэк завершения эл-та void callbackData(void *userdata, const char *content, int len); //коллбэк значения эл-та char* stripinvalidtag(char* xml, int len) //ГРЯЗНЫЙ ХАК нужен чтобы до парсинга удалить кривые теги //в сообщениях вида иначе будет ошибка парсинга { const char* teg1 = ""; const char* teg2 = ""; //int bytesdone = 0; //просмотрено байт char* pos = (char*)xml; while (pos < xml + len) { char* x1 = strstr(pos, teg1); char* x2 = strstr(pos, teg2); if ((x1 != NULL)&&(x2 != NULL)) { for(char* p = x1 + strlen(teg1); p < x2; p++) { if ((*p == '<')||(*p == '>')) //убираем html теги *p = ' '; } pos = (x1>x2)? x1:x2; //берем наибольшую pos++; } else break; } return xml; } Item* xmlparse(const char* xml, int len, std::string& errmsg) //xml строка с xml len ее размер в байтах { XML_Parser parser; void* ret; parser = XML_ParserCreate(NULL/*"UTF-8"*/); XML_SetUserData(parser, (void*) &ret); XML_SetElementHandler(parser, callbackStartElement, callbackEndElement); //устанавливаем колбэки XML_SetCharacterDataHandler(parser, callbackData); Item* roottree = new Item(""); //создаем корневой эл-т дерева curitem.push(roottree); //и делаем его текущим int retcode = XML_Parse(parser, xml, len, XML_TRUE); //собственно парсинг if (retcode == XML_STATUS_ERROR) { kLogPrintf("XML Error: %s\n", XML_ErrorString(XML_GetErrorCode(parser))); errmsg = std::string("XML error:") + std::string(XML_ErrorString(XML_GetErrorCode(parser))); } XML_ParserFree(parser); while (!curitem.empty()) curitem.pop(); //очищаем стек return roottree; //возвращаем постороенное дерево } void callbackStartElement(void* userdata, const char* name, const char** atts) { //kLogPrintf("\t+ %s\n",name); //аттрибуты тегов типа
//length=4 это атрибут (в boinc таких тегов нет?) /* for(int i = 0; atts[i]; i += 2) printf(" %s= '%s'", atts[i], atts[i + 1]); printf("\n"); */ //создаем новый эл-т дерева Item* pitem = new Item(name); //добавляем созданный эл-т в вышестоящий (если он есть) if (!curitem.empty()) { Item* parentitem = curitem.top(); //владелец всегда на верху стека parentitem->addsubitem(pitem); } //делаем созданный эл-т текущим (кладем в стек) curitem.push(pitem); } void callbackEndElement(void* userdata, const char* name) { //kLogPrintf("\t- %s\n",name); //удаляем текущий эл-т из стека (текущим становится его родитель) curitem.pop(); } void callbackData(void *userdata, const char *content, int len) { char *tmp = (char*)malloc(len+1); strncpy(tmp, content, len); tmp[len] = '\0'; //data = (void *) tmp; //kLogPrintf("\ncallbackData()-->[%s]<-- len=%d\n",tmp,len); //заносим значение в текущий эл-т bool empty = true; for (unsigned int i = 0; i < strlen(tmp); i++) { if (tmp[i] != ' ') { empty = false; break; } } if ( (!empty) && (strcmp(tmp,"\n") != 0) ) //пропускаем пустые строки { Item* pitem = curitem.top(); //текущий на верху стека pitem->appendvalue(tmp); } free(tmp); } boinctui-2.7.1/src/cfgform.h0000664000175000017500000000306614536642777013610 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef CFGFORM_H #define CFGFORM_H #include #include #include "nform.h" #include "cfg.h" #include "nstatictext.h" class CfgForm : public NForm { public: CfgForm(int lines, int rows/*, Config* cfg*/); void genfields(bool extfields); //создаст массив полей (extfields если нужно добавить хост) virtual void eventhandle(NEvent* ev); //обработчик событий protected: void updatecfg(); //сохраняет данные из формы в cfg //Config* cfg; bool extfields; //true если поле для доп хоста видимо int nhost; //макс номер хоста с 0го (включаа дополнительный если есть) }; #endif //CFGFORM_Hboinctui-2.7.1/src/nhline.cpp0000664000175000017500000000205114536642777013766 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include "nhline.h" void NHLine::refresh() { wbkgd(win,bgcolor); wattrset(win,getcolorpair(COLOR_WHITE,getbgcolor())); if ( asciilinedraw == 1) whline(win, '-', getwidth()-0); else whline(win, ACS_HLINE, getwidth()-0); NView::refresh(); };boinctui-2.7.1/src/kclog.cpp0000664000175000017500000000555714536642777013626 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= // * для ведения логов #ifdef LINUX #include #endif #include #include #include #include "kclog.h" #define K_NO_THREAD_COLOR_LOG //отключаем раскраску тредов ибо в этом проекте нахрен не нужно #ifdef DEBUG FILE* kLog = NULL; /// ANSI цвета const char* colors[7] = {"\033[0;0;31m","\033[0;0;32m","\033[0;0;33m","\033[0;0;34m","\033[0;0;35m","\033[0;0;36m","\033[0;0;37m"}; #endif /// открывает лог файл на запись void kLogOpen(const char* filename) { #ifdef DEBUG if (filename == NULL) { kLog = stdout; } else { char* tmpfile = (char*) malloc(256); #ifdef WIN32 sprintf(tmpfile,"%s/%s",getenv("TEMP"),filename); //для win32 используем юзерский temp //const char* tmpdir = getenv("TEMP"); #else //для линукса используем фиксированный путь sprintf(tmpfile,"/tmp/%s",filename); #endif if ((kLog = fopen(tmpfile,"a")) == NULL) { //kLogPrintf("ERROR: can't create log file %s\n",tmpfile.c_str()); } else { kLogPrintf("\nINFO: log opened success\n"); } free(tmpfile); } #endif } /// закрывает лог файл void kLogClose() { #ifdef DEBUG kLogPrintf("\nINFO: log close\n"); fclose(kLog); #endif } /// вывести информацию в лог заданным цветом void kCLogPrintf(char* color, char* fmt, ...) { #ifdef DEBUG if (kLog == NULL) kLogOpen(); fprintf(kLog,"%s",color); va_list args; va_start(args, fmt); vfprintf(kLog, fmt, args); va_end(args); fprintf(kLog,"\033[0m"); fflush(kLog); #endif } /// вывести информацию в лог void kLogPrintf(const char* fmt, ...) { #ifdef DEBUG if (kLog == NULL) kLogOpen(); #ifndef K_NO_THREAD_COLOR_LOG fprintf(kLog,"%s",colors[pthread_self() % (sizeof(colors)/sizeof(colors[0]))]); #endif va_list args; va_start(args, fmt); vfprintf(kLog, fmt, args); va_end(args); #ifndef K_NO_THREAD_COLOR_LOG fprintf(kLog,"\033[0m"); #endif fflush(kLog); #endif } boinctui-2.7.1/src/nmessagebox.cpp0000664000175000017500000001313414536642777015030 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include #include "kclog.h" #include "nmessagebox.h" // ============================================================================= NMButton::NMButton(const char* text, NEvent* pevent, ...) : NStaticText(NRect(3, 20, getmaxy(stdscr)/2-3/2,getmaxx(stdscr)/2-20/2)) { appendstring(getcolorpair(COLOR_WHITE, COLOR_CYAN)," "); appendstring(getcolorpair(COLOR_WHITE, COLOR_CYAN) | A_BOLD ,text); appendstring(getcolorpair(COLOR_WHITE, COLOR_CYAN)," "); this->pevent = pevent; //размер кнопки resize(1, mbstrlen(text) + 2); //список клавиш на которые реагирует эта кнопка va_list pk; va_start(pk, pevent); int ch = va_arg(pk, int); while ( ch != 0) { keys.push_back((char)ch); ch = va_arg(pk, int); //следующий ключ } va_end(pk); } void NMButton::eventhandle(NEvent* ev) //обработчик событий { NStaticText::eventhandle(ev); //предок if ( ev->done ) return; //одиночный или двойной клик NMouseEvent* mevent = (NMouseEvent*)ev; if (( ev->type == NEvent::evMOUSE ) && (mevent->cmdcode & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED))) { if (isinside(mevent->row, mevent->col)) { ev->done = true; NEvent* tmp = pevent; pevent = NULL; putevent(tmp); //активируем событие связанное с этой кнопкой } } //клавиатура if ( ev->type == NEvent::evKB ) { if ( keys.end() != std::find(keys.begin(), keys.end(), ev->cmdcode) ) { kLogPrintf("NMButton::eventhandle() got '%c' key\n", ev->cmdcode); if (pevent) { ev->done = true; NEvent* tmp = pevent; pevent = NULL; putevent(tmp); //активируем событие связанное с этой кнопкой } } } } // ============================================================================= NMessageBox::NMessageBox(const char* text) : NGroup(NRect(3, 40, 1, 1)) { //расчитать сколько строк нужно для отображения контента int contentheight = 0; int bsize = strlen(text); //количество байт int result = 0; //подсчитанное кол-во символов int nbytes = 0; //просмотренное кол-во байтов //int nlines = 0; //количество экранных строк int col = getwidth() - 4; const char* p = text; do { col++; if ((col >= getwidth() - 4)||(*p == '\n')) { if (*p == '\n') col = 0; else col = 1; contentheight++; //след строка } int symlen = mblen(p,bsize-nbytes); nbytes = nbytes + symlen; result++; p = p + symlen; //адрес начала след символа } while ( (*p != 0)&&(nbytes < bsize) ); //дошли до конца //заполняем содержимое content = new NStaticText(NRect(contentheight, getwidth()-4, 2, 2)); content->setbgcolor(getcolorpair(COLOR_WHITE, getbgcolor())); insert(content); content->appendstring(getcolorpair(COLOR_WHITE, getbgcolor()) | A_BOLD, text); modalflag = true; resize(contentheight + 6,getwidth()); wattrset(win,getcolorpair(COLOR_WHITE, getbgcolor()) | A_BOLD); if(asciilinedraw == 1) wborder(win, '|', '|', '-', '-', '+', '+', '+', '+'); else box(win,0,0); //content->setalign(1); move(getmaxy(stdscr)/2-getheight()/2,getmaxx(stdscr)/2-getwidth()/2); //центрируем } void NMessageBox::addbutton(NMButton* button) //добавить кнопку { insert(button); std::list::iterator it; int w = 0; //суммарная ширина всех кнопок for (it = ++items.begin(); it != items.end(); it++) // ++ пропустить content { w = w + (*it)->getwidth() + 2; // +2 промежутки между кнопками } int row = getheight() - 3; int col = (getwidth() - w) / 2 + 2; for (it = ++items.begin(); it != items.end(); it++) { (*it)->move(row, col); col = col + (*it)->getwidth() + 2; } } void NMessageBox::eventhandle(NEvent* ev) //обработчик событий { NGroup::eventhandle(ev); //предок if ( ev->done ) return; //одиночный или двойной клик //NMouseEvent* mevent = (NMouseEvent*)ev; if (/*(*/ ev->type == NEvent::evMOUSE /*) && (mevent->cmdcode & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED))*/) { //блокируем все мышиные мнутри окна // if (isinside(mevent->row, mevent->col)) ev->done = true; } //клавиатура if (ev->type == NEvent::evKB ) { //блокировать все клавиатурные кроме кода закрытия формы if (ev->keycode != 27) ev->done = true; } } boinctui-2.7.1/src/ngroup.cpp0000664000175000017500000000742514536642777014035 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include "ngroup.h" NGroup::~NGroup() { std::list::iterator it; for(it = items.begin(); it != items.end(); it++) { delete (*it); } } NView* NGroup::getitembyid(const char* id) //получить эл-т зная id его класса { NView* result = NULL; std::list::iterator it; for(it = items.begin(); it != items.end(); it++) { if (strcmp((*it)->getid(), id) == 0) { result = (*it); break; } } return result; } bool NGroup::destroybyid(const char* id) //удалить (с деструкцией) эл-т зная id его класса { bool result = false; NView* item = getitembyid(id); if (item != NULL) { remove(item); delete(item); result = true; } return result; } void NGroup::setneedrefresh() { NView::setneedrefresh(); std::list::iterator it; for(it = items.begin(); it != items.end(); it++) //перерисовать все подэлементы { (*it)->setneedrefresh(); } } void NGroup::refresh() { NView::refresh(); //предок std::list::iterator it; for(it = items.begin(); it != items.end(); it++) //перерисовать все подэлементы { (*it)->refresh(); } } void NGroup::move(int begrow, int begcol) { //перемещаем само окно NView::move(begrow, begcol); //предок //перемещаем содержимое (относительно этого окна) std::list::iterator it; for(it = items.begin(); it != items.end(); it++) //перместить все подэлементы { (*it)->move((*it)->getbegrow(),(*it)->getbegcol()); } } void NGroup::centermodalitems(int maxy, int maxx) //центрировать все модальные эл-ты (maxy,maxx -размер экрана) { std::list::iterator it; for(it = items.begin(); it != items.end(); it++) //ищем модальные подэлементы { if ((*it)->ismodal()) (*it)->move(maxy/2-(*it)->getheight()/2,maxx/2-(*it)->getwidth()/2); } } void NGroup::eventhandle(NEvent* ev) //обработчик событий { //если событие уже кем-то обработано, то просто выходим if (ev->done) return; //посылаем событие всем своим подэлементам (последние вставленные //получат первыми. Если один из подэл-тов обработал, то выходим std::list::reverse_iterator rit; for(rit = items.rbegin(); rit != items.rend(); rit++) //отправить всем подэлементам { (*rit)->eventhandle(ev); if (ev->done) return; //прекращаем если событие обработано } //раз подэл-ты не обработали пытаемся обработать самостоятельно NView::eventhandle(ev); //предок } boinctui-2.7.1/src/nselectlist.h0000664000175000017500000000465414536642777014522 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef NSELECTLIST_H #define NSELECTLIST_H #include "nscrollview.h" class NSelectList : public NScrollView //список со скроллингом и селектором { public: NSelectList(NRect rect) : NScrollView(rect) { selectedindex = -1; setselectorenable(true); setselectorbgcolor(COLOR_WHITE); }; void addstring(void* userobj, int attr, const char* fmt, ...); //userobj произвольные данные связанные со строкой void addstring(void* userobj, NColorString* sctring); virtual void drawcontent(); virtual void refresh(); virtual void selectorup(); virtual void selectordown(); virtual void setselectorpos(int n) { selectedindex = n; needrefresh = true; }; //передвинуть селектор на строку n void* getselectedobj(); //вернет указатель или NULL void setselectorbgcolor(short color) { selectorbgcolor = color; }; //virtual bool objcmpeqv(void* obj1, void* obj2) { return obj1==obj2; }; void setselectorenable(bool b) { selectorenable = b; }; //изменить видимость селектора protected: //void* selectedobj; //выделенный объект int selectedindex; //номер выделенной строки bool selectorenable; //true если видимость селектора разрешена (не значит что он видим) std::vector objects; //объекты, ассоциированные с визуальными строками short selectorbgcolor; //номер цвета фона выделеной строки }; #endif //NSELECTLIST_Hboinctui-2.7.1/src/nmenu.h0000664000175000017500000000473014536642777013306 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef NMENU_H #define NMENU_H #if HAVE_LIBNCURSESW == 1 && NCURSESW_HAVE_SUBDIR == 1 #include #else #include #endif #include #include "ngroup.h" #include "nscrollbar.h" class NMenu : public NGroup { public: NMenu(NRect rect, bool horis = false); virtual ~NMenu(); virtual void refresh(); void additem(const char* name, const char* comment); //добавить эл-т в меню virtual void eventhandle(NEvent* ev); //обработчик событий void setbackground(int attr) { set_menu_back(menu, attr); wattrset(win, attr); bgattr = attr; wbkgdset(win,attr); }; void setforeground(int attr) { set_menu_fore(menu, attr); fgattr = attr; }; void postmenu() { if (!posted) {post_menu(menu); posted = true;} }; void unpostmenu() { if (posted) {unpost_menu(menu); posted = false;} }; virtual bool createsubmenu() { return false; }; //открыть субменю virtual void destroysubmenu(); //закрыть субменю virtual bool action() { return false; }; //вызывается при нажатии Enter protected: MENU* menu; ITEM** mitems; //масив элементов std::list itemnames; //имена эл-тов меню std::list itemcomments; //комментарии к эл-там меню int bgattr; //цвет текста и фона невыделенного эл-та int fgattr; //цвет текста и фона выделенного эл-та bool ishoris;//true если меню горизонтальное private: bool posted; //true после post_menu() NScrollBar* scrollbar; }; #endif //NMENU_Hboinctui-2.7.1/src/net.h0000664000175000017500000000344514536642777012754 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef NET_H #define NET_H #include #include class TConnect //информация о соединении с boinc сервером { public: TConnect(const char* shost, const char* sport) { this->shost = strdup(shost); this->sport = strdup(sport); hsock = -1; }; virtual ~TConnect() { disconnect(); free(shost); free(sport); }; int getsock() {return hsock;}; void sendreq(const char* fmt, va_list vl); //отправить запрос на сервер void sendreq(const char* fmt, ...); //отправить запрос на сервер char* waitresult(); //получить ответ на запрос char* gethost() { return shost; }; char* getport() { return sport; }; bool isconnected() { return (hsock != -1); }; protected: virtual void createconnect (/*const char* shost, const char* sport*/); virtual void disconnect(); int hsock; //дескриптор сокета char* shost; char* sport; }; #endif // NET_H boinctui-2.7.1/src/nscrollbar.cpp0000664000175000017500000001021014536642777014646 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013,2014 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include "nscrollbar.h" #include "kclog.h" NScrollBar::NScrollBar(NRect rect, chtype chtop, chtype chbottom, chtype chinactive) : NView(rect) { bgcolor = 0; this->chtop = chtop; this->chbottom = chbottom; this->chinactive = chinactive; setvisible(true); } void NScrollBar::setpos(int vmin, int vmax, int vpos1, int vpos2) { //если видимая часть больше или равна контенту то выключаем setvisible(!((vpos1<=vmin)&&(vpos2>=vmax))); if ((this->vmin!=vmin)||(this->vmax!=vmax)||(this->vpos1!=vpos1)||(this->vpos2!=vpos2)) { this->vmin=vmin; this->vmax=vmax; this->vpos1=vpos1; this->vpos2=vpos2; if (vmin>vmax) vmax = vmin; if (vpos1 > vpos2) vpos2 = vpos1; if (vpos1 < vmin) vpos1 = vmin; if (vpos2 > vmax) vpos2 = vmax; //kLogPrintf("NScrollBar::setpos(vmin=%d, vmax=%d, vpos1=%d, vpos2=%d)\n",vmin, vmax, vpos1, vpos2); refresh(); } } void NScrollBar::refresh() { wbkgd(win,bgcolor); wattrset(win,getcolorpair(COLOR_WHITE,getbgcolor())); chtype topsymbol = asciilinedraw ? '+'| (chtop & A_BOLD) : chtop; chtype bottomsymbol = asciilinedraw ? '+' | (chbottom & A_BOLD) : chbottom; chtype bodysymbol = asciilinedraw ? 'X' : ACS_CKBOARD; if (!visible) bodysymbol = asciilinedraw ? '|' | (chinactive & A_BOLD) : chinactive; int rowmin = 0; //строка с которой начинаем рисовать фон int rowmax = getheight() - 1; //строка до которой рисуем фон включительно if (chtop != 0) //верхний концевой символ есть { mvwaddch(win,0,0,topsymbol); rowmin = 1; } if (chbottom != 0)//нижний концевой символ есть { mvwaddch(win,getheight()-1,0,bottomsymbol); rowmax--; //укорачиваем } //фоновый заполнитель int len = rowmax - rowmin + 1; //высота заполнителя в символах mvwvline(win, rowmin, 0, bodysymbol, len); if (visible) { //отрисовка позиции if ((vpos2>vpos1)&&(vmax>vmin)) { double scale = double(len-1)/(vmax-vmin); //сколько единиц на экранную строку int len2 = round(scale * (vpos2-vpos1)); //число выделенных строк int rowpos1 = rowmin + round(scale * (vpos1-vmin)); //строка начала выделения if (len2<1) //len2 всегда 1 и более len2=1; //подпорки с краем диапазона чтобы были видны малые фрагменты //в начале и в конце if ((rowpos1==rowmin)&&(vpos1>vmin)) { if (rowpos1=rowmax)&&(vpos2rowmin) rowpos1--; //слегка приподнять вверх чтобы показать что это не конец } if (vpos2==vmax) len2=len-rowpos1+1; //kLogPrintf("len=%d vmin=%d vmax=%d vpos1=%d vpos2=%d scale=%f rowmin=%d rowmax=%d rowpos1=%d len2=%d\n",len, vmin,vmax,vpos1,vpos2,scale,rowmin,rowmax,rowpos1,len2); //рисуем выделение mvwvline(win,rowpos1,0,' ' | getcolorpair(COLOR_CYAN,COLOR_WHITE), len2); } } NView::refresh(); } boinctui-2.7.1/src/mainprog.cpp0000664000175000017500000004660714536642777014344 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include #include #include "kclog.h" #include "mainprog.h" #include "tuievent.h" #include "nmessagebox.h" #include "statwin.h" MainProg::MainProg() { uistate = 0; done = false; gsrvlist = new SrvList(); evtimertime = 0; //запускаем таймер с нуля //основное окно wmain = new MainWin(NRect(getmaxy(stdscr)-2, getmaxx(stdscr), 1, 0)); //создаем основное окно insert(wmain); wmain->setserver(gsrvlist->getcursrv()); //отображать первый в списке сервер menu = new TopMenu(); menu->setserver(gsrvlist->getcursrv()); //отображать первый в списке сервер insert(menu); wmain->updatecaption(); //статус строка wstatus = new NStaticText(NRect(1, getmaxx(stdscr), getmaxy(stdscr)-1, 0)); //создаем окно статуса insert(wstatus); wstatus->setbgcolor(getcolorpair(COLOR_WHITE,COLOR_GREEN)); updatestatuslinecontent(); } MainProg::~MainProg() { kLogPrintf("MainProg::~MainProg()\n"); gCfg->save(); delete gsrvlist; } void MainProg::smartresize() { if (!MainProg::needresize) return; struct winsize size; ioctl(fileno(stdout), TIOCGWINSZ, (char *) &size); resizeterm(size.ws_row, size.ws_col); menu->resize(1, getmaxx(stdscr)); //ширина верхнего меню wmain->resize(getmaxy(stdscr)-2, getmaxx(stdscr)); wstatus->resize(1, getmaxx(stdscr)); //ширина статус строки wstatus->move(getmaxy(stdscr)-1,0); //позиция статус строки centermodalitems(getmaxy(stdscr),getmaxx(stdscr)); //центрировать модальные формы (если есть) MainProg::needresize = false; } void MainProg::updatestatuslinecontent() { int attrYG = A_BOLD | getcolorpair(COLOR_YELLOW,COLOR_GREEN); int attrWG = A_BOLD | getcolorpair(COLOR_WHITE,COLOR_GREEN); int attrBG = A_BOLD | getcolorpair(COLOR_BLACK,COLOR_GREEN) | A_BOLD; if (uistate & stUIMODALFORM) { wstatus->setstring(attrYG, " Esc"); wstatus->appendstring(attrWG, " Cancel"); } if (uistate & stUISTATWIN) { wstatus->setstring(attrYG, " Esc"); wstatus->appendstring(attrWG, " Cancel"); wstatus->appendstring(attrWG, " |"); wstatus->appendstring(attrYG, " PgUp/PgDn"); wstatus->appendstring(attrWG, " V.Scroll"); wstatus->appendstring(attrWG, " |"); wstatus->appendstring(attrYG, " Left/Right"); wstatus->appendstring(attrWG, " H.Scroll"); wstatus->appendstring(attrWG, " |"); wstatus->appendstring(attrYG, " U"); wstatus->appendstring(attrWG, " Host/User score"); } if (uistate & stUITASKINFO) { wstatus->setstring(attrYG, " Esc"); wstatus->appendstring(attrWG, " Cancel"); wstatus->appendstring(attrWG, " |"); wstatus->appendstring(attrYG, " PgUp/PgDn"); wstatus->appendstring(attrWG, " Scroll "); } if ( (uistate == 0)||(uistate == stUISELECTOR) ) { wstatus->setstring(attrYG, " PgUp/PgDn"); wstatus->appendstring(attrWG, " Scroll Msg |"); wstatus->appendstring(attrYG, " +/-"); wstatus->appendstring(attrWG, " Resize Msg |"); wstatus->appendstring(attrYG, " Up/Dn"); wstatus->appendstring(attrWG, " Select |"); if (uistate & stUISELECTOR) { wstatus->appendstring(attrYG, " S"); wstatus->appendstring(attrWG, "uspend"); wstatus->appendstring(attrWG, " |"); wstatus->appendstring(attrYG, " R"); wstatus->appendstring(attrWG, "esume |"); wstatus->appendstring(attrYG, " Enter"); wstatus->appendstring(attrWG, " Info"); } else { wstatus->appendstring(attrBG, " Suspend"); wstatus->appendstring(attrWG, " |"); wstatus->appendstring(attrBG, " Resume"); wstatus->appendstring(attrWG, " |"); wstatus->appendstring(attrBG, " Enter Info"); } wstatus->appendstring(attrWG, " |"); wstatus->appendstring(attrYG, " F9/M"); wstatus->appendstring(attrWG, " Menu |"); wstatus->appendstring(attrYG, " V"); wstatus->appendstring(attrWG, " Statistics |"); } } void MainProg::eventhandle(NEvent* ev) //обработчик событий КОРНЕВОЙ! { NProgram::eventhandle(ev); if (ev->done) //если событие не обработано обработать здесь return; if (ev->type == NEvent::evKB) //клавиатурные { switch(ev->keycode) { case 'q': case 'Q': done = true; //выходим break; case 'n': case 'N': menu->disable(); if (gsrvlist->getcursrv()) { gsrvlist->nextserver(); wmain->setserver(gsrvlist->getcursrv()); menu->setserver(gsrvlist->getcursrv()); evtimertime = 0; //для перезапуска таймера для форсированонй перерисовки wmain->updatecaption(); } break; case 'p': case 'P': menu->disable(); if (gsrvlist->getcursrv()) { gsrvlist->prevserver(); wmain->setserver(gsrvlist->getcursrv()); menu->setserver(gsrvlist->getcursrv()); evtimertime = 0; wmain->updatecaption(); } break; case 'c': case 'C': if (getitembyid(typeid(CfgForm).name()) == NULL) { menu->disable(); CfgForm* cfgform = new CfgForm(15,76/*,cfg*/); insert(cfgform); cfgform->settitle("Configuration"); cfgform->refresh(); uistate = uistate | stUIMODALFORM; updatestatuslinecontent(); } break; case 'S': case 's': { TaskInfo* tinfo = (TaskInfo*)wmain->wtask->getselectedobj(); if (tinfo) //только если есть выделенный эл-т gsrvlist->getcursrv()->optask(tinfo->projecturl.c_str(), tinfo->taskname.c_str(),"suspend_result"); break; } case 'V': case 'v': { if (!destroybyid(typeid(StatWin).name())) { menu->disable(); StatWin* statwin = new StatWin(gsrvlist->getcursrv()); insert(statwin); statwin->move(getmaxy(stdscr)/2-statwin->getheight()/2,getmaxx(stdscr)/2-statwin->getwidth()/2); //центрируем uistate = uistate | stUISTATWIN; } else uistate = uistate & ~stUISTATWIN; updatestatuslinecontent(); break; } case 'R': case 'r': { TaskInfo* tinfo = (TaskInfo*)wmain->wtask->getselectedobj(); if (tinfo) //только если есть выделенный эл-т gsrvlist->getcursrv()->optask(tinfo->projecturl.c_str(), tinfo->taskname.c_str(),"resume_result"); break; } case 'A': case 'a': { TaskInfo* tinfo = (TaskInfo*)wmain->wtask->getselectedobj(); if (tinfo) //только если есть выделенный эл-т { TuiEvent* ev = new TuiEvent(evABORTRES); ev->bdata1 = false; putevent(ev); //создаем событие с кодом 2 "abort_result" } break; } case 27: menu->disable(); //деструктим все какие есть модельные окна destroybyid(typeid(CfgForm).name()); //деструктим форму destroybyid(typeid(NMessageBox).name()); //деструктим форму if (destroybyid(typeid(StatWin).name())) //деструктим форму uistate = uistate & ~stUISTATWIN; if (destroybyid(typeid(TaskInfoWin).name())) //деструктим форму { wmain->wtask->setselectorenable(true); uistate = uistate & ~stUITASKINFO; } uistate = uistate & ~stUIMODALFORM; updatestatuslinecontent(); break; case 'M': case 'm': case KEY_F(9): if (!menu->isenable()) { menu->enable(); menu->action(); } else menu->disable(); break; default: kLogPrintf("KEYCODE=%d\n", ev->keycode); break; } //switch } if (ev->type == NEvent::evPROG) //прграммные { switch(ev->cmdcode) { case evCFGCH: //событие при изменении конфига { menu->disable(); destroybyid(typeid(CfgForm).name()); //деструктим форму //реакция на изменение конфига gsrvlist->refreshcfg(); wmain->setserver(gsrvlist->getcursrv()); //отображать первый в списке сервер menu->setserver(gsrvlist->getcursrv()); //отображать первый в списке сервер wmain->updatecaption(); evtimertime = 0; //для перезапуска таймера для форсированонй перерисовки break; } case evABOUT: //событие About win { if (!destroybyid(typeid(AboutWin).name())) { AboutWin* about = new AboutWin(2,40); insert(about); about->move(getmaxy(stdscr)/2-about->getheight()/2,getmaxx(stdscr)/2-about->getwidth()/2); //центрируем uistate = uistate | stUIMODALFORM; } else uistate = uistate & ~stUIMODALFORM; updatestatuslinecontent(); break; } case evPOPUPMSG: { TuiEvent* ev1 = (TuiEvent*)ev; NMessageBox* mbox = new NMessageBox((ev1->sdata1 + "\n" + ev1->sdata2).c_str()); NEvent* buttonNev = new NEvent(NEvent::evKB, 27); //событие для кнопки Ok mbox->addbutton(new NMButton("Ok",buttonNev, 'O','o',27,'\n',0)); insert(mbox); uistate = uistate | stUIMODALFORM; break; } case evKEYBIND: //событие KeyBinding win { if (!destroybyid(typeid(HelpWin).name())) { HelpWin* help = new HelpWin(2,40); insert(help); help->move(getmaxy(stdscr)/2-help->getheight()/2,getmaxx(stdscr)/2-help->getwidth()/2); //центрируем uistate = uistate | stUIMODALFORM; } else uistate = uistate & ~stUIMODALFORM; updatestatuslinecontent(); break; } case evBENCHMARK: //запустить бенчмарк { Srv* srv = gsrvlist->getcursrv(); if (srv != NULL) srv->runbenchmarks(); break; } case evADDPROJECT: //добавить проект { if (!destroybyid(typeid(AddProjectForm).name())) { TuiEvent* ev1 = (TuiEvent*)ev; //Srv* srv = gsrvlist->getcursrv(); if (ev1->srv != NULL) { AddProjectForm* addform = new AddProjectForm(30,65,ev1->srv,ev1->sdata1.c_str(),ev1->bdata1, ev1->bdata2); insert(addform); addform->move(getmaxy(stdscr)/2-addform->getheight()/2,getmaxx(stdscr)/2-addform->getwidth()/2); //центрируем uistate = uistate | stUIMODALFORM; } } else uistate = uistate & ~stUIMODALFORM; updatestatuslinecontent(); break; } case evADDACCMGR: //добавить акк менеджер { if (!destroybyid(typeid(AddAccMgrForm).name())) { TuiEvent* ev1 = (TuiEvent*)ev; //Srv* srv = gsrvlist->getcursrv(); if (ev1->srv != NULL) { AddAccMgrForm* addmgrform = new AddAccMgrForm(30,65,ev1->srv,ev1->sdata1.c_str()); insert(addmgrform); addmgrform->move(getmaxy(stdscr)/2-addmgrform->getheight()/2,getmaxx(stdscr)/2-addmgrform->getwidth()/2); //центрируем uistate = uistate | stUIMODALFORM; } } else uistate = uistate & ~stUIMODALFORM; updatestatuslinecontent(); break; } case evPROJECTOP: //операции над проектом { TuiEvent* ev1 = (TuiEvent*)ev; const char* projname = ev1->sdata1.c_str(); const char* projop = ev1->sdata2.c_str(); if (!ev1->bdata1) //если нет флага подтвержденного события, то не выполняем а спрашиваем юзера { menu->disable(); //выключаем меню //создаем окно сообщения с подтверждением std::stringstream s; s << "Please Confirm\n\n" << "Project : "<< projname << "\nOperation : " << projop; NMessageBox* mbox = new NMessageBox(s.str().c_str()); TuiEvent* buttonYev = new TuiEvent(evPROJECTOP, ev1->srv, projname, projop); //событие для кнопки Y buttonYev->bdata1 = true; //флаг подтвержденности mbox->addbutton(new NMButton("Yes",buttonYev, 'Y','y',0)); NEvent* buttonNev = new NEvent(NEvent::evKB, 27); //событие для кнопки N mbox->addbutton(new NMButton("No",buttonNev, 'N','n',27,0)); insert(mbox); uistate = uistate | stUIMODALFORM; } else { kLogPrintf("evPROJECT confirmed event detected\n"); ev1->srv->opproject(projname, projop); //выполняем действие if (destroybyid(typeid(NMessageBox).name())) //удаляем окно подтверждения (если есть) uistate = uistate & ~stUIMODALFORM; } updatestatuslinecontent(); break; } case evABORTRES: //событие действий над проектами "abort_result" и.т.д. { TaskInfo* tinfo = (TaskInfo*)wmain->wtask->getselectedobj(); if (tinfo) //только если есть выделенный эл-т { TuiEvent* ev1 = (TuiEvent*)ev; if (!ev1->bdata1) //если нет флага подтвержденного события, то не выполняем а спрашиваем юзера { menu->disable(); //выключаем меню //создаем окно сообщения с подтверждением std::stringstream s; s << "Please Confirm\n\n" << "Task : " << tinfo->taskname << "\nOperation : " << "Abort"; NMessageBox* mbox = new NMessageBox(s.str().c_str()); TuiEvent* buttonYev = new TuiEvent(evABORTRES); //событие для кнопки Y buttonYev->bdata1 = true; //флаг подтвержденности mbox->addbutton(new NMButton("Yes",buttonYev, 'Y','y',0)); NEvent* buttonNev = new NEvent(NEvent::evKB, 27); //событие для кнопки N mbox->addbutton(new NMButton("No",buttonNev, 'N','n',27,0)); insert(mbox); uistate = uistate | stUIMODALFORM; } else { kLogPrintf("evABORTRES confirmed event detected\n"); Srv* srv = gsrvlist->getcursrv(); srv->optask(tinfo->projecturl.c_str(), tinfo->taskname.c_str(),"abort_result"); //выполняем действие if (destroybyid(typeid(NMessageBox).name())) //удаляем окно подтверждения (если есть) uistate = uistate & ~stUIMODALFORM; } updatestatuslinecontent(); break; } } case evTASKSELECTORON: { uistate = uistate | stUISELECTOR; updatestatuslinecontent(); break; } case evTASKSELECTOROFF: { uistate = uistate & ~stUISELECTOR; updatestatuslinecontent(); break; } case evTASKINFO: { TaskInfo* tinfo = (TaskInfo*)wmain->wtask->getselectedobj(); if (tinfo) //только если есть выделенный эл-т { wmain->wtask->setselectorenable(false); TaskInfoWin* taskinfowin = new TaskInfoWin("Task Info Raw View", gsrvlist->getcursrv(), tinfo->projecturl.c_str(), tinfo->taskname.c_str()); insert(taskinfowin); taskinfowin->move(getmaxy(stdscr)/2-taskinfowin->getheight()/2,getmaxx(stdscr)/2-taskinfowin->getwidth()/2); //центрируем uistate = uistate | stUITASKINFO; updatestatuslinecontent(); } } case evASCIIMODECHANGE: { gCfg->setivalue("line_draw_mode",asciilinedraw); refresh(); break; } case evTRANSPARENTBGMODECHANGE: { gCfg->setivalue("transparent_background",(transparentbg==0)?1:0); //transparentbg = (transparentbg==0)?1:0; //refresh(); menu->disable(); //выключаем меню //создаем окно сообщения с подтверждением NMessageBox* mbox = new NMessageBox("Need restart boinctui"); NEvent* buttonNev = new NEvent(NEvent::evKB, 27); //событие для кнопки N mbox->addbutton(new NMButton("Yes",buttonNev, 'Y','y','\n',27,0)); insert(mbox); uistate = uistate | stUIMODALFORM; break; } } //switch } } bool MainProg::mainloop() //основной цикл порождающий события { sigset_t newset; sigemptyset(&newset); sigaddset(&newset, SIGWINCH); //маска для сигнала if (!gCfg->errmsg.empty()) putevent(new TuiEvent(evPOPUPMSG, "Config error:", gCfg->errmsg.c_str())); else { if (gCfg->isdefault) //если конфига нет то открыть форму putevent(new NEvent(NEvent::evKB, 'C')); //создаем событие иммитирующее нажатие 'C' } do { //блокировка сигнала изменения окна SIGWINCH на время отрисовки (из-за нереентерабельности курсес) sigprocmask(SIG_BLOCK, &newset, 0); //если нужен ресайз - перерисовать полностью if (MainProg::needresize) { smartresize(); refresh(); menu->refresh(); //wmain->erase(); wstatus->erase(); wmain->refresh(); wstatus->refresh(); } #ifndef EVENTTHREAD //если настало время посылаем evTIMER if (time(NULL) - evtimertime > EVTIMERINTERVAL) { NEvent* event = new NEvent(NEvent::evTIMER, 0); //создаем событие таймера putevent(event); //отправить в очередь time(&evtimertime); } //есть символ в буфере -> нужно создать событие int ic; if ( (ic = getch()) != ERR ) //символ(ы) есть? { NEvent* event = NULL; if (KEY_MOUSE == ic) { // mouse event MEVENT mevent; if (OK == getmouse(&mevent)) event = new NMouseEvent(mevent.bstate, mevent.y, mevent.x); //создаем мышиное событие else kLogPrintf("getmouse() err\n"); } else // keyboard event event = new NEvent(NEvent::evKB, ic); //создаем клавиатурное событие if (event != NULL) putevent(event); //отправить в очередь } #endif //есть события в очереди - выполняем while(!evqueueempty()) { NEvent* event = popevent(); //получить первое событие из очереди this->eventhandle(event); //отправить событие обработчику #ifdef DEBUG if ((event->type != NEvent::evTIMER)&&(!event->done)) kLogPrintf("WARNING! lost event %s\n", event->tostring().c_str()); #endif delete event; //удаляем отработанное событие //обновляем экран update_panels(); doupdate(); //физически выполняет перерисовку } //разблокируем SIGWINCH sigprocmask(SIG_UNBLOCK, &newset, 0); #ifdef EVENTTHREAD usleep(10000); //10 milisec #endif } while(!done); return true; } boinctui-2.7.1/src/nview.cpp0000664000175000017500000001057514536642777013653 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include "nview.h" #include "ngroup.h" #include "kclog.h" #include int asciilinedraw = 0; //1-рисовать рамки символами +----+ int transparentbg = 0; //1-прозрачный бэкграунд int getbgcolor() //вернет цвет бакграунда (в зависимости от настройки transparentbg) { if(transparentbg==1) return -1; else return COLOR_BLACK; } int getcolorpair(int fcolor, int bcolor) //получить пару для комбинации цветов { //for 8-color terminals //COLORS 0..7 //COLOR_PAIRS 64 [(0),1..63] 0-predefined //for xterm-256-color //COLORS=256 [0..255] //COLOR_PAIRS 256 [(0),1..255] 0-predefined static std::map, int> colorpairs; //kLogPrintf("getcolorpair(%d,%d) size=%d", fcolor, bcolor, colorpairs.size()); std::pair colorpair = std::make_pair(fcolor, bcolor); int npair = 0; std::map, int>::const_iterator it = colorpairs.find(colorpair); if (it != colorpairs.end()) { //kLogPrintf(" pair already in map"); npair = (*it).second; } else { //kLogPrintf(" insert NEW pair"); npair = colorpairs.size() + 1; if (npair < COLOR_PAIRS ) { init_pair(npair, fcolor, bcolor); colorpairs.insert(std::make_pair(colorpair, npair)); } else npair = 0; } //kLogPrintf(" ->%d\n", npair); return COLOR_PAIR(npair); } NView::NView(NRect rect) { this->rect = rect; win = newwin(rect.rows, rect.cols, rect.begrow, rect.begcol); //создаем окно curses pan = new_panel(win); scrollok(win,false); needrefresh = true; owner = NULL; modalflag = false; #ifdef DEBUG refreshcount = 0; //счетчик обновлений #endif wbkgdset(win,getcolorpair(COLOR_WHITE,getbgcolor())); //бакграунд werase(win); //заполняем цветом фона } void NView::setowner(NGroup* owner) { this->owner = owner; //позиционировать относительно овнера move(getbegrow(),getbegcol()); } void NView::resize(int rows, int cols) { wresize(win, rows, cols); rect.rows = rows; rect.cols = cols; needrefresh = true; } void NView::refresh() //перерисовать { if (needrefresh) { #ifdef DEBUG refreshcount++; mvwprintw(win,0,getmaxx(win)-10,"r=%d",refreshcount); #endif update_panels(); //doupdate(); needrefresh = false; } } int NView::getabsbegrow() //получить начальную строку (на экране) { if (owner == NULL) return getbegrow(); else return getbegrow() + owner->getabsbegrow(); } int NView::getabsbegcol() //получить начальный столбец (на экране) { if (owner == NULL) return getbegcol(); else return getbegcol() + owner->getabsbegcol(); } bool NView::isinside(int row, int col) //true если координаты внутри окна (row col абсолютные!) { bool result = true; int absbegrow = getabsbegrow(); int absbegcol = getabsbegcol(); if ((row < absbegrow)||(col < absbegcol)) result = false; if ((row > absbegrow + rect.rows - 1)||(col > absbegcol+ rect.cols - 1)) result = false; return result; } void NView::move(int begrow, int begcol) { rect.begrow = begrow; rect.begcol = begcol; move_panel(pan, getabsbegrow(), getabsbegcol()); } void NView::putevent(NEvent* ev) //отправить событие по цепочке владельцев в очередь { if (owner != NULL) owner->putevent(ev); } boinctui-2.7.1/src/ngroup.h0000664000175000017500000000340014536642777013467 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef NGROUP_H #define NGROUP_H #include #include "nview.h" class NGroup : public NView { public: NGroup(NRect rect) : NView(rect) {}; virtual ~NGroup(); void insert(NView* view) { view->setowner(this); items.push_back(view); }; void remove(NView* view) { items.remove(view); }; NView* getitembyid(const char* id); //получить эл-т зная id его класса bool destroybyid(const char* id); //удалить (с деструкцией) эл-т зная id его класса virtual void refresh(); virtual void eventhandle(NEvent* ev); //обработчик событий virtual void setneedrefresh(); virtual void move(int begrow, int begcol); void centermodalitems(int maxy, int maxx); //центрировать все модальные эл-ты (maxy,maxx -размер экрана) protected: std::list items; //список вложенных элементов }; #endif // NGROUP_H boinctui-2.7.1/src/nprogram.h0000664000175000017500000000453314536642777014012 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef NPROGRAM_H #define NPROGRAM_H #ifdef EVENTTHREAD #include #endif #include #include "ngroup.h" #define EVTIMERINTERVAL 2 //число секунд через которые генерируется evTIMER class NProgram : public NGroup { public: static bool needresize; //true если произошло изменение размеров терминала NProgram(); #ifdef EVENTTHREAD ~NProgram() { stopflag=true; pthread_join(thread, NULL); pthread_mutex_destroy(&mutex); }; void lock() { pthread_mutex_lock(&mutex); }; void unlock() { pthread_mutex_unlock(&mutex); }; bool evqueueempty() { bool result; lock(); result=evqueue.empty(); unlock(); return result; }; NEvent* popevent() { NEvent* result; lock(); result=evqueue.front(); evqueue.pop(); unlock(); return result; }; #else bool evqueueempty() { return evqueue.empty(); }; NEvent* popevent() { NEvent* result=evqueue.front(); evqueue.pop(); return result; }; #endif virtual void putevent(NEvent* ev); //отправить событие по цепочке владельцев в очередь static void sig_winch(int signo); //вызывается при изменении размеров терминала private: std::queue evqueue; //очередь событий #ifdef EVENTTHREAD pthread_mutex_t mutex; pthread_t thread; bool stopflag; static void* evcreationthread(void* args); //трейд опрашивающий клавиатуру и мышь #endif }; #endif //NPROGRAM_Hboinctui-2.7.1/src/infopanel.h0000664000175000017500000000753314536642777014143 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef INFOPANEL_H #define INFOPANEL_H #include "nview.h" #include "resultdom.h" #include "srvdata.h" struct ProjectStat //статистика по проекту { std::string name; //имя проекта std::string sstatus; //строка состояния проекта double user; //очки по проекту (всего для юзера) double host; //очки по проекту (всего для хоста) time_t laststattime; //дата последней статистики double userlastday; //очки юзера за последний день по каждому проекту double hostlastday; //очки хоста за последний день по каждому проекту static bool CmpAbove( ProjectStat stat1, ProjectStat stat2 ) //для сортировки проектов true если дата stat1 > stat2 { //суммарная для юзера и хоста double score1 = stat1.userlastday + stat1.hostlastday; double score2 = stat2.userlastday + stat2.hostlastday; if (stat1.laststattime == stat2.laststattime) return (score1 > score2); //даты равны -> больше тот у кого больше очков else return (stat1.laststattime > stat2.laststattime); //больше тот у кого дата больше /* //оба с нулевыми (или оба с ненеулевыми) очками -> ставниваем по датам if ( ((score1 == 0)&&(score2 == 0)) || ((score1 > 0)&&(score2 > 0)) ) { if (stat1.laststattime == stat2.laststattime) { //даты равны -> больше тот у кого больше очков return (score1 > score2); } else //больше stat1 если у него дата больше return (stat1.laststattime > stat2.laststattime); } // если stat1 с ненулевыми очками (stat2 соотв с нулевыми) -> stat1 больше return (score1 > 0 ); */ }; }; class InfoPanel : public NView { public: InfoPanel(NRect rect) : NView(rect) {}; void updatedata(); virtual void refresh(); void setserver(Srv* srv) { this->srv = srv; }; virtual void eventhandle(NEvent* ev); //обработчик событий protected: Srv* srv; std::string getdayname(time_t ltime); //название дня "today" "yesterday" "" //---для процессов--- int nalltasks; int nactivetasks; int nruntasks; int nqueuetasks; int ndonetasks; int nothertasks; //---для дисков--- double dtotal; double dfree; double dboinc; double dallowed; //---статистика cуммарная--- double usertotal; double useravg; double hosttotal; double hostavg; //---статистика за сегодня--- time_t laststattime; //дата последней статистики double lastdayuser; double lastdayhost; std::vector projects; //статистика по отдельным проектам }; #endif //INFOPANEL_H boinctui-2.7.1/src/taskwin.h0000664000175000017500000000475514536642777013653 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef TASKWIN_H #define TASKWIN_H #include "nselectlist.h" #include "resultdom.h" #include "srvdata.h" struct TaskInfo { TaskInfo(const char* taskname, const char* projecturl) {this->taskname = taskname; this->projecturl = projecturl; }; std::string taskname; std::string projecturl; }; class TaskWin : public NSelectList { public: TaskWin(NRect rect/*, Config* cfg*/); virtual ~TaskWin(); void updatedata(); //обновить данные с серверa virtual void clearcontent(); virtual void eventhandle(NEvent* ev); //обработчик событий void setserver(Srv* srv) { this->srv = srv; startindex = 0; clearcontent(); selectedindex = -1; }; bool iscolvisible(int n) { return ((1 << n)&columnmask); }; //true если n-ная колонка видимая void coldisable(int n) { columnmask = columnmask & (~(1 << n)); saveopttoconfig();}; //установить флаг невидимости n-ной колонки void colenable(int n) { columnmask = columnmask | (1 << n); saveopttoconfig();}; //установить флаг видимости n-ной колонки void saveopttoconfig(); //сохранить маску и т.д. в дереве конфига //unsigned int getcolumnmask() { return columnmask; }; protected: Srv* srv; //текущий отображаемый сервер unsigned int columnmask; //маска видмсости колонок int taskslistmode; //0 все задачи 1 кроме завершенных 2 только активные int taskssortmode; //0 нет сортировки 1 state 2 done 3 project 4 est 5 d/l 6 app 7 task // Config* cfg; }; #endif //TASKWIN_H boinctui-2.7.1/src/addmgrform.cpp0000664000175000017500000002313514536642777014641 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include "addmgrform.h" #include "mbstring.h" #include "kclog.h" #include "tuievent.h" char* strlowcase(char* s); //в нижний регистр AddAccMgrForm::AddAccMgrForm(int rows, int cols, Srv* srv, const char* mgrname) : NForm(rows,cols) { this->srv = srv; settitle(mgrname); this->mgrname = mgrname; Item* account_manager = NULL; if (srv !=NULL) account_manager = srv->findaccountmanager(mgrname); //поля int row = 0; genfields(row,account_manager); //пересчитываем высоту формы, чтобы влезли все поля и центрируем int r,c =0; scale_form(frm, &r, &c); kLogPrintf("field_count=%d scale_form()->%d,%d\n", field_count(frm), r, c); resize(r+3,c+2); set_current_field(frm, fields[0]); //фокус на поле post_form(frm); this->refresh(); } void AddAccMgrForm::genfields(int& line, Item* mgr) //создаст массив полей { FIELD* f; delfields(); //сообщение об ошибке errmsgfield = getfieldcount(); f = addfield(new_field(1, getwidth()-2, line++, 0, 0, 0)); set_field_buffer(f, 0, "Error"); set_field_back(f, getcolorpair(COLOR_WHITE,COLOR_RED) | A_BOLD); field_opts_off(f, O_ACTIVE); //статический текст field_opts_off(f, O_VISIBLE); //по умолчанию невидима //получить url и имя менеджера (или из конфига или от boinc клиента if (mgr != NULL) { Item* url = mgr->findItem("url"); if (url !=NULL) mgrurl = url->getsvalue(); } else { //взять url из конфига (если есть) Item* boinctui_cfg = gCfg->getcfgptr(); if (boinctui_cfg != NULL) { std::vector mgrlist = boinctui_cfg->getItems("accmgr"); std::vector::iterator it; for (it = mgrlist.begin(); it != mgrlist.end(); it++) { Item* name = (*it)->findItem("name"); if (name != NULL) if (name->getsvalue() == mgrname) { Item* url = (*it)->findItem("url"); if (url != NULL) { mgrurl = url->getsvalue(); break; } } } } } //имя менеджера f = addfield(new_field(1, getwidth()-4, line, 2, 0, 0)); set_field_buffer(f, 0, "Description "); set_field_back(f, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD); field_opts_off(f, O_ACTIVE); //статический текст namefield = getfieldcount(); f = addfield(new_field(1, 40, line++, 15, 0, 0)); if (mgr != NULL) { field_opts_off(f, O_STATIC); field_opts_off(f, O_ACTIVE); //статический текст } else set_field_back(f, getcolorpair(COLOR_WHITE,COLOR_CYAN) | A_BOLD); field_opts_off(f, O_AUTOSKIP); set_max_field(f,128); //max width 128 char buf[129]; strncpy(buf, gettitle(), 128); buf[128] = '\0'; char* p; p = ltrim(buf); rtrim(buf); set_field_buffer(f, 0, p); //url line++; f = addfield(new_field(1, getwidth()-4, line, 2, 0, 0)); set_field_buffer(f, 0, "URL "); set_field_back(f, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD); field_opts_off(f, O_ACTIVE); //статический текст urlfield = getfieldcount(); f = addfield(new_field(1, 40, line++, 15, 0, 0)); if (mgr != NULL) { field_opts_off(f, O_STATIC); field_opts_off(f, O_ACTIVE); //статический текст } else set_field_back(f, getcolorpair(COLOR_WHITE,COLOR_CYAN) | A_BOLD); field_opts_off(f, O_AUTOSKIP); set_max_field(f,128); //max width 128 set_field_buffer(f, 0, mgrurl.c_str()); //help line++; f = addfield(new_field(3, getwidth()-4, line++, 2, 0, 0)); set_field_buffer(f, 0, "If you have not yet registered with this account manager" \ " please do so before proceeding."); set_field_back(f, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD); field_opts_off(f, O_ACTIVE); //статический текст line = line + 2; //user name line++; f = addfield(new_field(1, 10, line, 2 , 0, 0)); set_field_buffer(f, 0, "username"); set_field_back(f, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD); field_opts_off(f, O_ACTIVE); //статический текст usernamefield = getfieldcount(); f = addfield(new_field(1, 40, line++, 15, 0, 0)); field_opts_off(f, O_AUTOSKIP); set_field_back(f, getcolorpair(COLOR_WHITE,COLOR_CYAN) | A_BOLD); //password line++; f = addfield(new_field(1, 10, line, 2 , 0, 0)); set_field_buffer(f, 0, "password"); set_field_back(f, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD); field_opts_off(f, O_ACTIVE); //статический текст passwfield = getfieldcount(); f = addfield(new_field(1, 40, line++, 15, 0, 0)); set_field_back(f, getcolorpair(COLOR_WHITE,COLOR_CYAN) | A_BOLD); field_opts_off(f, O_AUTOSKIP); //подсказки line++; f = addfield(new_field(1, getwidth()-25, line++, 20 , 0, 0)); set_field_buffer(f, 0, "Enter-Ok Esc-Cancel"); set_field_back(f, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD); field_opts_off(f, O_ACTIVE); //статический текст //финализация списка полей addfield(NULL); } void AddAccMgrForm::eventhandle(NEvent* ev) //обработчик событий { if ( ev->done ) return; //NMouseEvent* mevent = (NMouseEvent*)ev; if ( ev->type == NEvent::evMOUSE) { NForm::eventhandle(ev); //предок } if ( ev->type == NEvent::evKB ) { ev->done = true; switch(ev->keycode) { case KEY_ENTER: case '\n': //ENTER { form_driver(frm, REQ_NEXT_FIELD); //костыль чтобы текущее поле не потеряло значение char* username = rtrim(field_buffer(fields[usernamefield],0)); char* passw = rtrim(field_buffer(fields[passwfield],0)); mgrurl = rtrim(field_buffer(fields[urlfield],0)); char* mgrname = rtrim(field_buffer(fields[namefield],0)); kLogPrintf("AddAccMgrForm OK username=[%s] passw=[%s]\n", username, passw); if (srv!=NULL) { std::string errmsg; bool success = srv->accountmanager(mgrurl.c_str(), username, passw, false, errmsg); if (success) { Item* account_manager = NULL; if (srv !=NULL) account_manager = srv->findaccountmanager(mgrname); if (account_manager == NULL) //для кастомных менеджеров сохраняем в конфигах { //проверить есть-ли уже в конфиге такой аккаунт менеджер //то обновляем существующую запись, иначе добавляем новую bool exist = false; Item* boinctui_cfg = gCfg->getcfgptr(); if (boinctui_cfg != NULL) { std::vector mgrlist = boinctui_cfg->getItems("accmgr"); std::vector::iterator it; for (it = mgrlist.begin(); it != mgrlist.end(); it++) { Item* namecfg = (*it)->findItem("name"); Item* urlcfg = (*it)->findItem("url"); if (namecfg != NULL) if (strcmp(namecfg->getsvalue(),mgrname) == 0) { exist = true; //обновить значение url в конфиге Item* urlcfg = (*it)->findItem("url"); if (urlcfg != NULL) urlcfg->setsvalue(mgrurl.c_str()); } if (urlcfg != NULL) { if (strcmp(urlcfg->getsvalue(),mgrurl.c_str()) == 0) { exist = true; //обновить значение имени в конфиге Item* namecfg = (*it)->findItem("name"); if (namecfg != NULL) namecfg->setsvalue(mgrname); } } if (exist) break; } if (!exist) { //записать в конфиг как новый Item* accmgr = new Item("accmgr"); boinctui_cfg->addsubitem(accmgr); Item* name = new Item("name"); name->setsvalue(mgrname); Item* url = new Item("url"); url->setsvalue(mgrurl.c_str()); accmgr->addsubitem(name); accmgr->addsubitem(url); } } } putevent(new TuiEvent(evADDACCMGR)); //создаем событие чтобы закрыть форму } else { //СООБЩЕНИЕ ОБ ОШИБКЕ errmsg = " Error: " + errmsg; set_field_buffer(fields[errmsgfield], 0, errmsg.c_str()); field_opts_on(fields[errmsgfield], O_VISIBLE); //делаем видимой строку ошибки this->refresh(); } } break; } case 27: putevent(new TuiEvent(evADDACCMGR, srv, mgrname.c_str())); //код закрытия окна break; default: kLogPrintf("AddAccMgrForm::KEYCODE=%d\n", ev->keycode); ev->done = false; NForm::eventhandle(ev); //предок break; } //switch } } boinctui-2.7.1/src/resultparse.h0000664000175000017500000000240114536642777014526 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef RESULTPARSE_H #define RESULTPARSE_H #include "resultdom.h" Item* xmlparse(const char* xml, int len, std::string& errmsg); //xml строка с xml len ее размер в байтах char* stripinvalidtag(char* xml, int len); //ГРЯЗНЫЙ ХАК нужен чтобы до парсинга удалить кривые теги //в сообщениях вида иначе будет ошибка парсинга #endif // RESULTPARSE_H boinctui-2.7.1/src/cfg.h0000664000175000017500000000431414536642777012721 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef CFG_H #define CFG_H #include "resultdom.h" #include "nview.h" class Config { public: Config(const char* filename); ~Config(); void load(); void save(); void generatedefault(); Item* getcfgptr() { if ( root!= NULL) return root->findItem("boinctui_cfg"); else return NULL; }; int getivalue(Item* node, const char* name); //ищет name начиная с node int getivalue(const char* name) { return getivalue(getcfgptr(), name); }; //ищет name начиная с корня void setivalue(Item* node, const char* name, int value); //создаст в node подэл-т name со значением value void setivalue(const char* name, int value) { setivalue(getcfgptr(), name, value); }; //создаст в корне подэл-т name со значением value void addhost(const char* host, const char* port, const char* pwd, const char* hostid); bool isdefault; //true если конфиг не найден и создан дефолтный std::string errmsg; //строка ошибки возникшей при загрузке файла конфига std::string cmdlinehost=""; std::string cmdlineport="31416"; std::string cmdlinepwd=""; bool cmdlocalhost=false; protected: char* fullname; //полное имя файла Item* root; //корень дерева конфига }; extern Config* gCfg; #endif //CFG_H boinctui-2.7.1/src/ncolorstring.cpp0000664000175000017500000000555414536642777015247 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include "ncolorstring.h" NColorStringPart::NColorStringPart(int attr, const char* fmt, va_list vl) { char buf[1024]; vsnprintf(buf, sizeof(buf), fmt, vl); this->s = buf; this->attr = attr; } NColorString::NColorString(int attr, const char* fmt, ...) { va_list args; va_start(args, fmt); vappend(attr,fmt,args); va_end(args); } NColorString::NColorString(int attr, const char* fmt, va_list vl) { vappend(attr,fmt,vl); } NColorString::~NColorString() { std::list::iterator it; for (it = parts.begin(); it != parts.end(); it++) { delete (*it); } } void NColorString::append(int attr, const char* fmt, ...) { va_list args; va_start(args, fmt); NColorStringPart* part = new NColorStringPart(attr, fmt, args); va_end(args); append(part); } void NColorString::vappend(int attr, const char* fmt, va_list vl) { NColorStringPart* part = new NColorStringPart(attr, fmt, vl); append(part); } int NColorString::getlen() //вернет длинну в ЭКРАННЫХ СИМВОЛАХ { int result = 0; std::list::iterator it; for (it = parts.begin(); it != parts.end(); it++) { result = result + (*it)->getlen(); } return result; } NColorString& NColorString::operator=(const NColorString& v) { clear(); std::list::const_iterator it; for ( it = v.parts.begin(); it != v.parts.end(); it++ ) { append((*it)->attr, (*it)->s.c_str()); } return *this; } bool NColorString::operator==(const NColorString& v) { bool result = true; if (v.parts.size() != parts.size()) return false; //различается кол-во эл-тов //сравниваем поэлементно std::list::const_iterator it1; std::list::const_iterator it2; it2 = v.parts.begin(); for ( it1 = parts.begin(); it1 != parts.end(); it1++ ) { if (*(*it1) == *(*it2)) it2++; else return false; //часть отличается } return result; } boinctui-2.7.1/src/tui-main.cpp0000664000175000017500000001242314536642777014240 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include #include #if HAVE_LIBNCURSESW == 1 && NCURSESW_HAVE_SUBDIR == 1 #include #else #include #endif #include #include #include "kclog.h" #include "mainprog.h" std::string locale; void initcurses() { locale = setlocale(LC_ALL, NULL); setlocale(LC_ALL, ""); setlocale(LC_MESSAGES, ""); initscr(); noecho(); curs_set(0); keypad(stdscr,true); //разрешаем стрелки и т.п. #ifdef ENABLEMOUSE mousemask(ALL_MOUSE_EVENTS, NULL); // Report all mouse events #endif timeout(100); //ожидание для getch() 100 милисекунд use_default_colors(); start_color(); } void donecurses() { clear(); refresh(); endwin(); setlocale(LC_ALL, locale.c_str()); } void printhelp() { printf ( "\n\nusage: \n" " boinctui [--help] [--boinchost=:] [--pwd=]\n\n" " -b, --boinchost ip address and port of boinc server host\n" " -p, --pwd boinc password\n" " -h, --help print this help and exit\n" "\nexamples: \n" " boinctui --boinchost=192.168.1.123 --pwd=my_password -default port 31416 is used\n" " boinctui --boinchost=192.168.1.123:31416 -connect with empty password\n" " boinctui --boinchost=localhost -connect to localhost with defaul port and\n" " password from /var/lib/boinc-client/gui_rpc_auth.cfg\n" "\n" ); } std::string hostname2ip(std::string& hostname) { std::string result=""; struct hostent *he; struct in_addr **addr_list; if ((he=gethostbyname(hostname.c_str()))==NULL) { printf("cat't resolve gethostbyname"); return result; } addr_list = (struct in_addr **) he->h_addr_list; for(int i=0; addr_list[i]!=NULL; i++) { char ip[100]; strcpy(ip,inet_ntoa(*addr_list[i])); if(i>0) result+=","; result+=ip; } return result; } bool parseargs(int argc, char ** argv) { bool result=true; int c; while (1) { static struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"boinchost", required_argument, 0, 'b'}, {"pwd", required_argument, 0, 'p'}, {0, 0, 0, 0} }; int option_index = 0; c = getopt_long (argc, argv, "hb:p:",long_options, &option_index); if (c == -1) break; switch (c) { case 0: if (long_options[option_index].flag != 0) break; printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case 'h': printhelp(); result=false; break; case 'b': { gCfg->cmdlinehost=optarg; int pos=gCfg->cmdlinehost.find_last_of(":"); if(pos!=std::string::npos) { gCfg->cmdlineport=gCfg->cmdlinehost.substr(pos+1); gCfg->cmdlinehost.resize(pos); } char ip[100]; std::string hostip=hostname2ip(gCfg->cmdlinehost); gCfg->cmdlocalhost=(hostip.find("127.0.0.1")!=std::string::npos); printf ("boinc server '%s' %s %s\n" , gCfg->cmdlinehost.c_str() ,(gCfg->cmdlinehost!=hostip)?hostip.c_str():"" ,(gCfg->cmdlocalhost)?"(local host)":"" ); printf ("boinc server TCP port '%s'\n", gCfg->cmdlineport.c_str()); break; } case 'p': gCfg->cmdlinepwd=optarg; break; case '?': result=false; break; default: break; } } return result; } int main(int argc, char ** argv) { MainProg* mainprog; kLogOpen("boinctui.log"); #ifdef DEBUG struct mallinfo minf1 = mallinfo(); #endif gCfg = new Config(".boinctui.cfg"); if(parseargs(argc,argv)) { initcurses(); mainprog = new MainProg(); mainprog->refresh(); mainprog->mainloop(); //запускаем осн. цикл событий delete mainprog; donecurses(); } #ifdef DEBUG struct mallinfo minf2 = mallinfo(); kLogPrintf("mallinfo.uordblks= %d-%d = %d (bytes leak)\n",minf1.uordblks,minf2.uordblks, minf2.uordblks-minf1.uordblks); //malloc_stats(); #endif kLogClose(); exit(EXIT_SUCCESS); } boinctui-2.7.1/src/nview.h0000664000175000017500000000677414536642777013326 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef NVIEW_H #define NVIEW_H #include #if HAVE_LIBNCURSESW == 1 && NCURSESW_HAVE_SUBDIR == 1 #include #else #include #endif #include "nrect.h" #include "nevent.h" class NGroup; void initcolorpairs(); int getcolorpair(int fcolor, int bcolor); //получить пару для комбинации цветов int getbgcolor(); //вернет цвет бакграунда (в зависимости от настройки transparentbg) extern int asciilinedraw; //1-рисовать рамки символами +----+ extern int transparentbg; //1-прозрачный бэкграунд class NView //базовый визуальный класс { public: NView(NRect rect); virtual ~NView() { del_panel(pan); delwin(win); }; //virtual void draw() {}; virtual void resize(int rows, int cols); virtual void move(int begrow, int begcol); PANEL* getpan() { return pan; }; //!!!!!!!!!!!!!!!!!!!! int getwidth() { return rect.cols; }; //ширина в символах int getheight() { return rect.rows; }; //высота в строках int getbegrow() { return rect.begrow; }; //начальная строка int getbegcol() { return rect.begcol; }; //начальный столбец void erase() { werase(win); }; //очистить bool isinside(int row, int col); //true если координаты внутри окна (row col абсолютные!) virtual void refresh(); //перерисовать virtual void setneedrefresh() { needrefresh = true; }; virtual void eventhandle(NEvent* ev) {/*EMPTY*/}; //обработчик событий virtual void putevent(NEvent* ev); //отправить событие по цепочке владельцев в очередь void setowner(NGroup* owner); virtual const char* getid() { return typeid(*this).name(); }; //возвращает имя класса virtual bool ismodal() { return modalflag; }; protected: NGroup* owner; //владелец эл-та WINDOW* win; //окно curses PANEL* pan; //панель curses на основе окна win bool needrefresh; //устанавливается в true когда нужна перерисовка #ifdef DEBUG int refreshcount; //счетчик обновлений #endif bool modalflag; //true если этот эл-т модальный int getabsbegrow(); //получить начальную строку (абсолютную на экране) int getabsbegcol(); //получить начальный столбец (абсолютный на экране) private: NRect rect; //координаты и размер }; #endif //NVIEW_Hboinctui-2.7.1/src/about.h0000664000175000017500000000216214536642777013273 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef ABOUT_H #define ABOUT_H #include "ngroup.h" class AboutWin : public NGroup { public: AboutWin(int rows, int cols); ~AboutWin() { delete caption; }; virtual void eventhandle(NEvent* ev); //обработчик событий protected: char* caption; //строка заголовка }; #endif //ABOUT_Hboinctui-2.7.1/src/helpwin.h0000664000175000017500000000224714536642777013633 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef HELPWIN_H #define HELPWIN_H #include "ngroup.h" #include "nstatictext.h" class HelpWin : public NGroup { public: HelpWin(int rows, int cols); ~HelpWin() { delete caption; }; virtual void eventhandle(NEvent* ev); //обработчик событий protected: char* caption; //строка заголовка NStaticText* text1; }; #endif //HELPWIN_Hboinctui-2.7.1/src/nscrollview.cpp0000664000175000017500000001602714536642777015070 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include "nscrollview.h" NScrollView::~NScrollView() { clearcontent(); } void NScrollView::addstring(int attr, const char* fmt, ...) { va_list args; va_start(args, fmt); NColorString* cs = new NColorString(attr, fmt, args); va_end(args); addstring(cs); } void NScrollView::clearcontent() { std::vector::iterator it; for (it = content.begin(); it != content.end(); it++) { delete (*it); } content.clear(); startindex=0; needrefresh = true; } void NScrollView::drawcontent() //отрисовывает буфер строк { //выводим строки начиная со startindex for (int line = 0; line < getheight(); line++) //цикл по экранным строкам { if (startindex+line < (int)content.size()) { NColorString* cstring = content[startindex + line]; std::list::iterator it; wmove(win,line,0); for (it = cstring->parts.begin(); it != cstring->parts.end(); it++) //цикл по частям тек строки { NColorStringPart* part = *it; wattrset(win,part->attr); //включаем атрибут wprintw(win,"%s",part->s.c_str()); // wattrset(win,0); //отключаем атрибут } wclrtoeol(win); //очищаем до конца строки } else //очищаем нижнюю незанятую часть окна (если есть) { wmove(win,line,0); wclrtoeol(win); //очищаем до конца строки } } if (scrollbar) //если есть связанный скроллбар то обновляем его { scrollbar->setpos(0,content.size(),startindex, startindex+getheight()); } } void NScrollView::refresh() { if (needrefresh) { drawcontent(); NView::refresh(); } } void NScrollView::resize(int rows, int cols) { NView::resize(rows, cols); if (autoscroll) { setautoscroll(true); //костыль чтобы при ресайзе переустановилась позиция при автоскроле } } void NScrollView::scrollto(int delta)//сдвинуть отображение на drlta строк вверх или вниз { if ((int)content.size()>getheight()) { //kLogPrintf("NScrollView::scrollto(%d) startindex=%d content.size()=%d getheight()=%d\n",delta, startindex, content.size(), getheight()); int oldstartindex = startindex; startindex = startindex + delta; if ( startindex < 0 ) startindex = 0; if ( startindex > (int)content.size()-getheight() ) startindex = content.size()-getheight()/* + 1*/; //+1 чтобы оставлять пустую строку if (oldstartindex != startindex) //позиция изменилась нужно перерисовываться needrefresh = true; } }; void NScrollView::setautoscroll(bool b) //true чтобы включить автоскроллинг { int oldstartindex = startindex; autoscroll = b; if (b) { startindex = content.size()-getheight(); if ( startindex < 0 ) startindex = 0; } if (oldstartindex != startindex) //позиция изменилась нужно перерисовываться needrefresh = true; }; void NScrollView::setstartindex(int n) //установить отображение со строки n { if (((int)content.size()-n) < getheight()) //последняя строка видимая на экране { startindex = content.size()-getheight(); //поднять вверх if (startindex < 0) //но не выше нулевой startindex = 0; } else startindex = n; } int NScrollView::getmaxcontentwidth() //вернет максимальную длину строки (в экранных символях) в content { int result = 0; std::vector::iterator it; for(it = content.begin(); it != content.end(); it++) { if (result < (*it)->getlen()) { result = (*it)->getlen(); } } return result; } void NScrollView::eventhandle(NEvent* ev) //обработчик событий { NView::eventhandle(ev); //предок if ( ev->done ) return; //реакция на мышь NMouseEvent* mevent = (NMouseEvent*)ev; if ( ev->type == NEvent::evMOUSE ) { //скроллинг по колесу if (isinside(mevent->row, mevent->col)) { //колесо вверх #if NCURSES_MOUSE_VERSION > 1 if (mevent->cmdcode & BUTTON4_PRESSED) //NOT TESTED #else if (mevent->cmdcode & BUTTON4_PRESSED) #endif { scrollto(-getheight()/2); //вверх на полокна setautoscroll(false); ev->done = true; } //колесо вниз #if NCURSES_MOUSE_VERSION > 1 if (mevent->cmdcode & BUTTON5_PRESSED) //NOT TESTED #else if ( mevent->cmdcode & (BUTTON2_PRESSED | REPORT_MOUSE_POSITION)) //REPORT_MOUSE_POSITION подпорка иначе теряет эвенты при быстрой прокрутке вниз #endif { if (!getautoscroll()) { int oldpos = getstartindex(); scrollto(getheight()/2); //вниз на пол окна if ( oldpos == getstartindex()) //позиция не изменилась (уже достигли конца) setautoscroll(true); //включаем автоскроллинг ev->done = true; } } } } //клавиатура /* if ( ev->type == NEvent::evKB ) { ev->done = true; switch(ev->keycode) { case KEY_PPAGE: content->scrollto(-getheight()/2); //вверх на полокна content->setautoscroll(false); break; case KEY_NPAGE: if (!content->getautoscroll()) { int oldpos = content->getstartindex(); content->scrollto(getheight()/2); //вниз на пол окна if ( oldpos == content->getstartindex()) //позиция не изменилась (уже достигли конца) content->setautoscroll(true); //включаем автоскроллинг } break; default: //блокировать все клавиатурные кроме кода закрытия формы if (ev->keycode == 27) ev->done = false; } //switch } */ if (ev->done) //если обработали, то нужно перерисоваться refresh(); } boinctui-2.7.1/src/nevent.h0000664000175000017500000000471514536642777013466 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef NEVENT_H #define NEVENT_H #ifdef DEBUG #include #include #endif //#include "kclog.h" class NEvent //класс описывающий событие создаваемое например при нажатии клавиш { public: enum Type { evKB, evMOUSE, evPROG, evTIMER }; //evPROG событие генерируемое самой прораммой NEvent(NEvent::Type type, int keycode) { this->type = type; this->done = false; this->keycode = keycode;}; virtual ~NEvent() { /*kLogPrintf("~NEvent()\n");*/ }; NEvent::Type type; bool done; //true если обработано union { int keycode; //код клавиатуры int cmdcode; //произвольный код команды }; #ifdef DEBUG virtual std::string tostring() { std::stringstream s; s << this << " " << type << "("; switch (type) { case evKB: s << "evKB keycode=" << keycode; break; case evMOUSE: s << "evMOUSE"; break; case evPROG: s << "evPROG"; break; case evTIMER: s << "evTIMER"; break; }; s << ")"; return s.str(); }; #endif }; class NMouseEvent : public NEvent { public: NMouseEvent(int bstate, int row, int col) : NEvent(evMOUSE, bstate) //bstate (see mmask_t ncurses.h) { this->col = col; this->row = row; }; virtual ~NMouseEvent() { /*kLogPrintf("~NMouseEvent()\n");*/ }; int row; int col; #ifdef DEBUG virtual std::string tostring() { std::stringstream s; s << NEvent::tostring() << "{row=" << row << ",col=" << col << ",bstate=" << std::hex << cmdcode; s << "}"; return s.str(); }; #endif }; #endif //NEVENT_Hboinctui-2.7.1/src/nrect.h0000664000175000017500000000241214536642777013272 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef NRECT_H #define NRECT_H class NRect //прямоугольная область //нумерация строк и столбцов идет от 0 { public: NRect() {}; NRect(int rows, int cols, int begrow, int begcol) {this->begrow = begrow; this->begcol = begcol; this->rows = rows; this->cols = cols;}; int begrow; int begcol; int rows; //высота (число строк) int cols; //ширина (число колонок) }; #endif //NRECT_Hboinctui-2.7.1/src/nmessagebox.h0000664000175000017500000000331614536642777014476 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef NMESSAGEBOX_H #define NMESSAGEBOX_H #include #include "ngroup.h" #include "nstatictext.h" #include "tuievent.h" class NMButton : public NStaticText //кнопка внутри NMessageBox { public: NMButton(const char* text, NEvent* pevent, ...); ~NMButton() { if (pevent) delete pevent; }; void eventhandle(NEvent* ev); //обработчик событий private: NEvent* pevent; //евент генерируемый кнопкой при нажатии std::list keys; //на какие коды она реагирует }; class NMessageBox : public NGroup //стандартный диалог вида Ok/Cancel или Yes/No { public: NMessageBox(const char* text); void eventhandle(NEvent* ev); //обработчик событий void addbutton(NMButton* button); //добавить кнопку private: NStaticText* content; }; #endif //NMESSAGEBOX_Hboinctui-2.7.1/src/nselectlist.cpp0000664000175000017500000001115014536642777015042 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include #include "nselectlist.h" #include "kclog.h" void NSelectList::addstring(void* userobj, int attr, const char* fmt, ...) { va_list args; va_start(args, fmt); NColorString* cs = new NColorString(attr, fmt, args); va_end(args); NScrollView::addstring(cs); objects.push_back(userobj); } void NSelectList::addstring(void* userobj, NColorString* cstring) { NScrollView::addstring(cstring); objects.push_back(userobj); } void NSelectList::drawcontent() //отрисовывает буфер строк { //выводим строки начиная со startindex for (int line = 0; line < getheight(); line++) //цикл по экранным строкам { if (startindex+line < (int)content.size()) //цикл по строкам { NColorString* cstring = content[startindex + line]; std::list::iterator it; wmove(win,line,0); for (it = cstring->parts.begin(); it != cstring->parts.end(); it++) //цикл по частям тек строки { NColorStringPart* part = *it; if ((!selectorenable)||(startindex + line != selectedindex)) //эта строка не выделена или селектор выключен wattrset(win,part->attr); //включаем атрибут else { //получаем из атрибута цвета для текста и фона short f,b; f = b = 0; unsigned int a = 0; a = a | (part->attr & A_BOLD); //нужен-ли аттрибут pair_content(PAIR_NUMBER(part->attr),&f,&b); //цвета тек куска для пары с номером PAIR_NUMBER(part->attr) //kLogPrintf("part->attr=%X PAIR_NUMBER(%X) -> #%d f=%x b=%x attr=%x\n",part->attr, part->attr,PAIR_NUMBER(part->attr),f,b,a); //kLogPrintf("A_BOLD=%X\n",A_BOLD); wattrset(win, getcolorpair(f, selectorbgcolor) | a); //включаем новый цвет и атрибут } wprintw(win,"%s",part->s.c_str()); } //цикл частей одной строки //wattrset(win,0); //отключаем атрибут //очищаем до конца строки if ((!selectorenable)||(startindex + line != selectedindex)) wclrtoeol(win); else { wbkgdset(win,getcolorpair(COLOR_WHITE,selectorbgcolor)); wclrtoeol(win); //очищаем до конца строки wbkgdset(win,getcolorpair(COLOR_WHITE, getbgcolor())); } } else //очищаем нижнюю незанятую часть окна (если есть) { wmove(win,line,0); wclrtoeol(win); //очищаем до конца строки } } if (scrollbar) //если есть связанный скроллбар то обновляем его { scrollbar->setpos(0,content.size(),startindex, startindex+getheight()); } } void NSelectList::refresh() { if (needrefresh) { drawcontent(); NView::refresh(); //Именно так!!! } } void* NSelectList::getselectedobj() { if ((selectedindex >= 0)&&(selectedindex < (int)objects.size())) { return objects[selectedindex]; } else return NULL; } void NSelectList::selectorup() { if (selectedindex >= 0) { selectedindex--; needrefresh = true; //проверяем не нужно ли скролить if (selectedindex - startindex < 4) //видимых строк выше серлектора осталось { scrollto(-1); } } } void NSelectList::selectordown() { if (selectedindex < (int)content.size()) { selectedindex++; needrefresh = true; //проверяем не нужно ли скролить if ((startindex + getheight() < (int)content.size())&&(startindex + getheight() - selectedindex < 4)) //видимых строк ниже серлектора осталось { scrollto(1); } } } boinctui-2.7.1/src/nwin.h0000664000175000017500000000152214536642777013133 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef NWIN_H #define NWIN_H #endif //NWIN_Hboinctui-2.7.1/src/statwin.cpp0000664000175000017500000002360714536642777014214 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012-2014 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include #include #include #include "kclog.h" #include "statwin.h" #define COLWIDTH 10 //ширина колонки для одного проекта StatWin::StatWin(Srv* srv) : NGroup(NRect(getmaxy(stdscr) - 10, getmaxx(stdscr) - 60, 3, 3)) { modalflag = true; this->srv = srv; this->hpos = 0; this->hostmode = true; content = new NScrollView(NRect(getheight()-4, getwidth()-4, 2, 2)); insert(content); updatedata(); //корректируем высоту в меньшую сторону если возможно if (content->getstringcount() < content->getheight()) { content->resize(content->getstringcount(), content->getwidth()); resize(content->getheight() + 4, getwidth()); } //растягиваем по ширине content->resize(content->getheight(), content->getmaxcontentwidth()); resize(getheight(), content->getwidth() + 4); if (getwidth() > getmaxx(stdscr) - 10) //если слишком широко обрезаем { resize(getheight(), getmaxx(stdscr) - 10); content->resize(content->getheight(), getwidth() - 4); } scrollbar = new NScrollBar(NRect(getheight()-2,1, content->getbegrow()-1, getwidth()-1), 0, 0, ACS_VLINE); content->setscrollbar(scrollbar); insert(scrollbar); updatecaption(); refresh(); } void StatWin::updatecaption() { this->caption = " Statistics "; //обновить заголовок окна if (hostmode) this->caption += "[host] "; else this->caption += "[user] "; if (srv == NULL) return; if(asciilinedraw == 1) wborder(win, '|', '|', '-', '-', '+', '+', '+', '+'); else box(win,0,0); mvwprintw(win,0,getwidth()/2-(caption.size()/2), "%s",this->caption.c_str()); } void StatWin::updatedata() { if (!srv) return; if (srv->statisticsdom.empty()) return; //===данные статистики=== int startindexsave = content->getstartindex(); content->clearcontent(); projects.clear(); std::map > allstat; Item* tmpstatedom = srv->statedom.hookptr(); Item* tmpstatisticsdom = srv->statisticsdom.hookptr(); Item* statistics = tmpstatisticsdom->findItem("statistics"); if (statistics!=NULL) { std::vector project_statistics = statistics->getItems("project_statistics"); std::vector::iterator it; std::map daysumhost; //сумарные очки по всем проектам для хоста std::map daysumuser; //сумарные очки по всем проектам для юзера for (it = project_statistics.begin(); it!=project_statistics.end(); it++) //цикл списка проектов { double laststatH = 0; double laststatU = 0; ProjStat project; project.name = srv->findProjectName(tmpstatedom, (*it)->findItem("master_url")->getsvalue()); // project.sumhost = 0; // project.sumuser = 0; std::vector days = (*it)->getItems("daily_statistics"); std::vector::iterator it2; for (it2 = days.begin(); it2 != days.end(); it2++) //циул по дням одного проекта { DayStat day; day.day = (*it2)->findItem("day")->getdvalue(); //время из статистики; double x1 = (*it2)->findItem("host_total_credit")->getdvalue(); day.scorehost = x1 - laststatH; double x2 = (*it2)->findItem("user_total_credit")->getdvalue(); day.scoreuser = x2 - laststatU; if (it2 != days.begin()) //самый старый день не учитываем (из-за отсутствия laststat) project.days.push_back(day); //добавить день в проект laststatH = x1; laststatU = x2; //накапливаем суммарные за этот день if ( 0 == daysumhost.count(day.day)) daysumhost[day.day] = day.scorehost; else daysumhost[day.day] += day.scorehost; if ( 0 == daysumuser.count(day.day)) daysumuser[day.day] = day.scoreuser; else daysumuser[day.day] += day.scoreuser; } projects.push_back(project); //добавляем в общую матрицу } //проекты //сортируем чтобы более актуальные попали в начало списка if (hostmode) std::sort(projects.begin(), projects.end(), ProjStat::CmpAboveH); else std::sort(projects.begin(), projects.end(), ProjStat::CmpAboveU); //формируем содержимое окна на основе структуры projects std::vector::iterator itprj; std::list daylist; //для заголовков дней NColorString* cs = new NColorString(getcolorpair(COLOR_CYAN, getbgcolor()) | A_BOLD, " %-*s %-*s", COLWIDTH-2, "", COLWIDTH-2, "Summary"); int n = hpos; for (itprj = projects.begin(); itprj != projects.end(); itprj++, n--) //проекты { if ( n > 0 ) continue; //пропустить если отображаем не с первого проекта (гориз скроллинг) std::string s = (*itprj).name.c_str(); if (s.size() > COLWIDTH) s.resize(COLWIDTH); cs->append(getcolorpair(COLOR_RED, getbgcolor()) | A_BOLD, " %*s ", COLWIDTH, s.c_str()); //имена проектов std::list::iterator itdays; for(itdays = (*itprj).days.begin(); itdays!=(*itprj).days.end(); itdays++) { if (find (daylist.begin(), daylist.end(), (*itdays).day) == daylist.end()) //еще нет в списке daylist.push_back((*itdays).day); //добавляем } } content->addstring(cs); daylist.sort(); std::list::reverse_iterator itday; for (itday = daylist.rbegin(); itday != daylist.rend(); itday++) //дни { tm* daytm = localtime(&(*itday)); char buf[128] = "?"; strftime(buf, sizeof(buf),"%-2e %b",daytm); //"%-e %b %-k:%M" NColorString* cs = new NColorString(getcolorpair(COLOR_WHITE, getbgcolor()) | A_BOLD, "%-*s", COLWIDTH, buf); cs->append(getcolorpair(COLOR_CYAN, getbgcolor()) | A_BOLD, " %*ld ", COLWIDTH, hostmode ? daysumhost[*itday] : daysumuser[*itday]); n = hpos; for (itprj = projects.begin(); itprj != projects.end(); itprj++, n--) //перебрать все проекты по этому дню { if ( n > 0 ) continue; //пропустить если отображаем не с первого проекта (гориз скроллинг) //находим нужный день среди всех дней проекта std::list::iterator itdays; long int value = -1; for(itdays = (*itprj).days.begin(); itdays!=(*itprj).days.end(); itdays++) { if ((*itdays).day == *itday) { //найден нужный день if (hostmode) value = (*itdays).scorehost; else value = (*itdays).scoreuser; break; } } if (value != -1) cs->append(getcolorpair(COLOR_WHITE, getbgcolor()) | A_BOLD, " %*ld ",COLWIDTH, value); else cs->append(getcolorpair(COLOR_WHITE, getbgcolor()) | A_BOLD, " %*s ",COLWIDTH, "-"); } content->addstring(cs); } } content->setstartindex(startindexsave); srv->statisticsdom.releaseptr(tmpstatisticsdom); srv->statedom.releaseptr(tmpstatedom); } void StatWin::eventhandle(NEvent* ev) //обработчик событий { NGroup::eventhandle(ev); //предок if ( ev->done ) return; //реакция на мышь NMouseEvent* mevent = (NMouseEvent*)ev; if ( ev->type == NEvent::evMOUSE ) { //блокируем все что внутри if (isinside(mevent->row, mevent->col)) ev->done = true; //закрываем при любом клике независимо от координат if (mevent->cmdcode & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED)) { putevent(new NEvent(NEvent::evKB, 27)); ev->done = true; } } //клавиатура if ( ev->type == NEvent::evKB ) { ev->done = true; switch(ev->keycode) { case 'U': case 'u': hostmode = !hostmode; updatedata(); updatecaption(); break; case KEY_PPAGE: content->scrollto(-getheight()/2); //вверх на полокна break; case KEY_NPAGE: if (!content->getautoscroll()) { //int oldpos = content->getstartindex(); content->scrollto(getheight()/2); //вниз на пол окна } break; case KEY_LEFT: if ( hpos > 0 ) hpos--; updatedata(); break; case KEY_RIGHT: { int w1 = (projects.size()-hpos) * COLWIDTH + 38; //сколько символов нужно для отображения всех видимых столбцов if (w1 > getwidth()) hpos++; updatedata(); break; } default: //блокировать все клавиатурные кроме кода закрытия формы if (ev->keycode == 27) ev->done = false; } //switch if (ev->done) //если обработали, то нужно перерисоваться refresh(); } if ( ev->type == NEvent::evTIMER ) { updatedata(); //запросить данные с сервера refresh(); //перерисовать окно } } boinctui-2.7.1/src/cfg.cpp0000664000175000017500000001605014536642777013254 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include #include #include #include "cfg.h" #include "resultparse.h" #include "kclog.h" #include "commondef.h" Config* gCfg; Config::Config(const char* filename) { root = NULL; //полный путь к конфигу if (filename == NULL) fullname = NULL; else { //хоум каталог const char* homepath = getenv("HOME"); //полный путь fullname = (char*)malloc(strlen(homepath)+strlen(filename)+2); sprintf(fullname,"%s/%s",homepath,filename); kLogPrintf("FULLCFGPATH=%s\n",fullname); fflush(stdout); } //загружаем если файл уже есть или генерируем дефолтный load(); asciilinedraw = getivalue("line_draw_mode"); transparentbg = getivalue("transparent_background"); } Config::~Config() { save(); if (root != NULL) delete root; if (fullname == NULL) free(fullname); } void Config::load() { isdefault = true; if (fullname == NULL) { generatedefault(); return; } struct stat st; int retcode = lstat(fullname, &st); if (retcode != 0) //файла нет? { //делаем дефолтный generatedefault(); return; } //читаем файл FILE* pfile; pfile = fopen(fullname,"r"); if (pfile!=NULL) { kLogPrintf("SIZE=%ld\n",st.st_size); char* buf = (char*)malloc(st.st_size + 1); size_t n = fread (buf,1,st.st_size,pfile); buf[n]=0; kLogPrintf("%s\n",buf); root = xmlparse(buf, st.st_size, errmsg); if (!errmsg.empty()) errmsg = fullname + std::string("\n") + errmsg; fclose (pfile); isdefault = false; } //upgrade config version Item* boinctui_cfg=getcfgptr(); if(boinctui_cfg!=NULL) { std::string vercfg=""; std::string verprog=XSTR(VERSION); Item* v=boinctui_cfg->findItem("version"); if(v!=NULL) { vercfg=v->getsvalue(); } else { Item* version=new Item("version"); version->setsvalue(XSTR(VERSION)); boinctui_cfg->addsubitem(version); } if(vercfg!=verprog) kLogPrintf("prog ver='%s' config ver='%s' need upgrade\n",verprog.c_str(),vercfg.c_str()); if((vercfg=="")&&(verprog=="2.6.0")) { //column_view_mask Item* column_view_mask = boinctui_cfg->findItem("column_view_mask"); if (column_view_mask == NULL) //создать { column_view_mask = new Item("column_view_mask"); column_view_mask->setivalue(-1); boinctui_cfg->addsubitem(column_view_mask); } unsigned int columnmask = column_view_mask->getivalue(); unsigned int x1 = 0x001F & columnmask; //# state done% project est unsigned int x2 = 0x0060 & columnmask; //dl application unsigned int x3 = 0x0080 & columnmask; //task columnmask = x1 | (0x1 << 5) | (x2 << 1) | (0x1 << 8) | (x3 << 2); column_view_mask->setivalue(columnmask); //tasks_sort_mode Item* tasks_sort_mode = boinctui_cfg->findItem("tasks_sort_mode"); if (tasks_sort_mode == NULL) //создать { tasks_sort_mode = new Item("tasks_sort_mode"); tasks_sort_mode->setivalue(-1); tasks_sort_mode->addsubitem(tasks_sort_mode); } unsigned int taskssortmode = tasks_sort_mode->getivalue(); switch (taskssortmode) { case 5: taskssortmode=6; break; case 7: taskssortmode=9; break; } tasks_sort_mode->setivalue(taskssortmode); } } } void Config::save() { if (!errmsg.empty()) return; //если была ошибка при загрузке то файл не перезаписываем if (fullname == NULL) return; if (root == NULL) return; kLogPrintf("Save Config to FULLCFGPATH=%s\n",fullname); Item* cfg = root->findItem("boinctui_cfg"); if (cfg == NULL) return; std::string configxml = cfg->toxmlstring(); kLogPrintf("\n%s\n",cfg->toxmlstring().c_str()); FILE* pfile = fopen(fullname,"w"); if (pfile!=NULL) { fwrite(cfg->toxmlstring().c_str(),1, strlen(cfg->toxmlstring().c_str()),pfile); fclose (pfile); } } void Config::addhost(const char* shost, const char* sport, const char* spwd, const char* shostid) { if ( (strlen(shost) == 0)||(strlen(sport) == 0) ) return; //пустые не заносим Item* boinctui_cfg = getcfgptr(); if (boinctui_cfg == NULL) return; Item* srv = new Item("server"); Item* host = new Item("host"); host->appendvalue(shost); srv->addsubitem(host); Item* port = new Item("port"); port->appendvalue(sport); srv->addsubitem(port); if (strlen(spwd) > 0) { Item* pwd = new Item("pwd"); pwd->appendvalue(spwd); srv->addsubitem(pwd); } Item* hostid = new Item("hostid"); hostid->appendvalue(shostid); srv->addsubitem(hostid); boinctui_cfg->addsubitem(srv); } void Config::generatedefault() { kLogPrintf("generatedafault()\n"); root = new Item(""); //корневой Item* cfg = new Item("boinctui_cfg"); root->addsubitem(cfg); addhost("127.0.0.1","31416","","Local Server"); } int Config::getivalue(Item* node, const char* name) //ищет name начиная с node { int result = 0; if (node != NULL) { Item* item = node->findItem(name); if (item != NULL) result = item->getivalue(); } return result; } void Config::setivalue(Item* node, const char* name, int value) //создаст в node подэл-т name со значением value { Item* basenode = node; if (basenode == NULL) basenode = root; //если узел не указан используем корневой if (basenode == NULL) return; //ничего не делаем Item* item = basenode->findItem(name); //эл-та нет - нужно создать if (item == NULL) { item = new Item(name); basenode->addsubitem(item); } //устнавливаем значение item->setivalue(value); } boinctui-2.7.1/src/cfgform.cpp0000664000175000017500000001621514536642777014143 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include "cfgform.h" #include "mbstring.h" #include "kclog.h" #include "tuievent.h" CfgForm::CfgForm(int rows, int cols/*, Config* cfg*/) : NForm(rows,cols) { genfields(false); //set_form_fields(frm, fields); post_form(frm); } void CfgForm::genfields(bool extfields) //создаст массив полей (extfields если нужно добавить хост) { delfields(); this->extfields = extfields; //читаем из конфига Item* boinctui_cfg = gCfg->getcfgptr(); if (boinctui_cfg == NULL) return; std::vector slist = boinctui_cfg->getItems("server"); if (slist.empty()) extfields = true; //поля ввода для серверов nhost = slist.size(); //число хостов if (extfields) nhost++; //новый добавочный хост std::vector::iterator it; int i = 0; //номер хоста int nl = 2; //номер экранной строки //статический заголовок полей хостов FIELD* field = addfield(new_field(1, 53, nl, 5, 0, 0)); field_opts_off(field, O_ACTIVE); //статический текст set_field_buffer(field, 0, "host port pwd label"); set_field_back(field, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD); nl = nl + 1; //поля для хостов for (i = 0; i < nhost; i++) //цикл по хостам { //поле для хоста field = addfield(new_field(1, 15, nl, 5, 0, 0)); set_field_back(field, getcolorpair(COLOR_WHITE,COLOR_CYAN) | A_BOLD); field_opts_off(field, O_AUTOSKIP); field_opts_off(field, O_STATIC); set_max_field(field,128); //max width 128 //set_field_type(field[nf], TYPE_ALNUM, 0); if (i < (int)slist.size()) { Item* host = slist[i]->findItem("host"); if (host != NULL) set_field_buffer(field, 0, host->getsvalue()); } if (i == 0) set_current_field(frm, field); //фокус на поле //поле для порта field = addfield(new_field(1, 5, nl, 17+5, 0, 0)); set_field_back(field, getcolorpair(COLOR_WHITE,COLOR_CYAN) | A_BOLD); set_field_type(field, TYPE_INTEGER, 0, 0, 65535); field_opts_off(field, O_AUTOSKIP); if (i < (int)slist.size()) { Item* port = slist[i]->findItem("port"); if (port != NULL) set_field_buffer(field, 0, port->getsvalue()); } //поле для пароля field = addfield(new_field(1, 20, nl, 29, 0, 0)); set_field_back(field, getcolorpair(COLOR_WHITE,COLOR_CYAN) | A_BOLD); field_opts_off(field, O_AUTOSKIP); field_opts_off(field, O_STATIC); set_max_field(field,128); //max width 128 if (i < (int)slist.size()) { Item* pwd = slist[i]->findItem("pwd"); if (pwd != NULL) set_field_buffer(field, 0, pwd->getsvalue()); } // hostid field field = addfield(new_field(1, 20, nl, 51, 0, 0)); set_field_back(field, getcolorpair(COLOR_WHITE,COLOR_CYAN) | A_BOLD); field_opts_off(field, O_AUTOSKIP); field_opts_off(field, O_STATIC); set_max_field(field,128); if (i < slist.size()) { Item* hostid = slist[i]->findItem("hostid"); if (hostid != NULL) set_field_buffer(field, 0, hostid->getsvalue()); } nl = nl + 2; } //клавиши упр-я nl++; field = addfield(new_field(1, 44, nl, 5, 0, 0)); field_opts_off(field, O_ACTIVE); //статический текст if (extfields) set_field_buffer(field, 0, "Esc-Cancel Enter-Accept"); else set_field_buffer(field, 0, "Esc-Cancel Enter-Accept Ins-Add host"); set_field_back(field, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD); nl = nl + 2; //финализация списка полей addfield(NULL); //пересчитываем высоту формы, чтобы влезли все поля и центрируем resize(nl + 2,getwidth()); move(getmaxy(stdscr)/2-getheight()/2,getmaxx(stdscr)/2-getwidth()/2); } void CfgForm::eventhandle(NEvent* ev) //обработчик событий { if ( ev->done ) return; //NMouseEvent* mevent = (NMouseEvent*)ev; if ( ev->type == NEvent::evMOUSE) { //if (isinside(mevent->row, mevent->col)) NForm::eventhandle(ev); //предок } if ( ev->type == NEvent::evKB ) { ev->done = true; switch(ev->keycode) { case KEY_IC: //INSERT if (!extfields) { unpost_form(frm); genfields(true); post_form(frm); refresh(); kLogPrintf("INSERT NEW HOST\n"); } break; case KEY_ENTER: case '\n': //ENTER { form_driver(frm, REQ_NEXT_FIELD); //костыль чтобы текущее поле не потеряло значение kLogPrintf("ENTER\n"); updatecfg(); //обновить данные в cfg gCfg->save(); //сохранить на диск //gsrvlist->refreshcfg(); //ev->keycode = 27; //костыль чтобы осн программа сдестркутила форму конфига NEvent* event = new TuiEvent(evCFGCH);//NEvent(NEvent::evPROG, 1); //создаем програмное событие putevent(event); break; } case 27: kLogPrintf("ESC\n"); ev->done = false; //нет реакции на этот код (пусть получает владелец) break; default: kLogPrintf("CfgForm::KEYCODE=%d\n", ev->keycode); ev->done = false; NForm::eventhandle(ev); //предок break; } //switch } } void CfgForm::updatecfg() //сохраняет данные из формы в cfg { Item* boinctui_cfg = gCfg->getcfgptr(); if (boinctui_cfg == NULL) return; if (fields == NULL) return; //удаляем все старые записи "server" из конфига std::vector slist = boinctui_cfg->getItems("server"); std::vector::iterator it; for (it = slist.begin(); it != slist.end(); it++) boinctui_cfg->delsubitem(*it); //создаем новые записи //int n = field_count(frm); for (int i = 0; i < nhost; i++) //хосты из формы { int nf = 1 + i*4; //номер поля для имени хоста char* shost = rtrim(field_buffer(fields[nf],0)); char* sport = rtrim(field_buffer(fields[nf+1],0)); char* spwd = rtrim(field_buffer(fields[nf+2],0)); char* shostid = rtrim(field_buffer(fields[nf+3],0)); kLogPrintf("SERVER %d [%s:%s <%s> Label: %s]\n", i, shost, sport, spwd, shostid); gCfg->addhost(shost, sport, spwd, shostid); } } boinctui-2.7.1/src/msgwin.h0000664000175000017500000000324114536642777013464 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef MSGWIN_H #define MSGWIN_H #include "nscrollview.h" #include "resultdom.h" #include "srvdata.h" #include class MsgWin : public NScrollView { public: MsgWin(NRect rect):NScrollView(rect) { sprojectold=""; stimestampold=""; }; //virtual ~MsgWin() { }; void updatedata(); //обновить данные с сервера virtual void eventhandle(NEvent* ev); //обработчик событий void setserver(Srv* srv) { if (this->srv != srv) { this->srv = srv; clearcontent(); lastmsgno = 0; } }; protected: Srv* srv; //текущий отображаемый сервер int lastmsgno; //номер последнего полученного сообщения std::string sprojectold; //это для группировки по времени std::string stimestampold; //и имени проекта }; #endif //MSGWIN_H boinctui-2.7.1/src/msgwin.cpp0000664000175000017500000001206414536642777014022 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include "kclog.h" #include "msgwin.h" #include "net.h" #include "resultparse.h" void MsgWin::updatedata() //обновить данные с сервера { if (srv == NULL) return; if (srv->msgdom.empty()) { clearcontent(); lastmsgno = 0; return; } Item* tmpmsgdom = srv->msgdom.hookptr(); srv->msgdom.lock(); if (lastmsgno == srv->lastmsgno) //в srv есть новые еще не отрисованные сообщения? { srv->msgdom.unlock(); srv->msgdom.releaseptr(tmpmsgdom); return; } // === дополняем массив визуальных строк === if (lastmsgno == 0) clearcontent(); //очищаем если отображение идет с начала Item* msgs = tmpmsgdom->findItem("msgs"); if (msgs != NULL) { std::vector mlist = msgs->getItems("msg"); std::vector::iterator it; // static char tbufold[128]; // memset(tbufold, 0, sizeof(tbufold)); // static std::string sprojectold=""; for (it = mlist.begin(); it != mlist.end(); it++) //цикл по сообщениям { Item* number = (*it)->findItem("seqno"); //номер текущего сообщения if (number->getivalue()<=lastmsgno) continue; //пропускаем старые (уже добавленные ранее) сообщения Item* body = (*it)->findItem("body"); //текст сообщения Item* time = (*it)->findItem("time"); //время сообщения if ((body != NULL)&&(time != NULL)) { time_t t = time->getivalue(); //время в секундах от 1.1.1970 tm* ltime = localtime(&t); char tbuf[128]; strftime(tbuf, sizeof(tbuf),"%-e %b %-k:%M",ltime); Item* project = (*it)->findItem("project"); std::string sproject = "_no_"; std::string stimestamp(tbuf); if (project != NULL) sproject = project->getsvalue(); if ( (stimestamp != stimestampold)||(sproject != sprojectold)) //выводим имя и время проекта если они отличаются от предидущего { addstring(getcolorpair(COLOR_CYAN,getbgcolor()) ,"%s ", tbuf); //время сообщения content.back()->append(getcolorpair(COLOR_YELLOW,getbgcolor()),"%s",sproject.c_str()); //добавить имя проекта другим цветом stimestampold = stimestamp; sprojectold = sproject; } char* s = strdup(body->getsvalue()); char* ss = s; if (strncmp(s, " ![CDATA[",9) == 0) //удаляем обертку " !CDATA[...]] " если она есть { int slen = strlen(s); s[slen-3] = '\0'; ss = ss + 9; } addstring(getcolorpair(COLOR_WHITE,getbgcolor()), "%s", ss/*body->getsvalue()*/); //само сообщение free(s); } } } lastmsgno = srv->lastmsgno; //поскольку есть новые сообщения, то делаем автоскроллинг в конец setautoscroll(true); srv->msgdom.unlock(); srv->msgdom.releaseptr(tmpmsgdom); } void MsgWin::eventhandle(NEvent* ev) //обработчик событий { NScrollView::eventhandle(ev); //предок if ( ev->done ) return; if ( ev->type == NEvent::evKB ) { ev->done = true; switch(ev->keycode) { case KEY_PPAGE: //wprintw(win,"PgUp"); scrollto(-getheight()/2); //вверх на полокна setautoscroll(false); break; case KEY_NPAGE: //wprintw(win,"PgDn"); if (!getautoscroll()) { int oldpos = startindex; scrollto(getheight()/2); //вниз на пол окна if ( oldpos == startindex) //позиция не изменилась (уже достигли конца) setautoscroll(true); //включаем автоскроллинг } break; case KEY_HOME: scrollto(-content.size()); setautoscroll(false); break; case KEY_END: scrollto(content.size()); setautoscroll(false); break; default: ev->done = false; //нет реакции на этот код } //switch if (ev->done) //если обработали, то нужно перерисоваться refresh(); } if ( ev->type == NEvent::evTIMER ) { updatedata(); //запросить данные с сервера refresh(); //перерисовать окно } } boinctui-2.7.1/src/taskwin.cpp0000664000175000017500000005715614536642777014211 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include #include #include #include #include "taskwin.h" #include "net.h" #include "resultparse.h" #include "mbstring.h" #include "tuievent.h" #include "kclog.h" typedef bool (*FnResultCmpLess)( Item* res1, Item* res2 ); //тип для сортировки списка задач bool resultCmpLessByState( Item* res1, Item* res2 ) //для сортировки задач true если res1 < res2 { Item* active_task1 = res1->findItem("active_task"); Item* active_task2 = res2->findItem("active_task"); Item* ready_to_report1 = res1->findItem("ready_to_report"); Item* ready_to_report2 = res2->findItem("ready_to_report"); if ( (active_task1 != NULL)&&(active_task2 == NULL) ) return true; if ( (active_task2 != NULL)&&(active_task1 == NULL) ) return false; if ( (ready_to_report1 == NULL)&&(ready_to_report2 != NULL) ) return true; if ( (ready_to_report2 != NULL)&&(ready_to_report1 == NULL) ) return false; return false; } bool resultCmpLessByDone( Item* res1, Item* res2 ) //для сортировки задач true если res1 < res2 { Item* fraction_done1 = res1->findItem("fraction_done"); Item* fraction_done2 = res2->findItem("fraction_done"); Item* ready_to_report1 = res1->findItem("ready_to_report"); Item* ready_to_report2 = res2->findItem("ready_to_report"); //kLogPrintf("resultCmpLessByDone: res1 (%s) %p\n", res1->findItem("name")->getsvalue(), fraction_done1); //kLogPrintf("resultCmpLessByDone: res2 (%s) %p\n", res2->findItem("name")->getsvalue(), fraction_done2); if ( (fraction_done1 == NULL)&&(fraction_done2 == NULL) ) { if ((ready_to_report1 != NULL)&&(ready_to_report2 == NULL)) //завершенные считаем как наименьшие !!! return true; } if ( (fraction_done1 == NULL)&&(fraction_done2 != NULL) ) return true; //неактивные меньше активных if ( (fraction_done1 != NULL)&&(fraction_done2 != NULL) ) { //kLogPrintf("resultCmpLessByDone(%f,%f) = %c\n\n",fraction_done1->getdvalue(), fraction_done2->getdvalue(),fraction_done1->getdvalue() < fraction_done2->getdvalue() ? 't' : 'f'); return (fraction_done1->getdvalue() < fraction_done2->getdvalue()); } //kLogPrintf("false\n"); return false; } bool resultCmpAboveByDone( Item* res1, Item* res2 ) //для сортировки задач true если res1 > res2 { return resultCmpLessByDone(res2, res1); } bool resultCmpLessByProject( Item* res1, Item* res2 ) //для сортировки задач true если res1 < res2 { std::string pname1 = Srv::findProjectName(res1->getparent()/*->statedom*/, res1->findItem("project_url")->getsvalue()); std::string pname2 = Srv::findProjectName(res2->getparent()/*->statedom*/, res2->findItem("project_url")->getsvalue()); std::transform(pname1.begin(), pname1.end(),pname1.begin(), ::toupper); std::transform(pname2.begin(), pname2.end(),pname2.begin(), ::toupper); return (pname1 < pname2); } bool resultCmpLessByEstimate( Item* res1, Item* res2 ) //для сортировки задач true если res1 < res2 { Item* estimated_cpu_time_remaining1 = res1->findItem("estimated_cpu_time_remaining"); Item* estimated_cpu_time_remaining2 = res2->findItem("estimated_cpu_time_remaining"); Item* ready_to_report1 = res1->findItem("ready_to_report"); Item* ready_to_report2 = res2->findItem("ready_to_report"); Item* active_task1 = res1->findItem("active_task"); Item* active_task2 = res2->findItem("active_task"); if ( (ready_to_report1 == NULL) && (ready_to_report2 != NULL) ) return true; if ( (ready_to_report1 != NULL) && (ready_to_report2 == NULL) ) return false; if ( (active_task1 != NULL) && (active_task2 == NULL) ) return true; if ( (active_task1 == NULL) && (active_task2 != NULL) ) return false; if ( ( estimated_cpu_time_remaining1 != NULL) && (estimated_cpu_time_remaining2 != NULL) ) return (estimated_cpu_time_remaining1->getdvalue() < estimated_cpu_time_remaining2->getdvalue()); if ( ( estimated_cpu_time_remaining1 != NULL) && (estimated_cpu_time_remaining2 == NULL) ) return true; return false; } bool resultCmpLessByRcv( Item* res1, Item* res2 ) //для сортировки задач true если res1 < res2 { Item* received_time1 = res1->findItem("received_time"); Item* received_time2 = res2->findItem("received_time"); if ( ( received_time1 != NULL) && (received_time2 != NULL) ) return (received_time1->getdvalue() > received_time2->getdvalue()); if ( ( received_time1 != NULL) && (received_time2 == NULL) ) return true; return false; } bool resultCmpLessByDL( Item* res1, Item* res2 ) //для сортировки задач true если res1 < res2 { Item* report_deadline1 = res1->findItem("report_deadline"); Item* report_deadline2 = res2->findItem("report_deadline"); if ( ( report_deadline1 != NULL) && (report_deadline2 != NULL) ) return (report_deadline1->getdvalue() < report_deadline2->getdvalue()); if ( ( report_deadline1 != NULL) && (report_deadline2 == NULL) ) return true; return false; } /* bool resultCmpLessByApp( Item* res1, Item* res2 ) //для сортировки задач true если res1 < res2 { return false; //not implemented yet } */ bool resultCmpLessBySwap( Item* res1, Item* res2 ) //для сортировки задач true если res1 < res2 { Item* swap_size1 = res1->findItem("swap_size"); Item* swap_size2 = res2->findItem("swap_size"); if ( ( swap_size1 != NULL) && (swap_size2 != NULL) ) return (swap_size1->getdvalue() > swap_size2->getdvalue()); if ( ( swap_size1 != NULL) && (swap_size2 == NULL) ) return true; return false; } bool resultCmpLessByTask( Item* res1, Item* res2 ) //для сортировки задач true если res1 < res2 { Item* name1 = res1->findItem("name"); Item* name2 = res2->findItem("name"); std::string sname1 = name1->getsvalue(); std::string sname2 = name2->getsvalue(); std::transform(sname1.begin(), sname1.end(), sname1.begin(), ::toupper); std::transform(sname2.begin(), sname2.end(), sname2.begin(), ::toupper); return (sname1 < sname2); } std::string getresultstatestr(Item* result) { Item* state = result->findItem("state"); // Item* ready_to_report = result->findItem("ready_to_report"); Item* active_task_state = result->findItem("active_task_state"); if (result->findItem("ready_to_report") != NULL) //расчет завершен { if (state->getivalue() == 3) return "DoneEr"; //была завершена с ошибкой if (state->getivalue() == 6) return "Abort"; //была прервана // else return "Done"; } if (result->findItem("too_large") != NULL) //нет памяти "Waiting for memory" { //if (active_task_state->getivalue() == 9) return "WMem"; //"Waiting for memory" } if (result->findItem("suspended_via_gui") != NULL) //задача suspend via gui return "GSusp."; switch(state->getivalue()) { case 0: return "New"; case 1: return "Dwnld"; case 3: return "Err"; case 4: return "Upld"; case 6: return "Abort"; } if (active_task_state != NULL) { switch(active_task_state->getivalue()) { case 0: return "WaitR"; //разобраться с суспендом и возобновлением case 1: return "Run"; case 9: return "Susp."; case 5: return "Abort"; case 8: return "Quit"; case 10: return "Copy"; default: { std::stringstream ss; ss << "A" << active_task_state->getivalue(); return ss.str(); } } } return "Wait"; } std::string gethumanreadablesize(size_t size) { std::stringstream s; size_t sizemb=std::round(size/(1024.0*1024.0)); if(sizemb==0) s<<" - "; else { if(sizemb<9999) s<tm_yday > 0 ) s << t->tm_yday << "d"; else if ( t->tm_hour > 0 ) s << t->tm_hour << "h"; else if ( t->tm_min > 0 ) s << t->tm_min << "m"; else if ( t->tm_sec > 0 ) s << t->tm_sec << "s"; else s << "- "; */ return s.str(); } TaskWin::TaskWin(NRect rect/*, Config* cfg*/) : NSelectList(rect) { setselectorbgcolor(COLOR_CYAN); columnmask = ~0; taskslistmode = 0; taskssortmode = 1; //читаем опции из конфига если нет то создаем if (gCfg != NULL) { Item* rootcfg = gCfg->getcfgptr(); if (rootcfg != NULL) { Item* column_view_mask = rootcfg->findItem("column_view_mask"); if (column_view_mask == NULL) //создать { column_view_mask = new Item("column_view_mask"); column_view_mask->setivalue(columnmask); rootcfg->addsubitem(column_view_mask); } columnmask = column_view_mask->getivalue(); Item* tasks_list_mode = rootcfg->findItem("tasks_list_mode"); if (tasks_list_mode == NULL) //создать { tasks_list_mode = new Item("tasks_list_mode"); tasks_list_mode->setivalue(taskslistmode); rootcfg->addsubitem(tasks_list_mode); } taskslistmode = tasks_list_mode->getivalue(); Item* tasks_sort_mode = rootcfg->findItem("tasks_sort_mode"); if (tasks_sort_mode == NULL) //создать { tasks_sort_mode = new Item("tasks_sort_mode"); tasks_sort_mode->setivalue(taskssortmode); rootcfg->addsubitem(tasks_sort_mode); } taskssortmode = tasks_sort_mode->getivalue(); } } // this->cfg = cfg; }; TaskWin::~TaskWin() { kLogPrintf("TaskWin::~TaskWin()\n"); clearcontent(); } void TaskWin::saveopttoconfig() //сохранить маску и т.д. в дереве конфига { //пишем в конфиг if (gCfg != NULL) { Item* rootcfg = gCfg->getcfgptr(); if (rootcfg != NULL) { Item* column_view_mask = rootcfg->findItem("column_view_mask"); if (column_view_mask != NULL) column_view_mask->setivalue(columnmask); Item* tasks_list_mode = rootcfg->findItem("tasks_list_mode"); if (tasks_list_mode != NULL) tasks_list_mode->setivalue(taskslistmode); Item* tasks_sort_mode = rootcfg->findItem("tasks_sort_mode"); if (tasks_sort_mode != NULL) tasks_sort_mode->setivalue(taskssortmode); } } } void TaskWin::clearcontent() { int oldindex = getstartindex(); std::vector::iterator it; for (it = objects.begin(); it != objects.end(); it++) //очищаем строки ассоцииронанные с визуальными { if ((*it) != NULL) { TaskInfo* d = (TaskInfo*)(*it); delete d; } } objects.clear(); NSelectList::clearcontent(); setstartindex(oldindex); } void TaskWin::updatedata() //обновить данные с сервера { if (srv == NULL) return; int oldindex=getstartindex(); clearcontent(); if (srv->statedom.empty()) return; Item* tmpstatedom = srv->statedom.hookptr(); Item* client_state = tmpstatedom->findItem("client_state"); int i = 1; //счетчик заданий строк if (client_state != NULL) { std::vector results = client_state->getItems("result"); std::vector::iterator it; if (taskssortmode != 0) { //критерий сортировки FnResultCmpLess fcmpless = resultCmpLessByState; //по умолчанию switch(taskssortmode) { case 1: fcmpless = resultCmpLessByState; //по state break; case 2: fcmpless = resultCmpAboveByDone; //по done% break; case 3: fcmpless = resultCmpLessByProject; //по project break; case 4: fcmpless = resultCmpLessByRcv; //по rcv break; case 5: fcmpless = resultCmpLessByEstimate; //по estimate break; case 6: fcmpless = resultCmpLessByDL; //по deadline break; case 8: fcmpless = resultCmpLessBySwap; //по swap break; case 9: fcmpless = resultCmpLessByTask; //по task break; }//switch std::sort(results.begin(), results.end(), fcmpless); //сортируем } int tasknumber = 1; for (it = results.begin(); it!=results.end(); it++,i++) //цикл списка задач { Item* name = (*it)->findItem("name"); Item* fraction_done = (*it)->findItem("fraction_done"); if (name) { int column = 0; int attr = getcolorpair(COLOR_WHITE,getbgcolor()) | A_NORMAL; //ставим цвет по умолчанию NColorString* cs = new NColorString(attr, ""); std::string sstate = getresultstatestr(*it); //состояние задачи //цвет и атрибут в зависимости от состояния задачи if ((*it)->findItem("ready_to_report") != NULL) attr = getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD; if ((*it)->findItem("active_task") != NULL) attr = getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD; //ставим цвет по умолчанию + A_BOLD; if ( sstate == "Run") attr = getcolorpair(COLOR_YELLOW,getbgcolor()) | A_BOLD; if ( sstate == "Upld") attr = getcolorpair(COLOR_BLUE,getbgcolor()) | A_BOLD; if ( sstate == "Dwnld") attr = getcolorpair(COLOR_GREEN,getbgcolor()) | A_BOLD; int stateattr = attr; if (( sstate == "DoneEr" ) || ( sstate == "Abort" ) || ( sstate == "WMem" )) stateattr = getcolorpair(COLOR_RED,getbgcolor())/* | A_BOLD*/; //проверяем нужно-ли отображать эту задачу if ( !( (taskslistmode == 0) || ( ( taskslistmode == 1) && (sstate != "Done" ) ) || ( ( taskslistmode == 2) && ((*it)->findItem("active_task") != NULL) ) ) ) continue; //пропускаем задачи не подходящие фильтру tasklistmode //колонка 0 номер задачи if(iscolvisible(column++)) cs->append(attr, "%3d ", tasknumber++); //колонка 1 состояние char sdone[64]; if (!fraction_done) //для неактивных секция fraction_done отсутствует strcpy(sdone," - "); else sprintf(sdone,"%6.2f",100*fraction_done->getdvalue()); if (iscolvisible(column++)) cs->append(stateattr, "%-6s", sstate.c_str()); //колонка 2 процент выполнения и подвсетка для GPU задач int attrgpu = attr; Item* plan_class = (*it)->findItem("plan_class"); if (plan_class != NULL) { if ((strstr(plan_class->getsvalue(),"ati") != NULL )||(strstr(plan_class->getsvalue(),"opencl") != NULL)) attrgpu = getcolorpair(COLOR_MAGENTA,getbgcolor()) | A_BOLD; if (strstr(plan_class->getsvalue(),"cuda") != NULL ) attrgpu = getcolorpair(COLOR_GREEN,getbgcolor()) | A_BOLD; if (strstr(plan_class->getsvalue(),"intel") != NULL ) //NEED CHECK !!! attrgpu = getcolorpair(COLOR_BLUE,getbgcolor()) | A_BOLD; } if (( sstate != "Run" )||( sstate != "Done")) // attrgpu = attrgpu & (~A_BOLD); //выключаем болд для незапущенных attrgpu = attrgpu | A_BOLD; //включаем болд для незапущенных if(iscolvisible(column++)) cs->append(attrgpu, " %6s", sdone); //колонка 3 имя проекта std::string pname = srv->findProjectName(tmpstatedom, (*it)->findItem("project_url")->getsvalue());//findProjectName(srv->statedom, *it); char* sproject = strdup(pname.c_str()); if(iscolvisible(column++)) cs->append(attr, " %-20s", mbstrtrunc(sproject,20)); //колонка 4 время эстимейт if(iscolvisible(column++)) { Item* estimated_cpu_time_remaining = (*it)->findItem("estimated_cpu_time_remaining"); int attr2 = attr; if ( estimated_cpu_time_remaining != NULL ) { double dtime = estimated_cpu_time_remaining->getdvalue(); if ( ( sstate == "Run" )&&( dtime < 600)&&( dtime >= 0 ) ) //осталось [0-600[ сек attr2 = getcolorpair(COLOR_RED,getbgcolor()) | A_BOLD; if ( dtime >= 0) cs->append(attr2," %4s", gethumanreadabletimestr(dtime).c_str()); //естимейт else cs->append(attr2," %4s", "?"); //естимейт отрицательный (BOINC bug?) } else cs->append(attr2," %4s", "?"); } //колонка 5 received time column if(iscolvisible(column++)) { Item* received_time = (*it)->findItem("received_time"); int attr2 = attr; if (received_time != NULL) { double dtime = received_time->getdvalue(); double beforedl = time(NULL) - dtime; //число секунд c момента получениия задачи cs->append(attr2," %4s", gethumanreadabletimestr(beforedl).c_str()); } else cs->append(attr," %4s", "?"); } //колонка 6 время дедлайн if(iscolvisible(column++)) { Item* report_deadline = (*it)->findItem("report_deadline"); int attr2 = attr; if (report_deadline != NULL) { double dtime = report_deadline->getdvalue(); double beforedl = dtime - time(NULL); //число секунд до дедлайна if ( ( sstate != "Done")&&( beforedl < 3600 * 24 * 2) ) //осталось меньше 2-х дней attr2 = getcolorpair(COLOR_BLUE,getbgcolor()) | A_BOLD; cs->append(attr2," %4s", (beforedl>0) ? gethumanreadabletimestr(beforedl).c_str() : "dead"); } else cs->append(attr2," %4s", "?"); } //колонка 7 имя приложения if(iscolvisible(column++)) { char buf[256]; snprintf(buf, sizeof(buf),"%s","unknown application"); Item* wu_name = (*it)->findItem("wu_name"); if (wu_name != NULL) { Item* app = srv->findappbywuname(wu_name->getsvalue()); if (app != NULL) { Item* user_friendly_name = app->findItem("user_friendly_name"); if (user_friendly_name != NULL) snprintf(buf, sizeof(buf),"%s",user_friendly_name->getsvalue()); } } if (iscolvisible(column)) //если след колонка (task) видима нужно обрезать mbstrtrunc(buf,30); cs->append(attr," %-30s", buf); } //колонка 8 swap size if(iscolvisible(column++)) { Item* swap_size = (*it)->findItem("swap_size"); if (swap_size != NULL) { cs->append(attr," %5s ", gethumanreadablesize(swap_size->getdvalue()).c_str()); } else cs->append(attr," %5s ", " - "); } //колонка 9 имя задачи if(iscolvisible(column++)) cs->append(attr," %s", name->getsvalue()); //добавляем сформированную строку и поле данных с именем задачи (для селектора) //addstring(strdup(name->getsvalue()),cs); addstring(new TaskInfo(name->getsvalue(),(*it)->findItem("project_url")->getsvalue()), cs); free(sproject); } } //цикл списка задач } srv->statedom.releaseptr(tmpstatedom); setstartindex(oldindex); } void TaskWin::eventhandle(NEvent* ev) //обработчик событий { NSelectList::eventhandle(ev); //предок if ( ev->done ) return; bool selectorvisiblebak = (selectedindex >= 0)&&(selectedindex < (int)content.size()); //состояние селектора до //одиночный или двойной клик NMouseEvent* mevent = (NMouseEvent*)ev; if (( ev->type == NEvent::evMOUSE ) && (mevent->cmdcode & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED))) { if (isinside(mevent->row, mevent->col)) { //передвигаем слектор setselectorpos(mevent->row - getabsbegrow() + startindex); if (mevent->cmdcode & BUTTON1_DOUBLE_CLICKED) //даблклик putevent(new TuiEvent(evTASKINFO)); //событие для открытия raw task info ev->done = true; } } //клавиатура if ( ev->type == NEvent::evKB ) { ev->done = true; switch(ev->keycode) { case KEY_UP: selectorup(); break; case KEY_DOWN: selectordown(); break; case KEY_ENTER: case '\n': if ((selectedindex >= 0)&&(selectedindex < (int)content.size())) //селектор видимый putevent(new TuiEvent(evTASKINFO)); break; default: ev->done = false; //нет реакции на этот код } //switch } if (ev->type == NEvent::evPROG) //прграммные { if (ev->cmdcode == evABORTRES) //событие "abort_result" { ev->done =false; } if (ev->cmdcode == evCOLVIEWCH) //событие изменения видимости колонки { TuiEvent* ev1 = (TuiEvent*) ev; if (iscolvisible(ev1->idata1)) coldisable(ev1->idata1); else colenable(ev1->idata1); } if (ev->cmdcode == evVIEWMODECH) { TuiEvent* ev1 = (TuiEvent*) ev; taskslistmode = ev1->idata1; saveopttoconfig(); setstartindex(0); //отображать с начала selectedindex = -1; //указатель } if (ev->cmdcode == evSORTMODECH) { TuiEvent* ev1 = (TuiEvent*) ev; taskssortmode = ev1->idata1; saveopttoconfig(); } } //если изменилась видимость селектора, то генерируем соотв евент if (((selectedindex >= 0)&&(selectedindex < (int)content.size()) )&&(!selectorvisiblebak)) putevent(new TuiEvent(evTASKSELECTORON)); //селектор включился if (((selectedindex == -1)||(selectedindex == (int)content.size()))&&(selectorvisiblebak)) putevent(new TuiEvent(evTASKSELECTOROFF)); //селектор выключился if (ev->done) //если обработали, то нужно перерисоваться refresh(); //событие таймера if (ev->type == NEvent::evTIMER) //таймер { updatedata(); //запросить данные с сервера refresh(); //перерисовать окно } } boinctui-2.7.1/src/addprojectform.cpp0000664000175000017500000002725714536642777015533 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include "addprojectform.h" #include "mbstring.h" #include "kclog.h" #include "tuievent.h" //стрингификатор #define XSTR(S) STR(S) #define STR(S) #S #define ERROREX(msg) throw __FILE__ ":" XSTR(__LINE__) "[" msg "]"; char* strupcase(char* s) //в верхний регистр { char *p; for (p = s; *p != '\0'; p++) *p = (char) toupper(*p); return s; } char* strlowcase(char* s) //в нижний регистр { char *p; for (p = s; *p != '\0'; p++) *p = (char) tolower(*p); return s; } AddProjectForm::AddProjectForm(int rows, int cols, Srv* srv, const char* projname, bool userexist, bool byurl) : NForm(rows,cols) { this->srv = srv; settitle(projname); this->projname = projname; this->userexist = userexist; this->byurl = byurl; Item* project = NULL; if (srv !=NULL) project = srv->findprojectbynamefromall(projname); int row = 0; //поля try { genfields(row,project); } catch(const char* err) { kLogPrintf("ERROR EXCEPTION %s\n",err); } //пересчитываем высоту формы, чтобы влезли все поля и центрируем int r,c =0; scale_form(frm, &r, &c); kLogPrintf("field_count=%d scale_form()->%d,%d\n", field_count(frm), r, c); resize(r+3,c+2); post_form(frm); this->refresh(); } void AddProjectForm::genfields(int& line, Item* project) //создаст массив полей { FIELD* f; delfields(); //сообщение об ошибке errmsgfield = getfieldcount(); f = addfield(new_field(1, getwidth()-2, line++, 0, 0, 0)); if (!f) ERROREX(); if (E_OK != set_field_buffer(f, 0, "Error")) ERROREX(); if (E_OK != set_field_back(f, getcolorpair(COLOR_WHITE,COLOR_RED) | A_BOLD)) ERROREX(); if (E_OK != field_opts_off(f, O_ACTIVE)) //статический текст ERROREX(); if (E_OK != field_opts_off(f, O_VISIBLE)) //по умолчанию невидима ERROREX(); if (project != NULL) { //url Item* url = project->findItem("url"); std::string s = "url : "; if (url !=NULL) projurl = url->getsvalue(); s = s + projurl; f = addfield(new_field(1, getwidth()-4, line++, 1, 0, 0)); if (E_OK != set_field_buffer(f, 0, s.c_str())) ERROREX(); if (E_OK != set_field_back(f, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD)) ERROREX(); if (E_OK != field_opts_off(f, O_ACTIVE)) //статический текст ERROREX(); //area Item* general_area = project->findItem("general_area"); s = "General area : "; if (general_area !=NULL) s = s + general_area->getsvalue(); f = addfield(new_field(1, getwidth()-4, line++, 1, 0, 0)); if (!f) ERROREX(); if (E_OK != set_field_buffer(f, 0, s.c_str())) ERROREX(); if (E_OK != set_field_back(f, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD)) ERROREX(); if (E_OK != field_opts_off(f, O_ACTIVE)) //статический текст ERROREX(); //specific area Item* specific_area = project->findItem("specific_area"); s = "Specific area: "; if (specific_area !=NULL) s = s + specific_area->getsvalue(); f = addfield(new_field(1, getwidth()-4, line++, 1, 0, 0)); if (!f) ERROREX(); if (E_OK != set_field_buffer(f, 0, s.c_str())) ERROREX(); if (E_OK != set_field_back(f, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD)) ERROREX(); if (E_OK != field_opts_off(f, O_ACTIVE)) //статический текст ERROREX(); //home s = "Home : "; Item* home = project->findItem("home"); if (home !=NULL) s = s + home->getsvalue(); f = addfield(new_field(1, getwidth()-4, line++, 1, 0, 0)); if (!f) ERROREX(); if (E_OK != set_field_buffer(f, 0, s.c_str())) ERROREX(); if (E_OK != set_field_back(f, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD)) ERROREX(); if (E_OK != field_opts_off(f, O_ACTIVE)) //статический текст ERROREX(); //description s = "Description : "; line++; Item* description = project->findItem("description"); if (description !=NULL) s = s + description->getsvalue(); int h = s.size()/(getwidth() - 4) + 1; if (h > 4) h = 4; f = addfield(new_field(h, getwidth()-4, line, 1, 0, 0)); if (!f) ERROREX(); if (E_OK != set_field_buffer(f, 0, s.c_str())) ERROREX(); if (E_OK != set_field_back(f, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD)) ERROREX(); if (E_OK != field_opts_off(f, O_ACTIVE)) //статический текст ERROREX(); line += h+1; //platforms Item* platforms = project->findItem("platforms"); s = "Platforms : "; if (platforms !=NULL) { std::vector namelist = platforms->getItems("name"); //список названий платформ std::vector::iterator it; for (it = namelist.begin(); it!=namelist.end(); it++) { Item* name = (*it)->findItem("name"); if (it != namelist.begin()) s = s + ','; s = s + name->getsvalue(); } } h = s.size()/(getwidth() - 4) + 1; if (h > 5) h = 5; f = addfield(new_field(h, getwidth()-4, ++line, 1, 0, 0)); if (!f) ERROREX(); if (E_OK != set_field_buffer(f, 0, s.c_str())) ERROREX(); if (E_OK != set_field_back(f, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD)) ERROREX(); if (E_OK != field_opts_off(f, O_ACTIVE)) //статический текст ERROREX(); line += h + 1; } //project URL if (byurl) { line++; f = addfield(new_field(1, 10, line, 1 , 0, 0)); if (!f) ERROREX(); if (E_OK != set_field_buffer(f, 0, "ProjectURL")) ERROREX(); if (E_OK != set_field_back(f, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD)) ERROREX(); if (E_OK != field_opts_off(f, O_ACTIVE)) //статический текст ERROREX(); projurlfield = getfieldcount(); f = addfield(new_field(1, 40, line++, 15, 0, 0)); if (!f) ERROREX(); if (E_OK != field_opts_off(f, O_AUTOSKIP)) ERROREX(); if (E_OK != set_field_back(f, getcolorpair(COLOR_WHITE,COLOR_CYAN) | A_BOLD)) ERROREX(); } //email line++; f = addfield(new_field(1, 10, line, 1 , 0, 0)); if (!f) ERROREX(); if (E_OK != set_field_buffer(f, 0, "email")) ERROREX(); if (E_OK != set_field_back(f, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD)) ERROREX(); if (E_OK != field_opts_off(f, O_ACTIVE)) //статический текст ERROREX(); emailfield = getfieldcount(); f = addfield(new_field(1, 40, line++, 15, 0, 0)); if (!f) ERROREX(); if (E_OK != field_opts_off(f, O_AUTOSKIP)) ERROREX(); if (E_OK != set_field_back(f, getcolorpair(COLOR_WHITE,COLOR_CYAN) | A_BOLD)) ERROREX(); //password line++; f = addfield(new_field(1, 10, line, 1 , 0, 0)); if (!f) ERROREX(); if (E_OK != set_field_buffer(f, 0, "password")) ERROREX(); if (E_OK != set_field_back(f, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD)) ERROREX(); if (E_OK != field_opts_off(f, O_ACTIVE)) //статический текст ERROREX(); passwfield = getfieldcount(); f = addfield(new_field(1, 40, line++, 15, 0, 0)); if (!f) ERROREX(); if (E_OK != set_field_back(f, getcolorpair(COLOR_WHITE,COLOR_CYAN) | A_BOLD)) ERROREX(); if (E_OK != field_opts_off(f, O_AUTOSKIP)) ERROREX(); if (!userexist) { //user name line++; f = addfield(new_field(1, 10, line, 1 , 0, 0)); if (!f) ERROREX(); if (E_OK != set_field_buffer(f, 0, "username")) ERROREX(); if (E_OK != set_field_back(f, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD)) ERROREX(); if (E_OK != field_opts_off(f, O_ACTIVE)) //статический текст ERROREX(); usernamefield = getfieldcount(); f = addfield(new_field(1, 40, line++, 15, 0, 0)); if (!f) ERROREX(); if (E_OK != field_opts_off(f, O_AUTOSKIP)) ERROREX(); if (E_OK != set_field_back(f, getcolorpair(COLOR_WHITE,COLOR_CYAN) | A_BOLD)) ERROREX(); //team name line++; f = addfield(new_field(1, 10, line, 1 , 0, 0)); if (!f) ERROREX(); if (E_OK != set_field_buffer(f, 0, "teamname")) ERROREX(); if (E_OK != set_field_back(f, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD)) ERROREX(); if (E_OK != field_opts_off(f, O_ACTIVE)) //статический текст ERROREX(); teamfield = getfieldcount(); f = addfield(new_field(1, 40, line++, 15, 0, 0)); if (!f) ERROREX(); if (E_OK != set_field_back(f, getcolorpair(COLOR_WHITE,COLOR_CYAN) | A_BOLD)) ERROREX(); if (E_OK != field_opts_off(f, O_AUTOSKIP)) ERROREX(); } //подсказки line++; f = addfield(new_field(1, getwidth()-25, line++, 20 , 0, 0)); if (!f) ERROREX(); if (E_OK != set_field_buffer(f, 0, "Enter-Ok Esc-Cancel")) ERROREX(); if (E_OK != set_field_back(f, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD)) ERROREX(); if (E_OK != field_opts_off(f, O_ACTIVE)) //статический текст ERROREX(); //финализация списка полей addfield(NULL); } void AddProjectForm::eventhandle(NEvent* ev) //обработчик событий { if ( ev->done ) return; //NMouseEvent* mevent = (NMouseEvent*)ev; if ( ev->type == NEvent::evMOUSE) { NForm::eventhandle(ev); //предок } if ( ev->type == NEvent::evKB ) { ev->done = true; switch(ev->keycode) { case KEY_ENTER: case '\n': //ENTER { form_driver(frm, REQ_NEXT_FIELD); //костыль чтобы текущее поле не потеряло значение char* email = strlowcase(rtrim(field_buffer(fields[emailfield],0))); if (byurl) projurl = rtrim(field_buffer(fields[projurlfield],0)); char* passw = rtrim(field_buffer(fields[passwfield],0)); kLogPrintf("AddProjectForm OK name=[%s] url=[%s] email=[%s] passw=[%s]\n", projname.c_str(), projurl.c_str(), email, passw); if (srv!=NULL) { std::string errmsg; bool success = true; if (!userexist) //если аккаунта еще нет то создаем { char* username = strlowcase(rtrim(field_buffer(fields[usernamefield],0))); char* teamname = rtrim(field_buffer(fields[teamfield],0)); success = srv->createaccount(projurl.c_str(),email,passw, username, teamname, errmsg); } if (success) success = srv->projectattach(projurl.c_str(), projname.c_str(), email, passw, errmsg); //подключить проект if (success) putevent(new TuiEvent(evADDPROJECT)); //создаем событие чтобы закрыть форму else { //СООБЩЕНИЕ ОБ ОШИБКЕ errmsg = " Error: " + errmsg; set_field_buffer(fields[errmsgfield], 0, errmsg.c_str()); field_opts_on(fields[errmsgfield], O_VISIBLE); //делаем видимой строку ошибки this->refresh(); } } break; } case 27: putevent(new TuiEvent(evADDPROJECT)); //код закрытия окна break; default: kLogPrintf("AddProjectForm::KEYCODE=%d\n", ev->keycode); ev->done = false; NForm::eventhandle(ev); //предок break; } //switch } } boinctui-2.7.1/src/nform.cpp0000664000175000017500000001177014536642777013642 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include "nform.h" #include "mbstring.h" #include "kclog.h" NForm::NForm(int rows, int cols) : NGroup(NRect(rows,cols,0,0)) { fields = NULL; fieldcount = 0; modalflag = true; frm = new_form(NULL); ////////////////// scale_form(frm,&rows,&cols); addfield(NULL); set_form_win(frm, win); subwin = derwin(win, rows-2, cols-2, 1,1); set_form_sub(frm, subwin); wattrset(win,getcolorpair(COLOR_WHITE, getbgcolor()) | A_BOLD); title = NULL; needrefresh = true; //перемещаем в центр экрана //this->move(getmaxy(stdscr)/2-getheight()/2,getmaxx(stdscr)/2-getwidth()/2); curs_set(1); //курсор } NForm::~NForm() { unpost_form(frm); free_form(frm); delfields(); if (title != NULL) free(title); curs_set(0); //курсор delwin(subwin); } void NForm::resize(int rows, int cols) { NView::resize(rows, cols); wresize(subwin, rows-2, cols-2); } void NForm::settitle(const char* title) { this->title = (char*)malloc(strlen(title)+3); snprintf(this->title, strlen(title)+3," %s ",title); } FIELD* NForm::addfield(FIELD* field) { FIELD** tmp = (FIELD**)realloc(fields, (fieldcount+1)*sizeof(FIELD*)); //выделяем память под массив полей if(tmp!=NULL) { fields=tmp; fields[fieldcount] = field; fieldcount++; } if (field == NULL) set_form_fields(frm, fields); return field; } void NForm::delfields() { if (fields != NULL) { set_form_fields(frm, NULL); int n = fieldcount - 1; //последний NULL for (int i = 0; i < n; i++) { if (fields[i] != NULL) { int retcode = free_field(fields[i]); if (retcode != E_OK) kLogPrintf("NForm::delfields(): free_field(%p) retcode=%d\n", fields[i], retcode); } } free(fields); fields = NULL; fieldcount = 0; } } void NForm::refresh() { if(asciilinedraw == 1) wborder(win, '|', '|', '-', '-', '+', '+', '+', '+'); else box(frm->win, ACS_VLINE, ACS_HLINE); if(title != NULL) { mvwprintw(frm->win,0,getwidth()/2-mbstrlen(title)/2,"%s",title); //посередине } pos_form_cursor(frm); //восстановить позицию курсора ( после mvprintw() ) NGroup::refresh(); } bool NForm::clickatfield(int mrow, int mcol, FIELD* f) //true если клик внутри этого поля { bool result = true; int absbegrow = getabsbegrow(); int absbegcol = getabsbegcol(); kLogPrintf("frow=%d fcol=%d rows=%d cols=%d\n",f->frow,f->fcol,f->rows,f->cols); if ((mrow < absbegrow + f->frow)||(mcol < absbegcol + f->fcol)) result = false; if ((mrow > absbegrow + f->frow + f->rows - 1)||(mcol > absbegcol + f->fcol + f->cols - 1)) result = false; return result; } void NForm::eventhandle(NEvent* ev) //обработчик событий { NGroup::eventhandle(ev); //предок if ( ev->done ) return; NMouseEvent* mevent = (NMouseEvent*)ev; //одиночный или двойной клик if ( ev->type == NEvent::evMOUSE ) ev->done = true; if (( ev->type == NEvent::evMOUSE ) && (((mevent->cmdcode & BUTTON1_CLICKED))||((mevent->cmdcode & BUTTON1_DOUBLE_CLICKED)))) { if (isinside(mevent->row, mevent->col)) { if (fields != NULL) { int n = field_count(frm); for (int i = 0; i < n; i++) { if (clickatfield(mevent->row, mevent->col, fields[i])) { set_current_field(frm, fields[i]); form_driver(frm, REQ_END_LINE); break; } } } } } //клавиатура if ( ev->type == NEvent::evKB ) { ev->done = true; switch(ev->keycode) { case '\t': form_driver(frm, REQ_NEXT_FIELD); form_driver(frm, REQ_END_LINE); break; case KEY_BACKSPACE: form_driver(frm, REQ_DEL_PREV); break; case KEY_LEFT: form_driver(frm, REQ_PREV_CHAR); break; case KEY_RIGHT: form_driver(frm, REQ_NEXT_CHAR); break; case KEY_DC: form_driver(frm, REQ_DEL_CHAR); break; default: form_driver(frm,ev->keycode); //передаем в форму //ev->done = false; //нет реакции на этот код } //switch if (ev->done) //если обработали, то нужно перерисоваться refresh(); } } boinctui-2.7.1/src/nprogram.cpp0000664000175000017500000000655114536642777014347 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include #include "nprogram.h" #include "kclog.h" bool NProgram::needresize; NProgram::NProgram() : NGroup(NRect(getmaxy(stdscr), getmaxx(stdscr), 0, 0)) { NProgram::needresize = false; signal(SIGWINCH, NProgram::sig_winch); //обработчик сигнала ресайза терминала #ifdef EVENTTHREAD pthread_mutex_init(&mutex,NULL); stopflag = false; if ( 0 != pthread_create(&thread, NULL, evcreationthread, this)) kLogPrintf("NProgram::NProgram() pthread_create() error\n"); #endif } void NProgram::sig_winch(int signo) //вызывается при изменении размеров терминала { NProgram::needresize = true; } void NProgram::putevent(NEvent* ev) //отправить событие по цепочке владельцев в очередь { #ifdef EVENTTHREAD lock(); #endif evqueue.push(ev); //поместить в очередь #ifdef EVENTTHREAD unlock(); #endif #ifdef DEBUG kLogPrintf("NProgram::putevent(%s)\n",ev->tostring().c_str()); #endif } #ifdef EVENTTHREAD void* NProgram::evcreationthread(void* args) //трейд опрашивающий клавиатуру и мышь { NProgram* me = (NProgram*)args; kLogPrintf("NProgram::evcreationthread started\n"); time_t evtimertime; //time of last evTIMER time(&evtimertime); evtimertime=evtimertime-2; //костыль для уменьшения задержки первой отрисовки while(!me->stopflag) { //если настало время посылаем evTIMER if (time(NULL) - evtimertime > EVTIMERINTERVAL) { NEvent* event = new NEvent(NEvent::evTIMER, 0); //создаем событие таймера me->putevent(event); //отправить в очередь time(&evtimertime); } //есть символ в буфере -> нужно создать событие int ic; if ( (ic = getch()) != ERR ) //символ(ы) есть? { NEvent* event = NULL; if (KEY_MOUSE == ic) { // mouse event MEVENT mevent; if (OK == getmouse(&mevent)) event = new NMouseEvent(mevent.bstate, mevent.y, mevent.x); //создаем мышиное событие else kLogPrintf("getmouse() err\n"); } else // keyboard event event = new NEvent(NEvent::evKB, ic); //создаем клавиатурное событие if (event != NULL) me->putevent(event); //отправить в очередь } } kLogPrintf("NProgram::evcreationthread stopped\n"); pthread_exit(0); } #endif boinctui-2.7.1/src/helpwin.cpp0000664000175000017500000000664114536642777014170 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include "helpwin.h" #include "tuievent.h" HelpWin::HelpWin(int rows, int cols) : NGroup(NRect(rows, cols, getmaxy(stdscr)/2-rows/2,getmaxx(stdscr)/2-cols/2)) { caption = strdup(" Hot keys list "); modalflag = true; resize(18,60); wattrset(win,getcolorpair(COLOR_WHITE, getbgcolor()) | A_BOLD); if(asciilinedraw == 1) wborder(win, '|', '|', '-', '-', '+', '+', '+', '+'); else box(win,0,0); mvwprintw(win,0,getwidth()/2-(strlen(caption)/2),"%s",caption); text1 = new NStaticText(NRect(getheight()-2,getwidth()-2,/*rect.begrow+*/1,/*rect.begcol+*/1)); int attr1 = getcolorpair(COLOR_YELLOW, getbgcolor()) | A_BOLD; int attr2 = getcolorpair(COLOR_WHITE, getbgcolor()) | A_BOLD; text1->setstring(attr1, "\n Common Controls:\n"); text1->appendstring(attr2," \"N\" - View next BOINC host\n"); text1->appendstring(attr2," \"P\" - View previous BOINC host\n"); text1->appendstring(attr2," \"C\" - Edit configuration\n"); text1->appendstring(attr2," \"Q\" - Quit boinctui\n"); text1->appendstring(attr2," \"F9\"/\"M\" - Toggle main menu\n"); text1->appendstring(attr2," \"PgUp\"/\"PgDn\" - Scroll Messages Window\n"); text1->appendstring(attr2,"\n"); text1->appendstring(attr1," Task Controls:\n"); text1->appendstring(attr2," \"Up\"/\"Dn\" - Select task\n"); text1->appendstring(attr2," \"S\" - Suspend selected running task\n"); text1->appendstring(attr2," \"R\" - Resume selected suspended task\n"); text1->appendstring(attr2," \"A\" - Abort selected task\n"); text1->appendstring(attr2," \"Enter\" - View selected task raw info\n"); insert(text1); } void HelpWin::eventhandle(NEvent* ev) //обработчик событий { NGroup::eventhandle(ev); //предок if ( ev->done ) return; //закрываем при любом клике независимо от координат NMouseEvent* mevent = (NMouseEvent*)ev; if (( ev->type == NEvent::evMOUSE ) && (mevent->cmdcode & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED))) putevent(new TuiEvent(evKEYBIND)); if ( ev->type == NEvent::evKB ) { ev->done = true; switch(ev->cmdcode) { case 27: case KEY_ENTER: case ' ': case '\n': putevent(new TuiEvent(evKEYBIND)); //NEvent(NEvent::evPROG, 4)); //создаем событие с кодом 4 "окно Help" break; } //switch if (ev->done) //если обработали, то нужно перерисоваться refresh(); } } boinctui-2.7.1/src/nscrollbar.h0000664000175000017500000000347414536642777014331 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013,2014 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef NSCROLLBAR_H #define NSCROLLBAR_H #include "nview.h" class NScrollBar : public NView { public: NScrollBar(NRect rect, chtype chtop = 0, chtype chbottom = 0, chtype chinactive = ACS_VLINE); virtual ~NScrollBar() { }; void setbgcolor(int colorpair) { bgcolor = colorpair; }; virtual void refresh(); void setpos(int vmin, int vmax, int vpos1, int vpos2); void setvisible(bool value) { visible = value; }; protected: int bgcolor; //цвет фона chtype chtop; //символ вверху chtype chbottom;//символ внизу chtype chinactive; //символ которым заполняется когда неактивный int vmin; //минимальное значение int vmax; //максимальное значение int vpos1; //минимальное видимое значение int vpos2; //максимальное видимое значение bool visible;//true если скроллер видимый }; #endif //NSCROLLBAR_Hboinctui-2.7.1/src/about.cpp0000664000175000017500000000530414536642777013627 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include "about.h" #include "tuievent.h" #include "commondef.h" AboutWin::AboutWin(int rows, int cols) : NGroup(NRect(rows, cols, getmaxy(stdscr)/2-rows/2,getmaxx(stdscr)/2-cols/2)) { modalflag = true; caption = strdup(" BOINCTUI "); resize(12,getwidth()); wattrset(win,getcolorpair(COLOR_WHITE, getbgcolor()) | A_BOLD); if(asciilinedraw == 1) wborder(win, '|', '|', '-', '-', '+', '+', '+', '+'); else box(win,0,0); mvwprintw(win,0,getwidth()/2-(strlen(caption)/2),"%s",caption); char buf[1024]; snprintf(buf,sizeof(buf),"%s ver %s","BOINC Client manager", XSTR(VERSION)); mvwprintw(win,3,getwidth()/2-(strlen(buf)/2),"%s",buf); mvwprintw(win,5,getwidth()/2-(strlen("(c) Sergey Suslov")/2),"(c) Sergey Suslov"); mvwprintw(win,6,getwidth()/2-(strlen("suleman1971@gmail.com")/2),"suleman1971@gmail.com"); mvwprintw(win,7,getwidth()/2-(strlen("Community PRs included by")/2),"Community PRs included by"); mvwprintw(win,8,getwidth()/2-(strlen("Mark Pentler - GitHub: mpentler")/2),"Mark Pentler - GitHub: mpentler"); } void AboutWin::eventhandle(NEvent* ev) //обработчик событий { NGroup::eventhandle(ev); //предок if ( ev->done ) return; //закрываем при любом клике независимо от координат NMouseEvent* mevent = (NMouseEvent*)ev; if (( ev->type == NEvent::evMOUSE ) && (mevent->cmdcode & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED))) putevent(new TuiEvent(evABOUT)); if ( ev->type == NEvent::evKB ) { ev->done = true; switch(ev->cmdcode) { case 27: case KEY_ENTER: case ' ': case '\n': putevent(new TuiEvent(evABOUT)); //NEvent(NEvent::evPROG, 3)); //создаем событие с кодом 3 "окно About" break; } //switch if (ev->done) //если обработали, то нужно перерисоваться refresh(); } } boinctui-2.7.1/src/net.cpp0000664000175000017500000001024314536642777013301 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include #include #include #include #include #include #include #include #include #include #include "net.h" #include "kclog.h" void TConnect::createconnect(/*const char* shost, const char* sport*/) { kLogPrintf("connecting..."); //this->shost = strdup(shost); //this->sport = strdup(sport); struct sockaddr_in boincaddr; //resolving memset(&boincaddr,0, sizeof(boincaddr)); boincaddr.sin_family = AF_INET; boincaddr.sin_port = htons(atoi(sport)); if (inet_aton(shost,&boincaddr.sin_addr) == 0) //в shost не ip адрес { struct hostent *hostp = gethostbyname(shost); //пытаемся отресолвить if ( hostp == NULL ) kLogPrintf("host %s lookup failed\n",shost); else memcpy(&boincaddr.sin_addr, hostp->h_addr, sizeof(boincaddr.sin_addr)); } int hsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); //connection if (connect(hsock, (struct sockaddr *) &boincaddr, sizeof(boincaddr)) < 0) { kLogPrintf("connect %s:%s failed!\n",shost,sport); this->hsock = -1; } else { this->hsock = hsock; kLogPrintf("OK\n"); } } void TConnect::disconnect() { kLogPrintf("disconnecting %s:%s ...",shost,sport); if (hsock != -1) close(hsock); hsock = -1; kLogPrintf("OK\n"); } void TConnect::sendreq(const char* fmt, ...) //отправить запрос на сервер { va_list args; va_start(args, fmt); sendreq(fmt,args); va_end(args); } void TConnect::sendreq(const char* fmt, va_list vl) //отправить запрос на сервер { //формируем строку запроса char req[1024]; vsnprintf(req, sizeof(req), fmt, vl); //kLogPrintf("[%s]\n",req); //конектимся (если соединения еще нет) if (hsock == -1) createconnect(/*shost,sport*/); //отправляем запрос if (send(hsock, req, strlen(req), 0) != (int)strlen(req)) { kLogPrintf("send request %s:%s error\n",shost,sport); disconnect(); } } char* TConnect::waitresult() //получить ответ от сервера (потом нужно освобождать память извне) { if (hsock == -1) createconnect(/*shost,sport*/); //чтение частями из сокета char* answbuf = NULL; int totalBytesRcvd = 0; int answbuflen = 0; char bufpart[1024]; //фрагмент int bytesRcvd; do { if ((bytesRcvd = recv(hsock, bufpart, sizeof(bufpart), 0)) <= 0 ) { kLogPrintf("recv fail %s:%s\n",shost,sport); disconnect(); return NULL; } else //printf("allbytes= %d received %d bytes\n",totalBytesRcvd,bytesRcvd); //копируем в суммарный буфер answbuflen = answbuflen+bytesRcvd; answbuf = (char*)realloc(answbuf,answbuflen); if(answbuf==NULL) return NULL; memcpy(&answbuf[totalBytesRcvd], bufpart, bytesRcvd); totalBytesRcvd += bytesRcvd; if (answbuf[totalBytesRcvd-1] == '\003') { answbuf = (char*)realloc(answbuf,answbuflen + 1); answbuf[totalBytesRcvd-1] = '\0'; //003 -> 0 answbuf[totalBytesRcvd] = '\0'; //терминирующий 0 break; } } while (true); // printf("'%s' \nlen=%d\n", answbuf, strlen(answbuf)); return answbuf; } boinctui-2.7.1/src/srvdata.h0000664000175000017500000002010314536642777013620 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef SRVDATA_H #define SRVDATA_H #include #include #include #include #include "net.h" #include "resultdom.h" #include "cfg.h" struct DomPtr { DomPtr(Item* ptr) {refcount = 0; dom = ptr; }; Item* dom; //указатель на данные int refcount; //количество hook-ов данного указателя }; class PtrList { public: PtrList() { pthread_mutex_init(&mutex, NULL); needupdate = true; }; ~PtrList(); void lock() { pthread_mutex_lock(&mutex); }; void unlock() { pthread_mutex_unlock(&mutex); }; Item* hookptr(); //получить указатель из хвоста списка void releaseptr(Item* ptr); //сообщить списку что указатель больше не нужен (список сам решит нужно ли его удалять) void addptr(Item* ptr) { pthread_mutex_lock(&mutex); if (ptr != NULL) list.push_back(new DomPtr(ptr)); needupdate = false; pthread_mutex_unlock(&mutex);}; //добавить указатель в хвост списка bool empty() { pthread_mutex_lock(&mutex); bool result = list.empty(); pthread_mutex_unlock(&mutex); return result; }; bool needupdate; //говорит треду что нужно незамедлительно обновлять данные private: std::list list; pthread_mutex_t mutex; }; bool daily_statisticsCmpAbove( Item* stat1, Item* stat2 ); //для сортировки статистики true если дата stat1 > stat2 class Srv : public TConnect //описание соединения с сервером { public: Srv(const char* shost, const char* sport, const char* pwd, const char* hostid); virtual ~Srv(); void updateallprojects(); //обновить статистику static std::string findProjectName(Item* tree, const char* url); //найти в дереве tree имя проекта с заданным url std::string findProjectUrl(Item* tree, const char* name); //найти в дереве tree url проекта с заданным именем Item* findresultbyname(const char* resultname); Item* findprojectbyname(const char* projectname); //ищет в getstate Item* findprojectbynamefromall(const char* projectname); //ищет в allprojectsdom Item* findaccountmanager(const char* mgrname); //ищет менеджер по имени Item* findappbywuname(const char* wuname); //найти приложение для данного WU void opactivity(const char* op); //изменение режима активности BOINC сервера "always" "auto" "newer" void opnetactivity(const char* op); //изменение режима активности сети "always" "auto" "newer" void opgpuactivity(const char* op); //изменение режима активности GPU "always" "auto" "newer" void optask(const char* url, const char* name, const char* op); //действия над задачей ("suspend_result",...) void opproject(const char* name, const char* op); //действия над проектом ("project_suspend","project_resume",...) void runbenchmarks(); //запустить бенчмарк bool projectattach(const char* url, const char* prjname, const char* email, const char* pass, std::string& errmsg); //подключить проект bool createaccount(const char* url, const char* email, const char* pass, const char* username, const char* teamname, std::string& errmsg); //создать аккаунт bool accountmanager(const char* url, const char* username, const char* pass, bool useconfigfile, std::string& errmsg); //подключить аккаунт менеджер bool getprojectconfig(const char* url, std::string& errmsg); //получить c сервера файл конфигурации time_t getlaststattime(); //вернет время последней имеющейся статистики PtrList msgdom; //xml дерево сообщений int lastmsgno; //номер последнего сообщения полученного с сервера PtrList statedom; //xml дерево состояний PtrList ccstatusdom; //xml дерево для PtrList dusagedom; //xml дерево для PtrList statisticsdom; //xml дерево для Item* allprojectsdom; //xml дерево для PtrList acctmgrinfodom; //xml дерево для bool ccstatusdomneedupdate; //если true тред обновит ccstatusdom без ожидания Item* req(const char* fmt, ...); //выполнить запрос (вернет дерево или NULL) virtual void createconnect(); void setactive(bool b); //включить/выключить тред обновления данных bool isactive() {return active;}; void lock() { pthread_mutex_lock(&mutex); }; void unlock() { pthread_mutex_unlock(&mutex); }; bool loginfail; //true если получен unauthorize char* hostid; protected: void updatestate(); //обновить состояние void updatemsgs(); //обновить список сообщений void updatestatistics(); //обновить статистику void updatediskusage(); //обновить состояние void updateccstatus(); //обновить состояние void updateacctmgrinfo();//обновить статистику time_t gettimeelapsed(time_t t); //вернет соличество секунд между t и тек. временем bool login(); //авторизоваться на сервере char* pwd; private: unsigned int takt; //номер оборота цикла updatethread() static void* updatethread(void* args); //трейд опрашивающий сервер pthread_t thread; bool active; //true если трейд активен pthread_mutex_t mutex; }; class SrvList //список всех серверов { public: SrvList(/*Config* cfg*/); virtual ~SrvList(); //Srv* addserver(const char* shost, const char* sport) { return new Srv(shost, sport); }; //добавить сервер (вернет указаталь на сервер) void requestdata() {}; //опросить все сервера //Srv* findserver(const char* shost, const char* sport) { return servers.front(); }; //ЗАГЛУШКА здесь нужен поиск по аресу проту Srv* getcursrv() { if (cursrv != servers.end()) return (*cursrv); else return NULL; }; //получить текущий сервер или NULL void refreshcfg(); //перечитать из конфига void clear(); //удалить все соединения void nextserver(); //переключиться на след сервер в списке void prevserver(); protected: void addserver(Srv* c) { servers.push_back(c); }; std::list servers; //список соединений std::list::iterator cursrv; //текущиq сервер // Config* cfg; }; #endif //SRVDATA_H boinctui-2.7.1/src/ncolorstring.h0000664000175000017500000000451514536642777014710 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef NCOLORSTRING_H #define NCOLORSTRING_H #include #include #include #include "mbstring.h" #include "kclog.h" class NColorStringPart { public: NColorStringPart(int attr, const char* s) { this->s = s; this->attr = attr;}; NColorStringPart(int attr, const char* fmt, va_list vl); int getlen() { return mbstrlen(s.c_str()); }; //вернет длинну в ЭКРАННЫХ СИМВОЛАХ bool operator==(const NColorStringPart& v) { return (s == v.s)&&(attr == v.attr); }; NColorStringPart& operator=(const NColorStringPart& v) { s=v.s; attr=v.attr; return *this;}; std::string s; int attr; }; class NColorString { public: NColorString() { }; NColorString(int attr, const char* fmt, ...); NColorString(int attr, const char* fmt, va_list vl); NColorString(const NColorString& v) { *this=v; }; ~NColorString(); void append(int attr, const char* fmt, ...); void vappend(int attr, const char* fmt, va_list vl); std::list parts; int getlen(); //вернет длинну в ЭКРАННЫХ СИМВОЛАХ void clear() { while(!parts.empty()) { delete parts.front(); parts.remove(parts.front());} }; //очищаем строку NColorString& operator=(const NColorString& v); bool operator==(const NColorString& v); bool operator!=(const NColorString& v) { return !(*this==v); }; protected: void append(NColorStringPart* part) { parts.push_back(part); }; //добавить подстроку к строке }; #endif //NCOLORSTRING_Hboinctui-2.7.1/src/nvline.cpp0000664000175000017500000000205214536642777014005 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include "nvline.h" void NVLine::refresh() { wbkgd(win,bgcolor); wattrset(win,getcolorpair(COLOR_WHITE,getbgcolor())); if (asciilinedraw == 1) wvline(win, '|', getheight()-0); else wvline(win, ACS_VLINE, getheight()-0); NView::refresh(); };boinctui-2.7.1/src/srvdata.cpp0000664000175000017500000007663114536642777014174 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include #include #include #ifdef HAVE_OPENSSL #include #else #include #endif #include #include "srvdata.h" #include "resultparse.h" #include "kclog.h" #define STATE_TIME_INTERVAL 2 //интервал в секундах между запросами #define MSG_TIME_INTERVAL 2 //интервал в секундах между запросами #define DISKUSAGE_TIME_INTERVAL 60 //интервал в секундах между запросами #define STATISTICS_TIME_INTERVAL 300 //интервал в секундах между запросами #define CCSTATUS_TIME_INTERVAL 600 //интервал в секундах между запросами const int ERR_IN_PROGRESS = -204; const int BOINC_SUCCESS = 0; //============================================================================================= PtrList::~PtrList() { kLogPrintf("PtrList::~PtrList() list.size()=%d\n",list.size()); while(!list.empty()) { delete list.front(); list.erase(list.begin()); } pthread_mutex_destroy(&mutex); } Item* PtrList::hookptr() //получить указатель из хвоста списка { Item* result = NULL; pthread_mutex_lock(&mutex); if (!list.empty()) { list.back()->refcount++; result = list.back()->dom; } pthread_mutex_unlock(&mutex); return result; } void PtrList::releaseptr(Item* ptr) //сообщить списку что указатель больше не нужен (список сам решит нужно ли его удалять) { std::list::iterator it; pthread_mutex_lock(&mutex); //ищем элемент связанный с ptr for( it = list.begin(); it != list.end(); it++) { if ( (*it)->dom == ptr) //нашли { (*it)->refcount--; //уменьшаем счетчик ссылок } } //очищаем старые ненужные эл-ты bool done; do { done = true; for( it = list.begin(); it != list.end(); it++) { if ( ((*it) != list.back()) && ((*it)->refcount <= 0) ) //нашли (последний не трогаем) { delete (*it)->dom; delete (*it); list.erase(it); done = false; break; } } } while (!done); pthread_mutex_unlock(&mutex); } //============================================================================================= bool daily_statisticsCmpAbove( Item* stat1, Item* stat2 ) //для сортировки статистики true если дата stat1 > stat2 { Item* day1 = stat1->findItem("day"); Item* day2 = stat2->findItem("day"); if ( (day1 != NULL)&&(day2 != NULL) ) { if (day1->getdvalue() > day2->getdvalue()) return true; else return false; } return false; } //============================================================================================= SrvList::SrvList(/*Config* cfg*/) { // this->cfg = cfg; refreshcfg(); } SrvList::~SrvList() { kLogPrintf("SrvList::~SrvList() servers.size()=%d\n",servers.size()); clear(); } void SrvList::refreshcfg() //перечитать из конфига { clear(); //удаляем старые сервера (если есть) Item* boinctui_cfg = gCfg->getcfgptr(); if (boinctui_cfg == NULL) return; if(gCfg->cmdlinehost!="") { if((gCfg->cmdlinepwd=="")&&(gCfg->cmdlocalhost)) { std::string boincDataDirPath = BOINC_DIR; std::string guiRpcAuthCfgPath = boincDataDirPath + "/gui_rpc_auth.cfg"; std::ifstream ifs(guiRpcAuthCfgPath.c_str()); std::string s((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); for(auto c : s) { if(c>=0x20) gCfg->cmdlinepwd.push_back(c); } } servers.push_back(new Srv(gCfg->cmdlinehost.c_str(),gCfg->cmdlineport.c_str(),gCfg->cmdlinepwd.c_str(),"")); } std::vector slist = boinctui_cfg->getItems("server"); std::vector::iterator it; for (it = slist.begin(); it != slist.end(); it++) { Item* host = (*it)->findItem("host"); Item* port = (*it)->findItem("port"); Item* pwd = (*it)->findItem("pwd"); Item* hostid = (*it)->findItem("hostid"); if ((host != NULL)&&(port != NULL)) { std::string spwd=""; if(pwd!=NULL) spwd=pwd->getsvalue(); std::string shostid=""; if(hostid!=NULL) shostid=hostid->getsvalue(); servers.push_back(new Srv(host->getsvalue(), port->getsvalue(), spwd.c_str(), shostid.c_str())); } } if (!servers.empty()) { cursrv = servers.begin(); (*cursrv)->setactive(true); } } void SrvList::clear() //удалить все соединения { kLogPrintf("SrvList::clear()\n"); std::list::iterator it; cursrv = servers.begin(); for (it = servers.begin(); it != servers.end(); it++) //чистим все соединения { kLogPrintf("+delete server\n"); delete (*it); kLogPrintf("-server deleted success\n"); } servers.clear(); } void SrvList::nextserver() //переключиться на след сервер в списке { (*cursrv)->setactive(false); //деактивируем тред cursrv++; if (cursrv == servers.end()) //дошли до конца переходим в начало списка cursrv = servers.begin(); (*cursrv)->setactive(true); //активиркем тред } void SrvList::prevserver() { (*cursrv)->setactive(false); if (cursrv == servers.begin()) { cursrv = servers.end(); cursrv--; } else cursrv--; (*cursrv)->setactive(true); } //============================================================================================= Srv::Srv(const char* shost, const char* sport, const char* pwd, const char* hostid) : TConnect(shost, sport) { allprojectsdom = NULL; this->pwd = strdup(pwd); this->hostid = strdup(hostid); lastmsgno = 0; active = false; loginfail = false; ccstatusdomneedupdate = false; pthread_mutex_init(&mutex, NULL); } Srv::~Srv() { kLogPrintf("+Srv::~Srv() host=%s:%s\n",shost,sport); if (isactive()) { setactive(false); //завершаем опросный тред (если он есть) kLogPrintf("waiting stop...\n"); pthread_join(thread, NULL); //ждем пока тред остановится } if (allprojectsdom != NULL) delete allprojectsdom; if (pwd != NULL) delete pwd; if (hostid != NULL) delete hostid; pthread_mutex_destroy(&mutex); kLogPrintf("-Srv::~Srv()\n"); } Item* Srv::req(const char* fmt, ...) //выполнить запрос (вернет дерево или NULL) { if (hsock == -1) createconnect(); if (hsock == -1) return NULL; // === посылаем запрос === char req[1024]; strcpy(req, "\n"); strcat(req, fmt); strcat(req, "\n\n\003"); va_list args; lock(); va_start(args, fmt); sendreq(req, args); va_end(args); char* result = waitresult(); unlock(); if (result != NULL) //получен ответ { // === отрезаем теги const char* teg1 = ""; const char* teg2 = ""; char* b = strstr(result,teg1); char* e = strstr(result,teg2); if (( b == NULL)||( e == NULL)) { free(result); return NULL; } *e = '\0'; b = b + strlen(teg1); while ( (*b != '\0')&&(*b != '<') ) b++; //отрезаем лидирующие переводы строки и т.д. // === костыль ТОЛЬКО для if (strstr(fmt, "") != NULL) b = (char*)stripinvalidtag(b, strlen(b)); //убираем кривые теги // === разбираем ответ === lock(); std::string errmsg; Item* dom = xmlparse(b, strlen(b), errmsg); //парсим xml unlock(); free(result); //рез-т в тесктовом виде больше не нужен return dom; } else return NULL; } void Srv::createconnect() { lock(); TConnect::createconnect(); unlock(); loginfail = false; if (hsock != -1) loginfail = login(); } bool Srv::login() //авторизоваться на сервере { bool result = false; // if (strlen(pwd) == 0) // return true; //пароль не задан (считаем что логин серверу не требуется) //получить случайную строку (nonce) Item* r1 = req(""); if (r1 == NULL) return result; kLogPrintf("login() nonce='%s'\n", r1->toxmlstring().c_str()); Item* nonce = r1->findItem("nonce"); if ( nonce == NULL ) { delete r1; return result; } const char* snonce = r1->findItem("nonce")->getsvalue(); //расчитать хэш md5 от nonce+pwd unsigned char md5digest[MD5_DIGEST_LENGTH]; MD5_CTX c; MD5_Init(&c); MD5_Update(&c, snonce, strlen(snonce)); MD5_Update(&c, pwd , strlen(pwd)); MD5_Final(md5digest,&c); char shash[1024]; //строковое представление хэша for (int i=0;i\n%s\n",shash); kLogPrintf("login() Boinc answer ---\n%s\n", r2->toxmlstring().c_str()); if ( r2->findItem("unauthorized") != NULL ) //авторизация неуспешна result = true; delete r2; return result; } void Srv::updatestatistics() { statisticsdom.addptr(req("")); } void Srv::updateccstatus() //обновить состояние { ccstatusdom.addptr(req("")); } void Srv::updatediskusage() { dusagedom.addptr(req("")); } void Srv::updatestate() { statedom.addptr(req("")); } void Srv::updatemsgs() //обновить сообщения { Item* domtree1 = req(""); if (domtree1 == NULL) return; Item* seqno = domtree1->findItem("seqno"); if (seqno == NULL) { delete domtree1; return; } int curseqno = seqno->getivalue(); //кол-во сообщений на сервере в тек. момент delete domtree1; if (curseqno == lastmsgno) //если с прошлого вызова updatedata() новых сообщений нет, то просто выходим return; // === запрашиваем содержимое сообщений начиная с lastmsg сервере === char req2[256]; int msgno; //номер первого запрашиваемого сообщения if (lastmsgno>0) msgno = lastmsgno; //запрашиваем начиная с последнего отображенного else msgno = 0; //начинаем с первого snprintf(req2,sizeof(req2),"\n%d\n\n",msgno); Item* domtree = req(req2); if (domtree == NULL) return; // === дополняем массив визуальных строк === if (!msgdom.empty()) //если есть ранее полученные сообщения { Item* tmpmsgdom = msgdom.hookptr(); //объединяем ветку "msgs" новых сообщений с основным деревом (msgdom) msgdom.lock(); (tmpmsgdom->findItem("msgs"))->mergetree(domtree->findItem("msgs")); msgdom.unlock(); delete domtree; //очищаем рез-т msgdom.releaseptr(tmpmsgdom); } else msgdom.addptr(domtree); lastmsgno = curseqno; } void Srv::updateallprojects() { if (allprojectsdom != NULL) delete allprojectsdom; //очищаем предыдущий рез-т allprojectsdom = req(""); } void Srv::updateacctmgrinfo()//обновить статистику { acctmgrinfodom.addptr(req("")); } void Srv::opactivity(const char* op) //изменение режима активности BOINC сервера "always" "auto" "newer" { Item* d = req("<%s/>0",op); if (d != NULL) delete d; ccstatusdomneedupdate = true; } void Srv::opnetactivity(const char* op) //изменение режима активности сети "always" "auto" "newer" { Item* d = req("<%s/>0",op); if (d != NULL) delete d; ccstatusdomneedupdate = true; } void Srv::opgpuactivity(const char* op) //изменение режима активности GPU "always" "auto" "newer" { Item* d = req("<%s/>0",op); if (d != NULL) delete d; ccstatusdomneedupdate = true; } void Srv::optask(const char* url, const char* name, const char* op) //действия над задачей ("suspend_result",...) { Item* d = req("<%s>\n%s\n%s\n",op,url,name,op); if (d != NULL) delete d; } void Srv::opproject(const char* name, const char* op) //действия над проектом ("project_suspend","project_resume",...) { if (statedom.empty()) return; Item* tmpdom = statedom.hookptr(); std::string url = findProjectUrl(tmpdom,name); Item* d = req("<%s>\n%s\n",op,url.c_str(),op); statedom.releaseptr(tmpdom); if (d != NULL) delete d; } void Srv::runbenchmarks() //запустить бенчмарк { Item* d = req(""); if (d != NULL) delete d; } bool Srv::getprojectconfig(const char* url, std::string& errmsg) //получить c сервера файл конфигурации { //запрос на начало передачи Item* res = req("\n%s\n", url); if (res == NULL) return false; kLogPrintf("request=\n ?\n\n answer=\n%s\n", res->toxmlstring().c_str()); free(res); //ждем завершения bool done = false; int count = 30; //не больше 30 запросов do { res = req(""); if (res == NULL) return false; kLogPrintf("request=\n ?\n\n answer=\n%s\n", res->toxmlstring().c_str()); Item* error_num = res->findItem("error_num"); if (error_num != NULL) { int errnum = error_num->getivalue(); if (errnum == ERR_IN_PROGRESS) //ждать? sleep(1); //ERR_IN_PROGRESS ждем 1 сек else { free(res); break; } } else { Item* project_config = res->findItem("project_config"); if (project_config != NULL) done = true; else { free(res); break; } } free(res); } while((count--)&&(!done)); return done; } bool Srv::createaccount(const char* url, const char* email, const char* pass, const char* username, const char* teamname, std::string& errmsg) //создать аккаунт { kLogPrintf("createaccount(url=%s, email=%s, pass=%s, username=%s, teamname=%s)\n", url, email, pass, username, teamname); //расчитать хэш md5 от pass+email unsigned char md5digest[MD5_DIGEST_LENGTH]; MD5_CTX c; MD5_Init(&c); MD5_Update(&c, pass , strlen(pass)); MD5_Update(&c, email, strlen(email)); MD5_Final(md5digest,&c); char shash[1024]; //строковое представление хэша for (int i=0;i\n" " %s\n" " %s\n" " %s\n" " %s\n" " %s\n" "\n", url,email,shash,username,teamname); Item* res = req(sreq); if (res == NULL) return false; kLogPrintf("request=\n %s\n\n answer=\n%s\n",sreq, res->toxmlstring().c_str()); free(res); //ждем завершения int count = 30; //не больше 30 запросов snprintf(sreq,sizeof(sreq),""); bool done = false; do { res = req(sreq); if (res == NULL) return false; kLogPrintf("request=\n %s\n\n answer=\n%s\n",sreq, res->toxmlstring().c_str()); Item* error_num = res->findItem("error_num"); if ((error_num != NULL)&&(error_num->getivalue() != ERR_IN_PROGRESS)) { Item* error_msg = res->findItem("error_msg"); if (error_msg != NULL) errmsg = error_msg->getsvalue(); //возврат строки ошибки return false; } if (res->findItem("authenticator") != NULL) done = true; free(res); sleep(1); //ждем 1 сек } while((count--)&&(!done)); return true; } bool Srv::projectattach(const char* url, const char* prjname, const char* email, const char* pass, std::string& errmsg) //подключить проект { //расчитать хэш md5 от pass+email unsigned char md5digest[MD5_DIGEST_LENGTH]; MD5_CTX c; MD5_Init(&c); MD5_Update(&c, pass , strlen(pass)); MD5_Update(&c, email, strlen(email)); MD5_Final(md5digest,&c); char shash[1024]; //строковое представление хэша for (int i=0;i\n%s\n%s\n%s\n\n",url,email,shash); Item* res = req(sreq); if (res == NULL) return false; kLogPrintf("request=\n %s\n\n answer=\n%s\n",sreq, res->toxmlstring().c_str()); free(res); int count = 30; //не больше 30 запросов snprintf(sreq,sizeof(sreq),""); std::string sauthenticator; bool done = false; int maxcount = 30; do { res = req(sreq); if (res == NULL) return false; kLogPrintf("request=\n %s\n\n answer=\n%s\n",sreq, res->toxmlstring().c_str()); Item* error_num = res->findItem("error_num"); if (((error_num != NULL)||(strcmp(res->getname(),"error") == 0))&&(error_num->getivalue() != ERR_IN_PROGRESS)) { Item* error_msg = res->findItem("error_msg"); if (error_msg != NULL) errmsg += error_msg->getsvalue() + std::string(" "); if (strcmp(res->getname(),"error") == 0) errmsg += res->getsvalue(); return false; } Item* authenticator = res->findItem("authenticator"); if (authenticator != NULL) { sauthenticator = authenticator->getsvalue(); done = true; } free(res); sleep(1); //ждем 1 сек if (--maxcount < 0) { errmsg = "error timeout"; return false; } } while((count--)&&(!done)); if (!done) return false; //формируем запрос для подключения к проекту snprintf(sreq,sizeof(sreq),"\n%s\n%s\n%s\n\n",url,sauthenticator.c_str(),prjname); res = req(sreq); if (res == NULL) return false; kLogPrintf("request=\n %s\n\n answer=\n%s\n",sreq, res->toxmlstring().c_str()); Item* error = res->findItem("error"); if (error != NULL) { errmsg += error->getsvalue(); } bool result = (res->findItem("success") != NULL); free(res); return result; } bool Srv::accountmanager(const char* url, const char* username, const char* pass, bool useconfigfile, std::string& errmsg) //подключить аккаунт менеджер { if (strlen(url) > 0) { //получить конфиг (не знаю зачем!!!) if (!getprojectconfig(url,errmsg)) { errmsg = "Can't get config"; return false; } } char sreq[1024]; //формируем запрос if (useconfigfile) snprintf(sreq,sizeof(sreq),"\n\n\n"); else snprintf(sreq,sizeof(sreq),"\n%s\n%s\n%s\n\n",url,username,pass); Item* res = req(sreq); if (res == NULL) return false; kLogPrintf("request=\n %s\n\n answer=\n%s\n",sreq, res->toxmlstring().c_str()); //ждем завершения snprintf(sreq,sizeof(sreq),""); bool done = false; int count = 30; //не больше 30 запросов do { res = req(sreq); if (res == NULL) return false; kLogPrintf("request=\n %s\n\n answer=\n%s\n",sreq, res->toxmlstring().c_str()); Item* error_num = res->findItem("error_num"); if (error_num != NULL) { int errnum = error_num->getivalue(); if (errnum == BOINC_SUCCESS) //успешно done = true; else if (errnum != ERR_IN_PROGRESS) //ошибка выходим { Item* message = res->findItem("message"); if (message != NULL) errmsg = message->getsvalue(); //возврат строки ошибки free(res); return false; } else sleep(1); //ERR_IN_PROGRESS ждем 1 сек } free(res); } while((count--)&&(!done)); acctmgrinfodom.needupdate = true; //чтобы тред обновил данные sleep(1); //даем треду 1 сек на обновление kLogPrintf("RET %b\n",done); return done; } std::string Srv::findProjectName(Item* tree, const char* url) //найти в дереве tree имя проекта с заданным url { Item* client_state = tree->findItem("client_state"); if (client_state == NULL) return "ERR2"; std::vector projects = client_state->getItems("project"); //список проектов std::vector::iterator it; for (it = projects.begin(); it!=projects.end(); it++) { Item* master_url = (*it)->findItem("master_url"); if ( strcmp(url,master_url->getsvalue()) == 0 ) //url совпали НАШЛИ! { Item* project_name = (*it)->findItem("project_name"); return project_name->getsvalue(); } } return "???"; } std::string Srv::findProjectUrl(Item* tree, const char* name) //найти в дереве tree url проекта с заданным именем { Item* client_state = tree->findItem("client_state"); if (client_state == NULL) return "ERR2"; std::vector projects = client_state->getItems("project"); //список проектов std::vector::iterator it; for (it = projects.begin(); it!=projects.end(); it++) { Item* project_name = (*it)->findItem("project_name"); if ( strcmp(name, project_name->getsvalue()) == 0 ) //имена совпали НАШЛИ! { Item* master_url = (*it)->findItem("master_url"); return master_url->getsvalue(); } } return ""; } Item* Srv::findresultbyname(const char* resultname) { if (statedom.empty()) return NULL; if (resultname == NULL) return NULL; Item* tmpstatedom = statedom.hookptr(); Item* client_state = tmpstatedom->findItem("client_state"); if (client_state == NULL) { statedom.releaseptr(tmpstatedom); return NULL; } std::vector results = client_state->getItems("result"); //список задач std::vector::iterator it; for (it = results.begin(); it!=results.end(); it++) { Item* name = (*it)->findItem("name"); if ( strcmp(resultname,name->getsvalue()) == 0 ) //имена совпали НАШЛИ! { statedom.releaseptr(tmpstatedom); return (*it); } } statedom.releaseptr(tmpstatedom); return NULL; } Item* Srv::findprojectbyname(const char* projectname) { if (statedom.empty()) return NULL; if (projectname == NULL) return NULL; Item* tmpstatedom = statedom.hookptr(); Item* client_state = tmpstatedom->findItem("client_state"); if (client_state == NULL) { statedom.releaseptr(tmpstatedom); return NULL; } std::vector projects = client_state->getItems("project"); //список проектов std::vector::iterator it; for (it = projects.begin(); it!=projects.end(); it++) { Item* name = (*it)->findItem("project_name"); if ( strcmp(projectname,name->getsvalue()) == 0 ) //имена совпали НАШЛИ! { statedom.releaseptr(tmpstatedom); return (*it); } } statedom.releaseptr(tmpstatedom); return NULL; } Item* Srv::findprojectbynamefromall(const char* projectname) //ищет в allprojectsdom { if (allprojectsdom == NULL) return NULL; if (projectname == NULL) return NULL; Item* projects = allprojectsdom->findItem("projects"); if (projects == NULL) return NULL; std::vector projectlist = projects->getItems("project"); //список проектов std::vector::iterator it; for (it = projectlist.begin(); it!=projectlist.end(); it++) { Item* name = (*it)->findItem("name"); if ( strcmp(projectname,name->getsvalue()) == 0 ) //имена совпали НАШЛИ! { return (*it); } } return NULL; } Item* Srv::findaccountmanager(const char* mgrname) //ищет менеджер по имени { if (allprojectsdom == NULL) return NULL; if (mgrname == NULL) return NULL; Item* projects = allprojectsdom->findItem("projects"); if (projects == NULL) return NULL; std::vector mgrlist = projects->getItems("account_manager"); //список менеджеров std::vector::iterator it; for (it = mgrlist.begin(); it!=mgrlist.end(); it++) { Item* name = (*it)->findItem("name"); if ( strcmp(mgrname,name->getsvalue()) == 0 ) //имена совпали НАШЛИ! { return (*it); } } return NULL; } Item* Srv::findappbywuname(const char* wuname) //найти приложение для данного WU { if (statedom.empty()) return NULL; if (wuname == NULL) return NULL; Item* tmpstatedom = statedom.hookptr(); Item* client_state = tmpstatedom->findItem("client_state"); if (client_state == NULL) { statedom.releaseptr(tmpstatedom); return NULL; } std::vector wulist = client_state->getItems("workunit"); //список WU std::vector::iterator it; //ищем WU for (it = wulist.begin(); it!=wulist.end(); it++) { Item* name = (*it)->findItem("name"); if ( strcmp(wuname,name->getsvalue()) == 0 ) //имена совпали НАШЛИ WU! { Item* app_name = (*it)->findItem("app_name"); std::vector applist = client_state->getItems("app"); //список APP std::vector::iterator it2; for (it2 = applist.begin(); it2!=applist.end(); it2++) { Item* name = (*it2)->findItem("name"); if ( strcmp(app_name->getsvalue(),name->getsvalue()) == 0 ) //имена совпали НАШЛИ APP! { statedom.releaseptr(tmpstatedom); return (*it2); } } } } statedom.releaseptr(tmpstatedom); return NULL; } time_t Srv::getlaststattime() //вернет время последней имеющейся статистики { time_t result = 0; if (statisticsdom.empty()) return 0; Item* tmpstatisticsdom = statisticsdom.hookptr(); Item* statistics = tmpstatisticsdom->findItem("statistics"); if (statistics!=NULL) { std::vector project_statistics = statistics->getItems("project_statistics"); std::vector::iterator it; for (it = project_statistics.begin(); it!=project_statistics.end(); it++) //цикл списка проектов { std::vector daily_statistics = (*it)->getItems("daily_statistics"); //все дни проекта в этом векторе if (!daily_statistics.empty()) { std::sort(daily_statistics.begin(), daily_statistics.end(), daily_statisticsCmpAbove); //сортируем по убыванию дат Item* lastday = daily_statistics.front(); //последний день должен быть сверху double d = lastday->findItem("day")->getdvalue(); if (d > result) result = d; } } //проекты } statisticsdom.releaseptr(tmpstatisticsdom); return result; } time_t Srv::gettimeelapsed(time_t t) //вернет соличество секунд между t и тек. временем { return (time(NULL) - t); } void* Srv::updatethread(void* args) //трейд опрашивающий сервер { Srv* me = (Srv*)args; kLogPrintf("%s:%s::updatethread() started\n",me->gethost(),me->getport()); me->takt = 0; while(me->active) { //get data from remote server if ( me->statedom.empty() || ( (me->takt % STATE_TIME_INTERVAL) == 0 ) ) me->updatestate(); // if (me->isconnected()&&(!me->loginfail)) //если нет коннекта то пропускаем прочие запросы { if ( me->msgdom.empty() || ( (me->takt % MSG_TIME_INTERVAL) == 0 ) ) me->updatemsgs(); /// if ( me->statisticsdom.empty() || ( (me->takt % STATISTICS_TIME_INTERVAL) == 0 ) ) me->updatestatistics(); // if ( me->dusagedom.empty() || ( (me->takt % DISKUSAGE_TIME_INTERVAL) == 0 ) ) me->updatediskusage(); // if ( me->ccstatusdom.empty() || ( (me->takt % CCSTATUS_TIME_INTERVAL) == 0 ) || me->ccstatusdomneedupdate ) { me->updateccstatus(); // me->ccstatusdomneedupdate = false; } if (me->acctmgrinfodom.needupdate) me->updateacctmgrinfo(); //ин-я по аккаунт менеджеру } //спим 1 секунду проверяя me->ccstatusdomneedupdate for (int i = 0; i < 10; i++) { usleep(100000); //100 milisec if (me->ccstatusdomneedupdate) break; //прервать сон если нужен срочный апдейт } me->takt++; } kLogPrintf("%s:%s::updatethread() stopped\n",me->gethost(),me->getport()); return NULL; } void Srv::setactive(bool b) //включить/выключить тред обновления данных { if (isactive() != b) { if (b) { active = true; if ( 0 != pthread_create(&thread, NULL, updatethread, this)) kLogPrintf("pthread_create() error\n"); } else { active = false; //сигнализирует треду остановиться } } } boinctui-2.7.1/src/mainprog.h0000664000175000017500000000427114536642777014000 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef MAINPROG_H #define MAINPROG_H #include "nprogram.h" #include "msgwin.h" #include "taskwin.h" #include "mainwin.h" #include "cfgform.h" #include "cfg.h" #include "srvdata.h" #include "topmenu.h" #include "about.h" #include "helpwin.h" #include "addprojectform.h" #include "addmgrform.h" #include "taskinfowin.h" #define stUISELECTOR 1 //бит означающий что селектор задач включен #define stUIMODALFORM 2 //бит означающий что активна модальная форма #define stUITASKINFO 4 //бит означающий что активно окно и-и о задаче #define stUISTATWIN 8 //бит означающий что активно окно детальной статистики (StatWin) class MainProg : public NProgram { public: MainProg(); ~MainProg(); void smartresize(); bool mainloop(); virtual void eventhandle(NEvent* ev); //обработчик событий protected: TopMenu* menu; MainWin* wmain; NStaticText* wstatus; //Config* cfg; SrvList* gsrvlist; //глобальный список серверов bool done; //флаг требования завершения // void setcaption(); time_t evtimertime; //time of last evTIMER unsigned int uistate; //маска состояния интерфейса void updatestatuslinecontent(); }; #endif //MAINPROG_H boinctui-2.7.1/src/nscrollview.h0000664000175000017500000000563114536642777014534 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef NSCROLLVIEW_H #define NSCROLLVIEW_H #include #include "nview.h" #include "ncolorstring.h" #include "nscrollbar.h" class NScrollView : public NView //область со скроллингом { public: NScrollView(NRect rect, NScrollBar* scrollbar = NULL) : NView(rect) { this->scrollbar=scrollbar; startindex = 0; autoscroll = false; needrefresh = true;}; virtual ~NScrollView(); void addstring(int attr, const char* fmt, ...); void addstring(NColorString* s) { content.push_back(s); needrefresh = true; }; //добавляет строку void eventhandle(NEvent* ev); //обработчик событий void clearcontent(); //очищает строковый буфер virtual void drawcontent(); //отрисовывает буфер строк void scrollto(int delta); //сдвинуть отображение на drlta строк вверх или вниз void setstartindex(int n); //установить отображение со строки n int getstartindex() { return startindex; }; //получить номер первой видимой строки int getmaxcontentwidth(); //вернет максимальную длину строки (в экранных символях) в content bool getautoscroll() { return autoscroll; }; //true если включен режим автоскроллинга void setautoscroll(bool b); //true чтобы включить автоскроллинг void setscrollbar(NScrollBar* scrollbar) { this->scrollbar = scrollbar; }; virtual void resize(int rows, int cols); virtual void refresh(); int getstringcount() { return content.size();}; //число строк protected: std::vector content; //массив строк с цветовыми аттрибутами int startindex; //номер первой видимой строки bool autoscroll; //если true то будет прокручивать автоматом до конца NScrollBar* scrollbar; //скроллбар для этого эл-та (NULL если нет) }; #endif //NSCROLLVIEW_Hboinctui-2.7.1/src/nmenu.cpp0000664000175000017500000002211414536642777013635 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include "nmenu.h" #include "kclog.h" NMenu::NMenu(NRect rect, bool horis) : NGroup(rect) { mitems = NULL; ishoris = horis; posted = false; menu = new_menu(mitems); setbackground(getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD); setforeground(getcolorpair(COLOR_BLACK,COLOR_WHITE)); set_menu_grey(menu, getcolorpair(COLOR_RED,getbgcolor())); //цвет разделителей set_menu_win(menu, win); postmenu(); if (horis) scrollbar = NULL; else { scrollbar = new NScrollBar(NRect(getheight(),1, 1, getwidth()-1), 0, 0, ACS_VLINE | A_BOLD); insert(scrollbar); } } NMenu::~NMenu() { //kLogPrintf("NMenu::~NMenu()\n"); unpostmenu(); if (!ishoris) delwin(menu_sub(menu)); free_menu(menu); //освобождаем строки std::list::iterator it; for (it = itemnames.begin(); it != itemnames.end(); it++) { delete (*it); } for (it = itemcomments.begin(); it != itemcomments.end(); it++) { delete (*it); } //массив эл-тов if (mitems != NULL) { int i = 0; while (mitems[i] != NULL) free_item(mitems[i++]); free(mitems); } } void NMenu::destroysubmenu() //закрыть субменю { std::list::iterator it; bool done = false; while (!done) { done = true; for (it = items.begin(); it != items.end(); it++) { if (scrollbar==*it) continue; //подпорка delete *it; remove (*it); done = false; break; } } } void NMenu::additem(const char* name, const char* comment) //добавить эл-т в меню { unpostmenu(); mitems = (ITEM**)realloc(mitems,(itemnames.size()+1)*sizeof(ITEM*)); if(mitems==NULL) return; if (name == NULL) //финализация списка { mitems[itemnames.size()] = NULL; set_menu_items(menu, mitems); set_menu_mark(menu, " "); if ( !ishoris ) //для вертикальных есть рамка { int lines = itemnames.size(); //видимых эл-тов if ((lines>2)&&(lines + getbegrow() > getmaxy(stdscr) - 8)) lines = getmaxy(stdscr)-getbegrow() - 8; set_menu_format(menu, lines, 1); resize(lines+2,menu->width+3); //изменяем размер под кол-во эл-тов set_menu_sub(menu,derwin(win,getheight()-2,getwidth()-2,1,1)); if(asciilinedraw == 1) wborder(win, '|', '|', '-', '-', '+', '+', '+', '+'); else box(win,0,0); //рамка if (scrollbar) { scrollbar->resize(getheight()-2,1); scrollbar->move(1,getwidth()-1); scrollbar->setpos(0,itemnames.size(),top_row(menu),top_row(menu)+getheight()-2); scrollbar->refresh(); } } else //горизонтальное { set_menu_format(menu, 1, itemnames.size()); set_menu_sub(menu,derwin(win,getheight(),getwidth(),0,0)); menu_opts_off(menu, O_ROWMAJOR); menu_opts_off(menu, O_SHOWDESC); set_menu_mark(menu, " "); } //set_menu_win(menu, win); menu_opts_off(menu,O_SHOWMATCH); postmenu(); } else { if (strlen(name) > 0) { itemnames.push_back(strdup(name)); itemcomments.push_back(strdup(comment)); mitems[itemnames.size()-1] = new_item(itemnames.back(),itemcomments.back()); } else { itemnames.push_back(strdup(" ")); itemcomments.push_back(strdup(" ")); mitems[itemnames.size()-1] = new_item(itemnames.back(),itemcomments.back()); item_opts_off(mitems[itemnames.size()-1], O_SELECTABLE); } } } void NMenu::refresh() { //int rows, cols; //menu_format(menu, &rows, &cols); if (getheight() == 1) //только для горизонтального меню { //закрашиваем фоном правую часть строки wattrset(win,bgattr); wmove(win,0,menu->width); //clrtoeol(); int x,y; do { getyx(win, y, x); wprintw(win," "); } while (x < getwidth() - 1); //wattrset(win,0); } if (scrollbar) { scrollbar->setpos(0,itemnames.size(),top_row(menu),top_row(menu)+getheight()-2); scrollbar->refresh(); } NGroup::refresh(); } void NMenu::eventhandle(NEvent* ev) //обработчик событий { if ( ev->done ) return; //событие уже обработано кем-то ранее //отправляем всем подменю NGroup::eventhandle(ev); if ( ev->done ) return; //выходим если какое-то подменю обработало событие //пытаемся обработать самостоятельно int y,x; menu_format(menu, &y, &x); NMouseEvent* mevent = (NMouseEvent*)ev; //колесо прокрутки мыши if ( ev->type == NEvent::evMOUSE ) { if (isinside(mevent->row, mevent->col)) { //колесо вверх #if NCURSES_MOUSE_VERSION > 1 if (mevent->cmdcode & BUTTON4_PRESSED) //NOT TESTED #else if (mevent->cmdcode & BUTTON4_PRESSED) #endif { if ( y > 1 ) { if (item_index(current_item(menu)) > 0) //элемент не первый { //ITEM* preditem = mitems[item_index(current_item(menu)) - 1]; //предыдущий menu_driver(menu, REQ_SCR_UPAGE); } ev->done = true; } } //колесо вниз #if NCURSES_MOUSE_VERSION > 1 if (mevent->cmdcode & BUTTON5_PRESSED) //NOT TESTED #else if ( mevent->cmdcode & (BUTTON2_PRESSED | REPORT_MOUSE_POSITION)) //REPORT_MOUSE_POSITION подпорка иначе теряет эвенты при быстрой прокрутке вниз #endif { if ( y > 1 ) //вертикальное { ITEM* nextitem = mitems[item_index(current_item(menu)) + 1]; //какой следующий if (nextitem != NULL) //элемент не последний menu_driver(menu, REQ_SCR_DPAGE); ev->done = true; } } } } //одиночный или двойной клик if (( ev->type == NEvent::evMOUSE ) && (((mevent->cmdcode & BUTTON1_CLICKED))||((mevent->cmdcode & BUTTON1_DOUBLE_CLICKED)))) { if (isinside(mevent->row, mevent->col)) { int n; if (y > 1) //вертикальное n = mevent->row - getabsbegrow() - 1 + menu->toprow; else //горизонтальное n = mevent->col/(menu->itemlen+menu->spc_cols) - getabsbegcol(); if ((n >= 0)&&(n < item_count(menu))) { if ( (item_opts(mitems[n]) & O_SELECTABLE) != 0 ) { set_current_item(menu, mitems[n]); //сделеть n-ный активным destroysubmenu(); //закрыть субменю if ((y == 1)||(mevent->cmdcode & BUTTON1_DOUBLE_CLICKED)) action(); //putevent(new NEvent(NEvent::evKB, KEY_ENTER)); //открыть соотв субменю } ev->done = true; } } } if ( ev->type == NEvent::evKB ) { ev->done = true; switch(ev->keycode) { case KEY_ENTER: case '\n': action(); break; /* case KEY_RIGHT: if ( x > 1) menu_driver(menu, REQ_RIGHT_ITEM); else ev->done = false; break; case KEY_LEFT: if ( x > 1 ) menu_driver(menu, REQ_LEFT_ITEM); else ev->done = false; break; */ case KEY_UP: if ( y > 1 ) { if (item_index(current_item(menu)) > 0) //элемент не первый { ITEM* preditem = mitems[item_index(current_item(menu)) - 1]; //предыдущий menu_driver(menu, REQ_UP_ITEM); if ( (item_opts(preditem) & O_SELECTABLE) == 0 ) menu_driver(menu, REQ_UP_ITEM); //чтобы пропустить разделитель } } else ev->done = false; break; case KEY_DOWN: if ( y > 1 ) //вертикальное { ITEM* nextitem = mitems[item_index(current_item(menu)) + 1]; //какой следующий if (nextitem != NULL) //элемент не последний { menu_driver(menu, REQ_DOWN_ITEM); if ( (item_opts(nextitem) & O_SELECTABLE) == 0 ) menu_driver(menu, REQ_DOWN_ITEM); //чтобы пропустить разделитель } } else ev->done = false; break; default: //если событие нам неизвестно, то отказываемся от его //обработки (снимаем флаг done) ev->done = false; } //switch } if (ev->done) //если обработали, то нужно перерисоваться refresh(); } boinctui-2.7.1/src/taskinfowin.cpp0000664000175000017500000002764214536642777015062 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012-2014 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include #include "kclog.h" #include "taskinfowin.h" std::string raw2hr (Item* item) { std::stringstream result; if ( 0 == strcmp(item->getname(), "fraction_done") ) { double d = item->getdvalue(); result << std::setprecision(4) << d*100 << " %"; } if ( 0 == strcmp(item->getname(), "active_task_state") ) { int i = item->getivalue(); switch (i) { case 0: result << "uninitialized"; break; case 1: result << "executing"; break; case 9: result << "suspended"; break; case 5: result << "abort pending"; break; case 8: result << "quit pending"; break; case 10: result << "copy pending"; break; }//switch } if ( 0 == strcmp(item->getname(), "scheduler_state") ) { int i = item->getivalue(); switch (i) { case 1: result << "preempted"; break; case 2: result << "scheduled"; break; }//switch } if ( 0 == strcmp(item->getname(), "state") ) { int i = item->getivalue(); switch (i) { case 0: result << "new"; break; case 1: result << "downloading"; break; case 2: result << "downloaded"; break; case 3: result << "compute error"; break; case 4: result << "uploading"; break; case 5: result << "uploaded"; break; case 6: result << "aborted"; break; case 7: result << "upload failed"; break; }//switch } if ( 0 == strcmp(item->getname(), "exit_status") ) { int i = item->getivalue(); switch (i) { case 192: result << "exit statfile write"; break; case 193: result << "exit signal"; break; case 194: result << "aborted by client"; break; case 195: result << "exit child failed"; break; case 196: result << "exit disk limit exceeded"; break; case 197: result << "exit time limit exceeded"; break; case 198: result << "exit mem limit exceeded"; break; case 199: result << "exit client exiting"; break; case 200: result << "exit unstarted late"; break; case 201: result << "exit missing coproc"; break; case 202: result << "exit aborted by project"; break; case 203: result << "aborted via gui"; break; case 204: result << "exit unknown"; break; }//switch } if ( !strcmp(item->getname(), "received_time") || !strcmp(item->getname(), "report_deadline") || !strcmp(item->getname(), "completed_time") ) { time_t t = (time_t)item->getdvalue(); std::string s = ctime(&t); if (s.size() > 0) s.resize(s.size()-1); //убрать символ \n в конце result << s; } if ( !strcmp(item->getname(), "estimated_cpu_time_remaining") || !strcmp(item->getname(), "current_cpu_time") || !strcmp(item->getname(), "final_cpu_time") || !strcmp(item->getname(), "final_elapsed_time") || !strcmp(item->getname(), "checkpoint_cpu_time") || !strcmp(item->getname(), "elapsed_time") ) { time_t t = (time_t)item->getdvalue(); time_t t2; int days = t / (24 * 3600); t2 = t - (days * 24 * 3600); int hours = t2 / 3600; t2 = t2 - hours * 3600; int mins = t2 / 60; int secs = t2 - mins * 60; if (days) result << days << "d " << hours << "h " << mins << "m " << secs << "s"; else { if (hours) result << hours << "h " << mins << "m " << secs << "s"; else { if (mins) result << mins << "m " << secs << "s"; else result << secs << "s"; } } } if( !strcmp(item->getname(), "swap_size") || !strcmp(item->getname(), "working_set_size") || !strcmp(item->getname(), "working_set_size_smoothed") ) { double d = item->getdvalue()/(1024*1024*1024); if (d < 1) { d *= 1024; result << std::setprecision(4) << d << "MB"; } else { result << std::setprecision(4) << d << "GB"; } } return result.str(); } void Tree2Text(Item* item, std::vector >& vout, int& maxlen1, int& maxlen2) { std::vector v = item->getItems(""); //получить все эл-ты std::vector::iterator it2; for (it2 = v.begin(); it2!=v.end(); it2++) //цикл по эл-там задачи { if ((*it2)->isnode()) { vout.push_back(std::pair( "", "")); //разделитель Tree2Text(*it2, vout, maxlen1, maxlen2); //рекурсия vout.push_back(std::pair( "", "")); //разделитель } else { std::string sval = (*it2)->getsvalue(); std::string svalhr = raw2hr(*it2); if (svalhr.length()) sval = sval + " (" + svalhr + ")"; if ((int)strlen((*it2)->getname()) > maxlen1) maxlen1 = strlen((*it2)->getname()); if ((int)sval.length()/*strlen((*it2)->getsvalue())*/ > maxlen2) maxlen2 = sval.length() /*strlen((*it2)->getsvalue())*/; vout.push_back(std::pair((*it2)->getname(), sval/*(*it2)->getsvalue()*/)); } } } //поиск в векторе v переменной с именем varname. Вернет значение или "" std::string FindVar(std::vector >& v, std::string& varname) { std::string result = ""; std::vector >::iterator it; for (it = v.begin(); it!=v.end(); it++) { if ((*it).first == varname) { result = (*it).second; break; } } return result; } // ============================================================================= TaskInfoWin::TaskInfoWin(const char* caption, Srv* srv, const char* projecturl, const char* taskname) : NGroup(NRect(getmaxy(stdscr) - 10, getmaxx(stdscr) - 60, 3, 3)) { modalflag = true; this->srv = srv; this->projecturl = projecturl; this->taskname = taskname; this->caption = " "; this->caption = this->caption + caption; this->caption = this->caption + " "; content = new NScrollView(NRect(getheight()-4, getwidth()-4, 2, 2)); insert(content); updatedata(); //корректируем высоту в меньшую сторону если возможно if (content->getstringcount() < content->getheight()) { content->resize(content->getstringcount(), content->getwidth()); resize(content->getheight() + 4, getwidth()); } //растягиваем по ширине content->resize(content->getheight(), maxlen1 + maxlen2 + 10); resize(getheight(), content->getwidth() + 4); if (getwidth() > getmaxx(stdscr) - 10) //если слишком широко обрезаем { resize(getheight(), getmaxx(stdscr) - 10); content->resize(content->getheight(), getwidth() - 4); } if(asciilinedraw == 1) wborder(win, '|', '|', '-', '-', '+', '+', '+', '+'); else box(win,0,0); mvwprintw(win,0,getwidth()/2-(strlen(caption)/2), "%s",this->caption.c_str()); scrollbar = new NScrollBar(NRect(content->getheight()+2,1, content->getbegrow()-1, getwidth()-1), 0, 0, ACS_VLINE); content->setscrollbar(scrollbar); insert(scrollbar); refresh(); } void TaskInfoWin::updatedata() { if (srv == NULL) return; //===данные по процессам=== if (srv->statedom.empty()) return; Item* tmpstatedom = srv->statedom.hookptr(); Item* client_state = tmpstatedom->findItem("client_state"); std::vector > ss; maxlen1 = 0; maxlen2 = 0; int oldstartindex = content->getstartindex(); if (client_state != NULL) { content->clearcontent(); std::vector results = client_state->getItems("result"); std::vector::iterator it; for (it = results.begin(); it!=results.end(); it++) //цикл списка задач { Item* project_url = (*it)->findItem("project_url"); Item* name = (*it)->findItem("name"); if ((project_url != NULL)&& (name != NULL)&& (strcmp(project_url->getsvalue(), projecturl.c_str()) == 0)&& (strcmp(name->getsvalue(), taskname.c_str()) == 0)) { //имя проекта std::string pname = srv->findProjectName(tmpstatedom, (*it)->findItem("project_url")->getsvalue()); ss.push_back(std::pair("PROJECT NAME", pname)); //имя приложения char buf[256]; snprintf(buf, sizeof(buf),"%s","unknown application"); Item* wu_name = (*it)->findItem("wu_name"); if (wu_name != NULL) { Item* app = srv->findappbywuname(wu_name->getsvalue()); if (app != NULL) { Item* user_friendly_name = app->findItem("user_friendly_name"); if (user_friendly_name != NULL) snprintf(buf, sizeof(buf),"%s",user_friendly_name->getsvalue()); } } ss.push_back(std::pair("APP NAME", buf)); ss.push_back(std::pair("", "")); //raw данные Tree2Text(*it, ss, maxlen1, maxlen2); break; } } //цикл списка задач needrefresh = true; } srv->statedom.releaseptr(tmpstatedom); //заполняем визуальные строки std::vector >::iterator it; for (it = ss.begin(); it!=ss.end(); it++) { int varcolor = getcolorpair(COLOR_WHITE, getbgcolor()) | A_BOLD; int valcolor = getcolorpair(COLOR_WHITE, getbgcolor()) | A_BOLD; if ((FindVar(ssbak, (*it).first) != (*it).second)&&(!ssbak.empty())) valcolor = getcolorpair(COLOR_CYAN, getbgcolor()) | A_BOLD; NColorString* cs = new NColorString(varcolor, "%-*s ", maxlen1, (*it).first.c_str()); cs->append(valcolor, "%s\n", (*it).second.c_str()); content->addstring(cs); } ssbak = ss; content->setstartindex(oldstartindex); } void TaskInfoWin::eventhandle(NEvent* ev) //обработчик событий { NGroup::eventhandle(ev); //предок if ( ev->done ) return; //реакция на мышь NMouseEvent* mevent = (NMouseEvent*)ev; if ( ev->type == NEvent::evMOUSE ) { //блокируем все что внутри if (isinside(mevent->row, mevent->col)) ev->done = true; //закрываем при любом клике независимо от координат if (mevent->cmdcode & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED)) { putevent(new NEvent(NEvent::evKB, 27)); ev->done = true; } } //клавиатура if ( ev->type == NEvent::evKB ) { ev->done = true; switch(ev->keycode) { case KEY_PPAGE: content->scrollto(-getheight()/2); //вверх на полокна content->setautoscroll(false); break; case KEY_NPAGE: if (!content->getautoscroll()) { int oldpos = content->getstartindex(); content->scrollto(getheight()/2); //вниз на пол окна if ( oldpos == content->getstartindex()) //позиция не изменилась (уже достигли конца) content->setautoscroll(true); //включаем автоскроллинг } break; default: //блокировать все клавиатурные кроме кода закрытия формы if (ev->keycode == 27) ev->done = false; } //switch if (ev->done) //если обработали, то нужно перерисоваться refresh(); } if ( ev->type == NEvent::evTIMER ) { updatedata(); //запросить данные с сервера refresh(); //перерисовать окно } } boinctui-2.7.1/src/topmenu.cpp0000664000175000017500000010477514536642777014220 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include "topmenu.h" #include "tuievent.h" #include "kclog.h" //Названия пунктов верхнего меню #define M_FILE "File" #define M_VIEW "View" #define M_PROJECTS "Projects" #define M_TASKS "Tasks" #define M_ACTIVITY "Activity" #define M_HELP "Help" //Названия пунктов меню "File" #define M_NEXT_HOST "Next BOINC host" #define M_PREV_HOST "Prev BOINC host" #define M_CONFIG_HOSTS "Configure host list" #define M_VIEW_STATS "View Statistics" #define M_RUN_BENCHMARKS "Run CPU benchmarks" #define M_QUIT "Quit boinctui" //Названия пунктов меню "View" #define M_VIEW_NUMBER "Task number column" #define M_VIEW_STATE "Task state column" #define M_VIEW_DONE "Percent done column" #define M_VIEW_PROJECT "Project name column" #define M_VIEW_ESTIMATE "Estimate time column" #define M_VIEW_RCV "Receive time column" #define M_VIEW_DEADLINE "Deadline time column" #define M_VIEW_APPNAME "Application name column" #define M_VIEW_SWAP "Swap size column" #define M_VIEW_TASKNAME "Task name column" #define M_ALL_TASKS "All tasks" #define M_HIDE_DONE "Hide done tasks" #define M_ACTIVE_ONLY "Active tasks only" #define M_UNSORTED "Unsorted tasks list" #define M_SORT_BY_STATE "Sort by state" #define M_SORT_BY_DONE "Sort by done %" #define M_SORT_BY_PROJECT "Sort by project name" #define M_SORT_BY_ESTIMATE "Sort by estimate time" #define M_SORT_BY_RCV "Sort by receive time" #define M_SORT_BY_DL "Sort by deadline" #define M_SORT_BY_APP "Sort by application" #define M_SORT_BY_SWAP "Sort by swap size" #define M_SORT_BY_TASK "Sort by task name" #define M_ASCII_LINE_DRAW "ASCII line draw" #define M_TRANSPARENT_BG "Transparent background" //Названия пунктов меню "Projects" #define M_ADD_PROJECT "Add project" #define M_ADD_PROJECT_BY_URL "Add project by URL" #define M_CONNECT_MANAGER "Connect to account manager" #define M_SYNCHRONIZE_MANAGER "Synchronize with manager" #define M_DISCONNECT_MANAGER "Stop using account manager" //Меню списка менеджеров #define M_ADD_NEW_MGR "Add new account manager" //Названия пунктов подменю "Projects/Имя проекта" #define M_UPDATE_PROJECT "Update project" #define M_SUSPEND_PROJECT "Suspend project" #define M_RESUME_PROJECT "Resume project" #define M_NO_NEW_TASKS_PROJECT "No new tasks" #define M_ALLOW_NEW_TASKS_PROJECT "Allow new tasks" #define M_RESET_PROJECT "Reset project" #define M_DETACH_PROJECT "Detach project" //Названия пунктов меню "Add project/User Exist" #define M_PROJECT_USER_EXIST "Existing user" #define M_PROJECT_NEW_USER "Create new user account" //Названия пунктов меню "Tasks" #define M_SUSPEND_TASK "Suspend task" #define M_RESUME_TASK "Resume task" #define M_ABORT_TASK "Abort task" #define M_INFO_TASK "View raw task info" //Названия пунктов меню "Activity" #define M_ACTIVITY_ALWAYS "Run always" #define M_ACTIVITY_AUTO "Run based on preferences" #define M_ACTIVITY_NEVER "Suspend" #define M_GPU_ACTIVITY_ALWAYS "GPU run always" #define M_GPU_ACTIVITY_AUTO "GPU run based on preferences" #define M_GPU_ACTIVITY_NEVER "GPU suspend" #define M_NET_ACTIVITY_ALWAYS "Network activity always available" #define M_NET_ACTIVITY_AUTO "Network activity based on preferences" #define M_NET_ACTIVITY_NEVER "Network activity suspend" //Названия пунктов меню "Help" #define M_ABOUT "About" #define M_KEY_BINDINGS "Hot keys list" TopMenu::TopMenu(/*Config* cfg*/) : NMenu(NRect(1,getmaxx(stdscr),0,0),true) { setserver(NULL); //this->cfg = cfg; additem(M_FILE,""); additem(M_VIEW,""); additem(M_PROJECTS,""); additem(M_TASKS,""); additem(M_ACTIVITY,""); additem(M_HELP,""); additem(NULL,NULL); setbackground(getcolorpair(COLOR_WHITE,COLOR_GREEN)|A_BOLD); enableflag = true; disable(); } bool TopMenu::action() //открыть субменю { bool result = false; if (!items.empty()) //если уже открыто выходим return false; //создаем подменю int begincol = (menu->itemlen+menu->spc_cols)*item_index(current_item(menu)) + menu->spc_cols; //смещение на экране по горизонтали if ( strcmp(item_name(current_item(menu)),M_FILE) == 0 ) { insert(new FileSubMenu(NRect(5,25,1, begincol))); result = true; } if ( strcmp(item_name(current_item(menu)),M_VIEW) == 0 ) { insert(new ViewSubMenu(NRect(5,25,1, begincol)/*, cfg*/)); result = true; } if ( strcmp(menu->curitem->name.str,M_PROJECTS) == 0 ) { insert(new ProjectsSubMenu(NRect(5,25,1, begincol), srv)); result = true; } if ( strcmp(item_name(current_item(menu)),M_TASKS) == 0 ) { insert(new TasksSubMenu(NRect(5,25,1, begincol))); result = true; } if ( strcmp(item_name(current_item(menu)),M_ACTIVITY) == 0 ) { insert(new ActivitySubMenu(NRect(5,25,1, begincol), srv)); result = true; } if ( strcmp(item_name(current_item(menu)),M_HELP) == 0 ) { insert(new HelpSubMenu(NRect(5,25,1, begincol))); result = true; } return result; } void TopMenu::eventhandle(NEvent* ev) //обработчик событий { if ( !isenable() /*&& ( ev->type != NEvent::evMOUSE)*/ ) { if ( ev->type == NEvent::evMOUSE) { NMouseEvent* mevent = (NMouseEvent*)ev; if ((mevent->cmdcode & BUTTON1_CLICKED) && (isinside(mevent->row, mevent->col))) enable(); //влючить по клику } else return; //не обрабатывать клавиатурные если меню не активно } if ( ev->done ) return; //не обрабатывать если уже обработано кем-то ранее //отправляем событие всем подменю NMenu::eventhandle(ev); //предок if ( ev->done ) return; //выход если какое-то подменю отработало событие //пытаемся обработать самостоятельно if ( ev->type == NEvent::evKB ) { ev->done = true; switch(ev->keycode) { case KEY_ENTER: case '\n': if (!createsubmenu()) ev->done = false; //пусть обрабатывает владелец break; case KEY_UP: //открыть подменю по стрелкевверх case KEY_DOWN: //открыть подменю по стрелкевниз action(); break; case 27: if ( !items.empty() ) destroysubmenu(); else ev->done = false; //пусть обрабатывает владелец break; case KEY_RIGHT: menu_driver(menu, REQ_RIGHT_ITEM); if ( !items.empty() ) //подменю открыто { destroysubmenu(); //закрыть старое action(); //открыть новое } break; case KEY_LEFT: menu_driver(menu, REQ_LEFT_ITEM); if ( !items.empty() ) //подменю открыто { destroysubmenu(); //закрыть старое action(); //открыть новое } break; default: ev->done = false; //нет реакции на этот код } //switch } //если клик мыши до сих пор не обработан //значит он за пределами меню и меню нужно гасить if ( ev->type == NEvent::evMOUSE) { NMouseEvent* mevent = (NMouseEvent*)ev; if ((mevent->cmdcode & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED)) && (!ev->done)) disable(); //выключить по клику вне меню } if (ev->done) //если обработали, то нужно перерисоваться refresh(); } //============================================================================================= FileSubMenu::FileSubMenu(NRect rect) : NMenu(rect) { additem(M_NEXT_HOST," N"); additem(M_PREV_HOST," P"); additem(M_CONFIG_HOSTS," C"); additem(M_VIEW_STATS," V"); additem(M_RUN_BENCHMARKS,""); additem(M_QUIT," Q"); additem(NULL,NULL); } bool FileSubMenu::action() { putevent(new NEvent(NEvent::evKB, KEY_F(9))); //закрыть осн меню if ( strcmp(item_name(current_item(menu)),M_NEXT_HOST) == 0 ) putevent(new NEvent(NEvent::evKB, 'N')); //создаем событие иммитирующее нажатие 'N' if ( strcmp(item_name(current_item(menu)),M_PREV_HOST) == 0 ) putevent(new NEvent(NEvent::evKB, 'P')); if ( strcmp(item_name(current_item(menu)),M_CONFIG_HOSTS) == 0 ) putevent(new NEvent(NEvent::evKB, 'C')); //создаем событие иммитирующее нажатие 'C' if ( strcmp(item_name(current_item(menu)),M_VIEW_STATS) == 0 ) putevent(new NEvent(NEvent::evKB, 'V')); //создаем событие иммитирующее нажатие 'V' if ( strcmp(item_name(current_item(menu)),M_RUN_BENCHMARKS) == 0 ) putevent(new TuiEvent(evBENCHMARK)); //NEvent(NEvent::evPROG, 5)); //создаем событие запускающее бенчмарк if ( strcmp(item_name(current_item(menu)),M_QUIT) == 0 ) putevent(new NEvent(NEvent::evKB, 'Q')); //создаем событие иммитирующее нажатие 'Q' return true; } //============================================================================================= ViewSubMenu::ViewSubMenu(NRect rect/*, Config* cfg*/) : NMenu(rect) { int colnum = 0; additem(M_VIEW_NUMBER, iscolenable(/*cfg,*/colnum++) ? "[*]" : "[ ]"); additem(M_VIEW_STATE, iscolenable(/*cfg,*/colnum++) ? "[*]" : "[ ]"); additem(M_VIEW_DONE, iscolenable(/*cfg,*/colnum++) ? "[*]" : "[ ]"); additem(M_VIEW_PROJECT, iscolenable(/*cfg,*/colnum++) ? "[*]" : "[ ]"); additem(M_VIEW_ESTIMATE, iscolenable(/*cfg,*/colnum++) ? "[*]" : "[ ]"); additem(M_VIEW_RCV, iscolenable(/*cfg,*/colnum++) ? "[*]" : "[ ]"); additem(M_VIEW_DEADLINE, iscolenable(/*cfg,*/colnum++) ? "[*]" : "[ ]"); additem(M_VIEW_APPNAME, iscolenable(/*cfg,*/colnum++) ? "[*]" : "[ ]"); additem(M_VIEW_SWAP, iscolenable(/*cfg,*/colnum++) ? "[*]" : "[ ]"); additem(M_VIEW_TASKNAME, iscolenable(/*cfg,*/colnum++) ? "[*]" : "[ ]"); additem("",""); int taskslistmode = 0; if (gCfg != NULL) { Item* rootcfg = gCfg->getcfgptr(); if (rootcfg != NULL) { Item* tasks_list_mode = rootcfg->findItem("tasks_list_mode"); taskslistmode = tasks_list_mode->getivalue(); } } additem(M_ALL_TASKS, (taskslistmode == 0) ? "(*)" : "( )"); additem(M_HIDE_DONE, (taskslistmode == 1) ? "(*)" : "( )"); additem(M_ACTIVE_ONLY, (taskslistmode == 2) ? "(*)" : "( )"); additem("",""); int taskssortmode = 0; if (gCfg != NULL) { Item* rootcfg = gCfg->getcfgptr(); if (rootcfg != NULL) { Item* tasks_sort_mode = rootcfg->findItem("tasks_sort_mode"); taskssortmode = tasks_sort_mode->getivalue(); } } additem(M_UNSORTED, (taskssortmode == 0) ? "(*)" : "( )"); additem(M_SORT_BY_STATE, (taskssortmode == 1) ? "(*)" : "( )"); additem(M_SORT_BY_DONE, (taskssortmode == 2) ? "(*)" : "( )"); additem(M_SORT_BY_PROJECT, (taskssortmode == 3) ? "(*)" : "( )"); additem(M_SORT_BY_RCV, (taskssortmode == 4) ? "(*)" : "( )"); additem(M_SORT_BY_ESTIMATE, (taskssortmode == 5) ? "(*)" : "( )"); additem(M_SORT_BY_DL, (taskssortmode == 6) ? "(*)" : "( )"); //additem(M_SORT_BY_APP, (taskssortmode == 7) ? "(*)" : "( )"); //not implemented yet additem(M_SORT_BY_SWAP, (taskssortmode == 8) ? "(*)" : "( )"); additem(M_SORT_BY_TASK, (taskssortmode == 9) ? "(*)" : "( )"); additem("",""); additem(M_ASCII_LINE_DRAW, (asciilinedraw == 1) ? "[*]" : "[ ]"); additem(M_TRANSPARENT_BG, (transparentbg == 1) ? "[*]" : "[ ]"); additem(NULL,NULL); } bool ViewSubMenu::iscolenable(/*Config* cfg,*/ int n) { bool result = false; //читаем из конфига if (gCfg != NULL) { Item* rootcfg = gCfg->getcfgptr(); if (rootcfg != NULL) { Item* column_view_mask = rootcfg->findItem("column_view_mask"); unsigned int columnmask = column_view_mask->getivalue(); result = (1 << n) & columnmask; } } return result; } bool ViewSubMenu::action() { putevent(new NEvent(NEvent::evKB, KEY_F(9))); //закрыть осн меню if ( strcmp(item_name(current_item(menu)),M_ALL_TASKS) == 0 ) { putevent(new TuiEvent(evVIEWMODECH, 0)); return true; } if ( strcmp(item_name(current_item(menu)),M_HIDE_DONE) == 0 ) { putevent(new TuiEvent(evVIEWMODECH, 1)); return true; } if ( strcmp(item_name(current_item(menu)),M_ACTIVE_ONLY) == 0 ) { putevent(new TuiEvent(evVIEWMODECH, 2)); return true; } if ( strcmp(item_name(current_item(menu)), M_UNSORTED) == 0 ) { putevent(new TuiEvent(evSORTMODECH, 0)); return true; } if ( strcmp(item_name(current_item(menu)), M_SORT_BY_STATE) == 0 ) { putevent(new TuiEvent(evSORTMODECH, 1)); return true; } if ( strcmp(item_name(current_item(menu)), M_SORT_BY_DONE) == 0 ) { putevent(new TuiEvent(evSORTMODECH, 2)); return true; } if ( strcmp(item_name(current_item(menu)), M_SORT_BY_PROJECT) == 0 ) { putevent(new TuiEvent(evSORTMODECH, 3)); return true; } if ( strcmp(item_name(current_item(menu)), M_SORT_BY_RCV) == 0 ) { putevent(new TuiEvent(evSORTMODECH, 4)); return true; } if ( strcmp(item_name(current_item(menu)), M_SORT_BY_ESTIMATE) == 0 ) { putevent(new TuiEvent(evSORTMODECH, 5)); return true; } if ( strcmp(item_name(current_item(menu)), M_SORT_BY_DL) == 0 ) { putevent(new TuiEvent(evSORTMODECH, 6)); return true; } if ( strcmp(item_name(current_item(menu)), M_SORT_BY_APP) == 0 ) { putevent(new TuiEvent(evSORTMODECH, 7)); return true; } if ( strcmp(item_name(current_item(menu)), M_SORT_BY_SWAP) == 0 ) { putevent(new TuiEvent(evSORTMODECH, 8)); return true; } if ( strcmp(item_name(current_item(menu)), M_SORT_BY_TASK) == 0 ) { putevent(new TuiEvent(evSORTMODECH, 9)); return true; } if ( strcmp(item_name(current_item(menu)), M_ASCII_LINE_DRAW) == 0 ) { asciilinedraw = !asciilinedraw; putevent(new TuiEvent(evASCIIMODECHANGE)); return true; } if ( strcmp(item_name(current_item(menu)), M_TRANSPARENT_BG) == 0 ) { putevent(new TuiEvent(evTRANSPARENTBGMODECHANGE)); return true; } putevent(new TuiEvent(evCOLVIEWCH,item_index(current_item(menu)), false)); return true; } //============================================================================================= HelpSubMenu::HelpSubMenu(NRect rect) : NMenu(rect) { additem(M_ABOUT,""); additem(M_KEY_BINDINGS,""); additem(NULL,NULL); } bool HelpSubMenu::action() { putevent(new NEvent(NEvent::evKB, KEY_F(9))); //закрыть осн меню if ( strcmp(item_name(current_item(menu)),M_ABOUT) == 0 ) putevent(new TuiEvent(evABOUT)); //NEvent(NEvent::evPROG, 3)); //создаем событие с кодом 3 "окно About" if ( strcmp(item_name(current_item(menu)),M_KEY_BINDINGS) == 0 ) putevent(new TuiEvent(evKEYBIND));//NEvent(NEvent::evPROG, 4)); //создаем событие с кодом 4 "окно Key Bindings" return true; } //============================================================================================= ProjectsSubMenu::ProjectsSubMenu(NRect rect, Srv* srv) : NMenu(rect) { this->srv = srv; std::string acctmgrname = ""; if (srv != NULL) { if (!srv->acctmgrinfodom.empty()) { Item* tmpacctmgrinfodom = srv->acctmgrinfodom.hookptr(); Item* acct_mgr_name = tmpacctmgrinfodom->findItem("acct_mgr_name"); if (acct_mgr_name != NULL) acctmgrname = acct_mgr_name->getsvalue(); Item* acct_mgr_url = tmpacctmgrinfodom->findItem("acct_mgr_url"); if (acct_mgr_url != NULL) accmgrurl = acct_mgr_url->getsvalue(); srv->acctmgrinfodom.releaseptr(tmpacctmgrinfodom); } } additem(M_ADD_PROJECT,""); additem(M_ADD_PROJECT_BY_URL,""); if (acctmgrname.empty()) additem(M_CONNECT_MANAGER,""); else { additem(M_SYNCHRONIZE_MANAGER,acctmgrname.c_str()); additem(M_DISCONNECT_MANAGER,acctmgrname.c_str()); } //имена подключенных проектов additem("",""); if ((srv != NULL)&&(!srv->statedom.empty())) { Item* tmpstatedom = srv->statedom.hookptr(); Item* client_state = tmpstatedom->findItem("client_state"); if (client_state != NULL) { std::vector projects = client_state->getItems("project"); for (unsigned int i = 0; i < projects.size(); i++) { Item* project_name = projects[i]->findItem("project_name"); if (project_name != NULL) { std::string status = ""; //строка состояния if (projects[i]->findItem("suspended_via_gui") != NULL) status = status + "[Susp.]"; if (projects[i]->findItem("dont_request_more_work") != NULL) status = status + "[N.N.Tsk]"; additem(project_name->getsvalue(),status.c_str()); } } } srv->statedom.releaseptr(tmpstatedom); } additem(NULL,NULL); } bool ProjectsSubMenu::action() { //bool result = false; if (items.size() > 1) //если уже открыто выходим (>1 из-за скроллбара) return false; //формируем код операции для подменю bool actiondone = false; //создаем подменю int begincol = 2/*getwidth() - 2*/; //смещение на экране по горизонтали int beginrow = 2 + item_index(current_item(menu)); //смещение на экране по вертикали if ( strcmp(item_name(current_item(menu)), M_ADD_PROJECT) == 0 ) //подключиться к новому проекту { insert(new ProjectAllListSubMenu(NRect(5,25,beginrow, begincol), srv)); actiondone = true; } if ( strcmp(item_name(current_item(menu)), M_ADD_PROJECT_BY_URL) == 0 ) //подключиться к проекту по url { if (srv != NULL) { const char* prjname = item_name(current_item(menu)); //создаем подменю для выбора новый/существующий пользователь int begincol = getwidth() - 2; //смещение на экране по горизонтали int beginrow = 2 + item_index(current_item(menu)) - top_row(menu); //смещение на экране по вертикали insert(new ProjectUserExistSubMenu(NRect(5,25,beginrow, begincol), srv, prjname, true)); } actiondone = true; } if ( strcmp(item_name(current_item(menu)), M_CONNECT_MANAGER) == 0 ) //подключить менеджер { insert(new ProjectAccMgrSubMenu(NRect(5,25,beginrow, begincol), srv)); actiondone = true; } if ( strcmp(item_name(current_item(menu)), M_DISCONNECT_MANAGER) == 0 ) //отключить менеджер { putevent(new NEvent(NEvent::evKB, KEY_F(9))); //закрыть осн меню std::string errmsg; if (srv != NULL) srv->accountmanager("","","",false,errmsg); actiondone = true; } if ( strcmp(item_name(current_item(menu)), M_SYNCHRONIZE_MANAGER) == 0 ) //синхронизироваться с менеджером { putevent(new NEvent(NEvent::evKB, KEY_F(9))); //закрыть осн меню std::string errmsg; if (srv != NULL) srv->accountmanager(accmgrurl.c_str(),"","",true,errmsg); actiondone = true; } //если ни одна M_ константа не подошла значит это название проекта if (!actiondone) { insert(new ProjectListSubMenu(NRect(5,25,beginrow, begincol), srv, item_name(current_item(menu)))); } return true; } void ProjectsSubMenu::eventhandle(NEvent* ev) //обработчик событий { if ( ev->done ) return; NMenu::eventhandle(ev); //предок if ( ev->done ) return; if ( ev->type == NEvent::evKB ) { ev->done = true; switch(ev->keycode) { case 27: if ( items.size() > 1 ) //1 из-за скроллбара destroysubmenu(); else ev->done = false; //пусть обрабатывает владелец break; default: ev->done = false; //нет реакции на этот код } //switch if (ev->done) //если обработали, то нужно перерисоваться refresh(); } } //============================================================================================= TasksSubMenu::TasksSubMenu(NRect rect) : NMenu(rect) { additem(M_SUSPEND_TASK," S"); additem(M_RESUME_TASK ," R"); additem(M_ABORT_TASK ," A"); additem(M_INFO_TASK ," Enter"); additem(NULL,NULL); } bool TasksSubMenu::action() { putevent(new NEvent(NEvent::evKB, KEY_F(9))); //закрыть осн меню if ( strcmp(item_name(current_item(menu)),M_SUSPEND_TASK) == 0 ) putevent(new NEvent(NEvent::evKB, 'S')); //создаем событие иммитирующее нажатие 'S' if ( strcmp(item_name(current_item(menu)),M_RESUME_TASK) == 0 ) putevent(new NEvent(NEvent::evKB, 'R')); //создаем событие иммитирующее нажатие 'R' if ( strcmp(item_name(current_item(menu)),M_ABORT_TASK) == 0 ) { TuiEvent* ev = new TuiEvent(evABORTRES); ev->bdata1 = false; putevent(ev); //NEvent(NEvent::evPROG, 2)); //создаем событие с кодом 2 "abort_result" } if ( strcmp(item_name(current_item(menu)),M_INFO_TASK) == 0 ) putevent(new NEvent(NEvent::evKB, KEY_ENTER)); //создаем событие имитирующее нажатие 'Enter' return true; } //============================================================================================= ActivitySubMenu::ActivitySubMenu(NRect rect, Srv* srv) : NMenu(rect) { unpost_menu(menu); this->srv = srv; if ((srv != NULL)&&(!srv->ccstatusdom.empty())) { Item* tmpccstatusdom = srv->ccstatusdom.hookptr(); Item* task_mode = tmpccstatusdom->findItem("task_mode"); additem(M_ACTIVITY_ALWAYS, ((task_mode!=NULL)&&(task_mode->getivalue() == 1)) ? "(*)" : "( )"); //1 always additem(M_ACTIVITY_AUTO,((task_mode!=NULL)&&(task_mode->getivalue() == 2)) ? "(*)" : "( )"); //2 pref additem(M_ACTIVITY_NEVER,((task_mode!=NULL)&&(task_mode->getivalue() == 3)) ? "(*)" : "( )"); //3 never if (!srv->statedom.empty()) { Item* tmpstatedom = srv->statedom.hookptr(); Item* have_ati = tmpstatedom->findItem("have_ati"); Item* have_cuda = tmpstatedom->findItem("have_cuda"); if ( (have_cuda != NULL)||(have_ati !=NULL) ) { Item* gpu_mode = tmpccstatusdom->findItem("gpu_mode"); additem("",""); //delimiter additem(M_GPU_ACTIVITY_ALWAYS, ((gpu_mode!=NULL)&&(gpu_mode->getivalue() == 1)) ? "(*)" : "( )"); //1 always additem(M_GPU_ACTIVITY_AUTO,((gpu_mode!=NULL)&&(gpu_mode->getivalue() == 2)) ? "(*)" : "( )"); //2 pref additem(M_GPU_ACTIVITY_NEVER,((gpu_mode!=NULL)&&(gpu_mode->getivalue() == 3)) ? "(*)" : "( )"); //3 never } srv->statedom.releaseptr(tmpstatedom); } Item* network_mode = tmpccstatusdom->findItem("network_mode"); additem("",""); //delimiter additem(M_NET_ACTIVITY_ALWAYS, ((network_mode!=NULL)&&(network_mode->getivalue() == 1)) ? "(*)" : "( )"); //1 always additem(M_NET_ACTIVITY_AUTO,((network_mode!=NULL)&&(network_mode->getivalue() == 2)) ? "(*)" : "( )"); //2 pref additem(M_NET_ACTIVITY_NEVER,((network_mode!=NULL)&&(network_mode->getivalue() == 3)) ? "(*)" : "( )"); //3 never srv->ccstatusdom.releaseptr(tmpccstatusdom); } additem(NULL,NULL); } bool ActivitySubMenu::action() { putevent(new NEvent(NEvent::evKB, KEY_F(9))); //закрыть все меню if (srv != NULL) { if ( strcmp(item_name(current_item(menu)),M_ACTIVITY_ALWAYS) == 0 ) srv->opactivity("always"); if ( strcmp(item_name(current_item(menu)),M_ACTIVITY_AUTO) == 0 ) srv->opactivity("auto"); if ( strcmp(item_name(current_item(menu)),M_ACTIVITY_NEVER) == 0 ) srv->opactivity("never"); if ( strcmp(item_name(current_item(menu)),M_GPU_ACTIVITY_ALWAYS) == 0 ) srv->opgpuactivity("always"); if ( strcmp(item_name(current_item(menu)),M_GPU_ACTIVITY_AUTO) == 0 ) srv->opgpuactivity("auto"); if ( strcmp(item_name(current_item(menu)),M_GPU_ACTIVITY_NEVER) == 0 ) srv->opgpuactivity("never"); if ( strcmp(item_name(current_item(menu)),M_NET_ACTIVITY_ALWAYS) == 0 ) srv->opnetactivity("always"); if ( strcmp(item_name(current_item(menu)),M_NET_ACTIVITY_AUTO) == 0 ) srv->opnetactivity("auto"); if ( strcmp(item_name(current_item(menu)),M_NET_ACTIVITY_NEVER) == 0 ) srv->opnetactivity("never"); } return true; } //============================================================================================= ProjectListSubMenu::ProjectListSubMenu(NRect rect, Srv* srv, std::string projname) : NMenu(rect) { this->srv = srv; this->projname = projname; additem(M_UPDATE_PROJECT,""); additem(M_SUSPEND_PROJECT ,""); additem(M_RESUME_PROJECT,""); additem(M_NO_NEW_TASKS_PROJECT,""); additem(M_ALLOW_NEW_TASKS_PROJECT,""); additem(M_RESET_PROJECT,""); additem(M_DETACH_PROJECT,""); additem(NULL,NULL); } bool ProjectListSubMenu::action() { if (srv != NULL) { const char* sop = NULL; bool confirmed = false; if ( strcmp(item_name(current_item(menu)),M_SUSPEND_PROJECT) == 0 ) {//Suspend project confirmed = true; //действие не требует подтверждения юзером sop = "project_suspend"; } if ( strcmp(item_name(current_item(menu)),M_RESUME_PROJECT) == 0 ) {//Resume project confirmed = true; //действие не требует подтверждения юзером sop = "project_resume"; } if ( strcmp(item_name(current_item(menu)),M_UPDATE_PROJECT) == 0 ) {//Update project confirmed = true; //действие не требует подтверждения юзером sop = "project_update"; } if ( strcmp(item_name(current_item(menu)),M_NO_NEW_TASKS_PROJECT) == 0 ) {//No New Task project confirmed = true; //действие не требует подтверждения юзером sop = "project_nomorework"; } if ( strcmp(item_name(current_item(menu)),M_ALLOW_NEW_TASKS_PROJECT) == 0 ) {//Allow More Work project confirmed = true; //действие не требует подтверждения юзером sop = "project_allowmorework"; } if ( strcmp(item_name(current_item(menu)),M_RESET_PROJECT) == 0 ) {//Reset project sop = "project_reset"; } if ( strcmp(item_name(current_item(menu)),M_DETACH_PROJECT) == 0 ) {//Detach project sop = "project_detach"; } if (sop) { TuiEvent* ev = new TuiEvent(evPROJECTOP, srv, projname.c_str(),sop); ev->bdata1 = confirmed; putevent(ev); } } //создаем событие закрывающее меню putevent(new NEvent(NEvent::evKB, KEY_F(9))); return true; } void ProjectListSubMenu::eventhandle(NEvent* ev) //обработчик событий { if ( ev->done ) return; NMenu::eventhandle(ev); //предок if ( ev->done ) return; if ( ev->type == NEvent::evKB ) { ev->done = true; switch(ev->keycode) { case KEY_RIGHT: //блокируем стрелку вправо break; case KEY_LEFT: putevent(new NEvent(NEvent::evKB, 27)); //закрыть это подменю break; default: ev->done = false; //нет реакции на этот код } //switch if (ev->done) //если обработали, то нужно перерисоваться refresh(); } } //============================================================================================= ProjectAllListSubMenu::ProjectAllListSubMenu(NRect rect, Srv* srv) : NMenu(rect) { this->srv = srv; if (srv != NULL) { srv->updateallprojects(); if ( srv->allprojectsdom != NULL) { Item* projects = srv->allprojectsdom->findItem("projects"); if (projects != NULL) { std::vector projlist = projects->getItems("project"); for (unsigned int i = 0; i < projlist.size(); i++) { Item* name = projlist[i]->findItem("name"); Item* general_area = projlist[i]->findItem("general_area"); if (name != NULL) { std::string status = ""; //строка тематика проекта if (general_area != NULL) status = general_area->getsvalue(); status.resize(20); additem(name->getsvalue(),status.c_str()); } } } } } additem(NULL,NULL); } bool ProjectAllListSubMenu::action() { if (srv != NULL) { const char* prjname = item_name(current_item(menu)); //создаем подменю для выбора новый/существующий пользователь int begincol = getwidth() - 2; //смещение на экране по горизонтали int beginrow = 2 + item_index(current_item(menu)) - top_row(menu); //смещение на экране по вертикали insert(new ProjectUserExistSubMenu(NRect(5,25,beginrow, begincol), srv, prjname, false)); } return true; } void ProjectAllListSubMenu::eventhandle(NEvent* ev) //обработчик событий { if ( ev->done ) return; NMenu::eventhandle(ev); //предок if ( ev->done ) return; if ( ev->type == NEvent::evKB ) { ev->done = true; switch(ev->keycode) { case KEY_RIGHT: //блокируем стрелку вправо break; case KEY_LEFT: putevent(new NEvent(NEvent::evKB, 27)); //закрыть это подменю break; case 27: if ( items.size() > 1 ) //1 из-за кроллбара destroysubmenu(); else ev->done = false; //пусть обрабатывает владелец break; default: ev->done = false; //нет реакции на этот код } //switch if (ev->done) //если обработали, то нужно перерисоваться refresh(); } } //============================================================================================= ProjectAccMgrSubMenu::ProjectAccMgrSubMenu(NRect rect, Srv* srv) : NMenu(rect) { this->srv = srv; //стандартные менеджеры if (srv != NULL) { srv->updateallprojects(); if ( srv->allprojectsdom != NULL) { Item* projects = srv->allprojectsdom->findItem("projects"); if (projects != NULL) { std::vector mgrlist = projects->getItems("account_manager"); for (unsigned int i = 0; i < mgrlist.size(); i++) { Item* name = mgrlist[i]->findItem("name"); if (name != NULL) additem(name->getsvalue(),""); } } } } //менеджеры из конфига Item* boinctui_cfg = gCfg->getcfgptr(); if (boinctui_cfg != NULL) { std::vector mgrlist = boinctui_cfg->getItems("accmgr"); std::vector::iterator it; for (it = mgrlist.begin(); it != mgrlist.end(); it++) { Item* name = (*it)->findItem("name"); if (name != NULL) additem(name->getsvalue(),""); } } //пункт добавить новый менеджер additem("",""); additem(M_ADD_NEW_MGR,""); additem(NULL,NULL); } bool ProjectAccMgrSubMenu::action() { putevent(new NEvent(NEvent::evKB, KEY_F(9))); //создаем событие закрывающее меню if (srv != NULL) { if (strcmp(item_name(current_item(menu)), M_ADD_NEW_MGR) != 0) putevent(new TuiEvent(evADDACCMGR, srv, item_name(current_item(menu)))); //создаем событие открвыающее форму менеджера else putevent(new TuiEvent(evADDACCMGR, srv, "Unnamed")); //создаем событие открвыающее форму менеджера } return true; } void ProjectAccMgrSubMenu::eventhandle(NEvent* ev) //обработчик событий { if ( ev->done ) return; NMenu::eventhandle(ev); //предок if ( ev->done ) return; if ( ev->type == NEvent::evKB ) { ev->done = true; switch(ev->keycode) { case KEY_RIGHT: //блокируем стрелку вправо break; case KEY_LEFT: putevent(new NEvent(NEvent::evKB, 27)); //закрыть это подменю break; default: ev->done = false; //нет реакции на этот код } //switch if (ev->done) //если обработали, то нужно перерисоваться refresh(); } } //============================================================================================= ProjectUserExistSubMenu::ProjectUserExistSubMenu(NRect rect, Srv* srv, const char* prjname, bool byurl) : NMenu(rect) { this->srv = srv; this->prjname = prjname; this->byurl = byurl; additem(M_PROJECT_USER_EXIST,""); additem(M_PROJECT_NEW_USER,""); additem(NULL,NULL); } bool ProjectUserExistSubMenu::action() { //создаем событие закрывающее меню putevent(new NEvent(NEvent::evKB, KEY_F(9))); if (srv != NULL) { if ( strcmp(item_name(current_item(menu)),M_PROJECT_USER_EXIST) == 0 ) putevent(new TuiEvent(evADDPROJECT, srv, prjname.c_str(), true, this->byurl)); if ( strcmp(item_name(current_item(menu)),M_PROJECT_NEW_USER) == 0 ) putevent(new TuiEvent(evADDPROJECT, srv, prjname.c_str(), false, this->byurl)); } return true; } void ProjectUserExistSubMenu::eventhandle(NEvent* ev) //обработчик событий { if ( ev->done ) return; NMenu::eventhandle(ev); //предок if ( ev->done ) return; if ( ev->type == NEvent::evKB ) { ev->done = true; switch(ev->keycode) { case KEY_RIGHT: //блокируем стрелку вправо break; case KEY_LEFT: putevent(new NEvent(NEvent::evKB, 27)); //закрыть это подменю break; default: ev->done = false; //нет реакции на этот код } //switch if (ev->done) //если обработали, то нужно перерисоваться refresh(); } } boinctui-2.7.1/src/nhline.h0000664000175000017500000000225314536642777013437 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef NHLINE_H #define NHLINE_H #include "nview.h" class NHLine : public NView { public: NHLine(NRect rect, const char* s) : NView(rect) { bgcolor = 0; }; virtual ~NHLine() { }; void setbgcolor(int colorpair) { bgcolor = colorpair; }; virtual void refresh(); protected: int bgcolor; //цвет фона const char* mbsym; //символ }; #endif //NHLINE_Hboinctui-2.7.1/src/addmgrform.h0000664000175000017500000000277114536642777014311 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef ADDMGRFORM_H #define ADDMGRFORM_H #include #include #include "nform.h" #include "nstatictext.h" #include "srvdata.h" class AddAccMgrForm : public NForm { public: AddAccMgrForm(int lines, int rows, Srv* srv, const char* mgrname); void genfields(int& line, Item* mgr); //создаст массив полей virtual void eventhandle(NEvent* ev); //обработчик событий protected: int namefield; int passwfield; int errmsgfield; int usernamefield; int urlfield; Srv* srv; std::string mgrname; //имя акк менеджера std::string mgrurl; //url подключаемого менеджера }; #endif //ADDMGRFORM_Hboinctui-2.7.1/src/commondef.h0000664000175000017500000000021114536642777014121 0ustar ssss#ifndef COMMONDEF_H #define COMMONDEF_H //стрингификатор #define XSTR(S) STR(S) #define STR(S) #S #endif //COMMONDEF_H boinctui-2.7.1/src/mainwin.h0000664000175000017500000000472414536642777013631 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef MAINWIN_H #define MAINWIN_H #include "ngroup.h" #include "taskwin.h" #include "msgwin.h" #include "nstatictext.h" #include "nhline.h" #include "nvline.h" #include "nscrollbar.h" #include "infopanel.h" #include "srvdata.h" class MainWin : public NGroup { public: MainWin(NRect rect/*, Config* cfg*/); virtual void refresh(); virtual void resize(int rows, int cols); void setserver(Srv* srv); //установить отображаемый сервер // virtual void move(int begrow, int begcol); virtual void eventhandle(NEvent* ev); //обработчик событий TaskWin* wtask; //окно задач MsgWin* wmsg; //окно эвентов NStaticText* tablheader; //заголовок таблицы процессов NScrollBar* msgscrollbar; //скроллбар панели сообщений NScrollBar* taskscrollbar; //скроллбар панели задач InfoPanel* panel1; //инф-ная панель NColorString* caption; //строка заголовка void updatecaption(); protected: Srv* srv; NHLine* hline; //гориз линия завершающая таблицу процессов NVLine* vline; //верт линия отделяющая инф панель std::vector colname; //список названий колонок void setcoltitle(); int wtaskheightpercent; //высота в процентах*100 списка задач относительно всего окна (10000 == 100%) void saveopttoconfig(); //сохранить высоту списка задач и т.д. в дереве конфига }; #endif //MAINWIN_Hboinctui-2.7.1/src/kclog.h0000664000175000017500000000221714536642777013261 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= // * для ведения логов #ifndef KCLOG_H_ #define KCLOG_H_ #include /// открывает лог файл на запись void kLogOpen(const char* filename = NULL); /// закрывает лог файл void kLogClose(); /// вывести информацию в лог void kLogPrintf(const char* fmt, ...); #endif /*KCLOG_H_*/ boinctui-2.7.1/src/nstatictext.h0000664000175000017500000000304714536642777014536 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef NSTATICTEXT_H #define NSTATICTEXT_H #include "nview.h" #include "ncolorstring.h" class NStaticText : public NView { public: NStaticText(NRect rect) : NView(rect) { content = new NColorString(0,""); align = 0; setbgcolor(getcolorpair(COLOR_WHITE,getbgcolor()));}; virtual ~NStaticText() { delete content; }; void appendstring(int attr, const char* fmt, ...); void setstring(int attr, const char* fmt, ...); void setbgcolor(int colorpair) { bgcolor = colorpair; }; void setalign(int align) { this->align = align; }; //0-левое 2-правое 1-центр virtual void refresh(); protected: NColorString* content; int align; //вравнивание int bgcolor; //цвет фона }; #endif //NSTATICTEXT_Hboinctui-2.7.1/src/nvline.h0000664000175000017500000000225314536642777013455 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef NVLINE_H #define NVLINE_H #include "nview.h" class NVLine : public NView { public: NVLine(NRect rect, const char* s) : NView(rect) { bgcolor = 0; }; virtual ~NVLine() { }; void setbgcolor(int colorpair) { bgcolor = colorpair; }; virtual void refresh(); protected: int bgcolor; //цвет фона const char* mbsym; //символ }; #endif //NVLINE_Hboinctui-2.7.1/src/nform.h0000664000175000017500000000352014536642777013301 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef NFORM_H #define NFORM_H #include #include #if HAVE_LIBNCURSESW == 1 && NCURSESW_HAVE_SUBDIR == 1 #include #else #include #endif #include "ngroup.h" class NForm : public NGroup { public: NForm(int lines, int rows); virtual ~NForm(); virtual void refresh(); virtual void resize(int rows, int cols); virtual void settitle(const char* title); virtual const char* gettitle() { return title; }; virtual void eventhandle(NEvent* ev); //обработчик событий virtual FIELD* addfield(FIELD* field); int getfieldcount() { return fieldcount; }; virtual void delfields(); //удаляет все поля protected: bool clickatfield(int mrow, int mcol, FIELD* f); //true если клик внутри этого поля char* title; //заголовок FIELD** fields; int fieldcount; //число полей включая NULL FORM* frm; //форма ncurses WINDOW* subwin; //подокно curses }; #endif //NFORM_Hboinctui-2.7.1/src/mainwin.cpp0000664000175000017500000002274314536642777014165 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include "mainwin.h" #include "tuievent.h" #include "kclog.h" #define INFPANWIDTH 20 //ширина инф панели MainWin::MainWin(NRect rect/*, Config* cfg*/) : NGroup(rect) { //читаем опции из конфига если нет то создаем wtaskheightpercent = 5000; if (gCfg != NULL) { Item* rootcfg = gCfg->getcfgptr(); if (rootcfg != NULL) { Item* wtask_height_percent = rootcfg->findItem("wtask_height_percent"); if (wtask_height_percent == NULL) //создать { wtask_height_percent = new Item("wtask_height_percent"); wtask_height_percent->setivalue(wtaskheightpercent); rootcfg->addsubitem(wtask_height_percent); } wtaskheightpercent = wtask_height_percent->getivalue(); } } colname.push_back(" # "); colname.push_back("state "); colname.push_back(" done%%"); colname.push_back(" project "); colname.push_back(" est"); colname.push_back(" rcv"); colname.push_back(" dl "); colname.push_back(" application "); colname.push_back(" swap "); colname.push_back(" task"); tablheader = new NStaticText(NRect(1, rect.cols -2-(INFPANWIDTH)-1, 1, 1)); tablheader->setstring(getcolorpair(COLOR_CYAN,getbgcolor()) | A_BOLD," # state done%% project est d/l task"); int wtaskheight = getheight() * wtaskheightpercent / 10000.0; if (wtaskheight < 5) wtaskheight = 5; if (wtaskheight > getheight() - 10) wtaskheight = getheight() - 10; wtask = new TaskWin(NRect(wtaskheight/*getheight()/2*/, getwidth()-2-(INFPANWIDTH)-1, 2, 1)); //создаем окно процессов внутри wmain setcoltitle(); taskscrollbar = new NScrollBar(NRect(wtask->getheight()+2,1, wtask->getbegrow()-2, getwidth()-INFPANWIDTH-2), ACS_TTEE | A_BOLD, 0, ACS_VLINE | A_BOLD); //скроллбар панели задач wtask->setscrollbar(taskscrollbar); wmsg = new MsgWin(NRect(getheight()-wtask->getheight()-4, getwidth()-2-(INFPANWIDTH+1), wtask->getheight()+3, 1)); //создаем окно евентов hline = new NHLine(NRect(1, getwidth()-2-(INFPANWIDTH+1), wtask->getheight()+2, 1), NULL); //горизонтальная линия // vline = new NVLine(NRect(wtask->getheight()+1/*getheight()-2*/, 1, 1, getwidth()-INFPANWIDTH-2), NULL); //вертикальная линия msgscrollbar = new NScrollBar(NRect(wmsg->getheight()+2,1, wmsg->getbegrow()-1, getwidth()-INFPANWIDTH-2/*vline->getbegcol()*/),/*ACS_RTEE*/ACS_VLINE | A_BOLD,ACS_BTEE | A_BOLD, ACS_VLINE | A_BOLD); //скроллбар панели сообщений wmsg->setscrollbar(msgscrollbar); panel1 = new InfoPanel(NRect(getheight()-2,INFPANWIDTH,1,getwidth()-INFPANWIDTH-1)); caption = new NColorString(0,""); insert(tablheader); insert(wtask); insert(wmsg); insert(hline); // insert(vline); insert(taskscrollbar); insert(msgscrollbar); insert(panel1); } void MainWin::resize(int rows, int cols) { NGroup::resize(rows, cols); tablheader->resize(1, getwidth()-2-(INFPANWIDTH)-1); int wtaskheight = getheight() * wtaskheightpercent / 10000.0; if (wtaskheight < 5) wtaskheight = 5; if (wtaskheight > getheight() - 10) wtaskheight = getheight() - 10; wtask->resize(wtaskheight/*getheight()/2*/, getwidth()-2-(INFPANWIDTH)-1); //размер окна задач wmsg->resize(getheight()-wtask->getheight()-4, getwidth()-2-(INFPANWIDTH+1)); wmsg->move(wtask->getheight()+3, 1); hline->resize(1, getwidth()-2-(INFPANWIDTH+1)); //горизонтальная линия hline->move(wtask->getheight()+2, 1); // vline->resize(wtask->getheight()+1/*getheight()-2*/, 1); // vline->move(1 , getwidth()-INFPANWIDTH-2); msgscrollbar->resize(wmsg->getheight()+2,1); msgscrollbar->move(wmsg->getbegrow()-1, getwidth()-INFPANWIDTH-2/*vline->getbegcol()*/); taskscrollbar->resize(wtask->getheight()+2,1); taskscrollbar->move(wtask->getbegrow()-2, getwidth()-INFPANWIDTH-2); panel1->resize(getheight()-2,INFPANWIDTH); panel1->move(1,getwidth()-INFPANWIDTH-1); } void MainWin::saveopttoconfig() //сохранить высоту списка задач и т.д. в дереве конфига { //пишем в конфиг if (gCfg != NULL) { Item* rootcfg = gCfg->getcfgptr(); if (rootcfg != NULL) { Item* wtask_height_percent = rootcfg->findItem("wtask_height_percent"); if (wtask_height_percent != NULL) wtask_height_percent->setivalue(wtaskheightpercent); } } } void MainWin::setserver(Srv* srv) //установить отображаемый сервер { this->srv = srv; wmsg->setserver(srv); wtask->setserver(srv); panel1->setserver(srv); } void MainWin::setcoltitle() { std::string s = ""; for (size_t i = 0; i < colname.size(); i++) { if (wtask->iscolvisible(i)) s = s + colname[i]; } tablheader->setbgcolor(getcolorpair(COLOR_WHITE,getbgcolor())); tablheader->setstring(getcolorpair(COLOR_CYAN,getbgcolor()) | A_BOLD, s.c_str()); } void MainWin::refresh() { wattrset(win, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD); if(asciilinedraw == 1) wborder(win, '|', '|', '-', '-', '+', '+', '+', '+'); else box(win, ACS_VLINE, ACS_HLINE); //рисуем заголовок wmove(win,0,(getwidth()/2)-(caption->getlen()+1)/2); std::list::iterator it; for (it = caption->parts.begin(); it != caption->parts.end(); it++) //цикл по частям тек строки { NColorStringPart* part = *it; wattrset(win,part->attr); wprintw(win,"%s",part->s.c_str()); //wattrset(win,0); } //wborder(win, ACS_VLINE, ACS_VLINE, ACS_HLINE, ACS_HLINE, ACS_ULCORNER, ACS_URCORNER, ACS_LLCORNER, ACS_LRCORNER); //wattroff(win, getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD); setcoltitle(); NGroup::refresh(); } void MainWin::updatecaption() { NColorString oldcaption = *caption; caption->clear(); if (srv) { std::string shostid=""; if(strlen(srv->hostid)>0) shostid="("+std::string(srv->hostid)+")"; caption->append(getcolorpair(COLOR_WHITE,getbgcolor()) | A_BOLD," Host %s:%s%s ",srv->gethost(),srv->getport(),shostid.c_str()); if (srv->loginfail) caption->append(getcolorpair(COLOR_WHITE,COLOR_RED) | A_BOLD,"unauthorized!"); else { if (!srv->isconnected()) caption->append(getcolorpair(COLOR_WHITE,COLOR_RED) | A_BOLD,"offline!"); } } else caption->append(getcolorpair(COLOR_WHITE,COLOR_RED) | A_BOLD,"no servers"); if (oldcaption != *caption) refresh(); } void MainWin::eventhandle(NEvent* ev) //обработчик событий { static int keycodebak = 0; static int keycodebakbak = 0; NGroup::eventhandle(ev); //предок if ( ev->done ) return; if (ev->type == NEvent::evKB) //клавиатурные { //костыль для работы +- на нумпаде независимо от numlock (прямая интерпретация ESC последовательности) if ((keycodebakbak == 27) && (keycodebak == 79) && (ev->keycode == 107)) ev->keycode = '+'; if ((keycodebakbak == 27) && (keycodebak == 79) && (ev->keycode == 109)) ev->keycode = '-'; switch(ev->keycode) { case '-': //меняем размер окна логов case '+': //меняем размер окна логов { int wtaskheight = getheight() * wtaskheightpercent / 10000.0; //высота в строках //игнорировать событие если дошли до ограничителей if ((ev->keycode == '+')&&(wtaskheight < 5)) break; if ((ev->keycode == '-')&&(wtaskheight > getheight() -10)) break; //расчитать новый процентный размер окна int delta = 10000.0/getheight(); if (ev->keycode == '+') delta*=-1; wtaskheightpercent+=delta; if (wtaskheightpercent > 10000) wtaskheightpercent = 10000; wtaskheightpercent-=10; if (wtaskheightpercent < 0) wtaskheightpercent = 0; //сохранить новое значение в конфиге saveopttoconfig(); //ресайз и перерисовка resize(getheight(),getwidth()); refresh(); break; } } keycodebakbak = keycodebak; keycodebak = ev->keycode; } if (ev->type == NEvent::evPROG) //прграммные { switch(ev->cmdcode) { case evCOLVIEWCH: //изменился набор колонок { setcoltitle(); tablheader->refresh(); wtask->refresh(); } } //switch } //событие таймера if (ev->type == NEvent::evTIMER) //таймер { updatecaption(); } } boinctui-2.7.1/src/tuievent.h0000664000175000017500000001057714536642777014035 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef TUIEVENT_H #define TUIEVENT_H #include "srvdata.h" #include "nevent.h" enum TuiEventType { evCFGCH, //конфигурация изменена evABORTRES, //abort selected result evABOUT, //открыть/закрыть откно About evKEYBIND, //открыть/закрыть откно Key Bindings evBENCHMARK, //run benchmark evADDPROJECT, //форма добавить проект evCOLVIEWCH, //переключение видимости колонки evVIEWMODECH, //переключение режима видимости All/Hide done/Active tasks only evSORTMODECH, //переключение режима сортировки списка задач 0-unsorted 1-state e.t.c. evADDACCMGR, //форма акк менеджера evPROJECTOP, //операции над проектом evTASKINFO, //генерируется когда нужно открыть окно детальной информации о задаче evTASKSELECTORON, //генерируется когда селектор задач становится видимым evTASKSELECTOROFF, //генерируется когда селектор задач становится скрытым evASCIIMODECHANGE, //генерируется при переключении режима ASCII рамок evTRANSPARENTBGMODECHANGE, //генерируется при переключении прозрачности бэкграунда evPOPUPMSG //генерируется когда нужно открыть попап сообщение }; class TuiEvent : public NEvent //класс программных событий специфичных для boinctui { public: TuiEvent(TuiEventType type) : NEvent(evPROG, type) {}; TuiEvent(TuiEventType type, Srv* srv, const char* prjname, bool userexist, bool byurl) : NEvent(evPROG, type) //событие для добавления проекта { this->srv = srv; this->sdata1 = prjname; this->bdata1 = userexist; this->bdata2 = byurl; }; TuiEvent(TuiEventType type, Srv* srv, const char* mgrname) : NEvent(evPROG, type) //событие для подключения к менеджеру { this->srv = srv; this->sdata1 = mgrname; }; TuiEvent(TuiEventType type, Srv* srv, const char* projname, const char* projop) : NEvent(evPROG, type) //событие для действий с проектами { this->srv = srv; this->sdata1 = projname; this->sdata2 = projop; this->bdata1 = false; //true - если получено подтверждение }; TuiEvent(TuiEventType type ,int ncolumn, bool enable) : NEvent(evPROG, type) //событие переключения видимости колонки { this->idata1 = ncolumn; this->bdata1 = enable; }; TuiEvent(TuiEventType type ,int mode) : NEvent(evPROG, type) //событие режим видимости задач { this->idata1 = mode; }; TuiEvent(TuiEventType type, const char* caption, const char* msg) : NEvent(evPROG, type) //событие попап сообщения { this->sdata1 = caption; this->sdata2 = msg; }; virtual ~TuiEvent() { /*kLogPrintf("~TuiEvent()\n");*/ }; Srv* srv; std::string sdata1; //произвольная строка std::string sdata2; //произвольная строка bool bdata1; //произвольная bool переменная bool bdata2; //произвольная bool переменная int idata1; //произвольное целое }; #endif //TUIEVENT_H boinctui-2.7.1/src/mbstring.h0000664000175000017500000000245014536642777014006 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef MBSTRING_H #define MBSTRING_H int mbstrlen(const char* s); //вернет размер строки utf8 в СИМВОЛАХ (не байтах) без учета '\0' char* mbstrtrunc(char* s, int slen); //обрезать до длины slen символов (не байтов) без учета \0 char* rtrim(char* s); //удалить завершающие пробелы в строке char* ltrim(char* s); //удалить начальные пробелы в строке #endif // MBSTRING_H boinctui-2.7.1/src/topmenu.h0000664000175000017500000001263314536642777013654 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef TOPMENU_H #define TOPMENU_H #include "nmenu.h" #include "srvdata.h" class TopMenu : public NMenu //верхний уровень меню { public: TopMenu(/*Config* cfg*/); virtual void eventhandle(NEvent* ev); //обработчик событий void enable() { if (!enableflag) {enableflag = true; set_menu_fore(menu, selectorattr); /*action();*/ } }; void disable() { if (enableflag) {enableflag = false; selectorattr = menu_fore(menu); set_menu_fore(menu, menu_back(menu)); destroysubmenu(); }; /*цвет указателя = цвет фона*/ }; bool isenable() { return enableflag; }; void setserver(Srv* srv) { this->srv = srv; }; //установить отображаемый сервер virtual bool action(); //открыть субменю protected: int selectorattr; //цвет указателя bool enableflag; //true если меню активно Srv* srv; //текущий отображаемый сервер // Config* cfg; }; class ViewSubMenu : public NMenu //выпадающие меню "View" { public: ViewSubMenu(NRect rect/*, Config* cfg*/); protected: virtual bool action(); //вызывается при нажатии Enter bool iscolenable(/*Config* cfg,*/ int n); }; class ProjectsSubMenu : public NMenu //выпадающие меню "Projects" { public: ProjectsSubMenu(NRect rect, Srv* srv); virtual void eventhandle(NEvent* ev); //обработчик событий protected: virtual bool action(); //вызывается при нажатии Enter Srv* srv; //текущий отображаемый сервер std::string accmgrurl; //url акк менеджера если есть }; class TasksSubMenu : public NMenu //выпадающие меню "Tasks" { public: TasksSubMenu(NRect rect); protected: virtual bool action(); //вызывается при нажатии Enter }; class FileSubMenu : public NMenu //выпадающие меню "File" { public: FileSubMenu(NRect rect); protected: virtual bool action(); //вызывается при нажатии Enter }; class ProjectListSubMenu : public NMenu //выпадающие меню второго уровня Список проектов { public: ProjectListSubMenu(NRect rect, Srv* srv, std::string projname); virtual void eventhandle(NEvent* ev); //обработчик событий protected: virtual bool action(); //вызывается при нажатии Enter Srv* srv; //текущий отображаемый сервер std::string projname; //имя проекта }; class ProjectAllListSubMenu : public NMenu //выпадающие меню второго уровня Список ВСЕХ проектов { public: ProjectAllListSubMenu(NRect rect, Srv* srv); virtual void eventhandle(NEvent* ev); //обработчик событий protected: virtual bool action(); //вызывается при нажатии Enter Srv* srv; //текущий отображаемый сервер }; class ProjectAccMgrSubMenu : public NMenu //выпадающие меню второго уровня Список Аккаунт менеджеров { public: ProjectAccMgrSubMenu(NRect rect, Srv* srv); virtual void eventhandle(NEvent* ev); //обработчик событий protected: virtual bool action(); //вызывается при нажатии Enter Srv* srv; //текущий отображаемый сервер }; class ProjectUserExistSubMenu : public NMenu //выпадающие меню третего New/Exist user { public: ProjectUserExistSubMenu(NRect rect, Srv* srv, const char* prjname, bool byurl); virtual void eventhandle(NEvent* ev); //обработчик событий protected: virtual bool action(); //вызывается при нажатии Enter Srv* srv; //текущий отображаемый сервер std::string prjname; //имя выбранного проекта bool byurl = false; //true если добавляем по url }; class ActivitySubMenu : public NMenu //выпадающие меню второго уровня Activity { public: ActivitySubMenu(NRect rect, Srv* srv); protected: virtual bool action(); //вызывается при нажатии Enter Srv* srv; //текущий отображаемый сервер }; class HelpSubMenu : public NMenu //выпадающие меню "Help" { public: HelpSubMenu(NRect rect); protected: virtual bool action(); //вызывается при нажатии Enter }; #endif //TOPMENU_Hboinctui-2.7.1/src/resultdom.cpp0000664000175000017500000001127614536642777014540 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include "resultdom.h" #include #include Item::~Item() { std::list::iterator it; //деструктим подэлементы for (it=subitems.begin(); it!=subitems.end(); it++) { delete *it; } //очищаем список subitems.clear(); } std::vector Item::getItems(const char* name) //получить из текущего эл-та список подэлементов с именем name (поиска в глубину НЕТ) { std::vector result; std::list::iterator it; if (strlen(name) > 0) { for (it=subitems.begin(); it!=subitems.end(); it++) { if ( strcmp((*it)->getname(),name) == 0 ) result.push_back(*it); } } else //если имя не задано вернет все имеющиеся { for (it=subitems.begin(); it!=subitems.end(); it++) result.push_back(*it); } return result; } Item* Item::findItem(const char* name) //ищет в поддереве (на всю глубину) элемент с именем name (вернет NULL если такого нет) { Item* result; if (strcmp(this->name.c_str(), name) == 0) { return this; //нашли - он сам и есть искомый эл-т } else //ищем во всех подэлементах { std::list::iterator it; for (it=subitems.begin(); it!=subitems.end(); it++) { result = (*it)->findItem(name); if (result != NULL) return result; //нашли! } } return NULL; //не нашли } void Item::setivalue(int ivalue) //присвоить целочисленное значение { char buff[256]; snprintf(buff,sizeof(buff),"%d",ivalue); setsvalue(buff); } double Item::getdvalue() //получить значение double { double result = 0.0; std::string numlocale = setlocale(LC_NUMERIC, NULL); setlocale(LC_NUMERIC, "C"); //чтобы работала sscanf с числами вида 1.234 а не 1,234 sscanf(svalue.c_str(), "%lf", &result); setlocale(LC_NUMERIC, numlocale.c_str()); return result; } void Item::mergetree(Item* tree) //объединяет tree с текущим эл-том { if (tree->getfullname() == this->getfullname()) //полные пути одинаковые { // Сливаем два узла в один std::list::iterator it; for (it = tree->subitems.begin(); it != tree->subitems.end(); it++) { addsubitem(*it); //все подэлементы из tree переносим в текущий узел } tree->subitems.clear(); //delete tree; //сам узел уже не нужен (все его эл-ты перенесены в this) } //else //{ // добавляем tree к текущему узлу // addsubitem(tree); //} } void Item::clearsubitems() //удалить все подэл-ты текущего узла { std::list::iterator it; for (it = subitems.begin(); it != subitems.end(); it++) delete (*it); subitems.clear(); } void Item::delsubitem(Item* subitem) //удалить подэлемент subitem из узла { std::list::iterator it; for (it = subitems.begin(); it != subitems.end(); it++) { if ((*it) == subitem) { delete (*it); subitems.remove(*it); break; } } } std::string Item::toxmlstring() //сериализация в строку { static int indent; std::string result = ""; std::string sindent = ""; //отступ for (int i = 0; i < indent; i++) sindent = sindent + " "; indent++; result = sindent + "<" + name + ">" + svalue + "\n"; std::list::iterator it; for (it=subitems.begin(); it!=subitems.end(); it++) { result = result + (*it)->toxmlstring(); } result = result + sindent + "\n"; indent--; return result; } boinctui-2.7.1/src/resultdom.h0000664000175000017500000000640714536642777014205 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef RESULTDOM_H #define RESULTDOM_H #include #include #include #include class Item //элемент дерева данных (например 1129827635.000000) { public: Item(const char* name) { this->name = name; parent = NULL; }; virtual ~Item(); bool isnode() { return !subitems.empty(); }; //true если имеет подэлементы void addsubitem(Item* item) { item->parent = this; subitems.push_back(item); }; //добавляет подэлемент void appendvalue(const char* svalue) { this->svalue = this->svalue + svalue; }; //дополняет строку значения void setsvalue(const char* svalue) { this->svalue = svalue; }; //устанавливает строку значения void setivalue(int ivalue); //присвоить целочисленное значение void mergetree(Item* tree); //объединяет tree с текущим эл-том void clearsubitems(); //удалить все подэл-ты текущего узла void delsubitem(Item* subitem); //удалить подэлемент subitem из узла const char* getsvalue() { return svalue.c_str(); }; //получить строку значения int getivalue() { return atoi(svalue.c_str());};//получить целочисленное double getdvalue(); //получить значение double const char* getname() { return name.c_str(); }; //получить имя эл-та std::string getfullname() { if (parent == NULL) return name; else return parent->getfullname()+"/"+name; }; //получить имя вместе со всеми владельщами Item* findItem(const char* name); //возвращает подэлемент с именем name или NULL (поиск на всю глубину) std::vector getItems(const char* name); //получить из текущего эл-та список подэлементов с именем name (поиска в глубину НЕТ) std::string toxmlstring(); //сериализация в строку Item* getparent() {return parent;}; protected: std::string name; //имя эл-та "disk_usage" std::string svalue; //строка значения "1129827635.000000" std::list subitems; //список вложенных эл-тов (если они есть) Item* parent; }; #endif //RESULTDOM_Hboinctui-2.7.1/src/infopanel.cpp0000664000175000017500000003375314536642777014501 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include #include #include "kclog.h" #include "infopanel.h" #include "net.h" #include "resultparse.h" Item* findDay( std::vector& days, time_t d ) //ищем в статистике день d если нет вернет NULL { std::vector::reverse_iterator rit; for (rit = days.rbegin(); rit != days.rend(); rit++) { Item* day = (*rit)->findItem("day"); if (day != NULL) { if ( day->getdvalue() == d ) return (*rit); } } return NULL; } std::string InfoPanel::getdayname(time_t ltime) //название дня "today" "yesterday" "" { time_t now = time(NULL); if ( now/(3600 * 24) == ltime/(3600 * 24) ) return "today"; if ( now/(3600 * 24) == 1+ltime/(3600 * 24) ) return "yesterday"; return ""; } void InfoPanel::refresh() { if (srv == NULL) return; if (srv->statedom.empty()) { needrefresh = true; werase(win); mvwprintw(win,0,0,"%s:%s\noffline",srv->gethost(),srv->getport()); NView::refresh(); return; } wattrset(win,getcolorpair(COLOR_WHITE,getbgcolor())); wattron(win, A_REVERSE); mvwprintw(win,0,0," Tasks "); wattroff(win, A_REVERSE); mvwprintw(win,1,0,"all %3d",nalltasks); mvwprintw(win,2,0,"active %3d",nactivetasks); mvwprintw(win,3,0,"run %3d",nruntasks); mvwprintw(win,4,0,"wait %3d",nqueuetasks); mvwprintw(win,5,0,"done %3d",ndonetasks); mvwprintw(win,6,0,"other %3d",nothertasks); wattron(win,A_REVERSE); mvwprintw(win,7,0," Storage "); wattroff(win,A_REVERSE); mvwprintw(win,8,0, "total %8.2fGb",dtotal/(1024*1024*1024)); mvwprintw(win,9,0, "free %8.2fGb",dfree/(1024*1024*1024)); mvwprintw(win,10,0,"allowed %8.2fGb",dallowed/(1024*1024*1024)); mvwprintw(win,11,0,"boinc %8.2fGb",dboinc/(1024*1024*1024)); wattron(win,A_REVERSE); mvwprintw(win,12,0," Statistics "); wattroff(win,A_REVERSE); bool compact = true; //компактный вывод статистики если user=host int line,col; getyx(win,line,col); if ( (!compact)||(std::abs(usertotal - hosttotal) > 1) ) { mvwprintw(win,line++,0,"user total%10.0f\n",usertotal); mvwprintw(win,line++,0,"host total%10.0f\n",hosttotal); } else mvwprintw(win,line++,0,"total %10.0f\n",usertotal); if ( (!compact)||(std::abs(useravg - hostavg) > 1) ) { mvwprintw(win,line++,0,"user avg %10.0f\n",useravg); mvwprintw(win,line++,0,"host avg %10.0f\n",hostavg); } else mvwprintw(win,line++,0,"average %10.0f\n",useravg); tm* ltime = localtime(&laststattime); char buf[128]; strftime(buf, sizeof(buf),"%-e %b",ltime); //"%-e %b %-k:%M" mvwprintw(win,line++,0,"%-s %s\n", buf, getdayname(laststattime).c_str()); //дата/время последней статистики //wattrset(win,0); if ( (!compact)||(std::abs(lastdayuser - lastdayhost) > 1) ) { if ( asciilinedraw == 1) { wmove(win,line++,0); wprintw(win,"+->user %10.0f\n",lastdayuser); wmove(win,line++,0); wprintw(win,"+->host %10.0f\n",lastdayhost); } else { mvwaddch(win,line++,0,ACS_LTEE); waddch(win,ACS_HLINE); wprintw(win,">user %10.0f\n",lastdayuser); mvwaddch(win,line++,0,ACS_LLCORNER); waddch(win,ACS_HLINE); wprintw(win,">host %10.0f\n",lastdayhost); } } else { if( asciilinedraw == 1) { wmove(win,line++,0); wprintw(win,"-->daily %10.0f\n",lastdayhost); } else { mvwaddch(win,line++,0,ACS_LLCORNER); waddch(win,ACS_HLINE); wprintw(win,">daily %10.0f\n",lastdayhost); } } //по проектам mvwprintw(win, line++,0,"\n"); for (int i = 0; i < (int)projects.size(); i++) //цикл по названиям проектов { //расчитываем нужное кол-во строк int needlines = 2; if (!projects[i].sstatus.empty()) needlines++; if ( (!compact)||(std::abs(projects[i].user - projects[i].host) > 1) ) needlines += 2; else needlines++; if ( (!compact)||(std::abs(projects[i].userlastday - projects[i].hostlastday) > 1) ) needlines += 2; else needlines++; //проверяем сколько свободных строк осталось в окне if ( ( getheight()-line ) < needlines ) break; //не выводим если осталось мало строк //вывод на экран о проекте wattrset(win,getcolorpair(COLOR_YELLOW,getbgcolor())); mvwprintw(win,line++,0,"%s\n",projects[i].name.c_str()); if (!projects[i].sstatus.empty()) { wattrset(win,getcolorpair(COLOR_RED,getbgcolor())); mvwprintw(win,line++,0,"%s\n",projects[i].sstatus.c_str()); } wattrset(win,getcolorpair(COLOR_WHITE,getbgcolor())); if ( (!compact)||(std::abs(projects[i].user - projects[i].host) > 1) ) { mvwprintw(win,line++,0,"user total%10.0f\n",projects[i].user); mvwprintw(win,line++,0,"host total%10.0f\n",projects[i].host); } else mvwprintw(win,line++,0,"total %10.0f\n",projects[i].user); ltime = localtime(&projects[i].laststattime); strftime(buf, sizeof(buf),"%-e %b",ltime); //"%-e %b %-k:%M" mvwprintw(win,line++,0,"%-s %s\n",buf, getdayname(projects[i].laststattime).c_str()); if ( (!compact)||(std::abs(projects[i].userlastday - projects[i].hostlastday) > 1) ) { if (asciilinedraw == 1) { wmove(win,line++,0); wprintw(win,"+->user %10.0f\n",projects[i].userlastday); wmove(win,line++,0); wprintw(win,"+->host %10.0f\n",projects[i].hostlastday); } else { mvwaddch(win,line++,0,ACS_LTEE); waddch(win,ACS_HLINE); wprintw(win,">user %10.0f\n",projects[i].userlastday); mvwaddch(win,line++,0,ACS_LLCORNER); waddch(win,ACS_HLINE); wprintw(win,">host %10.0f\n",projects[i].hostlastday); } } else { if (asciilinedraw == 1) { wmove(win,line++,0); wprintw(win,"-->daily %10.0f\n",projects[i].userlastday); } else { mvwaddch(win,line++,0,ACS_LLCORNER); waddch(win,ACS_HLINE); wprintw(win,">daily %10.0f\n",projects[i].userlastday); } } } if ( line < getheight() ) wclrtobot(win); //чистим нижню часть окна (если не это не последняя строка иначе сотрем символ в правом нижнем) NView::refresh(); } void InfoPanel::updatedata() { if (srv == NULL) return; //===данные по процессам=== if (srv->statedom.empty()) return; Item* tmpstatedom = srv->statedom.hookptr(); Item* client_state = tmpstatedom->findItem("client_state"); nactivetasks = 0; ndonetasks = 0; nruntasks = 0; nqueuetasks = 0; if (client_state != NULL) { std::vector results = client_state->getItems("result"); std::vector::iterator it; nalltasks = results.size(); for (it = results.begin(); it!=results.end(); it++) //цикл списка задач { Item* ready_to_report = (*it)->findItem("ready_to_report"); if (ready_to_report != NULL) ndonetasks++; Item* active_task = (*it)->findItem("active_task"); if (active_task != NULL) { nactivetasks++; if (active_task->findItem("active_task_state")->getivalue() == 1) nruntasks++; } else { if (ready_to_report == NULL) nqueuetasks++; } } //цикл списка задач nothertasks = nalltasks-nruntasks-ndonetasks-nqueuetasks; needrefresh = true; } //===данные по дискам=== if (srv->dusagedom.empty()) { srv->statedom.releaseptr(tmpstatedom); return; } Item* tmpdusagedom = srv->dusagedom.hookptr(); Item* disk_usage_summary = tmpdusagedom->findItem("disk_usage_summary"); if (disk_usage_summary != NULL) { dtotal = disk_usage_summary->findItem("d_total")->getdvalue(); dfree = disk_usage_summary->findItem("d_free")->getdvalue(); dboinc = disk_usage_summary->findItem("d_boinc")->getdvalue(); dallowed = disk_usage_summary->findItem("d_allowed")->getdvalue(); std::vector results = disk_usage_summary->getItems("project"); std::vector::iterator it; for (it = results.begin(); it!=results.end(); it++) //цикл списка задач { dboinc = dboinc + (*it)->findItem("disk_usage")->getdvalue(); } } //===данные статистики=== if (srv->statisticsdom.empty()) { srv->statedom.releaseptr(tmpstatedom); srv->dusagedom.releaseptr(tmpdusagedom); return; } laststattime = srv->getlaststattime(); // time_t predstattime = laststattime - (24*60*60); //предыдущий день usertotal = 0; useravg = 0; hosttotal = 0; hostavg = 0; lastdayuser = 0; lastdayhost = 0; double usertotallastday = 0; double hosttotallastday = 0; double usertotalpredday = 0; double hosttotalpredday = 0; projects.clear(); Item* tmpstatisticsdom = srv->statisticsdom.hookptr(); Item* statistics = tmpstatisticsdom->findItem("statistics"); if (statistics!=NULL) { std::vector project_statistics = statistics->getItems("project_statistics"); std::vector::iterator it; for (it = project_statistics.begin(); it!=project_statistics.end(); it++) //цикл списка проектов { ProjectStat st; //заполнить эту структуру st.name = srv->findProjectName(tmpstatedom,((*it)->findItem("master_url")->getsvalue())); st.sstatus = ""; //строка статуса if (!srv->statedom.empty()) { Item* project = srv->findprojectbyname(st.name.c_str()); if (project != NULL) { st.sstatus = st.sstatus + (project->findItem("suspended_via_gui")? "[Susp.] " : ""); st.sstatus = st.sstatus + (project->findItem("dont_request_more_work") ? "[N.N.Tsk.] " : ""); } } std::vector daily_statistics = (*it)->getItems("daily_statistics"); //все дни проекта в этом векторе std::sort(daily_statistics.begin(), daily_statistics.end(), daily_statisticsCmpAbove); //сортируем по убыванию дат if (!daily_statistics.empty()) { Item* lastday = findDay(daily_statistics, laststattime); //последний день Item* predday = NULL; // time_t d = lastday->findItem("day")->getdvalue(); //время из статистики if ( lastday != NULL) //для этого проекта последний день есть { usertotallastday = usertotallastday + lastday->findItem("user_total_credit")->getdvalue(); hosttotallastday = hosttotallastday + lastday->findItem("host_total_credit")->getdvalue(); //берем предпоследний if (daily_statistics.size() > 1) predday = daily_statistics[1]; } // else //в этом проекте за последний день ничего нет // { // predday = daily_statistics.front(); //последний день этого проекта учитываем как предыдущий // } //накапливаем статистику за предыдущий день (если есть) if (predday != NULL) { usertotalpredday = usertotalpredday + predday->findItem("user_total_credit")->getdvalue(); hosttotalpredday = hosttotalpredday + predday->findItem("host_total_credit")->getdvalue(); } //суммарно по всем дням и проектам Item* frontday = daily_statistics.front(); //берем последний несмотря на его дату if (daily_statistics.size() > 1) { Item* predfrontday; predfrontday = daily_statistics[1]; st.userlastday = frontday->findItem("user_total_credit")->getdvalue()-predfrontday->findItem("user_total_credit")->getdvalue(); st.hostlastday = frontday->findItem("host_total_credit")->getdvalue()-predfrontday->findItem("host_total_credit")->getdvalue(); } st.laststattime = frontday->findItem("day")->getdvalue(); usertotal = usertotal + frontday->findItem("user_total_credit")->getdvalue(); useravg = useravg + frontday->findItem("user_expavg_credit")->getdvalue(); hosttotal = hosttotal + frontday->findItem("host_total_credit")->getdvalue(); hostavg = hostavg + frontday->findItem("host_expavg_credit")->getdvalue(); st.user = frontday->findItem("user_total_credit")->getdvalue(); st.host = frontday->findItem("host_total_credit")->getdvalue(); } else { st.user = 0; st.host = 0; st.laststattime = 0; st.userlastday = 0; st.hostlastday = 0; } projects.push_back(st); //вставляем статистику в вектор проектов } //проекты lastdayuser = usertotallastday - usertotalpredday; lastdayhost = hosttotallastday - hosttotalpredday; //сортируем проекты чтобы наиболее актуальные отображались первыми std::sort(projects.begin(), projects.end(), ProjectStat::CmpAbove); } srv->statisticsdom.releaseptr(tmpstatisticsdom); srv->statedom.releaseptr(tmpstatedom); } void InfoPanel::eventhandle(NEvent* ev) //обработчик событий { NView::eventhandle(ev); //предок if ( ev->done ) return; if ( ev->type == NEvent::evTIMER ) { updatedata(); //запросить данные с сервера refresh(); //перерисовать окно } } boinctui-2.7.1/src/addprojectform.h0000664000175000017500000000333614536642777015170 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef ADDPROJECTFORM_H #define ADDPROJECTFORM_H #include #include #include "nform.h" #include "nstatictext.h" #include "srvdata.h" class AddProjectForm : public NForm { public: AddProjectForm(int lines, int rows, Srv* srv, const char* projname, bool userexist, bool byurl); void genfields(int& line, Item* project); //создаст массив полей virtual void eventhandle(NEvent* ev); //обработчик событий protected: int projurlfield; int emailfield; int passwfield; int errmsgfield; int usernamefield; int teamfield; Srv* srv; std::string projname; //имя подключаемого проекта std::string projurl; //url подключаемого проекта bool userexist; //true если юзер уже создан bool byurl; //сделать строку url редактируемой }; #endif //ADDPROJECTFORM_Hboinctui-2.7.1/src/taskinfowin.h0000664000175000017500000000307714536642777014523 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef TASKINFOWIN_H #define TASKINFOWIN_H #include #include #include "ngroup.h" #include "nscrollview.h" #include "tuievent.h" #include "nscrollbar.h" class TaskInfoWin : public NGroup //стандартный диалог вида Ok/Cancel или Yes/No { public: TaskInfoWin(const char* caption, Srv* srv, const char* projecturl, const char* taskname); void eventhandle(NEvent* ev); //обработчик событий void updatedata(); private: int maxlen1; int maxlen2; std::vector > ssbak; //прошлое значение std::string caption; std::string projecturl; std::string taskname; Srv* srv; NScrollView* content; NScrollBar* scrollbar; }; #endif //TASKINFOWIN_Hboinctui-2.7.1/src/mbstring.cpp0000664000175000017500000000534014536642777014342 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #include #include #include "mbstring.h" int mbstrlen(const char* s) //вернет размер строки utf8 в СИМВОЛАХ (не байтах) без учета '\0' { int bsize = strlen(s); //количество байт int result = 0; //подсчитанное кол-во символов int nbytes = 0; //просмотренное кол-во байтов const char* p = s; do { int symlen = mblen(p,bsize-nbytes); if (symlen <= 0) break; nbytes = nbytes + symlen; result++; p = p + symlen; //адрес начала след символа } while ( (*p != 0)&&(nbytes < bsize) ); return result; } char* mbstrtrunc(char* s, int slen) //обрезать до длины slen символов (не байтов) без учета \0 { if (mbstrlen(s)<=slen) //обрезать не надо и так короткая return s; int bsize = strlen(s); //количество байт int nbytes = 0; //просмотренное кол-во байтов int ns = 0; //просмотренное кол-во символов char* p = s; do { int symlen = mblen(p,bsize-nbytes); nbytes = nbytes + symlen; ns++; p = p + symlen; } while ( (*p != '\0')&&(nbytes < bsize)&&(ns < slen) ); *p = '\0'; //обрезаем return s; } char* rtrim(char* s) //удалить завершающие пробелы в строке { if (s == NULL) return NULL; if (strlen(s) == 0) return s; char* p = s + strlen(s) - 1; while ( p >= s) { if (*p == ' ') *p = 0; else break; p--; } return s; } char* ltrim(char* s) //удалить начальные пробелы в строке { if (s == NULL) return NULL; if (strlen(s) == 0) return s; char* p = s; while ( *p != '\0') { if (*p == ' ') p++; else break; } memmove(s, p, strlen(p)); return s; } boinctui-2.7.1/src/statwin.h0000664000175000017500000000550314536642777013654 0ustar ssss// ============================================================================= // This file is part of boinctui. // http://boinctui.googlecode.com // Copyright (C) 2012,2013 Sergey Suslov // // boinctui is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // boinctui is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details // . // ============================================================================= #ifndef STATWIN_H #define STATWIN_H #include #include #include "ngroup.h" #include "nscrollview.h" #include "tuievent.h" #include "nscrollbar.h" struct DayStat //статистика за один день проекта { time_t day; //день unsigned long int scorehost; unsigned long int scoreuser; }; struct ProjStat { std::string name; //имя проекта std::list days; //дни static bool CmpAboveH( ProjStat stat1, ProjStat stat2 ) //для сортировки проектов true если ... { std::list::iterator it; double stat1sum = 0; double stat2sum = 0; for (it = stat1.days.begin(); it != stat1.days.end(); it++) stat1sum += (*it).scorehost; for (it = stat2.days.begin(); it != stat2.days.end(); it++) stat2sum += (*it).scorehost; return stat1sum > stat2sum; }; static bool CmpAboveU( ProjStat stat1, ProjStat stat2 ) //для сортировки проектов true если ... { std::list::iterator it; double stat1sum = 0; double stat2sum = 0; for (it = stat1.days.begin(); it != stat1.days.end(); it++) stat1sum += (*it).scoreuser; for (it = stat2.days.begin(); it != stat2.days.end(); it++) stat2sum += (*it).scoreuser; return stat1sum > stat2sum; }; }; class StatWin : public NGroup //окно общей стстистики { public: StatWin(Srv* srv); void eventhandle(NEvent* ev); //обработчик событий void updatedata(); private: int hpos; //индекс первого отображаемого проекта (для гориз скроллинга) bool hostmode; //true - статистика для хоста (дефолт) false-для юзера std::vector > ssbak; //прошлое значение std::string caption; Srv* srv; NScrollView* content; NScrollBar* scrollbar; std::vector projects; //матрица статистики void updatecaption(); }; #endif //STATWIN_Hboinctui-2.7.1/redhat/0000775000175000017500000000000014536642777012467 5ustar ssssboinctui-2.7.1/redhat/boinctui.spec0000664000175000017500000000464214536642777015165 0ustar ssss# Generate RPM using: # $ cd ~ # $ rpmdev-setuptree # $ git clone https://github.com/suleman1971/boinctui # $ patch -p0 < boinctui-makefile.patch # $ cd boinctui # $ autoconf # $ ./configure --without-gnutls # $ make srctgz # $ cd .. # $ mv boinctui_2.6.0.orig.tar.gz rpmbuild/SOURCES/ # $ rm -rf boinctui* # $ cd rpmbuild/SPECS # $ rpmbuild -bb boinctui.spec # $ ls ../RPMS/ Name: boinctui Version: 2.6.0 Release: 1%{?dist} Summary: Fullscreen Text Mode Manager For BOINC Client Group: Applications/Communications License: GPLv3+ URL: https://github.com/suleman1971/boinctui # Source0: http://download.sourceforge.net/project/boinctui/boinctui_%{version}.tar.gz Source0: ../boinctui_%{version}.tar.gz BuildRequires: autoconf BuildRequires: gcc BuildRequires: ncurses-devel BuildRequires: expat-devel BuildRequires: openssl-devel BuildRequires: gcc-c++ Requires: ncurses Requires: expat Requires: openssl %description boinctui is a fullscreen text mode control tool for BOINC client It can manage local and remote clients (via boinc RPC), and allows you to switch between clients with a hot key. boinctui uses curses library and provides the following features: * Fullscreen curses based text user interface * Switch between several BOINC clients hosts via hot key * View task list (run, queue, suspend e.t.c state) * View message list * Suspend/Resume/Abort tasks * Update/Suspend/Resume/Reset/No New Task/Allow New Task for projects * Toggle activity state GPU and CPU tasks * Run benchmarks * Manage BOINC client on remote hosts via boinc_gui protocol %prep %setup -q -n %{name}-%{version} %build %__autoconf %configure --without-gnutls make %{?_smp_mflags} %make_build %install mkdir -p $RPM_BUILD_ROOT%{_mandir}/man1 #install -m 0644 debian/%{name}.1 %{buildroot}%{_mandir}/man1/ #gzip %{buildroot}%{_mandir}/man1/%{name}.1 %make_install %clean rm -rf %{buildroot} %files %attr(-, root, root) %{_bindir}/%{name} %attr(-, root, root) %{_mandir}/man1/%{name}.1.gz %attr(0644, root, root) %{_docdir}/%{name}/changelog #%doc changelog %license gpl-3.0.txt %changelog * Mon Aug 05 2019 Timothy Mullican 2.5.0-1 - Generate new RPM SPEC file to conform with best practices * Tue Feb 12 2013 Sergey Suslov 2.2.1-0 - Initial version of the package boinctui-2.7.1/Makefile.in0000664000175000017500000000464114536642777013272 0ustar ssssinclude config DEFS += -DVERSION=$(VERSION) @DEFS@ CPP = @CXX@ INSTALL_PROGRAM = install SRCS = ncolorstring.cpp nhline.cpp nvline.cpp nscrollview.cpp nselectlist.cpp nview.cpp \ ngroup.cpp nstatictext.cpp nform.cpp nprogram.cpp nmenu.cpp nmessagebox.cpp \ nscrollbar.cpp \ kclog.cpp cfg.cpp srvdata.cpp mbstring.cpp net.cpp resultparse.cpp resultdom.cpp \ mainprog.cpp infopanel.cpp mainwin.cpp msgwin.cpp taskwin.cpp tui-main.cpp \ cfgform.cpp topmenu.cpp about.cpp helpwin.cpp addprojectform.cpp addmgrform.cpp \ taskinfowin.cpp statwin.cpp OBJS = $(patsubst %.cpp,$(ODIR)/%.o,$(SRCS)) LIBS = @LIBS@ LDFLAGS = @LDFLAGS@ $(LIBS) CXXFLAGS = @CXXFLAGS@ ODIR = .obj SDIR = src exec_prefix = @prefix@ prefix = @prefix@ DATAROOTDIR = @datarootdir@ BINDIR = @bindir@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ DOCDIR = $(DATAROOTDIR)@docdir@ AM_CPPFLAGS = -DBOINC_DIR=\"@BOINC_DIR@\" BINDIR = @bindir@ ifeq (@HAVE_OPENSSL@, 1) DEFS += -DHAVE_OPENSSL endif ############################################################################### all: createobj $(OBJS) @echo "\nLinking...\n" $(CPP) -o $(PACKAGE_TARNAME) $(OBJS) $(LDFLAGS) $(ODIR)/%.o: $(SDIR)/%.cpp @echo " " $(CPP) -c $(CXXFLAGS) $(CPPFLAGS) $(AM_CPPFLAGS) $(DEFS) -o $(ODIR)/$*.o $< clean: rm -f $(ODIR)/*.o $(PACKAGE_TARNAME) config.log install: installman $(INSTALL_PROGRAM) -d $(DESTDIR)$(BINDIR) $(INSTALL_PROGRAM) $(PACKAGE_TARNAME) $(DESTDIR)$(BINDIR) $(INSTALL_PROGRAM) -d $(DESTDIR)$(DOCDIR) $(INSTALL_PROGRAM) changelog $(DESTDIR)$(DOCDIR) createobj: @if ! [ -d "$(ODIR)" ] ; then echo "create $(ODIR)"; mkdir $(ODIR); fi installman: @echo "install man (boinctui.1) to " $(DESTDIR)@mandir@/man1 " directory" mkdir -p $(DESTDIR)@mandir@/man1 install -m 0644 boinctui.1 $(DESTDIR)@mandir@/man1 #srctgz: clean # @if ! [ -d "../$(PACKAGE_TARNAME)-$(VERSION)" ] ; then echo "create symlink ../$(PACKAGE_TARNAME)-$(VERSION)->$(notdir $(CURDIR))"; ln -n -s $(notdir $(CURDIR)) ../$(PACKAGE_TARNAME)-$(VERSION); fi # cd ..; tar --exclude-vcs -vzcf $(PACKAGE_TARNAME)_$(VERSION).orig.tar.gz \ # $(PACKAGE_TARNAME)-$(VERSION)/src \ # $(PACKAGE_TARNAME)-$(VERSION)/redhat \ # $(PACKAGE_TARNAME)-$(VERSION)/Makefile.in \ # $(PACKAGE_TARNAME)-$(VERSION)/configure.in \ # $(PACKAGE_TARNAME)-$(VERSION)/config \ # $(PACKAGE_TARNAME)-$(VERSION)/debian \ # $(PACKAGE_TARNAME)-$(VERSION)/changelog \ # $(PACKAGE_TARNAME)-$(VERSION)/gpl-3.0.txt boinctui-2.7.1/configure.in0000664000175000017500000000750014536642777013533 0ustar ssss# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.68]) AC_INIT([boinctui], [VERSION], [BUG-REPORT-ADDRESS]) AC_CONFIG_SRCDIR([src]) #AC_CONFIG_HEADER([config.h:config.h.in]) #AC_CONFIG_HEADERS([config]) AC_PREFIX_DEFAULT(/usr) #AC_PREFIX_PROGRAM(make) AC_SYS_LARGEFILE # Checks for programs. AC_PROG_CXX #AC_PROG_CC #AC_PROG_CPP # Checks for libraries. AC_ARG_WITH( [ncursesw], [AS_HELP_STRING([--without-ncursesw],[fallback to plain ncurses (disable utf8 support)])], [ AC_CHECK_LIB(ncurses, main, , [AC_MSG_ERROR([Couldn't find ncurses library])] ) AC_CHECK_LIB(form, main, , [AC_MSG_ERROR([Couldn't find form library])] ) AC_CHECK_LIB(panel, main, , [AC_MSG_ERROR([Couldn't find panel library])] ) AC_CHECK_LIB(menu, main, , [AC_MSG_ERROR([Couldn't find menu library])] ) ], [ #use unicode ncursesw (default case) AC_CHECK_LIB(ncursesw, main, , [AC_MSG_ERROR([Couldn't find ncursesw library])] ) #AC_CHECK_LIB(ncurses++w, main, , [AC_MSG_ERROR([Couldn't find ncurses++w library])] ) AC_CHECK_LIB(formw, main, , [AC_MSG_ERROR([Couldn't find formw library])] ) AC_CHECK_LIB(panelw, main, , [AC_MSG_ERROR([Couldn't find panelw library])] ) AC_CHECK_LIB(menuw, main, , [AC_MSG_ERROR([Couldn't find menuw library])] ) ] ) AC_CHECK_LIB(expat, main, , [AC_MSG_ERROR([Couldn't find expat library])] ) AC_CHECK_LIB(pthread, main, , [AC_MSG_ERROR([Couldn't find pthread library])] ) AC_ARG_WITH( [gnutls], [AS_HELP_STRING([--without-gnutls],[use openssl instead gnutls-openssl])], [ HAVE_OPENSSL=1 AC_SUBST([HAVE_OPENSSL]) AC_CHECK_LIB(crypto , MD5_Init, , [AC_MSG_ERROR([Couldn't find crypto library])] ) ], [ #use gnutls-openssl (default case) AC_CHECK_LIB(gnutls-openssl , MD5_Init, , [AC_MSG_ERROR([Couldn't find gnutls-openssl library])] ) #AC_CHECK_LIB(gnutls , MD5_Init, , [AC_MSG_ERROR([Couldn't find gnutls library])] ) ] ) AC_ARG_WITH( [boinc-dir], [AS_HELP_STRING([--with-boinc-dir=DIR], [Specify the BOINC data directory])], [BOINC_DIR="$withval"], [BOINC_DIR="/var/lib/boinc-client"] ) AC_SUBST([BOINC_DIR]) # Checks for header files. AC_LANG_PUSH([C++]) AC_CHECK_HEADERS(\ [ \ pthread.h \ string.h stdlib.h stdio.h sys/stat.h unistd.h stdarg.h sys/ioctl.h arpa/inet.h \ locale.h malloc.h sys/socket.h netdb.h signal.h ctype.h \ algorithm string list vector queue stack sstream \ expat.h \ ] , , [AC_MSG_ERROR([Couldn't find some headers])] ) AC_ARG_WITH( [gnutls], [AS_HELP_STRING([--without-gnutls],[use openssl instead gnutls-openssl])], [ AC_CHECK_HEADERS(\ [ openssl/md5.h ] , , [AC_MSG_ERROR([Couldn't find openssl/md5.h header])] ) ], [ #use gnutls-openssl (default case) AC_CHECK_HEADERS(\ [ gnutls/openssl.h ] , , [AC_MSG_ERROR([Couldn't find gnutls/openssl.h header])] ) ] ) AC_ARG_WITH( [ncursesw], [AS_HELP_STRING([--without-ncursesw],[use ncurses instead ncursesw])], [ #use old curses AC_CHECK_HEADERS(\ [ curses.h form.h panel.h menu.h] , , [AC_MSG_ERROR([Couldn't find some curses header])] ) ], [ #use ncursesw (default case) AC_CHECK_HEADERS(\ [ ncursesw/curses.h ncursesw/form.h ncursesw/panel.h ncursesw/menu.h] , [ AC_DEFINE(NCURSESW_HAVE_SUBDIR,1) ], #cursesw headers are in default include dir? AC_CHECK_HEADERS(\ [ curses.h form.h panel.h menu.h] , [], [ AC_MSG_ERROR([Couldn't find some ncursesw header]) ] ) ) ] ) AC_LANG_POP([C++]) # Checks for typedefs, structures, and compiler characteristics. AC_HEADER_STDBOOL AC_TYPE_SIZE_T # Checks for library functions. AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK AC_FUNC_MALLOC AC_FUNC_REALLOC AC_CHECK_FUNCS([mblen memset setlocale socket strdup strstr]) # Output files AC_CONFIG_FILES([Makefile]) AC_OUTPUT boinctui-2.7.1/changelog0000664000175000017500000001203614536642777013074 0ustar ssssboinctui (2.7.1) * fix build with latest ncurses * fix invisible dark gray text boinctui (2.7.0) * command line parameters "--boinchost" and "--pwd" * fix build with autoconf 2.7.1 boinctui (2.6.0) * fix scrolling in statistics window and "raw task info" window * merged some features from boinctui-extended branch (maintained by Mark Pentler): transparent background, "receive time" and "swap size" columns in task window, host's label in task window, etc. boinctui (2.5.2) * task window scrolling fixed * fix build errors with gcc-11.2 boinctui (2.5.1) * implemented "Project/Add Project by URL" menu item * rpm spec file updated * fixed some build warnings * file gpl-3.0.txt included to source package boinctui (2.5.0) * implemented Statistics window * user can to add any account manager manualy, in addition to BAM and GridRepublic, via "Add new account manager" menu item * bugfix: account manager authorization failed, when using uppercase symbols in password boinctui (2.4.4) * add "Waiting for memory" task state * bugfix: invisible forms at archlinux * bugfix: log timestamp groupping * bugfix: fix clang build boinctui (2.4.3) * bugfix: invisible colors at xterm-256color * bugfix: random crash until program exiting * bugfix: numpad '+' '-' do not work without numlock mode * bugfix: build crash if ncursesw headers are placed not in ncursesw subdir boinctui (2.4.2) * bugfix: than boinctui connected to new version boinc-client, messages at log window has wrong format * timestamp end project name shown in message list only than they have changed boinctui (2.4.1) * bugfix: gcc6 build fail boinctui (2.4.0) * resizable message panel * bugfix: more accurately daily scores visualization boinctui (2.3.6) * bugfix: crach due boinctui.cfg incorrect. * more informative time format at task panel boinctui (2.3.5) * implemented human readable values in raw task info window * bugfix: incorrect dead line time for expired tasks boinctui (2.3.4) * bugfix: message list was shrink after any html tags in message body * bugfix: unusable scrollbar in some of menues boinctui (2.3.3) * implemented mouse support * scrollable widgets has scrollbars now * optional ASCII line drawing mode (useful for wrong terminals like putty etc.) * message "unauthorize" add to caption then authorization failed on boinc-client * bugfix: last item of long menu has incomplet submenu * bugfix: many memory leaks boinctui (2.3.1) * implemented detail task raw info window * network requests moved to separete threads (ui not freeze then network hang) * confirmation dialogs for some operations (abort task, detach project etc.) * "Projects" menu restructured * shortcut "A" added for abort selected task * status line context depended * configuration form automatically show at first boinctui start * at "sort by estimate time" mode completed tasks moved to the end of list boinctui (2.2.1) * bugfix: double free memory (potential crash after edit host list via Config form) * "Sort by deadline" was added into View menu boinctui (2.2.0) * tasks list can be sorted by some columns * implemented toggle "all tasks"/"hide done tasks"/"active only" * migrate from openssl to gnutls-openssl * bugfixes: - unexpected crash in configuration form - sometimes statistics panel doesn't update immediately after switch between hosts boinctui (2.1.1) *bugfix: Configuration host list form's fields don't allow long strings boinctui (2.1.0) *"application name" column was added to task list * each column in task list can on/off via menu "View" * optional key "--without-ncursesw" was added to configure script. This key can disable utf8 and perform linking with plain ncurses * implemented support account managers (BAM etc). Attach/Detach/Syncronize * implemented add/detach project directly (without account manager) as existing user or as new user boinctui (1.2.0) * bugfixes: - percent done was always 0% on same locale setting - workaround for negative estimate time * Percent done for GPU tasks are color highlight (green for CUDA tasks, magenta for OpenCL) * implemented GPU activity operations: - run GPU always. - run GPU based on preferences. - suspend GPU always. boinctui (1.1.0) * bugfixes: - any color combinations are invisible on any terminals - incorrect visualization on any white background terminals * implemented network activity operations: - run always. - run based on preferences. - suspend always. * implemented "Run benchmarks" boinctui (1.0.0) * implemented project operations: - suspend. - resume. - reset. - no new tasks. - allow new tasks. * add "abort task" in task menu * implemented "Activity" features: - run always. - run based on preferences. - suspend always. * any bugfixes. * color schem optimization. boinctui (0.0.1) * Initial Release. boinctui-2.7.1/gpl-3.0.txt0000664000175000017500000010451514536642777013047 0ustar ssss GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . boinctui-2.7.1/boinctui.10000664000175000017500000000247614536642777013127 0ustar ssss.\" Hey, EMACS: -*- nroff -*- .TH BOINCTUI 1 "21-JAN-2016" .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME boinctui \- Fullscreen text mode manager for BOINC client .SH SYNOPSIS .B boinctui .SH DESCRIPTION BOINC can be configured in many ways. And the monitoring of scientific progress contributed to one's own machines is rewarding. For remote machines or to avoid moving the hands of your keyboard, this package provides, all for your UNIX command line: .br * Fullscreen curses based text user interface .br * Switch between several BOINC clients hosts via hot key .br * View task list (run, queue, suspend e.t.c state) .br * View message list .br * Suspend/Resume/Abort tasks .br * Update/Suspend/Resume/Reset/No New Task/Allow New Task for projects .br * Toggle activity state GPU and CPU tasks .br * Run benchmarks .br * Manage BOINC client on remote hosts via boinc_gui protocol .SH SEE ALSO .BR boinc-manager (1), .br https://github.com/suleman1971/boinctui boinctui-2.7.1/config0000664000175000017500000000024514536642777012411 0ustar ssssTARGET = boinctui VERSION = 2.7.1 #DEFS += -DVERSION=$(VERSION) #DEFS += -DDEBUG DEFS += -DENABLEMOUSE #DEFS += -DEVENTTHREAD DEFS += -DNCURSES_INTERNALS