#include #include #include #include #include "ba8201.h" #include "ba8301.h" /////////////////////////////////////////////////////////// // TReport_font /////////////////////////////////////////////////////////// XVT_FNTID TReport_font::get_xvt_font(const TWindow& win) const { if (win.win() != _win_mapped) { int nSize = _size; if (win.win() != 883) // Non e' una stampa! { const int cpi = 120 / DEFAULT_FONT_SIZE; const PNT pnt0 = win.log2dev(0,0); const PNT pnt1 = win.log2dev(cpi*100,100); const int ppi = pnt1.h - pnt0.h; const TString emme(cpi, 'M'); int mi = 0, me = 0, ma = 2*(pnt1.v - pnt0.v); int best = 0, best_error = 0; while (mi <= ma) { me = (mi+ma)/2; XVT_FNTID fontid = xvt_font_create(); xvt_font_set_family(fontid, "Courier New"); xvt_font_set_size(fontid, me); xvt_dwin_set_font(win.win(), fontid); const int width = xvt_dwin_get_text_width(win.win(), emme, -1); const int error = abs(width - ppi); xvt_font_destroy(fontid); if (best == 0 || error < best_error) { best = me; best_error = error; if (error == 0) break; } if (width > ppi) ma = me-1; else mi = me+1; } nSize = cpi * best / _cpi; } XVT_FNTID fontid = xvt_font_create(); xvt_font_set_family(fontid, (char*)(const char*)_name); xvt_font_set_size(fontid, nSize); xvt_font_set_style(fontid, _style); TReport_font& myself = *(TReport_font*)this; myself.unmap(); myself._fontid = fontid; myself._win_mapped = win.win(); xvt_dwin_get_font_metrics(_win_mapped, &myself._leading, &myself._ascent, &myself._descent); } return _fontid; } void TReport_font::unmap() { if (_fontid != NULL) { xvt_font_destroy(_fontid); _fontid = NULL; } _win_mapped = NULL_WIN; } void TReport_font::create(const char* name, int size, XVT_FONT_STYLE_MASK style) { _name = name; _size = size; _style = style; _cpi = 120 / _size; unmap(); } void TReport_font::copy(const TReport_font& font) { create(font.name(), font.size(), font.style()); } int TReport_font::compare(const TSortable& s) const { const TReport_font& f = (const TReport_font&)s; int cmp = _name.compare(f.name(), -1, true); if (cmp == 0) { cmp = _size - f.size(); if (cmp == 0) cmp = _style - f.style(); } return cmp; } void TReport_font::save(TXmlItem& item) const { TXmlItem& font = item.AddChild("font"); font.SetAttr("face", _name); font.SetAttr("size", _size); if (_style & XVT_FS_BOLD) font.SetAttr("bold", "1"); if (_style & XVT_FS_ITALIC) font.SetAttr("italic", "1"); if (_style & XVT_FS_UNDERLINE) font.SetAttr("underline", "1"); } bool TReport_font::load(const TXmlItem& item) { const TXmlItem* font = item.FindFirstChild("font"); if (font != NULL) { const TString& name = font->GetAttr("face"); const int size = font->GetIntAttr("size", 10); XVT_FONT_STYLE_MASK style = 0; if (font->GetIntAttr("bold")) style |= XVT_FS_BOLD; if (font->GetIntAttr("italic")) style |= XVT_FS_ITALIC; if (font->GetIntAttr("underline")) style |= XVT_FS_UNDERLINE; create(name, size, style); } return font != NULL; } TReport_font::TReport_font() : _fontid(NULL), _win_mapped(NULL_WIN) { create("Courier New", DEFAULT_FONT_SIZE, XVT_FS_NONE); } TReport_font::TReport_font(const TReport_font& f) : _fontid(NULL), _win_mapped(NULL_WIN) { copy(f); } TReport_font::~TReport_font() { unmap(); } /////////////////////////////////////////////////////////// // TReport_expr /////////////////////////////////////////////////////////// class TReport_expr : public TExpression { TReport& _report; TVariant _var; protected: virtual int parse_user_func(const char* name, int nparms) const; virtual void evaluate_user_func(int index, int nparms, TEval_stack& stack, TTypeexp type) const; bool is_numeric(const char* str) const; public: TReport_expr(TReport& rep, const char* exp); const TVariant& as_variant(TFieldtypes ft); }; int TReport_expr::parse_user_func(const char* name, int nparms) const { return -1; } void TReport_expr::evaluate_user_func(int index, int nparms, TEval_stack& stack, TTypeexp type) const { } bool TReport_expr::is_numeric(const char* str) const { if (str == NULL || *str == '\0' || *str == '0') return false; // Se comincia per zero va preservato! if (*str == '-') { str++; if (*str <= ' ') return false; } while (*str) { if (strchr("0123456789.", *str) == NULL) return false; str++; } return true; } const TVariant& TReport_expr::as_variant(TFieldtypes ft) { set_type(ft == _alfafld || ft == _nullfld ? _strexpr : _numexpr); const TString& str = as_string(); switch (ft) { case _datefld: _var.set(TDate(str)); break; case _longfld: _var.set(atol(str)); break; case _realfld: _var.set(real(str)); break; default : _var.set(str); break; }; return _var; } TReport_expr::TReport_expr(TReport& rep, const char* exp) : _report(rep) { set(exp, _strexpr); } TObject* TReport_expr_cache::key2obj(const char* key) { return new TReport_expr(*_report, key); } TReport_expr& TReport_expr_cache::operator[](const char* key) { return *(TReport_expr*)objptr(key); } TObject* TReport_image_cache::key2obj(const char* key) { TImage* img = NULL; TFilename pathname = key; if (pathname.custom_path()) img = new TImage(pathname); return img; } TImage* TReport_image_cache::image(const TString& key) { return (TImage*)objptr(key); } TReport_image_cache::TReport_image_cache() : TCache(7) { } /////////////////////////////////////////////////////////// // Utility /////////////////////////////////////////////////////////// void advanced_draw_rect(TWindow& win, const RCT& r, int border, COLOR fore, COLOR back) { const bool has_pen = border > 0; const bool has_brush = color_distance(back, COLOR_WHITE) != 0; if (has_pen || has_brush) { if (has_pen) win.set_pen(fore, border, PAT_SOLID); else win.hide_pen(); if (has_brush) win.set_brush(back, PAT_SOLID); else win.hide_brush(); xvt_dwin_draw_rect(win.win(), (RCT*)&r); } } void advanced_draw_text(TWindow& win, const char* text, const RCT& r, char halign, char valign) { const short dx = r.right-r.left; const short dy = r.bottom-r.top; short x = r.left; short y = r.bottom; if (halign != 'L') { const int tw = xvt_dwin_get_text_width(win.win(), text, -1); switch (halign) { case 'C': x += (dx - tw)/2; break; case 'R': x = r.right-tw; break; default : break; } } // Text Height int leading, ascent, descent; xvt_dwin_get_font_metrics(win.win(), &leading, &ascent, &descent); switch (valign) { case 'C': y -= (dy - ascent)/2; break; case 'T': y = r.top + leading + ascent; break; default : y -= descent; break; } xvt_dwin_draw_text(win.win(), x, y, text, -1); } static void set_num_attr(TXmlItem& item, const char* attr, long num, short def = 0) { if (num != def) { const real n = num / CENTO; item.SetAttr(attr, n.string()); } } static void set_col_attr(TXmlItem& item, const char* attr, COLOR col, COLOR def = COLOR_BLACK) { if (color_distance(col, def) != 0) { TString16 str; str.format("#%06X", col & 0xFFFFFF); item.SetAttr(attr, str); } } static short get_num_attr(const TXmlItem& item, const char* attr, short def = 0) { const TString& str = item.GetAttr(attr); if (str.not_empty()) { real n = str; n *=CENTO ; def = (short)n.integer(); } return def; } static COLOR get_col_attr(const TXmlItem& item, const char* attr, COLOR col) { const TString& str = item.GetAttr(attr); if (str[0] == '#') sscanf(str, "#%X", &col); return col; } static char get_chr_attr(const TXmlItem& item, const char* attr, char c) { const TString& str = item.GetAttr(attr); if (str[0] > ' ') c = toupper(str[0]); return c; } /////////////////////////////////////////////////////////// // TReport_section /////////////////////////////////////////////////////////// TReport_section* TReport_section::father_section() const { if (level() <= 0) { if (type() != 'B') return _report.find_section('B', 0); } else return _report.find_section('B', type() == 'B' ? 0 : 1); return NULL; } const TReport_font& TReport_section::font() const { const TReport_font* f = _font; if (f == NULL) { TReport_section* father = father_section(); if (father == NULL) f = &_report.font(); else f = &father->font(); } return *f; } void TReport_section::set_font(const TReport_font& f) { if (_font != NULL) { delete _font; _font = NULL; } if (font() != f) _font = new TReport_font(f); } void TReport_section::unmap_font() { if (_font != NULL) _font->unmap(); for (int i = last(); i >= 0; i--) field(i).unmap_font(); } int TReport_section::add(TObject* obj) { TReport_field* rf = (TReport_field*)obj; rf->set_section(this); return TArray::add(obj); } int TReport_section::add(TObject& obj) { TReport_field& rf = (TReport_field&)obj; rf.set_section(this); return TArray::add(obj); } int TReport_section::find_field_pos(int id) { for (int i = items()-1; i >= 0; i--) { if (field(i).id() == id) break; } return i; } TReport_field* TReport_section::find_field(int id) { const int pos = find_field_pos(id); if (pos >= 0) return &field(pos); return NULL; } TPoint TReport_section::compute_size() const { if (hidden()) return TPoint(0,0); TPoint s = _size; for (int i = 0; i < items(); i++) { const TReport_field& rf = field(i); if (rf.shown()) { const TRectangle& r = rf.get_rect(); if (r.right() > s.x) s.x = r.right(); if (r.bottom() > s.y) s.y = r.bottom(); } } return s; } bool TReport_section::compute_rect(TRectangle& rct) const { rct.set(TPoint(0, 0), compute_size()); return !rct.is_empty(); } void TReport_section::draw(TWindow& win, TReport_draw_mode rdm) const { if (shown() || rdm == rdm_edit) { for (int i = 0; i < items(); i++) { const TReport_field& f = field(i); f.draw(win, rdm); } } } bool TReport_section::load_fields() { const bool ok = active() || shown(); if (ok) { for (int i = 0; i < items(); i++) { TReport_field& f = field(i); f.load_field(); } } return ok; } bool TReport_section::execute_prescript() { bool ok = true; if (active()) { TString80 str; if (items() > 0) report().set_curr_field(&field(0)); else report().set_curr_field(NULL); ok = _prescript.execute(report(), str); } for (int i = 0; i < items(); i++) { TReport_field& f = field(i); f.execute_prescript(); } return ok; } bool TReport_section::execute_postscript() { bool ok = true; for (int i = 0; i < items(); i++) { TReport_field& f = field(i); f.execute_postscript(); } if (active()) { TString80 str; ok = _postscript.execute(report(), str); } return ok; } void TReport_section::save(TXmlItem& root) const { TXmlItem& item = root.AddChild("section"); char* tipo = NULL; switch (type()) { case 'H': tipo = "Head"; break; case 'F': tipo = "Foot"; break; default : tipo = "Body"; break; } item.SetAttr("type", tipo); item.SetAttr("level", level()); set_num_attr(item, "width", width()); set_num_attr(item, "height", height()); item.SetAttr("hidden", _hidden); item.SetAttr("deactivated", _deactivated); item.SetAttr("hidden_if_needed", hidden_if_needed()); item.SetAttr("pagebreak", _page_break); if (grouped_by().not_empty()) item.AddChild("groupby") << grouped_by(); if (has_font()) font().save(item); _prescript.save(item, "prescript"); _postscript.save(item, "postscript"); for (int i = 0; i < items(); i++) { const TReport_field& rf = field(i); rf.save(item); } } void TReport_section::load(const TXmlItem& sec) { set_width(get_num_attr(sec, "width")); set_height(get_num_attr(sec, "height")); force_page_break(sec.GetBoolAttr("pagebreak")); hide_if_needed(sec.GetBoolAttr("hidden_if_needed")); show(!sec.GetBoolAttr("hidden")); activate(!sec.GetBoolAttr("deactivated")); TReport_font font; if (font.load(sec)) set_font(font); if (level() > 1) { const TXmlItem* gb = sec.FindFirstChild("groupby"); if (gb != NULL) { TString str; gb->GetEnclosedText(str); group_by(str); } } for (int j = 0; j < sec.GetChildren(); j++) { const TXmlItem& fld = *sec.GetChild(j); if (fld.GetTag() == "field") { TReport_field* rf = new TReport_field(this); if (rf->load(fld)) add(rf); else delete rf; } } _prescript.load(sec, "prescript"); _postscript.load(sec, "postscript"); } TReport_section::TReport_section(TReport& r, char t, int l) : _report(r), _type(t), _level(l), _font(NULL), _size(0,0), _page_break(false), _hidden_if_needed(false), _hidden(false), _deactivated(false) { } TReport_section::~TReport_section() { if (_font) delete _font; } /////////////////////////////////////////////////////////// // TReport_script /////////////////////////////////////////////////////////// TString& TReport_script::translate_message() const { TToken_string source(_src, '\n'); TToken_string line(256, '|'); TString cmd, arg, fld; TString& alex = get_tmp_string(); FOR_EACH_TOKEN(source, srcrow) { line = srcrow; if (!line.starts_with("MESSAGE ")) continue; line.ltrim(8); line.trim(); const bool msg_empty = line.starts_with("EMPTY "); if (msg_empty) { line.ltrim(6); line.trim(); alex << "0 = IF "; } FOR_EACH_TOKEN(line, tok) { const TFixed_string msg(tok); const int comma = msg.find(','); if (comma > 0) { cmd = msg.left(comma); arg = msg.mid(comma+1); fld = arg; if (fld[0] != '#') fld.insert("#", 0); } else { cmd = msg; arg.cut(0); fld.cut(0); } if (cmd.starts_with("CO")) // COPY { alex << "#THIS @ " << fld << " ! "; } else if (cmd.starts_with("AD")) // ADD { alex << "#THIS @ " << fld << " @ + "<< fld << " ! "; } else if (cmd.starts_with("IN")) // INC { alex << fld << " @ 1 + "<< fld << " ! "; } else if (cmd.starts_with("RE")) // RESET { alex << "\"\" " << fld << " ! "; } else if (cmd.starts_with("SH")) // SHOW { alex << fld << " SHOW "; } else if (cmd.starts_with("EN")) // EN { alex << fld << " ENABLE "; } else if (cmd.starts_with("DI")) // DISABLE { alex << fld << " DISABLE "; } else if (cmd.starts_with("HI")) // HIDE { alex << fld << " HIDE "; } } if (msg_empty) alex << "THEN "; } return alex; } void TReport_script::set(const char* source) { if (_src != source) { destroy(); _src = source; } } bool TReport_script::execute(TReport& rep, TString& output) { bool good = ok(); if (good) { if (_bc == NULL) { _bc = new TBytecode; if (_src.starts_with("MESSAGE ")) good = rep.compile(translate_message(), *_bc); else good = rep.compile(_src, *_bc); } if (good) good = rep.execute(*_bc, output); } return good; } bool TReport_script::execute(TReport_field& rf) { bool good = ok(); if (good) { TString str; TReport& rep = rf.section().report(); rep.set_curr_field(&rf); good = execute(rep, str); } return good; } void TReport_script::destroy() { if (_bc != NULL) { delete _bc; _bc = NULL; } _src.cut(0); } void TReport_script::save(TXmlItem& root, const char* tag) const { if (ok()) { TXmlItem& script = root.AddChild(tag); script << _src; } } bool TReport_script::load(const TXmlItem& root, const char* tag) { destroy(); TXmlItem* script = root.FindFirstChild(tag); if (script != NULL) script->GetEnclosedText(_src); return ok(); } TReport_script::TReport_script() : _bc(NULL) { } TReport_script::~TReport_script() { destroy(); } /////////////////////////////////////////////////////////// // TReport_field /////////////////////////////////////////////////////////// void TReport_field::set_pos(long x, long y) { _rct.x = x; _rct.y = y; } void TReport_field::set_size(long w, long h) { _rct.set_width(w); _rct.set_height(h); } void TReport_field::offset(const TPoint& pt) { _rct.x += pt.x; _rct.y += pt.y; } const TReport_font& TReport_field::font() const { return _font != NULL ? *_font : _section->font(); } void TReport_field::set_font(const TReport_font& f) { if (_font != NULL) { delete _font; _font = NULL; } if (f != font()) _font = new TReport_font(f); } void TReport_field::unmap_font() { if (_font != NULL) _font->unmap(); } void TReport_field::copy(const TReport_field& rf) { _section = rf._section; _id = rf.id(); _type = rf.type(); _rct = rf._rct; _fgcolor = rf._fgcolor; _bgcolor = rf._bgcolor; _border = rf._border; _halign = rf._halign; _valign = rf._valign; _picture = rf._picture; _field = rf._field; _hidden = rf.hidden(); _deactivated = rf.deactivated(); _hide_zeroes = rf._hide_zeroes; _selected = false; set_font(rf.font()); } const char* TReport_field::type_name() const { const char* n = NULL; switch (_type) { case 'D': n = "Data"; break; case 'E': n = "Ellisse"; break; case 'I': n = "Immagine"; break; case 'L': n = "Linea"; break; case 'N': n = "Numero"; break; case 'P': n = "Prezzo"; break; case 'R': n = "Rettangolo"; break; case 'S': n = "Stringa"; break; case 'T': n = "Testo"; break; case 'V': n = "Valuta"; break; default : break; } return n; } TFieldtypes TReport_field::var_type() const { TFieldtypes ft = _nullfld; switch (_type) { case 'D': ft = _datefld; break; case 'P': // Prezzo case 'V': // Valuta case 'N': ft = _realfld; break; case 'I': case 'S': ft = _alfafld; break; default : ft = _nullfld; break; } return ft; } void TReport_field::set(const char* str) { _var = str; _var.convert_to(var_type()); } void TReport_field::set(const TVariant& var) { _var = var; _var.convert_to(var_type()); } bool TReport_field::load_field() { const bool ok = !_field.blank(); if (ok) { const TFieldtypes ft = var_type(); if (ft != _nullfld) section().report().evaluate(_field, _var, ft); else _var.set_null(); } return ok; } bool TReport_field::execute_prescript() { bool ok = true; if (active()) ok = _prescript.execute(*this); return ok; } bool TReport_field::execute_postscript() { return deactivated() || _postscript.execute(*this); } void TReport_field::draw_rect(TWindow& win) const { RCT r; win.log2dev(get_rect(), r); advanced_draw_rect(win, r, border(), fore_color(), back_color()); } void TReport_field::draw_text(TWindow& win, const char* text) const { RCT r; win.log2dev(get_rect(), r); advanced_draw_rect(win, r, border(), fore_color(), back_color()); xvt_dwin_set_font(win.win(), font().get_xvt_font(win)); win.set_color(fore_color(), back_color()); advanced_draw_text(win, text, r, _halign, _valign); } void TReport_field::draw(TWindow& win, TReport_draw_mode rdm) const { if (rdm != rdm_edit && hidden()) return; PAT_STYLE back_pattern = PAT_HOLLOW; if (rdm == rdm_edit) { if (hidden() || deactivated()) { if (hidden() && deactivated()) back_pattern = PAT_DIAGCROSS; else back_pattern = hidden() ? PAT_FDIAG : PAT_BDIAG; } } switch (_type) { case 'E': { const bool has_pen = border() > 0; const bool has_brush = color_distance(back_color(), COLOR_WHITE) != 0; if (has_pen) win.set_pen(fore_color(), border(), PAT_SOLID); else win.hide_pen(); if (has_brush) win.set_brush(back_color(), PAT_SOLID); else win.hide_brush(); RCT r; win.log2dev(get_rect(), r); xvt_dwin_draw_oval(win.win(), &r); if (rdm == rdm_edit && back_pattern != PAT_HOLLOW) { win.set_brush(COLOR_GRAY, back_pattern); xvt_dwin_draw_oval(win.win(), &r); back_pattern = PAT_HOLLOW; } } break; case 'I': { RCT r; win.log2dev(get_rect(), r); TReport& rep = section().report(); if (rdm == rdm_edit) { TVariant var; section().report().evaluate(_field, var, _alfafld); const TString& name = var.as_string(); const TImage* img = rep.image(name); if (img != NULL && img->ok()) img->draw(win.win(), r); } else { const TString& name = get().as_string(); const TImage* img = rep.image(name); if (img != NULL && img->ok()) img->draw(win.win(), r); } draw_rect(win); } break; case 'L': { win.set_pen(fore_color(), border()); const TRectangle& r = get_rect(); win.line((short)r.left(), (short)r.top(), (short)r.right(), (short)r.bottom()); back_pattern = PAT_HOLLOW; } break; case 'R': draw_rect(win); break; case 'T': draw_text(win, _picture); break; case 'N': case 'P': case 'V': if (zeroes_hidden() && _var.as_real().is_zero()) break; default : if (rdm == rdm_edit) { if (border() <= 0) // Rendi piu' visibile il bordo dei campi che non ce l'hanno { RCT r; win.log2dev(get_rect(), r); advanced_draw_rect(win, r, 1, COLOR_LTGRAY, COLOR_WHITE); } if (id() > 0) { TString16 str; str << id(); draw_text(win, str); } else draw_text(win, _field); } else draw_text(win, _var.as_string()); break; } if (rdm == rdm_edit) { RCT r; win.log2dev(get_rect(), r); if (back_pattern != PAT_HOLLOW) { win.set_pen(COLOR_LTGRAY); win.set_brush(COLOR_LTGRAY, back_pattern); xvt_dwin_draw_rect(win.win(), &r); } if (selected()) { const int k = 4; RCT s = r; s.right = s.left+k; s.bottom = s.top+k; advanced_draw_rect(win, s, 0, COLOR_WHITE, COLOR_LTGRAY); s = r; s.left = s.right-k; s.top = s.bottom-k; advanced_draw_rect(win, s, 0, COLOR_WHITE, COLOR_LTGRAY); } } } void TReport_field::set_groups(const TString& groups) { _groups.reset(); _groups.set(groups); } const TString& TReport_field::groups() const { TString& str = get_tmp_string(); str << _groups; return str; } bool TReport_field::in_group(int group) const { if (group <= 0) return _groups.first_one() > 0; return _groups[group]; } void TReport_field::save(TXmlItem& root) const { TXmlItem& fld = root.AddChild("field"); fld.SetAttr("type", type_name()); const TRectangle& rct = get_rect(); fld.SetAttr("id", _id); set_num_attr(fld, "x", rct.left()); set_num_attr(fld, "y", rct.top()); set_num_attr(fld, "width", rct.width()); set_num_attr(fld, "height", rct.height(), 100); fld.SetAttr("hidden", _hidden); fld.SetAttr("deactivated", _deactivated); fld.SetAttr("zeroes_hidden", _hide_zeroes); set_col_attr(fld, "bg_color", back_color(), COLOR_WHITE); set_col_attr(fld, "fg_color", fore_color(), COLOR_BLACK); if (has_font()) font().save(fld); if (in_group(0)) fld.AddChild("groups") << groups(); switch (horizontal_alignment()) { case 'C': fld.SetAttr("align", "center"); break; case 'R': fld.SetAttr("align", "right"); break; case 'J': fld.SetAttr("align", "justify"); break; default : break; }; switch (vertical_alignment()) { case 'T': fld.SetAttr("valign", "top"); break; case 'C': fld.SetAttr("valign", "center"); break; default : break; }; fld.SetAttr("border", border()); fld.SetAttr("text", picture()); if (field().not_empty()) fld.AddChild("source") << field(); _prescript.save(fld, "prescript"); _postscript.save(fld, "postscript"); } bool TReport_field::load(const TXmlItem& fld) { set_type(get_chr_attr(fld, "type", 'T')); set_id(fld.GetIntAttr("id")); set_column(get_num_attr(fld, "x")); set_row(get_num_attr(fld, "y")); set_width(get_num_attr(fld, "width")); set_height(get_num_attr(fld, "height", 100)); show(!fld.GetBoolAttr("hidden")); activate(!fld.GetBoolAttr("deactivated")); hide_zeroes(fld.GetBoolAttr("zeroes_hidden")); set_border(fld.GetIntAttr("border")); set_back_color(get_col_attr(fld, "bg_color", COLOR_WHITE)); set_fore_color(get_col_attr(fld, "fg_color", COLOR_BLACK)); set_horizontal_alignment(get_chr_attr(fld, "align", 'L')); set_vertical_alignment(get_chr_attr(fld, "valign", 'B')); set_picture(fld.GetAttr("text")); TXmlItem* src = fld.FindFirstChild("source"); if (src != NULL) src->GetEnclosedText(_field); TReport_font font; if (font.load(fld)) set_font(font); TXmlItem* grp = fld.FindFirstChild("groups"); if (grp != NULL) { TString str; grp->GetEnclosedText(str); set_groups(str); } _prescript.load(fld, "prescript"); _postscript.load(fld, "postscript"); return true; } int TReport_field::compare(const TSortable& s) const { const TReport_field& rf = (TReport_field&)s; int cmp = _rct.y - rf._rct.y; if (cmp == 0) { cmp = _rct.x - rf._rct.x; if (cmp == 0) cmp = _id - rf._id; } return cmp; } TReport_field::TReport_field(TReport_section* sec) : _section(sec), _id(0), _type('T'), _font(NULL), _halign('L'), _valign('T'), _selected(false), _hidden(false), _deactivated(false), _hide_zeroes(false), _border(0), _fgcolor(COLOR_BLACK), _bgcolor(COLOR_WHITE) { set_pos(0,0); set_size(1600,100); } TReport_field::TReport_field(const TReport_field& rf) : _font(NULL) { copy(rf); } TReport_field::~TReport_field() { if (_font != NULL) delete _font; } /////////////////////////////////////////////////////////// // TReport /////////////////////////////////////////////////////////// void TReport::build_section_key(char type, int level, TString& key) const { key.format("%c%d", type, level); } TReport_section* TReport::find_section(char type, int level) const { TString4 key; build_section_key(type, level, key); TReport_section* sec = (TReport_section*)_sections.objptr(key); return sec; } bool TReport::kill_section(char type, int level) { TString4 key; build_section_key(type, level, key); return _sections.remove(key); } int TReport::find_max_level(char type) const { int lev = 1; char type1 = type; char type2 = ' '; if (type == 'H' || type == 'F') { type1 = 'H'; type2 = 'F'; } // Non puo' esistere footer di gruppo senza header TAssoc_array& ass = (TAssoc_array&)_sections; FOR_EACH_ASSOC_OBJECT(ass, h, k, o) if (k[0] == type1 || k[0] == type2) { const int l = k[1]-'0'; if (l > lev) lev = l; } return lev; } bool TReport::set_recordset(TRecordset* rs) { if (_recordset != NULL) { delete _recordset; _recordset = NULL; } _recordset = rs; return _recordset != NULL; } bool TReport::set_recordset(const TString& sql) { bool ok = false; if (sql.compare("SELECT", 6, true) == 0) ok = set_recordset(new TSQL_recordset(sql)); return ok; } TReport_section& TReport::section(char type, int level) { TReport_section* sec = find_section(type, level); if (sec == NULL) { sec = new TReport_section(*this, type, level); TString4 key; key.format("%c%d", type, level); _sections.add(key, sec); } return *sec; } // Parsa un riferimento a campo, gruppo o sezione // #B0 -> 2 B 0 // #101 -> 3 B 1 101 // #B1.101@ -> 4 B 1 101 int TReport::parse_field(const char* code, char& type, int& level, int& id) const { if (code[0] == '#') code++; if (isdigit(code[0]) || strcmp(code, "THIS") == 0) // Niente sezione davanti { TReport_field* rf = curr_field(); if (rf != NULL) { type = rf->section().type(); level = rf->section().level(); } id = atoi(code); } else { type = code[0]; if (type != 'H' && type != 'B' && type != 'F') // Non comincia con un codice sezione return 0; level = atoi((const char*)code + 1); TReport_section* sec = find_section(type, level); if (sec == NULL) return 1; const int dot = code[2] == '.' ? 2 : (code[3] == '.' ? 3 : -1); if (dot <= 0) return 2; id = atoi((const char*)code + dot + 1); } return strchr(code, '@') != NULL ? 4 : 3; } TReport_field* TReport::field(const TString& code) { char type; int level, id; const int k = parse_field(code, type, level, id); TReport_field* rf = NULL; if (k == 3) { if (id > 0) { TReport_section& sec = section(type, level); rf = sec.find_field(id); } else rf = curr_field(); } return rf; } bool TReport::evaluate(const char* expr, TVariant& var, TFieldtypes force_type) { TReport_expr& e = _expressions[expr]; // Caso semplice nonche' standard if (e.numvar() == 1) { const char* name = e.varname(0); if (*name == '#' && strcmp(name, expr) == 0) { const TFixed_string usr(name); if (get_usr_val(usr, var)) { if (force_type != _nullfld) var.convert_to(force_type); return true; } } } for (int i = 0; i < e.numvar(); i++) { const char* name = e.varname(i); bool ok = false; if (name[0] == '#') { const TFixed_string usr(name+1); ok = get_usr_val(usr, var); } else { const TFixed_string usr(name); ok = get_usr_val(usr, var); } if (!ok) var = name; if (var.type() == _alfafld) e.setvar(i, var.as_string()); else e.setvar(i, var.as_real()); } const TFieldtypes ft = force_type != _nullfld ? force_type : var.type(); var = e.as_variant(ft); return true; } void TReport::destroy() { _sections.destroy(); _description.cut(0); if (_recordset != NULL) { delete _recordset; _recordset = NULL; } } void TReport::load_sections(const TXmlItem& xml) { for (int i = 0; i < xml.GetChildren(); i++) { const TXmlItem& sec = *xml.GetChild(i); if (sec.GetTag() != "section") continue; const char type = sec.GetAttr("type")[0]; const int level = sec.GetIntAttr("level"); TReport_section& rs = section(type, level); rs.load(sec); } } bool TReport::load(const char* fname) { destroy(); TXmlItem xml; _path = fname; bool ok = xml.Load(_path); if (ok) { _lpi = xml.GetIntAttr("lpi", 6); _font.load(xml); const TXmlItem* desc = xml.FindFirstChild("description"); if (desc != NULL) desc->GetEnclosedText(_description); if (xml.FindFirstChild("section") != NULL) load_sections(xml); const TXmlItem* sql = xml.FindFirstChild("sql"); if (sql != NULL) { TString str; sql->GetEnclosedText(str); set_recordset(str); } } return ok; } bool TReport::save(const char* fname) const { char name[_MAX_FNAME]; xvt_fsys_parse_pathname (fname, NULL, NULL, name, NULL, NULL); bool ok = *name > ' '; if (ok) { TXmlItem xml; xml.SetTag("report"); xml.SetAttr("name", name); xml.SetAttr("lpi", lpi()); xml.AddChild("description") << _description; _font.save(xml); const char* sectype = "HBF"; for (int j = 0; j < 3; j++) { const int ml = find_max_level(sectype[j]); for (int i = 0; i <= ml; i++) { TReport_section& rs = ((TReport*)this)->section(sectype[j], i); rs.save(xml); } } if (_recordset != NULL) xml.AddChild("sql") << _recordset->query_text(); xml.Save(fname); } return ok; } void TReport::unmap_font() { _font.unmap(); FOR_EACH_ASSOC_OBJECT(_sections, h, k, o) { TReport_section& sec = *(TReport_section*)o; sec.unmap_font(); } } bool TReport::execute_prescript() { TString80 str; return _prescript.execute(*this, str); } bool TReport::execute_postscript() { TString80 str; return _postscript.execute(*this, str); } bool TReport::get_usr_val(const TString& name, TVariant& var) const { if (name == "#PAGE") { var = curr_page(); return true; } TReport_field* fld = ((TReport*)this)->field(name); if (fld != NULL) { var = fld->get(); return true; } if (_recordset != NULL) { if (name[0] == '#') { const TFixed_string str((const char*)name + 1); var = _recordset->get(str); } else var = _recordset->get(name); if (!var.is_null()) return true; } return TAlex_virtual_machine::get_usr_val(name, var); } bool TReport::set_usr_val(const TString& name, const TVariant& var) { TReport_field* fld = field(name); if (fld != NULL) { fld->set(var); return true; } return TAlex_virtual_machine::set_usr_val(name, var); } unsigned int TReport::compile_usr_word(const TString& name) const { const int words = 9; const char* const names[words] = { NULL, "DISABLE", "ENABLE", "GET_SIZE", "HIDE", "SET_BACK_COLOR", "SET_FORE_COLOR", "SET_SIZE", "SHOW" }; int i; for (i = words-1; i > 0; i--) if (name == names[i]) break; return i; } static void do_show(TReport_field& rf, void* jolly) { rf.show(jolly != NULL); } static void do_enable(TReport_field& rf, void* jolly) { rf.activate(jolly != NULL); } static void do_set_size(TReport_field& rf, void* jolly) { const TPoint& pt = *(const TPoint*)jolly; rf.set_size(pt.x, pt.y); } static void do_set_back_color(TReport_field& rf, void* jolly) { rf.set_back_color((COLOR)jolly); } static void do_set_fore_color(TReport_field& rf, void* jolly) { rf.set_fore_color((COLOR)jolly); } bool TReport::do_message(const TVariant& var, FLDMSG_FUNC msg, void* jolly) { char type; int level, id; const int k = parse_field(var.as_string(), type, level, id); switch (k) { case 2: // E' una sezione { TReport_section& sec = section(type, level); if (msg == do_show) sec.show(jolly != 0); else if (msg == do_enable) sec.activate(jolly != 0); } break; case 3: // E' un campo singolo { TReport_field* rf = id <= 0 ? curr_field() : section(type, level).find_field(id); if (rf != NULL) msg(*rf, jolly); } break; case 4: // E' un gruppo { TReport_section& sec = section(type, level); for (int i = 0; i < sec.items(); i++) { TReport_field& rf = sec.field(i); if (rf.in_group(id)) msg(rf, jolly); } } break; default: break; } return true; } bool TReport::execute_usr_word(unsigned int opcode, TVariant_stack& stack) { switch (opcode) { case 1: // DISABLE do_message(stack.pop(), do_enable, NULL); break; case 2: // ENABLE do_message(stack.pop(), do_enable, (void*)1); break; case 3: // GET_SIZE { const TReport_field* fld = field(stack.pop().as_string()); real w, h; if (fld != NULL) { const TRectangle& r = fld->get_rect(); w = r.width() / CENTO; h = r.height() / CENTO; } stack.push(w); stack.push(h); } break; case 4: // HIDE do_message(stack.pop(), do_show, NULL); break; case 5: // SET_BACK_COLOR { const COLOR rgb = stack.pop().as_color(); do_message(stack.pop(), do_set_back_color, (void*)rgb); } break; case 6: // SET_FORE_COLOR { const COLOR rgb = stack.pop().as_color(); do_message(stack.pop(), do_set_fore_color, (void*)rgb); } break; case 7: // SET_SIZE { const TVariant& fld = stack.pop(); const real h = stack.pop().as_real() * CENTO; const real w = stack.pop().as_real() * CENTO; const TPoint sz(w.integer(), h.integer()); do_message(fld, do_set_size, (void*)&sz); } break; case 8: // SHOW do_message(stack.pop(), do_show, (void*)1); break; default: return false; } return true; } TReport::TReport() : _lpi(6), _recordset(NULL), _curr_field(NULL) { // Brutte inizializzazioni, ma inevitabili _expressions.set_report(this); } TReport::~TReport() { destroy(); }