campo-sirio/ba/ba8302.cpp

1294 lines
29 KiB
C++
Raw Normal View History

#include <colors.h>
#include <expr.h>
#include <xml.h>
#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);
if (_fontid != NULL)
xvt_font_destroy(_fontid);
TReport_font& my = *(TReport_font*)this;
my._fontid = fontid;
my._win_mapped = win.win();
xvt_dwin_get_font_metrics(_win_mapped, &my._leading, &my._ascent, &my._descent);
}
return _fontid;
}
void TReport_font::create(const char* name, int size, XVT_FONT_STYLE_MASK style)
{
_name = name;
_size = size;
_style = style;
_cpi = 120 / _size;
if (_fontid != NULL)
{
xvt_font_destroy(_fontid);
_fontid = NULL;
_win_mapped = NULL_WIN;
}
}
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.FindFirst("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()
{
if (_fontid != NULL)
xvt_font_destroy(_fontid);
}
///////////////////////////////////////////////////////////
// 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* TExpression_cache::key2obj(const char* key)
{
return new TReport_expr(*_report, key);
}
TReport_expr& TExpression_cache::operator[](const char* key)
{ return *(TReport_expr*)objptr(key); }
///////////////////////////////////////////////////////////
// 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);
}
///////////////////////////////////////////////////////////
// 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);
}
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::execute_prescript()
{
bool ok = true;
if (active())
{
TString80 str;
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());
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)
{
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.FindFirst("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
///////////////////////////////////////////////////////////
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;
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(rf.type() == 'S' ? 1024 : 32);
TReport& rep = rf.section().report();
rep.set_curr_field(&rf);
good = execute(rep, str);
if (good)
rf.set(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.SetAttr("language", "Alex");
script << _src;
}
}
bool TReport_script::load(const TXmlItem& root, const char* tag)
{
destroy();
TXmlItem* script = root.FindFirst(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::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();
_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 'R': n = "Rettangolo"; break;
case 'S': n = "Stringa"; break;
case 'T': n = "Testo"; break;
default : break;
}
return n;
}
TFieldtypes TReport_field::var_type() const
{
TFieldtypes ft = _nullfld;
switch (_type)
{
case 'D': ft = _datefld; break;
case 'N': ft = _realfld; break;
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::execute_prescript()
{
if (!_field.blank())
{
const TFieldtypes ft = var_type();
if (ft != _nullfld)
section().report().evaluate(_field, _var, ft);
else
_var.set_null();
}
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 '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 'I':
case 'R': draw_rect(win); break;
case 'T': draw_text(win, _picture); 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);
}
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);
}
}
}
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);
}
}
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);
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);
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");
}
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;
}
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"));
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.FindFirst("source");
if (src != NULL)
src->GetEnclosedText(_field);
TReport_font font;
if (font.load(fld))
set_font(font);
_prescript.load(fld, "prescript");
_postscript.load(fld, "postscript");
return true;
}
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),
_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_field_ref
///////////////////////////////////////////////////////////
struct TReport_field_ref : public TObject
{
char _sectype;
int _seclevel;
int _fldid; // -1 = section; 0 = curent field; >0 = normal field
int _fldpos; // array position
};
TObject* TField_cache::key2obj(const char* key)
{
const TFixed_string code(key);
TReport_field_ref* rf = new TReport_field_ref;
rf->_sectype = ' ';
rf->_seclevel = rf->_fldid = rf->_fldpos = -1;
const char* strid = "";
const int dot = code.find('.');
if (dot == 2)
{
rf->_sectype = code[0];
if (isdigit(code[1]))
rf->_seclevel = atoi((const char*)code + 1);
strid = (const char*)code+3;
}
else
strid = code;
if (*strid > ' ')
{
rf->_fldid = atoi(strid);
TReport_section& sec = _report->section(rf->_sectype, rf->_seclevel);
rf->_fldpos = sec.find_field_pos(rf->_fldid);
}
return rf;
}
TReport_field* TField_cache::operator[](const char* key)
{
TReport_field_ref& ref = *(TReport_field_ref*)objptr(key);
if (ref._fldid <= 0)
return _report->curr_field();
char typ = ref._sectype;
int lev = ref._seclevel;
if (typ <= ' ' || lev < 0)
{
TReport_field* cf = _report->curr_field();
if (typ <= ' ') typ = cf->section().type();
if (lev < 0) lev = cf->section().level();
}
TReport_section& sec = _report->section(typ, lev);
TReport_field* fld = NULL;
if (ref._fldpos >= 0 && ref._fldpos < sec.items())
{
fld = &sec.field(ref._fldpos);
if (fld->id() == ref._fldid)
return fld;
}
ref._fldpos = sec.find_field_pos(ref._fldid);
fld = ref._fldpos >= 0 ? &sec.field(ref._fldpos) : NULL;
return fld;
}
///////////////////////////////////////////////////////////
// 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;
}
TReport_field* TReport::field(const TString& code)
{
return _fields[code];
}
bool TReport::evaluate_atom(const char* atom, TVariant& var)
{
const TFixed_string name(atom); // skip #
if (name == "PAGE")
{
var = curr_page();
return true;
}
const TReport_field* fld = field(name);
var = fld != NULL ? fld->get() : NULL_VARIANT;
return fld != NULL;
}
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 bool ok = evaluate_atom(name+1, var);
if (force_type != _nullfld)
var.convert_to(force_type);
return ok;
}
}
for (int i = 0; i < e.numvar(); i++)
{
const char* name = e.varname(i);
if (name[0] == '#')
{
evaluate_atom(name, var);
if (var.type() == _alfafld)
e.setvar(i, var.as_string());
else
e.setvar(i, var.as_real());
}
else
{
if (_recordset != NULL)
{
const TVariant& var = _recordset->get(name);
if (var.type() == _realfld || var.type() == _longfld)
e.setvar(i, var.as_real());
else
e.setvar(i, var.as_string());
}
else
e.setvar(i, name);
}
}
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.FindFirst("description");
if (desc != NULL)
desc->GetEnclosedText(_description);
if (xml.FindFirst("section") != NULL)
load_sections(xml);
const TXmlItem* sql = xml.FindFirst("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;
}
bool TReport::get_usr_val(const TString& name, TVariant& var) const
{
return ((TReport*)this)->evaluate(name, var, _nullfld);
}
bool TReport::set_usr_val(const TString& name, const TVariant& var)
{
return false;
}
unsigned int TReport::compile_usr_word(const TString& name) const
{
if (name == "GET_FIELD")
return 1;
if (name == "SET_FIELD")
return 2;
return 0;
}
bool TReport::execute_usr_word(unsigned int opcode, TVariant_stack& stack)
{
switch (opcode)
{
case 1:
{
TVariant& var = stack.peek();
evaluate(var.as_string(), var, _nullfld);
}
break;
case 2:
{
TVariant& var = stack.pop();
TVariant& val = stack.pop();
TReport_field* fld = field(var.as_string());
if (fld != NULL)
fld->set(val);
}
break;
default:
return false;
}
return true;
}
TReport::TReport() : _lpi(6), _recordset(NULL), _curr_field(NULL)
{
// Brutte inizializzazioni, ma inevitabili
_expressions.set_report(this);
_fields.set_report(this);
}
TReport::~TReport()
{
destroy();
}