Files correlati : ve1.exe Ricompilazione Demo : [ ] Commento : 0001653: 002554 - Dania - modulo di stampa fatture La stampa delle fatture non stampa l'ultima riga della descrizione, nel caso di diverse righe di descrizione aggiuntiva. (bug 1653) git-svn-id: svn://10.65.10.50/trunk@20560 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() && !_var.is_empty())
|
|
{
|
|
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();
|
|
}
|