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