#include #include #include #include #include #include #include #include #include #include #include static const char MAX_STRING[2] = {(char) 255, 0}; /////////////////////////////////////////////////////////// // TReport_font /////////////////////////////////////////////////////////// int compute_font_match(WINDOW win, int size, int ppi, int cpi) { const TString emme(cpi, 'M'); int mi = 0, ma = 2*size; int best = 0, best_error = 0; while (mi <= ma) { const int me = (mi+ma)/2; XVT_FNTID fontid = xvt_font_create(); xvt_font_set_family(fontid, DEFAULT_FONT_NAME); xvt_font_set_size(fontid, me); xvt_dwin_set_font(win, fontid); const int width = xvt_dwin_get_text_width(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; } return best; } XVT_FNTID TReport_font::get_xvt_font(const TWindow& win) const { WINDOW w = win.win(); if (w != _win_mapped) { int nSize = _size; if (w != PRINTER_WIN) // 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 int best = compute_font_match(w, abs(pnt1.v - pnt0.v), ppi, cpi); nSize = cpi * best / _cpi; } XVT_FNTID fontid = xvt_font_create(); xvt_font_set_family(fontid, _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 = w; } return _fontid; } XVT_FNTID TReport_font::get_preview_font(const TWindow& win, const TPoint& res) const { WINDOW w = win.win(); if (w != _win_mapped) { const int cpi = 120 / DEFAULT_FONT_SIZE; const PNT pnt0 = win.log2dev(0,0); const PNT pnt1 = win.log2dev(res.x,res.y); const int ppi = pnt1.h - pnt0.h; const int best = compute_font_match(w, (pnt1.v - pnt0.v), ppi, cpi); const int nSize = cpi * best / _cpi; XVT_FNTID fontid = xvt_font_create(); xvt_font_set_family(fontid, _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 = w; } 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::adapt(const TReport_font& oldfont, const TReport_font& newfont) { const int new_size = newfont.size() * _size / oldfont.size(); if (name() == oldfont.name() || name().blank()) create(newfont.name(), new_size, _style); else create(_name, new_size, _style); } 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() : _win_mapped(NULL_WIN), _fontid(NULL) { create(DEFAULT_FONT_NAME, DEFAULT_FONT_SIZE, XVT_FS_NONE); } TReport_font::TReport_font(const TReport_font& f) : _win_mapped(NULL_WIN), _fontid(NULL) { copy(f); } TReport_font::~TReport_font() { unmap(); } /////////////////////////////////////////////////////////// // TReport_expr /////////////////////////////////////////////////////////// static bool is_a_number(const char* str) { 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; } 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; 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 { } 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) { TString str = exp; str.strip_spaces(); set(str, _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) { } 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::compute_print_font(const TReport_font& oldfont, const TReport_font& newfont) { if (has_font()) { if (_print_font == NULL) _print_font = new TReport_font; *_print_font = font(); _print_font->adapt(oldfont, newfont); } for (int i = 0; i < items(); i++) { TReport_field& rf = field(i); rf.compute_print_font(oldfont, newfont); } } const TReport_font& TReport_section::print_font() const { if (_print_font != NULL && _report.use_printer_font()) return *_print_font; if (_font != NULL) return *_font; TReport_section* father = father_section(); if (father != NULL) return father->print_font(); return _report.print_font(); } const TString& TReport_section::prescript() const { return _prescript.get(); } void TReport_section::set_prescript(const char* src) { _prescript.set(src); TString desc; desc << type() << level() << " PRESCRIPT"; _prescript.set_description(desc); } const TString& TReport_section::postscript() const { return _postscript.get(); } void TReport_section::set_postscript(const char* src) { _postscript.set(src); TString desc; desc << type() << level() << " POSTSCRIPT"; _postscript.set_description(desc); } 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) { int i; for (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; } // Determina se e' possibile mantenere la sezione nella stessa pagina della successiva bool TReport_section::keep_with_next() const { return _keep_with_next && type() == 'H' && level() > 1; } // Determina se e' possibile spezzare la sezione su due pagine bool TReport_section::can_be_broken() const { return _can_break && type() == 'B' && level() > 0; } TPoint TReport_section::compute_size() const { if (hidden()) return TPoint(0,0); TPoint s = _size; // Lo sfondo occupa sempre tutta la pagina if (type() == 'B' && level() == 0) { s.x = s.y = 19600; return s; } if (_size.x <= 0 || _size.y <= 0) // Calcolo automatico necessario { for (int i = 0; i < items(); i++) { const TReport_field& rf = field(i); if (rf.active() && rf.shown()) { const TRectangle& r = rf.get_draw_rect(); if (_size.x <= 0 && r.right() > s.x) // Richiesto calcolo larghezza s.x = r.right(); if (_size.y <= 0 && r.bottom() > s.y) // Richiesto calcolo altezza s.y = r.bottom(); } } if ((s.x % 100) != 0) // Arrotonda alla colonna successiva s.x = (s.x / 100 + 1) * 100; if ((s.y % 100) != 0) // Arrotonda alla riga successiva s.y = (s.y / 100 + 1) * 100; } return s; } bool TReport_section::compute_rect(TRectangle& rct) const { rct.set(TPoint(0, 0), compute_size()); return !rct.is_empty(); } bool TReport_section::load_fields() { const bool ok = active(); if (ok) { for (int i = 0; i < items(); i++) { TReport_field& f = field(i); report().set_curr_field(&f); f.load_field(); } } return ok; } void TReport_section::init_dynamic_heights(const TBook& book) { for (int i = 0; i < items(); i++) { TReport_field& f = field(i); f.compute_draw_rect(book); } } bool TReport_section::execute_prescript(const TBook& book) { bool ok = true; if (active()) { if (items() > 0) report().set_curr_field(&field(0)); else report().set_curr_field(NULL); ok = _prescript.execute(report()); } for (int i = 0; ok && i < items(); i++) { TReport_field& f = field(i); ok = f.execute_prescript(); if (ok && f.dynamic_height()) f.compute_draw_rect(book); // Serve fondamentalmente per MESSAGE _DESCRIGA } return ok; } bool TReport_section::print_tools(TBook& book) const { const bool has_pen = border() > 0; const bool has_brush = pattern() >= PAT_SOLID && back_color() != COLOR_WHITE; const bool visible = has_pen || has_brush; if (visible) { book.set_pen(fore_color(), border()-1); book.set_brush(back_color(), pattern()); } return visible; } void TReport_section::print(TBook& book) const { if (shown() && active()) { if (print_tools(book)) { TRectangle rct; compute_rect(rct); if (_size.x <= 0) rct.set_width(book.logical_page_width()); if (type() == 'B' && level() <= 0) rct.set_height(book.logical_page_height()); if (radius() > 0) book.draw_round_rectangle(rct, radius()); else book.draw_rectangle(rct); } for (int i = 0; i < items(); i++) { const TReport_field& f = field(i); f.print(book); } } } void TReport_section::print_clipped(TBook& book, long top, long bottom) const { if (shown() && active()) { book.set_clip(top, bottom); print(book); book.set_clip(0, -1); } } 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()) ok = _postscript.execute(report()); 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, "x", pos().x); set_num_attr(item, "y", pos().y); set_num_attr(item, "width", width()); set_num_attr(item, "height", height()); set_col_attr(item, "bg_color", back_color(), COLOR_WHITE); set_col_attr(item, "fg_color", fore_color(), COLOR_BLACK); if (border() > 0) { item.SetAttr("border", border()); if (radius() > 0) item.SetAttr("radius", radius()); } if (pattern() != PAT_HOLLOW) item.SetAttr("pattern", pattern()); item.SetAttr("hidden", _hidden); item.SetAttr("deactivated", _deactivated); item.SetAttr("hidden_if_needed", hidden_if_needed()); item.SetAttr("page_break", _page_break); item.SetAttr("can_break", can_be_broken()); item.SetAttr("keep_with_next", keep_with_next()); item.SetAttr("repeat", repeat_on_page()); if (condition().not_empty()) item.AddChild("condition") << condition(); if (grouped_by().not_empty()) item.AddChild("groupby") << grouped_by(); if (recordset() != NULL) item.AddChild("sql") << recordset()->query_text(); 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); } if (type() == 'B' && level() > 0) // Save subsections if any { for (int s = 1; s <= 9; s++) { const int l = level()*10+s; if (_report.find_section('B', l)) { _report.section('H', l).save(root); _report.section('B', l).save(root); _report.section('F', l).save(root); } else break; } } } void TReport_section::load(const TXmlItem& sec) { _pos.x = get_num_attr(sec, "x"); _pos.y = get_num_attr(sec, "y"); set_width(get_num_attr(sec, "width")); set_height(get_num_attr(sec, "height")); set_border(sec.GetIntAttr("border")); set_pattern((PAT_STYLE)sec.GetIntAttr("pattern", PAT_HOLLOW)); set_radius(sec.GetIntAttr("radius")); set_back_color(get_col_attr(sec, "bg_color", COLOR_WHITE)); set_fore_color(get_col_attr(sec, "fg_color", COLOR_BLACK)); force_page_break(sec.GetBoolAttr("page_break")); can_break(sec.GetBoolAttr("can_break")); keep_with_next(sec.GetBoolAttr("keep_with_next")); hide_if_needed(sec.GetBoolAttr("hidden_if_needed")); set_repeat_on_page(sec.GetBoolAttr("repeat")); show(!sec.GetBoolAttr("hidden")); activate(!sec.GetBoolAttr("deactivated")); TReport_font font; if (font.load(sec)) set_font(font); if (level() > 0) { TString str; const TXmlItem* cnd = sec.FindFirstChild("condition"); if (cnd != NULL) { cnd->GetEnclosedText(str); set_condition(str); } if (level() > 1) { const TXmlItem* gb = sec.FindFirstChild("groupby"); if (gb != NULL) { gb->GetEnclosedText(str); group_by(str); } if (level() > 10) { const TXmlItem* sql = sec.FindFirstChild("sql"); if (sql != NULL) { sql->GetEnclosedText(str); set_recordset(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"); } void TReport_section::update_recordset_parent() { if (type() == 'B' && level() > 0) { // Update my recordset if (_recordset != NULL) { if (level() > 100) { const int father = level()/10; _recordset->set_parent(_report.section('B', father).recordset()); } else _recordset->set_parent(_report.recordset()); } // Update my children's recordset for (int i = 1; i <= 9; i++) { const int child = level()*10+i; TReport_section* rs = _report.find_section('B', child); if (rs != NULL) rs->update_recordset_parent(); else break; } } } bool TReport_section::set_recordset(TRecordset* rs) { if (type() == 'B') { if (_recordset != NULL) delete _recordset; _recordset = rs; update_recordset_parent(); } return _recordset != NULL; } bool TReport_section::set_recordset(const TString& sql) { TRecordset* rex = create_recordset(sql); set_recordset(rex); return rex != NULL; } bool TReport_section::get_record_field(const char* name, TVariant& var) const { if (_recordset != NULL) { var = _recordset->get(name); if (!var.is_null()) return true; if (level() > 100) { const TReport_section* sec = _report.find_section('B', level()/10); if (sec != NULL) // Should ALWAYS exist return sec->get_record_field(name, var); } } return false; } TReport_section::TReport_section(TReport& r, char t, int l) : _report(r), _type(t), _level(l), _pos(0,0), _size(0,0), _page_break(false), _hidden_if_needed(false), _can_break(false), _keep_with_next(false), _repeat(false), _hidden(false), _deactivated(false), _font(NULL), _print_font(NULL), _recordset(NULL), _bgcolor(COLOR_WHITE), _fgcolor(COLOR_BLACK), _pattern(PAT_HOLLOW), _border(0), _radius(0) { } TReport_section::~TReport_section() { if (_font) delete _font; if (_print_font) delete _print_font; } /////////////////////////////////////////////////////////// // TReport_script /////////////////////////////////////////////////////////// TString& TReport_script::translate_message(TReport& rep) const { TToken_string source(_src, '\n'); TToken_string line(256, '|'); TToken_string args(256, ','); TString cmd; TString alex, empty_alex; 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(); } FOR_EACH_TOKEN(line, tok) { const TFixed_string msg(tok); const int comma = msg.find(','); if (comma > 0) { cmd = msg.left(comma); args = msg.mid(comma+1); } else { cmd = msg; args.cut(0); } if (cmd[0] != '_') cmd.insert("_"); cmd.insert("MESSAGE"); if (rep.defined(cmd)) { TString& alx = msg_empty ? empty_alex : alex; TString arg; for (int i = args.items()-1; i >= 0; i--) { arg = args.get(i); // Controlla se c'e' bisogno di un # all'inizio if (arg[0] != '#' && arg[0] != '"' && !is_a_number(arg)) { char type; int level, id; if (i == 0 && rep.parse_field(arg, type, level, id) >= 3) arg.insert("#"); else { arg.insert("\""); arg << '"'; } } alx << arg << ' '; } alx << cmd << ' '; } else { cmd << " ?"; rep.log_error(cmd); } } } TString& src = get_tmp_string(); if (!empty_alex.blank()) { src = "#THIS @ EMPTY= IF\n"; src << empty_alex; src << "\nELSE\n"; src << alex; src << "\nTHEN"; } else src = alex; return src; } void TReport_script::set(const char* source) { if (_src != source) { destroy(); _src = source; } } void TReport_script::copy(const TReport_script& rs) { set(rs.get()); } bool TReport_script::compile(TReport& rep) { if (_bc == NULL) _bc = new TBytecode; bool good = true; if (_src.starts_with("MESSAGE ")) good = rep.compile(translate_message(rep), *_bc); else good = rep.compile(_src, *_bc); _bc->set_name(_desc); return good; } bool TReport_script::execute(TReport& rep) { bool good = true; if (ok()) { if (_bc == NULL) good = compile(rep); if (good) good = rep.execute(*_bc); } return good; } bool TReport_script::execute(TReport_field& rf) { bool good = true; if (ok()) { TReport& rep = rf.section().report(); rep.set_curr_field(&rf); good = execute(rep); } 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.SetAttr("description", _desc); script << _src; } } bool TReport_script::load(const TXmlItem& root, const char* tag) { destroy(); TXmlItem* script = root.FindFirstChild(tag); if (script != NULL) { _desc = script->GetAttr("description"); script->GetEnclosedText(_src); } return ok(); } TReport_script::TReport_script() : _bc(NULL) { } TReport_script::~TReport_script() { destroy(); } /////////////////////////////////////////////////////////// // TReport_array_item /////////////////////////////////////////////////////////// struct TReport_array_item : public TObject { protected: virtual TObject* dup() const; public: TString _code, _value; TReport_script _script; }; TObject* TReport_array_item::dup() const { TReport_array_item* i = new TReport_array_item; i->_code = _code; i->_value = _value; i->_script = _script; return i; } /////////////////////////////////////////////////////////// // 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; } void TReport_field::set_draw_pos(long x, long y) { _draw_rct.x = x; _draw_rct.y = y; } void TReport_field::set_draw_size(long w, long h) { _draw_rct.set_width(w); _draw_rct.set_height(h); } void TReport_field::set_dynamic_height(bool dh) { _dynamic_height = dh && _type == 'S' && _rct.height() > 0; } bool TReport_field::dynamic_height() const { return _dynamic_height; } const TRectangle& TReport_field::get_draw_rect() const { TRectangle& rct = ((TReport_field*)this)->_draw_rct; if (dynamic_height()) { TParagraph_string str(formatted_text(), rct.width()/100-1); // Sto un po' scarso int h = str.items() * 100; if (h <= 0) h = 100; if (h > _rct.height()) h = _rct.height(); rct.set_height(h); } return rct; } const TReport_font& TReport_field::font() const { return _font != NULL ? *_font : _section->font(); } const TReport_font& TReport_field::print_font() const { if (_print_font != NULL) return *_print_font; if (_font != NULL) return *_font; return _section->print_font(); } void TReport_field::compute_print_font(const TReport_font& oldfont, const TReport_font& newfont) { if (has_font()) { if (_print_font == NULL) _print_font = new TReport_font(font()); else *_print_font = font(); _print_font->adapt(oldfont, newfont); } } void TReport_field::set_font(const TReport_font& f) { if (_font != NULL) { delete _font; _font = NULL; } if (_section == NULL || f != font()) _font = new TReport_font(f); } void TReport_field::unmap_font() { if (_font != NULL) _font->unmap(); if (_print_font != NULL) _print_font->unmap(); } const TString& TReport_field::prescript() const { return _prescript.get(); } void TReport_field::set_prescript(const char* src) { TString80 desc; desc.format("%c%d.%d PRESCRIPT", section().type(), section().level(), id()); _prescript.set_description(desc); _prescript.set(src); } const TString& TReport_field::postscript() const { return _postscript.get(); } void TReport_field::set_postscript(const char* src) { TString80 desc; desc.format("%c%d.%d POSTSCRIPT", section().type(), section().level(), id()); _postscript.set_description(desc); _postscript.set(src); } void TReport_field::copy(const TReport_field& rf) { _id = rf.id(); _type = rf.type(); _rct = rf._rct; set_dynamic_height(rf.dynamic_height()); _fgcolor = rf._fgcolor; _bgcolor = rf._bgcolor; _border = rf._border; _radius = rf._radius; _pattern = rf._pattern; _shade_offset = rf._shade_offset; _halign = rf._halign; _valign = rf._valign; _picture = rf._picture; _field = rf._field; _hidden = rf.hidden(); _deactivated = rf.deactivated(); _hide_zeroes = rf._hide_zeroes; _field = rf._field; _alt_field = rf._alt_field; _prescript = rf._prescript; _postscript = rf._postscript; _list = rf._list; if (rf._font != NULL) set_font(*rf._font); _draw_hidden = _draw_deactivated = false; _selected = false; } const char* TReport_field::type_name() const { const char* n = NULL; switch (_type) { case 'A': n = "Array"; break; 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 'A': 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.full(); if (ok) { const TFieldtypes ft = var_type(); if (ft != _nullfld) { TReport& rep = section().report(); rep.evaluate(_field, _var, ft); if (_var.is_empty() && _alt_field.full()) rep.evaluate(_alt_field, _var, ft); } else _var.set_null(); } _draw_rct = _rct; _draw_hidden = _hidden; _draw_deactivated = _deactivated; return ok; } bool TReport_field::execute_prescript() { bool ok = true; if (!draw_deactivated()) { ok = _prescript.execute(*this); if (ok && type() == 'A') { TReport_array_item* item = get_array_item(); if (item != NULL) ok = item->_script.execute(*this); } } return ok; } bool TReport_field::execute_postscript() { return draw_deactivated() || _postscript.execute(*this); } COLOR TReport_field::link_color() const { return COLOR_BLUE; } void TReport_field::get_currency(TCurrency& cur) const { if (_codval.full()) { TVariant val; section().report().evaluate(_codval, val, _alfafld); cur.force_value(val.as_string()); } cur.set_price(_type == 'P'); cur.set_num(_var.as_real()); } TReport_array_item* TReport_field::get_array_item() const { if (type() == 'A') { const TString& val = _var.as_string(); int i = 0; for (i = _list.last(); i > 0; i--) { const TReport_array_item& item = (const TReport_array_item&)_list[i]; if (val == item._code) break; } return (TReport_array_item*)_list.objptr(i); } return NULL; } bool TReport_field::zeroes_hidden() const { return _hide_zeroes && strchr("DNVP", _type) != NULL; } const TString& TReport_field::formatted_text() const { if (zeroes_hidden() && _var.is_zero()) return EMPTY_STRING; switch (type()) { case 'A': { const TReport_array_item* item = get_array_item(); if (item != NULL) return item->_value; return EMPTY_STRING; } break; case 'D': { const TDate d = _var.as_date(); TString& tmp = get_tmp_string(); if (_picture.not_empty()) { if (_picture.find('#') >= 0) { TString8 str; str.format("%02d%02d%04d", d.day(), d.month(), d.year()); tmp.picture(_picture, str); } else tmp << _picture << ' ' << d; } else tmp = d.string(_rct.width() >= 1000 ? full : brief); return tmp; } break; case 'N': { const real n = _var.as_real(); TString& tmp = get_tmp_string(); if (_picture.not_empty()) tmp = n.string(_picture); else tmp = n.stringa(); return tmp; } break; case 'P': case 'V': { TCurrency cur; get_currency(cur); const bool dotted = _picture.find('.') > 0; return get_tmp_string() = cur.string(dotted); } break; default: if (_picture.full()) { TString& tmp = get_tmp_string(); if (_picture.find('#') >= 0) tmp.picture(_picture, _var.as_string()); else tmp << _picture << ' ' << _var.as_string(); return tmp; } if (dynamic_height()) { TString& tmp = get_tmp_string(); tmp = _var.as_string(); tmp.replace(char(0xB6), '\n'); tmp.rtrim(); return tmp; } return _var.as_string(); } return EMPTY_STRING; } bool TReport_field::print_tools(TBook& book) const { const bool has_pen = border() > 0; const bool has_brush = pattern() >= PAT_SOLID; const bool visible = has_pen || has_brush; if (visible) { book.set_pen(fore_color(), border()-1); book.set_brush(back_color(), pattern()); } return visible; } const TRectangle& TReport_field::compute_draw_rect(const TBook& book) { TRectangle& r = _draw_rct; r = _rct; if (dynamic_height()) { const TString& txt = formatted_text(); if (!txt.blank()) { TString_array para; book.compute_text_frame(txt, print_font(), r, para); if (r.height() > get_rect().height()) r.set_height(get_rect().height()); if (r.height() < 100) r.set_height(100); } else r.set_height(100); } return r; } const TRectangle& TReport_field::print_rect(const TRectangle& rect, TBook& book) const { if (pattern() == PAT_SOLID && shade_offset() != 0) { book.set_pen(COLOR_GRAY, 0); const COLOR color = blend_colors(section().back_color(), COLOR_BLACK, 0.5); book.set_brush(color, PAT_SOLID); TRectangle rct = rect; rct += TPoint(shade_offset(), shade_offset() * section().report().print_lpi() / print_font().cpi()); if (radius() > 0) book.draw_round_rectangle(rct, radius()); else book.draw_rectangle(rct); } if (print_tools(book)) { if (radius() > 0) book.draw_round_rectangle(rect, radius()); else book.draw_rectangle(rect); } return rect; } const TRectangle& TReport_field::print_rect(TBook& book) const { const TRectangle& rect = get_draw_rect(); return print_rect(rect, book); } void TReport_field::print(TBook& book) const { if (draw_deactivated()) return; if (draw_hidden()) { if (link().not_empty()) // Devo "stampare" i link anche se nascosti { TRectangle rct = get_draw_rect(); rct.set_height(0); rct.set_width(0); book.draw_link(rct, formatted_text(), link()); } return; } switch (_type) { case 'E': if (print_tools(book)) book.draw_ellipse(get_draw_rect()); break; case 'I': { const TString& name = get().as_string(); const TRectangle& rct = get_draw_rect(); book.draw_image(rct, name); if (border() > 0) { book.set_pen(fore_color(), border()-1); book.set_brush(COLOR_WHITE, PAT_HOLLOW); book.draw_rectangle(rct); } } break; case 'L': if (border() > 0) { book.set_pen(fore_color(), border()-1); book.draw_line(get_draw_rect()); } break; case 'R': print_rect(book); break; case 'T': if (!_picture.blank()) { book.set_font(print_font()); const TRectangle& pr = print_rect(book); // Calcolo rettangolo dopo aver settato il font! book.set_text_align(horizontal_alignment(), vertical_alignment()); book.set_text_color(fore_color(), back_color()); book.draw_text(pr, _picture); } else print_rect(book); break; case 'N': if (field() == "#BOOKPAGES") { const TRectangle& pr = print_rect(book); book.draw_book_pages(pr); break; } default : { const TString& str = formatted_text(); if (!str.blank()) { book.set_font(print_font()); book.set_text_align(horizontal_alignment(), vertical_alignment()); book.set_text_color(fore_color(), back_color()); if (dynamic_height() || _rct.height() > 100) // Multiriga? { TString_array para; TRectangle rect = get_draw_rect(); book.compute_text_frame(str, print_font(), rect, para); print_rect(_draw_rct, book); // Stampa eventuale cornice book.draw_text(_draw_rct, para); // Stampa paragrafo } else { const TRectangle& pr = print_rect(book); book.draw_text(pr, str); if (link().not_empty()) book.draw_link(pr, str, link()); } } else { print_rect(book); } } break; } } 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; str.trim(); 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("dynamic_height", dynamic_height()); fld.SetAttr("hidden", _hidden); fld.SetAttr("deactivated", _deactivated); fld.SetAttr("hide_zero", zeroes_hidden()); 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 'B': fld.SetAttr("valign", "bottom"); break; case 'C': fld.SetAttr("valign", "center"); break; default : break; }; if (border() > 0) { fld.SetAttr("border", border()); if (radius() > 0) fld.SetAttr("radius", radius()); } if (pattern() != PAT_SOLID) fld.SetAttr("pattern", pattern()); else fld.SetAttr("shade_offset", shade_offset()); fld.SetAttr("text", picture()); fld.SetAttr("codval", codval()); fld.SetAttr("link", link()); if (field().not_empty()) fld.AddChild("source") << field(); if (alternate_field().not_empty()) fld.AddChild("alt_source") << alternate_field(); _prescript.save(fld, "prescript"); _postscript.save(fld, "postscript"); if (_type == 'A') { TXmlItem& list = fld.AddChild("list"); FOR_EACH_ARRAY_ITEM(_list, i, obj) { const TReport_array_item& item = *(const TReport_array_item*)obj; TXmlItem& li = list.AddChild("li"); li.SetAttr("Code", item._code); li.SetAttr("Value", item._value); if (item._script.ok()) li << item._script.get(); } } } bool TReport_field::load(const TXmlItem& fld) { const TString& t = fld.GetAttr("type"); set_type(t[0]); 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)); set_dynamic_height(fld.GetBoolAttr("dynamic_height")); _draw_rct = _rct; show(!fld.GetBoolAttr("hidden")); activate(!fld.GetBoolAttr("deactivated")); hide_zeroes(fld.GetBoolAttr("hide_zero")); set_border(fld.GetIntAttr("border")); set_pattern((PAT_STYLE)fld.GetIntAttr("pattern", PAT_SOLID)); set_radius(fld.GetIntAttr("radius")); set_shade_offset(fld.GetIntAttr("shade_offset")); 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", 'T')); set_picture(fld.GetAttr("text")); set_codval(fld.GetAttr("codval")); set_link(fld.GetAttr("link")); TXmlItem* src = fld.FindFirstChild("source"); if (src != NULL) src->GetEnclosedText(_field); TXmlItem* alt_src = fld.FindFirstChild("alt_source"); if (alt_src != NULL) alt_src->GetEnclosedText(_alt_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"); _list.destroy(); if (_type == 'A') { TXmlItem* list = fld.FindFirstChild("list"); TString str; for (int i = 0; i < list->GetChildren(); i++) { const TXmlItem* li = list->GetChild(i); TReport_array_item* rai = new TReport_array_item; rai->_code = li->GetAttr("Code"); rai->_value = li->GetAttr("Value"); li->GetEnclosedText(str); rai->_script.set(str); _list.add(rai); } } return true; } void TReport_field::get_list(TString_array& list) const { list.destroy(); FOR_EACH_ARRAY_ITEM(_list, i, obj) { const TReport_array_item& rai = (const TReport_array_item&)_list[i]; TToken_string* row = new TToken_string(50, SAFE_PIPE_CHR); row->add(rai._code, 0); row->add(rai._value, 1); row->add(rai._script.get(), 2); list.add(row); } } void TReport_field::set_list(const TString_array& list) { _list.destroy(); FOR_EACH_ARRAY_ROW(list, i, row) { TReport_array_item* rai = new TReport_array_item; rai->_code = row->get(0); rai->_value = row->get(); rai->_script.set(row->get()); _list.add(rai); } } int TReport_field::compare(const TSortable& s) const { const TReport_field& rf = (TReport_field&)s; int cmp = _id - rf._id; if (cmp == 0) { cmp = _rct.y - rf._rct.y; if (cmp == 0) cmp = _rct.x - rf._rct.x; } return cmp; } TReport_field::TReport_field(TReport_section* sec) : _section(sec), _id(0), _type('T'), _rct(0,0,1000,100), _fgcolor(COLOR_BLACK), _bgcolor(COLOR_WHITE), _pattern(PAT_HOLLOW), _radius(0), _shade_offset(0), _border(0), _halign('L'), _valign('T'),_dynamic_height(false), _font(NULL), _print_font(NULL), _hidden(false), _deactivated(false), _hide_zeroes(false), _selected(false), _draw_hidden(false), _draw_deactivated(false) { } TReport_field::TReport_field(const TReport_field& rf) : _section(NULL), _font(NULL), _print_font(NULL), _draw_hidden(false), _draw_deactivated(false) { copy(rf); } TReport_field::~TReport_field() { if (_font != NULL) delete _font; if (_print_font != NULL) delete _print_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 { TString8 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) { TString8 key; build_section_key(type, level, key); const bool ok = _sections.remove(key); if (ok) { // Cancello anche testa/coda corrispondente char kill_also[4]; memset(kill_also, 0, sizeof(kill_also)); if (level > 10) // Sottosezione { switch (type) { case 'H': kill_also[0] = 'F'; break; case 'F': kill_also[0] = 'H'; break; default : kill_also[0] = 'H'; kill_also[1] = 'F'; break; } } else { if (level > 1) { switch (type) { case 'H': kill_also[0] = 'F'; break; case 'F': kill_also[0] = 'H'; break; default : break; } } } for (int i = 0; kill_also[i] > ' '; i++) { build_section_key(kill_also[i], level, key); _sections.remove(key); } } return ok; } 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 = atoi(k+1); if (l > lev && l <= 9) lev = l; } return lev; } const TReport_font& TReport::print_font() const { return _use_printer_font ? _print_font : _font; } int TReport::cpi() const { const int udcpi = user_defined_cpi(); return udcpi > 0 ? udcpi : _font.cpi(); } int TReport::lpi() const { return _lpi; } int TReport::print_cpi() const { return (_use_printer_font || user_defined_cpi() <= 0) ? print_font().cpi() : cpi(); } int TReport::print_lpi() const { return _use_printer_font ? printer().get_lines_per_inch() : lpi(); } void TReport::load_printer_font() { if (_use_printer_font) { const TPrinter& p = printer(); _print_font.create(p.fontname(), p.get_char_size(), XVT_FS_NONE); FOR_EACH_ASSOC_OBJECT(_sections, h, k, o) { TReport_section* rs = (TReport_section*)o; rs->compute_print_font(_font, _print_font); } } } void TReport::update_recordset_parent() { if (recordset() != NULL) recordset()->set_parent(NULL); for (int i = find_max_level('B'); i > 0; i--) section('B', i).update_recordset_parent(); } bool TReport::set_recordset(TRecordset* rs) { if (_recordset != NULL && _recordset != rs) delete _recordset; _recordset = rs; update_recordset_parent(); return _recordset != NULL; } bool TReport::set_recordset(const TString& sql) { TRecordset* rex = create_recordset(sql); set_recordset(rex); return rex != NULL; } 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); TString8 key; build_section_key(type, level, key); _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]) || strncmp(code, "THIS", 4) == 0) // Niente sezione davanti { if (strchr(code, '.') != NULL) return 0; // Mi sono confuso con un a campo su file, es: 34.CODART TReport_field* rf = curr_field(); if (rf != NULL) { type = rf->section().type(); level = rf->section().level(); } if (code[0] == 'T') id = rf->id(); else id = atoi(code); } else { type = code[0]; if (type != 'H' && type != 'B' && type != 'F') // Non comincia con un codice sezione return 0; if (!isdigit(code[1])) // Non c'e' il livello return 0; level = atoi((const char*)code + 1); TReport_section* sec = find_section(type, level); if (sec == NULL) return 1; const char* pdot = strchr(code, '.'); const int dot = pdot ? int(pdot-code) : -1; if (dot <= 0) return 2; id = atoi((const char*)code + dot + 1); } return strchr(code, '@') != NULL ? 4 : 3; } TReport_field* TReport::field(const char* code) { char type = ' '; int level = -1, id = 0; const int k = parse_field(code, type, level, id); TReport_field* rf = NULL; if (k == 3) { if (id > 0) { TReport_section* sec = find_section(type, level); if (sec != NULL) 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 TFixed_string name(e.varname(0)); if (name == expr) { if (get_usr_val(name, var)) { if (force_type != _nullfld) var.convert_to(force_type); return true; } } } for (int i = 0; i < e.numvar(); i++) { const TFixed_string name(e.varname(i)); const bool ok = get_usr_val(name, var); if (!ok) var = name; if (var.is_string() || var.is_null()) e.setvar(i, var.as_string()); else { if (var.is_date()) e.setvar(i, var.as_date().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); set_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; _path.ext("rep"); _path.custom_path(); bool ok = xml.Load(_path); if (ok) { _cpi = xml.GetIntAttr("cpi", 0); // 0 cpi = use font size _lpi = xml.GetIntAttr("lpi", 6); _font.load(xml); _use_printer_font = xml.GetBoolAttr("use_printer_font"); _orientation = xml.GetIntAttr("orientation"); const TXmlItem* desc = xml.FindFirstChild("description"); if (desc != NULL) desc->GetEnclosedText(_description); _class = xml.GetAttr("class"); _command_line = xml.GetAttr("command"); // Carico la query principale PRIMA delle sezioni che potrebbero collegarvicisi const TXmlItem* sql = xml.FindFirstChild("sql"); if (sql != NULL) { TString str; sql->GetEnclosedText(str); set_recordset(str); } if (xml.FindFirstChild("section") != NULL) load_sections(xml); _include = xml.GetAttr("libraries"); include_libraries(); _prescript.load(xml, "prescript"); _postscript.load(xml, "postscript"); _params.destroy(); const TXmlItem* params = xml.FindFirstChild("parameters"); if (params != NULL) { TToken_string tok, str; for (int i = 0; i < params->GetChildren(); i++) { const TXmlItem* item = params->GetChild(i); tok = item->GetAttr("name"); if (!tok.blank()) { item->GetEnclosedText(str); tok.add(str); _params.add(tok); } } } _allegati.destroy(); const TXmlItem* all = xml.FindFirstChild("allegates"); if (all != NULL) { for (int i = 0; i < all->GetChildren(); i++) { const TXmlItem* item = all->GetChild(i); _allegati.add(item->GetAttr("name")); } } } 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("class", _class); xml.SetAttr("command", _command_line); if (_cpi > 0) xml.SetAttr("cpi", _cpi); xml.SetAttr("lpi", _lpi); if (!_description.blank()) xml.AddChild("description") << _description; xml.SetAttr("libraries", _include); _font.save(xml); xml.SetAttr("use_printer_font", use_printer_font() ? 1 : 0); xml.SetAttr("orientation", orientation()); 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(); _prescript.save(xml, "prescript"); _postscript.save(xml, "postscript"); if (_params.items() > 0) // Salva lista dei parametri se necessario { TXmlItem& params = xml.AddChild("parameters"); FOR_EACH_ARRAY_ROW(_params, i, str) if (!str->empty_items()) { TXmlItem& item = params.AddChild("item"); item.SetAttr("name", str->get(0)); item << str->get(); } } if (_allegati.items() > 0) // Salva lista dei parametri se necessario { TXmlItem& all = xml.AddChild("allegates"); FOR_EACH_ARRAY_ROW(_allegati, i, str) if (str->full()) { TXmlItem& item = all.AddChild("item"); item.SetAttr("name", *str); } } 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(); } } const TString& TReport::prescript() const { return _prescript.get(); } void TReport::set_prescript(const char* src) { _prescript.set(src); } const TString& TReport::postscript() const { return _postscript.get(); } void TReport::set_postscript(const char* src) { _postscript.set(src); } bool TReport::execute_prescript() { bool ok = true; warm_restart(); if (_prescript.ok()) { ok = _prescript.execute(*this); if (recordset() != NULL) recordset()->ask_variables(false); } else { bool bAsk = true; // Script dei poveri: lancia la maschera associata al report if (use_mask()) { TFilename msk = _path.name(); msk.ext("msk"); if (msk.custom_path()) { TFilename ini = msk; ini.ext("ini"); // Attenzione: se esiste il .ini allora e' una maschera delle vendite! if (!ini.exist()) { bAsk = false; // Non richiedere variabili const KEY key = run_form(msk.name()); ok = key != K_ESC && key != K_QUIT; } } } if (bAsk) { // Script dei poverissimi: chiede le eventuali variabili if (recordset() != NULL) recordset()->ask_variables(false); } } return ok; } bool TReport::execute_postscript() { return _postscript.execute(*this); } bool TReport::get_report_field(const TString& name, TVariant& var) const { bool found = false; const char* str = name; if (name[0] == '#') { if (name.starts_with("#REPORT.")) { str += 8; found = true; } else str++; } TReport_field* fld = ((TReport*)this)->field(str); if (fld != NULL) { var = fld->get(); return true; } if (xvt_str_compare_ignoring_case(str, "PAGE") == 0) { var = long(_rep_page); return true; } else if (xvt_str_compare_ignoring_case(str, "BOOKPAGE") == 0) { var = long(_book_page); return true; } else if (strncmp(str, "ALLEGATE", 8) == 0) { const int index = atoi(str + 9); if (index >= 0 && index < _allegati.items()) var = _allegati.row(index); return true; } return found; } bool TReport::get_record_field(const TString& name, TVariant& var) const { bool found = false; if (recordset() != NULL) { const char* str = name; if (name.starts_with("#RECORD.")) str += 8; // Elimino prefisso // Cerco il campo nel recordset della eventuale sottosezione di appartenenza if (_curr_field != NULL) found = _curr_field->section().get_record_field(str, var); // Se non lo trovo, allora lo cerco nel recordset principale if (!found) { var = recordset()->get(str); if (!var.is_null()) found = true; } } return found; } bool TReport::get_usr_val(const TString& name, TVariant& var) const { if (get_report_field(name, var)) return true; if (get_record_field(name, var)) return true; return TAlex_virtual_machine::get_usr_val(name, var); } bool TReport::set_usr_val(const TString& name, const TVariant& var) { const char* str = name; if (name[0] == '#') { if (name.starts_with("#REPORT.")) str += 8; else str++; } TReport_field* fld = field(str); if (fld != NULL) { fld->set(var); return true; } return TAlex_virtual_machine::set_usr_val(name, var); } size_t TReport::get_usr_words(TString_array& words) const { const char* const name[] = { "***", "DISABLE", "ENABLE", "GET_POS", "GET_SIZE", "HIDE", "ISAM_READ", "RUN_FORM", "SET_BACK_COLOR", "SET_FORE_COLOR", "SET_POS", "SET_SIZE", "SHOW", "TABLE_READ", "GET_FIRM_DATA", NULL }; size_t i; for (i = 0; name[i] != NULL; i++) words.add(name[i]); return i; } static void do_show(TReport_field& rf, void* jolly) { rf.set_draw_hidden(jolly == NULL); } static void do_enable(TReport_field& rf, void* jolly) { rf.set_draw_deactivated(jolly == NULL); } static void do_set_pos(TReport_field& rf, void* jolly) { const TPoint& pt = *(const TPoint*)jolly; rf.set_draw_pos(pt.x, pt.y); } static void do_set_size(TReport_field& rf, void* jolly) { const TPoint& pt = *(const TPoint*)jolly; rf.set_draw_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); const int items = sec.items(); for (int i = 0; i < items; i++) { TReport_field& rf = sec.field(i); if (rf.in_group(id)) msg(rf, jolly); } } break; default: break; } return true; } void TReport::report2mask(TMask & m) const { TVariant var; for (int i = m.fields()-1; i >= 0; i--) { TMask_field& f = m.fld(i); const TFieldref* ref = f.field(); if (ref != NULL) { const bool is_final = f.in_group(2); TString name = ref->name(); if (name[0] != '#') name.insert("#"); if (get_usr_val(name, var)) { if (is_final) { switch (f.class_id()) { case CLASS_CURRENCY_FIELD: case CLASS_REAL_FIELD: if (var.as_real() == 999999999L) var.set_null(); break; case CLASS_DATE_FIELD: if (var.as_date().year() == 9999) var.set_null(); break; default: if (var.as_string() == MAX_STRING) var.set_null(); else { const int from = ref->from(); int to = ref->to(); const TString & s = var.as_string(); if (from > 0 || to > 0) { if (to <= from) to = s.len(); s.mid(from, to - from); } } break; } } if (!var.is_null()) f.set(var.as_string()); } } } } TVariant & string2var(TVariant & v, const TFieldref * r, const TString & val) { const int from = r->from(); int to = r->to(); if (from > 0 || to > 0) { if (to <= from) to = val.len(); TString s = v.as_string(); s.overwrite(val, from, to - from); s.rtrim(); v = s; } else v = val; return v; } void TReport::mask2report(const TMask & m) { TVariant var; TRecordset* rset = recordset(); if (rset != NULL && rset->variables().items() == 0) rset = NULL; for (int i = m.fields()-1; i >= 0; i--) { TMask_field& f = m.fld(i); const TFieldref* ref = f.field(); if (ref != NULL) { const bool is_final = f.in_group(2); TString name = ref->name(); if (name[0] != '#') name.insert("#"); switch (f.class_id()) { case CLASS_CURRENCY_FIELD: case CLASS_REAL_FIELD: var = real(f.get()); if (var.is_empty()) var.set(is_final ? 999999999L : 0L); break; case CLASS_DATE_FIELD: var = TDate(f.get()); if (var.is_empty()) var.set(TDate(is_final ? 99991231L : 0L)); break; default: { TString val(f.get()); get_usr_val(name, var); if (val.empty()) val = is_final ? MAX_STRING : ""; string2var(var, ref, val); } break; } set_usr_val(name, var); if (rset != NULL) rset->set_var(name, var, true); } } } KEY TReport::run_form(TMask& m) { report2mask(m); KEY key = m.run(); if (key != K_QUIT && key != K_ESC) mask2report(m); // Rendi visibili tutte le variabili utente al report return key; } KEY TReport::run_form(const TString& maskname) { TFilename fname = maskname; fname.ext("msk"); KEY key = K_QUIT; if (fname.custom_path()) { TMask m(maskname); key = run_form(m); } return key; } void TReport::do_isam_read_output(const TRectype& file, TToken_string& out) { TVariant var; TString curr; FOR_EACH_TOKEN(out, tok) { // scansione sugli elementi dell'output curr = tok; int posrv = 0; const int poseq= curr.find('='); // divide la stringa corrente in lvalue e rvalue if (poseq > 0) { posrv = poseq+1; if (curr[posrv] == '=') posrv++; } if (poseq < 0) { const TFieldref fr(curr, 0); const TVariant var = fr.read(file); // preleva il nome del campo del file e lo legge dal record curr_field()->set(var); // setta il campo corrente } else { const TString& fld = curr.left(poseq); // preleva il nome del campo del form alla sinistra dell'uguale TReport_field* dest = field(fld); if (dest != NULL) { const TFieldref fr(curr.mid(posrv), 0); const TVariant var = fr.read(file); // preleva il nome del campo del file e lo legge dal record dest->set(var); // setta il campo corrente } } } } void TReport::msg_isam_read(TVariant_stack& stack) { int fkey = 1; // numero e chiave del file da leggere TString16 f_code = stack.pop().as_string(); // prende il codice del file da leggere const int exclam = f_code.find('!'); if (exclam > 0) { fkey = atoi(f_code.mid(exclam+1)); f_code.cut(exclam); } const int logicnum = table2logic(f_code); if (logicnum < LF_USER) return; // File sconosciuto TRectype keyrec(logicnum); if (logicnum == LF_TAB || logicnum == LF_TABCOM) { if (f_code[0] == '%') f_code.ltrim(1); keyrec.put("COD", f_code); } TToken_string in(stack.pop().as_string(), '!'); TVariant var; TString curr; FOR_EACH_TOKEN(in, tok) { // scansione sugli elementi dell'input curr = tok; const int poseq= curr.find('='); // divide la stringa corrente in lvalue e rvalue int posrv = poseq+1; if (curr[posrv] == '=') posrv++; evaluate(curr.mid(posrv), var, _alfafld); const TString& fld = curr.left(poseq); // preleva il nome del campo del file alla sinistra dell'uguale keyrec.put(fld, var.as_string()); // scrive il risultato dell'espressione nel campo del file } TToken_string out(stack.pop().as_string(), '!'); // Lista dei campi di output if (fkey <= 1) { const TRectype& rec = cache().get(keyrec); do_isam_read_output(rec, out); // Se rec e' vuoto azzera gli outputs } else { TLocalisamfile file(logicnum); TRectype& rec = file.curr(); rec = keyrec; file.setkey(fkey); if (file.read() != NOERR) rec.zero(); do_isam_read_output(rec, out); // Se rec e' vuoto azzera gli outputs } } void TReport::msg_table_read(TVariant_stack& stack) { const TString& t_code = stack.pop().as_string(); // prende il codice della tabella da leggere const int logicnum = table2logic(t_code); if (logicnum == LF_TAB || logicnum == LF_TABCOM) { const TString& codtab = stack.pop().as_string(); TVariant var; evaluate(codtab, var, _alfafld); const TRectype& rec = cache().get(t_code, var.as_string()); TToken_string out(stack.pop().as_string(), '!'); do_isam_read_output(rec, out); // Se rec e' vuoto azzera gli outputs } } void TReport::msg_firm(TVariant_stack& stack) { TReport_field& cf = *curr_field(); TString in = stack.pop().as_string(); const long codfirm = prefix().get_codditta(); TString key; key.format("%ld", codfirm); const TRectype & ditta = cache().get(LF_NDITTE, key); if (in[0]!='!') { const int pos = in.find("."); if (pos < 0) cf.set(ditta.get(in)); else if (pos > 0) { const TString file(in.left(pos - 1)); in = in.mid(pos + 1); key = ditta.get(NDT_TIPOA); key << "|" << ditta.get(NDT_CODANAGR); const TRectype & anag = cache().get(LF_ANAG, key); if (file == "ANAG" || file == "6") cf.set(anag.get(in)); else if (file == "COM" || file == "13") { const bool is_fisc = anag.get(ANA_INDRF).not_empty(); key = anag.get(ANA_STATORES); key << "|" << is_fisc ? anag.get(ANA_COMRF) : anag.get(ANA_COMRES); const TRectype & comune = cache().get(LF_COMUNI, key); cf.set(comune.get(in)); } else if (file == "ULC" || file == "13") { key.format("%ld|1", codfirm); const TRectype & unloc = cache().get(LF_UNLOC, key); cf.set(unloc.get(in)); } } return; } in.ltrim(1); if (in=="RAGSOC") { cf.set(ditta.get(NDT_RAGSOC)); return; } if (in=="TEL") { TString valore(16); valore = ditta.get(NDT_PTEL); if (valore.not_empty()) valore << '-'; valore << ditta.get(NDT_TEL); cf.set(valore); return; } if (in=="FAX") { TString valore(16); valore = ditta.get(NDT_PFAX); if (valore.not_empty()) valore << '-'; valore << ditta.get(NDT_FAX); cf.set(valore); return; } key = ditta.get(NDT_TIPOA); key << "|" << ditta.get(NDT_CODANAGR); const TRectype & anag = cache().get(LF_ANAG, key); const bool is_fisc = anag.get(ANA_INDRF).not_empty(); if (in=="IND") { cf.set(anag.get(is_fisc ? ANA_INDRF : ANA_INDRES)); return; } if (in=="NUM") { cf.set(anag.get(is_fisc ? ANA_CIVRF : ANA_CIVRES)); return; } if (in=="CAP") { cf.set(anag.get(is_fisc ? ANA_CAPRF : ANA_CAPRES)); return; } if (in=="IVA") { cf.set(anag.get("PAIV")); return; } if (in=="CF") { cf.set(anag.get("COFI")); return; } key.cut(0) << anag.get(ANA_STATORES) << '|' << anag.get(is_fisc ? ANA_COMRF : ANA_COMRES); const TRectype& comune = cache().get(LF_COMUNI, key); if (in=="COM") { cf.set(comune.get(COM_DENCOM)); return; } if (in=="PROV") { cf.set(comune.get(COM_PROVCOM)); return ; } key.format("%ld|1", codfirm); const TRectype & unloc = cache().get(LF_UNLOC, key); if (in=="REGSOC" || in=="REGIMP") { TString valore; valore = unloc.get(ULC_REGTRIB); valore.insert(" ", 2); valore.insert(" ", 6); valore.insert(" ", 11); valore.insert(" ", 21); valore.insert("Reg.Imp. ", 0); cf.set(valore); return; } if (in=="CCIAA") { TString valore; valore = unloc.get(ULC_NUMCCIAA); const TString & data = unloc.get(ULC_DATAICCIAA); if (data.not_empty()) valore << " del " << data; cf.set(valore); return; } } bool TReport::execute_usr_word(unsigned int opcode, TVariant_stack& stack) { switch (opcode) { case 1: // Placeholder break; case 2: // DISABLE do_message(stack.pop(), do_enable, NULL); break; case 3: // ENABLE do_message(stack.pop(), do_enable, (void*)1); break; case 4: // GET_POS { const TReport_field* fld = field(stack.pop().as_string()); real x, y; if (fld != NULL) { const TRectangle& r = fld->get_draw_rect(); x = r.x / CENTO; y = r.y / CENTO; } stack.push(x); stack.push(y); } break; case 5: // GET_SIZE { const TReport_field* fld = field(stack.pop().as_string()); real w, h; if (fld != NULL) { const TRectangle& r = fld->get_draw_rect(); w = r.width() / CENTO; h = r.height() / CENTO; } stack.push(w); stack.push(h); } break; case 6: // HIDE do_message(stack.pop(), do_show, NULL); break; case 7: // ISAM_READ msg_isam_read(stack); break; case 8: // RUN_FORM { const TString& msk = stack.pop().as_string(); const KEY key = run_form(msk); stack.push(key); } break; case 9: // SET_BACK_COLOR { const TVariant& fld = stack.pop(); const COLOR rgb = stack.pop().as_color(); do_message(fld, do_set_back_color, (void*)rgb); } break; case 10: // SET_FORE_COLOR { const TVariant& fld = stack.pop(); const COLOR rgb = stack.pop().as_color(); do_message(fld, do_set_fore_color, (void*)rgb); } break; case 11: // SET_POS { const TVariant& fld = stack.pop(); const real y = stack.pop().as_real() * CENTO; const real x = stack.pop().as_real() * CENTO; const TPoint pt(x.integer(), y.integer()); do_message(fld, do_set_pos, (void*)&pt); } break; case 12: // 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 13: // SHOW do_message(stack.pop(), do_show, (void*)1); break; case 14: // TABLE_READ msg_table_read(stack); break; case 15: // GET_FIRM_DATA msg_firm(stack); break; default: return false; } return true; } bool TReport::on_link(const TReport_link& lnk) { const TString& table = lnk.table(); const int logicnum = table2logic(table); if (logicnum >= LF_USER) { TRectype rec(logicnum);; if (logicnum == LF_TAB || logicnum == LF_TABCOM) rec.settab(table.right(3)); TAssoc_array& fields = lnk.fields(); TAssoc_array delayed; FOR_EACH_ASSOC_OBJECT(fields, h, k, o) { const TFieldref fld(k, logicnum); if (fld.from() > 0) delayed.add(k, *o); else { const TString* var = (const TString*)o; fld.write(*var, rec); } } if (delayed.items() > 0) { FOR_EACH_ASSOC_OBJECT(delayed, h, k, o) { const TFieldref fld(k, logicnum); const TString* var = (const TString*)o; fld.write(*var, rec); } } return rec.edit(); } return false; } void TReport::include_libraries(bool reload) { TAlex_virtual_machine::include_libraries(reload); if (reload || !defined("MESSAGE_ALIGN")) include("report.alx"); if (!_include.blank()) { FOR_EACH_TOKEN(_include, lib) { TFilename libname = lib; libname.trim(); if (libname.find('.') < 0) libname.ext("alx"); include(libname); } } } bool TReport::print_or_preview() { TReport_book book; book.add(*this); return book.print_or_preview(); } bool TReport::preview() { TReport_book book; book.add(*this); return book.preview(); } bool TReport::archive() { TReport_book book; book.add(*this); return book.archive(); } TReport::TReport() : _cpi(0), _lpi(6), _include(15, ','), _recordset(NULL), _curr_field(NULL), _use_printer_font(false), _orientation(0) { _expressions.set_report(this); _prescript.set_description("PRESCRIPT"); _postscript.set_description("POSTSCRIPT"); } TReport::~TReport() { destroy(); }