campo-sirio/include/report.cpp
guy 18a40d0a62 Patch level : 10.0
Files correlati     : ve1.exe
Ricompilazione Demo : [ ]
Commento            :
0001643: Gestione campi trasparenti nei report
Per quei campi dove non risulta settato il valore dello sfondo (trasparente, pieno, ecc..) metteremo di default pieno. Questo dovrebbe simulare il comportamento del programma prima della modifica.


git-svn-id: svn://10.65.10.50/trunk@20498 c028cbd2-c16b-5b4b-a496-9718f37d4682
2010-05-26 08:56:55 +00:00

3417 lines
80 KiB
C++
Executable File

#include <colors.h>
#include <defmask.h>
#include <expr.h>
#include <printer.h>
#include <recarray.h>
#include <relation.h>
#include <reprint.h>
#include <utility.h>
#include <xml.h>
#include <anagr.h>
#include <comuni.h>
#include <nditte.h>
#include <unloc.h>
static const char MAX_STRING[2] = { (char)255, 0 };
///////////////////////////////////////////////////////////
// TReport_rct
///////////////////////////////////////////////////////////
bool TReport_rct::contains(const TReport_rct& r) const
{
return r.left() >= left() && r.right() <= right() && r.top() >= top() && r.bottom() <= bottom();
}
bool TReport_rct::intersects(const TReport_rct& r) const
{
if (r.right() < x) return false;
if (r.x > right()) return false;
if (r.bottom() < y) return false;
if (r.y > bottom()) return false;
return true;
}
void TReport_rct::merge(const TReport_rct& rct)
{
long l = x, t = y, r = right(), b = bottom();
if (rct.x < l) l = rct.x;
if (rct.y < t) t = rct.y;
if (rct.right() > r) r = rct.right();
if (rct.bottom() > b) b = rct.bottom();
x=l; y=t; _size.x = r-l; _size.y = b-t;
}
///////////////////////////////////////////////////////////
// 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 TSize& 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 _boolfld: _var.set(str=="X"||str=="Y"||str=="1"); break;
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 (!same_color(col, def))
{
TString8 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(const TObject& obj)
{
return add(obj.dup());
}
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;
}
int TReport_section::code(TString& code) const
{
code.format("%c%d", type(), level());
return level();
}
// 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;
}
TReport_size TReport_section::compute_size() const
{
if (hidden())
return TReport_size(0,0);
TReport_size 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 TReport_rct& 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(TReport_rct& rct) const
{
rct.set(TReport_pnt(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 && fore_color() != COLOR_INVALID;
const bool has_brush = pattern() >= PAT_SOLID && back_color() != COLOR_WHITE || pattern() == PAT_SPECIAL;
const bool visible = has_pen || has_brush;
if (visible)
{
book.set_pen(fore_color(), border()-1);
if (pattern() == PAT_SPECIAL)
{
book.set_text_color(fore_color(), back_color()); // Il background serve come base dello shading
book.set_brush(shade_color(), pattern(), shade_angle());
}
else
book.set_brush(back_color(), pattern());
}
return visible;
}
void TReport_section::print(TBook& book) const
{
if (shown() && active())
{
TReport_rct 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 (print_tools(book))
{
if (radius() > 0)
book.draw_round_rectangle(rct, radius());
else
book.draw_rectangle(rct);
}
const int tot = items();
for (int i = 0; i < tot; 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;
const int tot = items();
for (int i = 0; i < tot; 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());
}
item.SetAttr("pattern", pattern());
if (pattern() == PAT_SPECIAL)
{
item.SetAttr("sh_angle", shade_angle());
set_col_attr(item, "sh_color", shade_color(), COLOR_GRAY);
}
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");
const int tot = items();
for (int i = 0; i < tot; 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_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));
set_pattern((PAT_STYLE)sec.GetIntAttr("pattern", PAT_HOLLOW));
if (pattern() == PAT_SPECIAL)
{
set_shade_color(get_col_attr(sec, "sh_color", COLOR_GRAY));
set_shade_angle(sec.GetIntAttr("sh_angle"));
}
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 && type() == 'B') // Solo body dei pulcini hanno la query
{
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), _shcolor(COLOR_GRAY), _pattern(PAT_HOLLOW),
_border(0), _radius(0), _shade_angle(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
///////////////////////////////////////////////////////////
TReport_field* TReport_field::next() const
{
const TArray& sec = section();
for (int i = sec.last()-1; i >= 0; i--)
if (sec.objptr(i) == this)
return (TReport_field*)sec.objptr(i+1);
return NULL;
}
TReport_field* TReport_field::prev() const
{
const TArray& sec = section();
for (int i = sec.last(); i > 0; i--)
if (sec.objptr(i) == this)
return (TReport_field*)sec.objptr(i-1);
return NULL;
}
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 TReport_size& 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 TReport_rct& TReport_field::get_draw_rect() const
{
// Dalla 4.0 il rettangolo e' sempre gia' calcolato correttamente!
return _draw_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();
}
void TReport_field::set_shadow_offset(int s)
{
_shadow_offset = s;
if (s != 0 && pattern() == PAT_HOLLOW)
set_pattern(PAT_SOLID);
}
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;
_txcolor = rf._txcolor; _shcolor = rf._shcolor;
_border = rf._border; _radius = rf._radius; _shade_angle = rf._shade_angle;
_pattern = rf._pattern; _shadow_offset = rf._shadow_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 'B': n = "Booleano"; 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 'B': ft = _boolfld; break;
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 TString& 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' && !_list.empty())
{
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 'B':
if (_var.as_bool())
return get_tmp_string() = "X";
else
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_text_color(text_color(), back_color());
if (pattern() == PAT_SPECIAL)
book.set_brush(shade_color(), pattern(), shade_angle());
else
book.set_brush(back_color(), pattern());
}
return visible;
}
const TReport_rct& TReport_field::compute_draw_rect(const TBook& book)
{
TReport_rct& r = _draw_rct;
r = _rct;
if (dynamic_height())
{
const TString& txt = formatted_text();
if (txt.full())
{
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); // r.set_height(0) could be better, but what about MESSAGE_ALIGN?
}
return r;
}
const TReport_rct& TReport_field::print_rect(const TReport_rct& rect, TBook& book) const
{
const int off = shadow_offset();
if (off != 0 && pattern() == PAT_SOLID) // Devo stampare l'ombra?
{
const COLOR color = blend_colors(section().back_color(), COLOR_BLACK, 0.5);
book.set_pen(color, 0);
book.set_brush(color, PAT_SOLID);
TReport_rct rct = rect;
rct += TReport_size(off, off * 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 TReport_rct& TReport_field::print_rect(TBook& book) const
{
const TReport_rct& 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().full()) // Devo "stampare" i link anche se nascosti
{
TReport_rct rct = get_draw_rect();
rct.set_empty();
book.draw_link(rct, formatted_text(), link());
}
return;
}
switch (_type)
{
case 'B':
if (is_power_reseller())
{
const TReport_rct& rctout = get_draw_rect();
const int side = 3*rctout.height()/4;
TReport_rct rctin(rctout.x, rctout.y, 2*side, side);
if (_halign == 'C') rctin.x += (rctout.width() - rctin.width())/2; else
if (_halign == 'R') rctin.x = rctout.right() - side;
if (_valign == 'C') rctin.y += (rctout.height() - rctin.height())/2; else
if (_valign == 'B') rctin.y = rctout.bottom() - rctin.height();
if (print_tools(book))
book.draw_rectangle(rctin);
if (get().as_bool())
{
rctin.deflate(rctin.width()/8, rctin.height()/8);
const TFixed_string name("res/ok.png");
book.draw_image(rctin, name);
}
}
else
{
const TString& str = formatted_text();
if (str.full())
{
book.set_font(print_font());
book.set_text_align(horizontal_alignment(), vertical_alignment());
book.set_text_color(text_color(), back_color());
const TReport_rct& pr = print_rect(book);
TString8 sec_code; section().code(sec_code);
book.draw_text(pr, str, sec_code);
}
print_rect(book);
}
break;
case 'E':
if (print_tools(book))
book.draw_ellipse(get_draw_rect());
break;
case 'I':
{
const TString& name = get().as_string();
const TReport_rct& 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.full())
{
book.set_font(print_font());
const TReport_rct& pr = print_rect(book); // Calcolo rettangolo dopo aver settato il font!
book.set_text_align(horizontal_alignment(), vertical_alignment());
book.set_text_color(text_color(), back_color());
TString8 sec_code; section().code(sec_code);
if (pr.height() > 100) // Multiriga?
{
TString_array para;
TReport_rct rect = pr; // Potrebbe risultare piu' grande del print_rect!
book.compute_text_frame(_picture, print_font(), rect, para);
book.draw_text(pr, para, sec_code); // Stampa paragrafo nello spazio assegnato
}
else
book.draw_text(pr, _picture, sec_code);
}
else
print_rect(book);
break;
case 'N':
if (field() == "#BOOKPAGES")
{
const TReport_rct& pr = print_rect(book);
book.draw_book_pages(pr);
break;
}
default :
{
const TString& str = formatted_text();
if (str.full())
{
book.set_font(print_font());
book.set_text_align(horizontal_alignment(), vertical_alignment());
book.set_text_color(text_color(), back_color());
TString8 sec_code; section().code(sec_code);
if (dynamic_height() || _rct.height() > 100) // Multiriga?
{
TString_array para;
TReport_rct 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, sec_code); // Stampa paragrafo
}
else
{
const TReport_rct& pr = print_rect(book);
book.draw_text(pr, str, sec_code);
if (link().full())
book.draw_link(pr, str, link());
}
}
else
{
print_rect(book);
}
}
break;
}
}
void TReport_field::add_groups(const TString& groups)
{
_groups.set(groups);
}
void TReport_field::del_groups(const TString& groups)
{
_groups.reset(groups);
}
void TReport_field::set_groups(const TString& groups)
{
_groups.reset();
add_groups(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.some_one();
return _groups[group];
}
void TReport_field::save(TXmlItem& root) const
{
TXmlItem& fld = root.AddChild("field");
fld.SetAttr("type", type_name());
const TReport_rct& 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);
set_col_attr(fld, "txt_color", text_color(), fore_color());
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());
}
fld.SetAttr("pattern", pattern());
if (pattern() == PAT_SPECIAL)
{
fld.SetAttr("sh_angle", shade_angle());
set_col_attr(fld, "sh_color", shade_color(), COLOR_GRAY);
}
fld.SetAttr("shade_offset", shadow_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_shadow_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_text_color(get_col_attr(fld, "txt_color", fore_color()));
if (pattern() == PAT_SPECIAL)
{
set_shade_color(get_col_attr(fld, "sh_color", COLOR_GRAY));
set_shade_angle(fld.GetIntAttr("sh_angle"));
}
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),
_txcolor(COLOR_BLACK), _fgcolor(COLOR_BLACK), _bgcolor(COLOR_WHITE),
_shcolor(COLOR_GRAY), _pattern(PAT_HOLLOW),
_radius(0), _shadow_offset(0), _shade_angle(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 campo su file, es: 34.CODART
id = atoi(code);
TReport_field* rf = curr_field();
if (rf != NULL)
{
type = rf->section().type();
level = rf->section().level();
if (code[0] == 'T')
id = rf->id();
}
}
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() || var.is_bool())
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");
_save_last_printer = xml.GetBoolAttr("save_printer");
_orientation = xml.GetIntAttr("orientation");
_page_split = xml.GetBoolAttr("page_split");
_page_merge = xml.GetBoolAttr("page_merge");
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("save_printer", save_last_printer() ? 1 : 0);
xml.SetAttr("orientation", orientation());
xml.SetAttr("page_split", page_split_allowed());
xml.SetAttr("page_merge", page_merge_allowed());
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_dot(const TVariant& var)
{
if (_curr_field != NULL)
{
_curr_field->set(var);
return true;
}
return TAlex_virtual_machine::execute_dot(var);
}
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;
}
if (xvt_str_compare_ignoring_case(str, "COPY") == 0)
{
var = long(_rep_copy);
return true;
} else
if (xvt_str_compare_ignoring_case(str, "COPIES") == 0)
{
var = long(_rep_copies);
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)
{
// Cerco il campo nel recordset della eventuale sottosezione di appartenenza
if (_curr_field != NULL)
found = _curr_field->section().get_record_field(name, var);
// Se non lo trovo, allora lo cerco nel recordset principale
if (!found)
{
var = recordset()->get(name);
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)
{
bool ok = false; // Viva l'ottimismo!
// Cerchiamo di capire cosa dobbiamo settare
const char* str = name;
if (name[0] == '#')
{
if (name.starts_with("#REPORT."))
str += 8;
else
str++;
}
char type;
int level, id;
const int k = parse_field(str, type, level, id);
switch (k)
{
case 2: // E' una sezione
if (var.is_zero()) // Posso solo azzerare tutti i numeri di una sezione
{
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.type() == 'N' || rf.type() == 'V') // E' un numero?
{
rf.set(var);
ok = true;
}
}
}
break;
case 3: // E' un campo singolo
{
TReport_field* rf = id <= 0 ? curr_field() : section(type, level).find_field(id);
if (rf != NULL)
{
rf->set(var);
ok = true;
}
}
break;
case 4: // E' un gruppo
if (var.is_zero()) // Posso solo azzerare tutti i numeri di 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))
{
rf.set(var);
ok = true;
}
}
}
break;
default: // Non so cos'e': lascio fare alla macchina virtuale
ok = TAlex_virtual_machine::set_usr_val(name, var);
break;
}
return ok;
}
size_t TReport::get_usr_words(TString_array& words) const
{
const char* const name[] =
{
"***", "DISABLE", "ENABLE",
"GET_ID", "GET_ID_NEXT", "GET_ID_PREV",
"GET_POS", "GET_SIZE", "HIDE", "ISAM_READ",
"RUN_FORM", "SET_BACK_COLOR", "SET_FORE_COLOR",
"SET_POS", "SET_SIZE", "SET_TEXT_COLOR", "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); }
static void do_set_text_color(TReport_field& rf, void* jolly)
{ rf.set_text_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); else
if (msg == do_set_size)
{
const TPoint& pt = *(const TPoint*)jolly;
sec.set_height(short(pt.y));
}
}
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;
TString name;
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);
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;
TString name;
TRecordset* rset = recordset();
//test incoerente con la forzatura del valore (non comparivano i valori..
//..delle variabili settate nella maschera e mai usate nel 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);
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); // Forza creazione variabile!
}
}
}
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);
switch (key)
{
case K_ENTER:
if (m.id2pos(DLG_PREVIEW) >= 0)
printer().set_printtype(winprinter);
break;
case 'A': //anteprima
printer().set_printtype(screenvis);
break;
case 'P': //pdf
printer().set_printtype(acrobatprinter);
break;
default:
break;
}
}
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 || logicnum == LF_TABMOD)
{
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;
}
}
// Scrive in var il codice del campo, con o senza sezione nel prefisso
// a seconda che sia un fratello del campo corrente o no
HIDDEN bool fld2id(TReport_field* fld, TVariant& var)
{
var.set_null();
if (fld != NULL)
{
TReport_section& sec = fld->section();
TReport& rep = sec.report();
TReport_field* curr = rep.curr_field();
if (curr == NULL || &sec != &curr->section())
{
TString16 str;
sec.code(str);
str << '.' << fld->id();
var.set(str);
}
else
var.set(fld->id());
}
return var.is_null();
}
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_ID
{
TVariant& var = stack.peek();
TReport_field* f = field(var.as_string());
fld2id(f, var);
}
break;
case 5: // GET_ID_NEXT
{
TVariant& var = stack.peek();
TReport_field* f = field(var.as_string());
if (f != NULL) f = f->next();
fld2id(f, var);
}
break;
case 6: // GET_ID_PREV
{
TVariant& var = stack.peek();
TReport_field* f = field(var.as_string());
if (f != NULL) f = f->prev();
fld2id(f, var);
}
break;
case 7: // GET_POS
{
real x, y;
int level, id;
char type;
const int k = parse_field(stack.pop().as_string(), type, level, id);
if (k != 3) // E' una sezione
x = y = ZERO;
else
{
const TReport_field* fld = section(type, level).find_field(id);
if (fld != NULL)
{
const TReport_rct& r = fld->get_draw_rect();
x = r.x / CENTO; y = r.y / CENTO;
}
}
stack.push(x); stack.push(y);
}
break;
case 8: // GET_SIZE
{
real w, h;
int level, id;
char type;
const int k = parse_field(stack.pop().as_string(), type, level, id);
if (k == 2) // E' una sezione
{
TReport_section& sec = section(type, level);
w = sec.width() / CENTO;
h = sec.height() / CENTO;
}
else
{
const TReport_field* fld = section(type, level).find_field(id);
if (fld != NULL)
{
const TReport_rct& r = fld->get_draw_rect();
w = r.width() / CENTO; h = r.height() / CENTO;
}
}
stack.push(w); stack.push(h);
}
break;
case 9: // HIDE
do_message(stack.pop(), do_show, NULL);
break;
case 10: // ISAM_READ
msg_isam_read(stack);
break;
case 11: // RUN_FORM
{
const TString& msk = stack.pop().as_string();
const KEY key = run_form(msk);
stack.push(key);
}
break;
case 12: // 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 13: // 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 14: // 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 15: // 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 16: // SET_TEXT_COLOR
{
const TVariant& fld = stack.pop();
const COLOR rgb = stack.pop().as_color();
do_message(fld, do_set_text_color, (void*)rgb);
}
break;
case 17: // SHOW
do_message(stack.pop(), do_show, (void*)1);
break;
case 18: // TABLE_READ
msg_table_read(stack);
break;
case 19: // 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::print()
{
TReport_book book;
book.add(*this);
return book.print();
}
bool TReport::preview()
{
TReport_book book;
book.add(*this);
return book.preview();
}
bool TReport::archive(bool signature)
{
TReport_book book;
book.add(*this);
return book.archive(NULL, signature);
}
TReport::TReport()
: _cpi(0), _lpi(6), _include(15, ','), _recordset(NULL), _curr_field(NULL),
_use_printer_font(false), _save_last_printer(false), _orientation(0),
_page_split(false), _page_merge(false), _rep_copy(1), _rep_copies(1)
{
_expressions.set_report(this);
_prescript.set_description("PRESCRIPT");
_postscript.set_description("POSTSCRIPT");
}
TReport::~TReport()
{
destroy();
}