// ------------------------------------------------------------------ // GoldED+ // Copyright (C) 1990-1999 Odinn Sorensen // Copyright (C) 1999-2000 Alexander S. Aganichev // ------------------------------------------------------------------ // 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 2 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, // MA 02111-1307 USA // ------------------------------------------------------------------ // $Id$ // ------------------------------------------------------------------ // Message viewer class implementation. // ------------------------------------------------------------------ #if defined(_MSC_VER) || defined(__MINGW32__) #include #endif #include #include // ------------------------------------------------------------------ GMsgHeaderView::GMsgHeaderView() { alive = false; at_row = at_column = width = height = 0; border_type = gwindow::bordertype_none; window_color = from_color = to_color = subject_color = BLUE|_LGREY; location_color = BLUE|_LGREY; title_color = highlight_color = RED|_LGREY; border_color = YELLOW|_LGREY; } // ------------------------------------------------------------------ GMsgHeaderView::~GMsgHeaderView() { Destroy(); } // ------------------------------------------------------------------ void GMsgHeaderView::Create() { alive = true; window.openxy( at_row, at_column, height, width, border_type, border_color, window_color ); } // ------------------------------------------------------------------ void GMsgHeaderView::Destroy() { if(alive) window.close(); else alive = false; } // ------------------------------------------------------------------ void GMsgHeaderView::Use(Area *areaptr, GMsg *msgptr) { area = areaptr; msg = msgptr; } // ------------------------------------------------------------------ void GMsgHeaderView::Paint() { ISub buf; int namewidth = CFG->disphdrnodeset.pos - CFG->disphdrnameset.pos; int nodewidth = CFG->disphdrdateset.pos - CFG->disphdrnodeset.pos; int datewidth = MinV(width - CFG->disphdrdateset.pos, CFG->disphdrdateset.len); #if defined(GUTLOS_FUNCS) g_set_ostitle_name(struplow(strtmp(area->echoid())), 0); #endif // Generate top line fields char buf1[16]; if((CFG->dispareano == ALWAYS) or (CFG->dispareano and area->board())) sprintf(buf1, "[%u] ", area->board()); else *buf1 = NUL; #if defined(_MSC_VER) || defined(__MINGW32__) char *top = (char*)alloca(width+1); #else __extension__ char top[width+1]; #endif strxmerge(top, width+1, " ", buf1, strtrim(strtmp(area->desc())), " (", area->isinternet() ? area->Internetaddress() : area->Aka().addr.make_string(buf), ") ", NULL); int desclen = strlen(top); window.printc(0, 0, border_color|ACSET, _box_table(W_BHEAD, 1)); window.prints(0, 1, title_color, top); if(msg->areakludgeid) strxmerge(top, width+1, " ", area->echoid(), " (", msg->areakludgeid, ") ", NULL); else strxmerge(top, width+1, " ", area->echoid(), " ", NULL); int taglen = strlen(top); if((width - (desclen + taglen + 2)) > 0) window.fill(0, desclen+1, 0, width-(taglen+1)-1, _box_table(W_BHEAD, 1), border_color|ACSET); window.prints(0, width-taglen-1, title_color, top); window.printc(0, width-1, border_color|ACSET, _box_table(W_BHEAD, 1)); // Generate message attributes string bool attrsgenerated = false; MakeAttrStr(buf, width-CFG->disphdrnodeset.pos, &msg->attr); if(*buf) { attrsgenerated = true; strsetsz(buf, width-CFG->disphdrnodeset.pos); window.prints(1, CFG->disphdrnodeset.pos, window_color, buf); } // Generate message number and reply links string char* ptr = buf; int list_max = msg->link.list_max(); ulong* replies = (ulong*)throw_calloc(list_max+1, sizeof(ulong)); ulong replyto, replynext; if(CFG->switches.get(disprealmsgno)) { ptr += sprintf(ptr, " %-5.5s: #%u [%u]", LNG->Msg, msg->msgno, area->Msgn.Count()+(msg->attr.nwm() ? 1 : 0)); replyto = msg->link.to(); replies[0] = msg->link.first(); replynext = msg->link.next(); for(int replyn=1; replynlink.list(replyn-1); } else { uint active = area->Msgn.Count() + (msg->attr.nwm() ? 1 : 0); ptr += sprintf(ptr, " %-5.5s: %u %s %u", LNG->Msg, msg->attr.nwm() ? active : area->Msgn.ToReln(msg->msgno), LNG->of, active); replyto = area->Msgn.ToReln(msg->link.to()); replies[0] = area->Msgn.ToReln(msg->link.first()); replynext = area->Msgn.ToReln(msg->link.next()); for(int replyn=1; replynMsgn.ToReln(msg->link.list(replyn-1)); } if(replyto) ptr += sprintf(ptr, " -%lu", replyto); for(int replyn=0,plus=0; (replyn<(list_max+1)) and (not attrsgenerated or ((ptr-buf)disphdrnodeset.pos)); replyn++) if(replies[replyn]) ptr += sprintf(ptr, " %s%lu", (plus++?"":"+"), replies[replyn]); if(replynext and (not attrsgenerated or ((ptr-buf)disphdrnodeset.pos))) sprintf(ptr, " *%lu", replynext); throw_free(replies); strsetsz(buf, attrsgenerated ? CFG->disphdrnodeset.pos : width); window.prints(1, 0, window_color, buf); // Get marks if(area->bookmark == msg->msgno) window.prints(1, 5, highlight_color, "\x11"); if(area->Mark.Count() and area->Mark.Find(msg->msgno)) window.prints(1, 7, highlight_color, "\x10"); // Generate from info bool nodegenerated = false; if(not area->isinternet()) { if(area->isecho() or not (*msg->ifrom and (*msg->realby or *msg->iorig))) { // Generate orig node data if(msg->orig.net) msg->orig.make_string(buf); else *buf = NUL; nodegenerated = true; strsetsz(buf, nodewidth); window.prints(2, CFG->disphdrnodeset.pos, from_color, buf); } } if((not area->isecho() or area->isnewsgroup()) and *msg->ifrom and *msg->realby) strxmerge(buf, (namewidth+nodewidth), msg->realby, " <", msg->iorig, ">", NULL); else if((not area->isecho() or area->isnewsgroup()) and *msg->ifrom and *msg->iorig) strxcpy(buf, msg->iorig, (namewidth+nodewidth)); else strxcpy(buf, msg->By(), (namewidth+nodewidth)); strsetsz(buf, nodegenerated ? namewidth : (namewidth+nodewidth)); window.prints(2, 0, window_color, LNG->From); window.prints(2, CFG->disphdrnameset.pos, ((msg->foundwhere&GFIND_FROM) or msg->attr.fmu() or (msg->attr.loc() and CFG->switches.get(displocalhigh))) ? highlight_color : from_color, buf); if(datewidth > 0) { if(msg->written) strftimei(buf, datewidth, LNG->DateTimeFmt, gmtime(&msg->written)); else *buf = NUL; strsetsz(buf, datewidth); window.prints(2, CFG->disphdrdateset.pos, from_color, buf); } // Generate dest node data nodegenerated = false; if(not area->isinternet()) { if(not (*msg->ito and (*msg->realto or *msg->idest))) { if(msg->dest.net and area->isnet()) { msg->dest.make_string(buf); if(msg->odest.net) { if((msg->odest.net != msg->dest.net) or (msg->odest.node != msg->dest.node)) { sprintf(buf+strlen(buf), " %s %u/%u", LNG->Via, msg->odest.net, msg->odest.node); } } nodegenerated = true; strsetsz(buf, nodewidth); window.prints(3, CFG->disphdrnodeset.pos, to_color, buf); } } } if((not area->isecho() or area->isnewsgroup()) and *msg->ito and *msg->realto) strxmerge(buf, (namewidth+nodewidth), msg->realto, " <", msg->idest, ">", NULL); else if((not area->isecho() or area->isnewsgroup()) and *msg->ito and *msg->idest) strxcpy(buf, msg->idest, (namewidth+nodewidth)); else strxcpy(buf, msg->To(), (namewidth+nodewidth)); strsetsz(buf, nodegenerated ? namewidth : (namewidth+nodewidth)); window.prints(3, 0, window_color, LNG->To); window.prints(3, CFG->disphdrnameset.pos, ((msg->foundwhere&GFIND_TO) or msg->attr.tou()) ? highlight_color : to_color, buf); if(datewidth > 0) { if(msg->arrived) strftimei(buf, datewidth, LNG->DateTimeFmt, gmtime(&msg->arrived)); else *buf = NUL; strsetsz(buf, datewidth); window.prints(3, CFG->disphdrdateset.pos, to_color, buf); } // Generate subjectline strxcpy(buf, (msg->attr.att() or msg->attr.frq() or msg->attr.urq()) ? LNG->File : LNG->Subj, 10); int lngsubjlen = strlen(buf); window.prints(4, 0, window_color, buf); strxcpy(buf, msg->re, width-lngsubjlen); strsetsz(buf, width-lngsubjlen); window.prints(4, lngsubjlen, (msg->foundwhere&GFIND_SUBJECT) ? highlight_color : subject_color, buf); // Generate bottom line window.fill(5, 0, 5, width-1, _box_table(W_BHEAD, 1), border_color|ACSET); // Calculate attach file sizes if(msg->attr.att()) { if(CFG->dispattachsize) { char buf2[GMAXPATH]; int begpos = strlen(LNG->File); strcpy(buf, msg->re); char* ptr = strtok(buf, " "); while(ptr) { if(*ptr == '^') ptr++; if((isalpha(*ptr) and (ptr[1] == ':')) or (ptr[0] == '\\') or (ptr[0] == '/')) strcpy(buf2, ptr); else sprintf(buf2, "%s%s", CFG->inboundpath, ptr); long sz = GetFilesize(MapPath(buf2)); if(sz == -1) sprintf(buf1, " %s ", LNG->n_a); else { switch(CFG->dispattachsize) { case ATTACH_BYTES: sprintf(buf1, " %li ", sz); break; case ATTACH_KBYTES: sprintf(buf1, " %lik ", (sz+512L)/1024L); break; } } window.prints(5, begpos+int(ptr-buf)-1, title_color, buf1); ptr = strtok(NULL, " "); } } } if(CFG->dispmsgsize and msg->txt and not _in_editor) { uint len = strlen(msg->txt); switch(CFG->dispmsgsize) { case DISPMSGSIZE_BYTES: sprintf(buf1, "%u", len); break; case DISPMSGSIZE_KBYTES: sprintf(buf1, "%uk", (len+512)/1024); break; case DISPMSGSIZE_LINES: sprintf(buf1, "%u", msg->lines); break; default: *buf1 = NUL; } if(*buf1) window.prints(5, 1, title_color, buf1); } if (CFG->disphdrlocation && !_in_editor) { std::string loc; LookupNodeLocation(msg, loc, LOOK_CITY1); if (loc.length()) loc = " " + loc; if (AA->isnet()) { std::string loc2; LookupNodeLocation(msg, loc2, LOOK_CITY2); if (loc.length()) loc += " | " + loc2; } if (loc.length()) { loc += " "; int pos = window.width() - loc.length() - 1; window.prints(5, pos, location_color, loc.c_str()); } } } // ------------------------------------------------------------------ GMsgBodyView::GMsgBodyView() { alive = false; scrollbar_visible = false; at_row = at_column = width = height = visible_width = 0; border_type = gwindow::bordertype_none; window_color = BLACK|_LGREY; highlight_color = WHITE|_RED; scrollbar_color = DGREY|_LGREY; border_color = YELLOW|_LGREY; } // ------------------------------------------------------------------ GMsgBodyView::~GMsgBodyView() { Destroy(); } // ------------------------------------------------------------------ void GMsgBodyView::Create() { alive = true; window.openxy( at_row, at_column, height, width, border_type, border_color, window_color, scrollbar_color ); dummy_line.txt = ""; dummy_line.type = 0; dummy_line.color = window_color; visible_width = width - (CFG->switches.get(disppagebar) ? 1 : 0); } // ------------------------------------------------------------------ void GMsgBodyView::Destroy() { if(alive) window.close(); else alive = false; } // ------------------------------------------------------------------ void GMsgBodyView::Use(Area *areaptr, GMsg *msgptr, int startline) { area = areaptr; msg = msgptr; // Find the first highlighted line and go to it if(msg->foundwhere & GFIND_BODY) { for(startline=0; startlinelines; startline++) { if(msg->line[startline]->type & GLINE_HIGH) break; } // Adjust position in window startline -= height / 3; if(startline < 0) startline = 0; else if((startline + height - 1) >= msg->lines) startline = msg->lines - height; } if(startline >= msg->lines) startline = msg->lines - 1; if(startline < 0) startline = 0; upperline = startline; lowerline = upperline + height - 1; can_pagedown = lowerline < (msg->lines-1); scrollbar_visible = CFG->switches.get(disppagebar) ? (msg->lines > height) : false; visible_width = scrollbar_visible ? width-1 : width; window.set_scrollbar_color(scrollbar_visible ? scrollbar_color : -1); } // ------------------------------------------------------------------ void GMsgBodyView::PaintLine(int row, Line *line) { // Calculate effective coordinates for vputs int vrow = gwin.active->srow + row; uint llen = line->txt.length(); int color = (line->type & GLINE_HIGH) ? highlight_color : line->color; // Trim line if it longer than should be. This actually happens in very rare // cases, but always when hex dump displayed. if(llen > visible_width) { llen = visible_width; line->txt.erase(llen); } // Print it if(not SearchHighlight(line, vrow, visible_width, highlight_color)) { if(line->type & GLINE_ORIG and strneql(line->txt.c_str(), " * Origin: ", 11)) { vputs(vrow, 0, color, " * Origin: "); StyleCodeHighlight(line->txt.c_str()+11, vrow, 11, not AA->attr().hex() and AA->adat->hidestylies, color); } else StyleCodeHighlight(line->txt.c_str(), vrow, 0, not AA->attr().hex() and AA->adat->hidestylies, color); int tlen = strlen(line->txt.c_str()); vputns(vrow, tlen, color, "", visible_width-tlen); } else vputns(vrow, 0, color, line->txt.c_str(), visible_width); } // ------------------------------------------------------------------ void GMsgBodyView::Paint() { window.activate_quick(); Line* dummy_index = NULL; Line** line_index = msg->line ? (msg->line + upperline) : &dummy_index; for(int row=0; rowlines > height)) { can_pagedown = true; upperline = 0; lowerline = height - 1; Paint(); return true; } return false; } // ------------------------------------------------------------------ int GMsgBodyView::Bottom() { if(msg->lines > height) { if(msg->lines <= height) { can_pagedown = true; upperline = 0; } else { can_pagedown = false; upperline = msg->lines - height; } lowerline = upperline + height - 1; Paint(); return true; } return false; } // ------------------------------------------------------------------ int GMsgBodyView::PageUp() { if(msg->lines > height) { can_pagedown = true; if(upperline) { upperline -= height - 1; if(upperline < 0) upperline = 0; lowerline = upperline + height - 1; Paint(); return true; } } return false; } // ------------------------------------------------------------------ int GMsgBodyView::PageDown() { if(msg->lines > height) { if(can_pagedown) { if(lowerline < msg->lines-1) { lowerline += height - 1; if(lowerline >= msg->lines-1) can_pagedown = false; upperline = lowerline - height + 1; Paint(); return true; } } } return false; } // ------------------------------------------------------------------ int GMsgBodyView::LineUp() { if(msg->lines > height) { if(upperline) { window.scroll_down(); upperline--; lowerline--; #ifdef GOLD_MOUSE gmou.HideCursor(); #endif PaintLine(0, msg->line[upperline]); #ifdef GOLD_MOUSE gmou.ShowCursor(); #endif can_pagedown = lowerline < (msg->lines-1); UpdateScrollbar(); return true; } } return false; } // ------------------------------------------------------------------ int GMsgBodyView::LineDown() { if(msg->lines > height) { if(lowerline < (msg->lines-1)) { window.scroll_up(); upperline++; lowerline++; #ifdef GOLD_MOUSE gmou.HideCursor(); #endif PaintLine(height-1, msg->line[lowerline]); #ifdef GOLD_MOUSE gmou.ShowCursor(); #endif can_pagedown = lowerline < (msg->lines-1); UpdateScrollbar(); return true; } } return false; } // ------------------------------------------------------------------ int GMsgBodyView::Continue() { if(can_pagedown) return PageDown(); return false; } // ------------------------------------------------------------------ int GMsgBodyView::ThumbTrack(int pos) { return ThumbPosition(pos); } // ------------------------------------------------------------------ int GMsgBodyView::ThumbPosition(int pos) { upperline = pos; lowerline = upperline + height - 1; can_pagedown = lowerline < (msg->lines-1); Paint(); return true; } // ------------------------------------------------------------------ void GMsgBodyView::UpdateScrollbar() { if(CFG->switches.get(disppagebar) and scrollbar_visible) window.vscrollbar(msg->lines, msg->lines-height, upperline); } // ------------------------------------------------------------------ void GMsgBodyView::prints(int wrow, int wcol, int atr, const char* str) { vputs(wrow, wcol, atr, str); } // ------------------------------------------------------------------