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
3417 lines
80 KiB
C++
Executable File
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();
|
|
}
|