campo-sirio/include/report.cpp

2468 lines
57 KiB
C++
Raw Normal View History

#include <colors.h>
#include <expr.h>
#include <image.h>
#include <recarray.h>
#include <relation.h>
#include <reprint.h>
#include <xml.h>
///////////////////////////////////////////////////////////
// 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, "Courier New");
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
{
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 int best = compute_font_match(win.win(), (pnt1.v - pnt0.v), ppi, cpi);
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;
}
XVT_FNTID TReport_font::get_preview_font(const TWindow& win, const TPoint& res) const
{
if (win.win() != _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(win.win(), (pnt1.v - pnt0.v), ppi, cpi);
const int 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() : _win_mapped(NULL_WIN), _fontid(NULL)
{
create("Courier New", 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)
{
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
///////////////////////////////////////////////////////////
bool advanced_set_draw_tools(TWindow& win, int border, COLOR fore, COLOR back)
{
const bool has_pen = border > 0;
const bool has_brush = (back & 0xFFFFFF) != (COLOR_WHITE & 0xFFFFFF);
const bool visible = has_pen || has_brush;
if (visible)
{
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();
}
return visible;
}
void advanced_draw_rect(TWindow& win, const RCT& r, int border, COLOR fore, COLOR back)
{
if (advanced_set_draw_tools(win, border, fore, back))
xvt_dwin_draw_rect(win.win(), (RCT*)&r);
}
void advanced_draw_justified_text(TWindow& win, const char* text, short x, short y, short dx)
{
TString txt(text); txt.rtrim();
int spaces = 0;
for (int s = 0; txt[s]; s++)
if (isspace(txt[s])) spaces++;
const int tw = xvt_dwin_get_text_width(win.win(), txt, -1);
if (tw < dx && spaces > 0)
{
txt << ' '; // Aggiunge spazio finale
const double kspc = double(dx - tw) / spaces;
int start = 0;
double kx = x;
for (int i = 0; txt[i]; i++)
{
if (isspace(txt[i]))
{
const bool last_word = txt[i+1] == '\0';
const TString& parola = txt.sub(start, i + (last_word ? 0 : 1));
const int lw = xvt_dwin_get_text_width(win.win(), parola, -1);
if (last_word) // ultima parola
kx = x+dx-lw;
xvt_dwin_draw_text(win.win(), int(kx+0.5), y, parola, -1);
kx += lw + kspc;
start = i+1;
}
}
}
else
xvt_dwin_draw_text(win.win(), x, y, text, -1);
}
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;
}
if (halign == 'J')
advanced_draw_justified_text(win, text, x, y, dx);
else
xvt_dwin_draw_text(win.win(), x, y, text, -1);
}
void advanced_draw_paragraph(TWindow& win, TString& para, const RCT& rct,
char halign, char valign)
{
const bool acapo = para.find('\n') >= 0;
const bool parag = para.find(char(0xB6)) >= 0;
int leading, ascent, descent;
xvt_dwin_get_font_metrics(win.win(), &leading, &ascent, &descent);
const int ky = leading + ascent + descent;
const int rct_height = rct.bottom - rct.top;
int rows = rct_height / ky;
if (acapo || parag || rows > 1) // Devo scrivere piu' righe?
{
const int kx = xvt_dwin_get_text_width(win.win(), "ABCDEFGH", 8) / 8;
const unsigned columns = (rct.right - rct.left) / kx;
if (parag)
para.replace(char('0xB6'), '\n');
TParagraph_string str(para, columns);
if (str.items() < rows)
rows = str.items();
int ybase = rct.top;
switch (valign)
{
case 'C': ybase += (rct_height - rows*ky) / 2; break;
case 'B': ybase += rct_height - rows*ky; break;
default : break;
}
for (int row = 0; row < rows; row++)
{
RCT rctline = rct;
rctline.top = ybase + ky*row;
rctline.bottom = rctline.top + ky;
const char* line = str.get();
if (halign == 'J' && (row == rows-1 || strlen(line) < columns/2))
halign = 'L';
advanced_draw_text(win, line, rctline, halign, 'T');
}
}
else
advanced_draw_text(win, para, rct, halign, valign);
}
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);
}
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;
}
TPoint TReport_section::compute_size() const
{
if (hidden())
return TPoint(0,0);
TPoint s = _size;
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);
f.load_field();
}
}
return ok;
}
bool TReport_section::execute_prescript()
{
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; i < items(); i++)
{
TReport_field& f = field(i);
f.execute_prescript();
}
return ok;
}
void TReport_section::print(TBook& book) const
{
if (shown() && active())
{
for (int i = 0; i < items(); i++)
{
const TReport_field& f = field(i);
f.print(book);
}
}
}
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());
item.SetAttr("hidden", _hidden);
item.SetAttr("deactivated", _deactivated);
item.SetAttr("hidden_if_needed", hidden_if_needed());
item.SetAttr("pagebreak", _page_break);
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 (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)
{
_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"));
force_page_break(sec.GetBoolAttr("pagebreak"));
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)
{
const TXmlItem* cnd = sec.FindFirstChild("condition");
if (cnd != NULL)
{
TString str;
cnd->GetEnclosedText(str);
set_condition(str);
}
}
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), _pos(0,0),
_size(0,0), _page_break(false), _hidden_if_needed(false),
_repeat(false), _hidden(false), _deactivated(false), _font(NULL)
{ }
TReport_section::~TReport_section()
{
if (_font)
delete _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 << " ?";
error_box(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
{
TString _code, _value;
TReport_script _script;
};
///////////////////////////////////////////////////////////
// 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
{
if (dynamic_height())
{
TRectangle& rct = ((TReport_field*)this)->_draw_rct;
rct = _rct;
int h = 100;
TParagraph_string str(formatted_text(), rct.width()/100);
str.rtrim();
h = str.items() * 100;
if (h <= 0)
h = 100;
if (h > _rct.height())
h = _rct.height();
rct.set_height(h);
return rct;
}
return _rct;
}
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();
}
const TString& TReport_field::prescript() const
{ return _prescript.get(); }
void TReport_field::set_prescript(const char* src)
{
TString desc; desc << section().type() << section().level() << '.' << id() << " PRESCRIPT";
_prescript.set_description(desc);
_prescript.set(src);
}
const TString& TReport_field::postscript() const
{ return _postscript.get(); }
void TReport_field::set_postscript(const char* src)
{
TString desc; desc << section().type() << section().level() << '.' << id() << " POSTSCRIPT";
_postscript.set_description(desc);
_postscript.set(src);
}
void TReport_field::copy(const TReport_field& rf)
{
_section = rf._section;
_id = rf.id();
_type = rf.type();
_rct = rf._rct;
set_dynamic_height(rf.dynamic_height());
_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;
_prescript = rf._prescript;
_postscript = rf._postscript;
_list = rf._list;
set_font(rf.font());
}
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.blank();
if (ok)
{
const TFieldtypes ft = var_type();
if (ft != _nullfld)
{
if (_field.starts_with("SELECT "))
{
TSQL_recordset qry(_field);
TString str;
for (int i = 0; i < qry.items(); i++)
{
if (i > 0) str << '\n';
for (unsigned int j = 0; j < qry.columns(); j++)
{
if (j > 0) str << ' ';
str << qry.get(j).as_string();
}
}
_var.set(str);
_var.convert_to(ft);
}
else
section().report().evaluate(_field, _var, ft);
if (_var.is_empty() && _alt_field.not_empty())
section().report().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.not_empty())
{
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;
}
const TString& TReport_field::formatted_text() const
{
if (_hide_zeroes && _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);
TString& tmp = get_tmp_string();
const bool dotted = _picture.find('.') > 0;
tmp = cur.string(dotted);
return tmp;
}
break;
default:
if (_picture.not_empty())
{
TString& tmp = get_tmp_string();
if (_picture.find('#') >= 0)
tmp.picture(_picture, _var.as_string());
else
tmp << _picture << ' ' << _var.as_string();
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 = (back_color() & 0xFFFFFF) != (COLOR_WHITE & 0xFFFFFF);
const bool visible = has_pen || has_brush;
if (visible)
{
book.set_pen(fore_color(), border()-1);
book.set_brush(back_color(), has_brush ? PAT_SOLID : PAT_HOLLOW);
}
return visible;
}
void TReport_field::print_rect(TBook& book) const
{
if (print_tools(book))
book.draw_rectangle(get_draw_rect());
}
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();
book.draw_image(get_draw_rect(), name);
if (border() > 0)
{
book.set_pen(fore_color(), border()-1);
book.set_brush(COLOR_WHITE, PAT_HOLLOW);
book.draw_rectangle(get_draw_rect());
}
}
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':
print_rect(book);
if (!_picture.blank())
{
book.set_font(font());
book.set_text_align(horizontal_alignment(), vertical_alignment());
book.set_text_color(fore_color(), back_color());
book.draw_text(get_draw_rect(), _picture);
}
break;
default :
{
print_rect(book);
const TString& str = formatted_text();
if (!str.blank())
{
book.set_font(font());
book.set_text_align(horizontal_alignment(), vertical_alignment());
book.set_text_color(fore_color(), back_color());
book.draw_text(get_draw_rect(), str);
if (link().not_empty())
book.draw_link(get_draw_rect(), str, link());
}
}
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", _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 'B': fld.SetAttr("valign", "bottom"); break;
case 'C': fld.SetAttr("valign", "center"); break;
default : break;
};
fld.SetAttr("border", border());
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_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);
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 = _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'), _rct(0,0,1000,100),
_fgcolor(COLOR_BLACK), _bgcolor(COLOR_WHITE),
_border(0), _halign('L'), _valign('T'),_dynamic_height(false), _font(NULL),
_hidden(false), _deactivated(false), _hide_zeroes(false), _selected(false)
{ }
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);
const bool ok = _sections.remove(key);
if (ok && level > 1 && type != 'B')
{
// Cancello anche testa/coda corrispondente
build_section_key(type == 'H' ? 'F' : 'H', 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)
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 ", 7, true) == 0)
ok = set_recordset(new TSQL_recordset(sql));
else
ok = set_recordset(new TISAM_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; 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 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 = -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())
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);
}
_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);
}
}
}
}
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());
if (!_description.blank())
xml.AddChild("description") << _description;
xml.SetAttr("libraries", _include);
_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();
_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();
}
}
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
{
// Script dei poveri: lancia la maschera associata al report
TFilename msk = _path.name(); msk.ext("msk");
if (msk.custom_path())
{
const KEY key = run_form(msk.name());
ok = key != K_ESC && key != K_QUIT;
}
else
{
// Script dei poverissimi: chiede le eventuali variabili
if (recordset() != NULL)
recordset()->ask_variables(true);
}
}
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++;
}
const TFixed_string n(str);
if (n == "PAGE")
{
var = curr_page();
return true;
}
TReport_field* fld = ((TReport*)this)->field(n);
if (fld != NULL)
{
var = fld->get();
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;
found = true;
}
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++;
}
const TFixed_string n(str);
TReport_field* fld = field(n);
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", 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);
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;
}
KEY TReport::run_form(const TString& maskname)
{
TFilename fname = maskname; fname.ext("msk");
KEY key = K_QUIT;
if (fname.custom_path())
{
TMask m(maskname);
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() == "~~~")
var.set_null();
break;
}
}
if (!var.is_null())
f.set(var.as_string());
}
}
}
key = m.run();
if (key != K_QUIT && key != K_ESC)
{
TRecordset* rset = recordset();
if (rset != NULL && rset->variables().items() == 0)
rset = NULL;
// Rendi visibili tutte le variabili utente al report
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);
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:
var = f.get();
if (var.is_empty())
var.set(is_final ? "~~~" : "");
break;
}
TString name = ref->name();
if (name[0] != '#')
name.insert("#");
set_usr_val(name, var);
if (rset != NULL)
rset->set_var(name, var);
}
}
}
}
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)
{
const TString& f_code = stack.pop().as_string(); // prende il codice del file da leggere
const int logicnum = table2logic(f_code);
if (logicnum < LF_USER)
return; // File sconosciuto
TRectype keyrec(logicnum);
if (logicnum == LF_TAB || logicnum == LF_TABCOM)
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
}
const TRectype& file = cache().get(keyrec);
if (!file.empty())
{
TToken_string out(stack.pop().as_string(), '!');
do_isam_read_output(file, out);
}
}
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& file = cache().get(t_code, var.as_string());
if (!file.empty())
{
TToken_string out(stack.pop().as_string(), '!');
do_isam_read_output(file, out);
}
}
}
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 COLOR rgb = stack.pop().as_color();
do_message(stack.pop(), do_set_back_color, (void*)rgb);
}
break;
case 10: // SET_FORE_COLOR
{
const COLOR rgb = stack.pop().as_color();
do_message(stack.pop(), 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;
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");
FOR_EACH_TOKEN(_include, lib)
{
TFilename libname = lib;
libname.trim();
if (libname.find('.') < 0)
libname.ext("alx");
include(libname);
}
}
TReport::TReport() : _lpi(6), _include(15, ','), _recordset(NULL), _curr_field(NULL)
{
_expressions.set_report(this);
_prescript.set_description("PRESCRIPT");
_postscript.set_description("POSTSCRIPT");
}
TReport::~TReport()
{
destroy();
}