campo-sirio/include/form.cpp
guy 2b68cb81ae Patch level : 2.0 nopatch
Files correlati     : ve0.exe
Ricompilazione Demo : [ ]
Commento            :

form.cpp      Aggiunto supporto per custom/bitamp
realtion.cpp  Semplici sostituzioni di cose ripetute n volte con una singola variabile
scanner.cpp   Aggiunti apici in segnalazione di errore
strings.cpp   Corretta lettura di una stringa da file ad EOF
tree.cpp      Corretto disegno linee in presenza di header (Elaborazioni differite)


git-svn-id: svn://10.65.10.50/trunk@11226 c028cbd2-c16b-5b4b-a496-9718f37d4682
2003-06-11 07:44:57 +00:00

4731 lines
119 KiB
C++
Executable File
Raw Blame History

#define __FORM_CPP
#include <applicat.h>
#include <currency.h>
#include <defmask.h>
#include <expr.h>
#include <form.h>
#include <msksheet.h>
#include <printer.h>
#include <relation.h>
#include <tabutil.h>
#include <utility.h>
#include "../ba/bafrm.h"
///////////////////////////////////////////////////////////
// Utility functions
///////////////////////////////////////////////////////////
// @doc INTERNAL
// @func Funzione che converte dalla notazione carattere al corrispondente
// enum <t pagetype>
//
// @rdesc Ritorna il <t pagetype> corrispondente
pagetype char2page(
char c) // @parm Notazione carattere del tipo di pagina
{
pagetype pt;
switch(c)
{
case '1':
case 'E':
pt = even_page; break;
case '2':
case 'F':
pt = first_page; break;
case '3':
case 'L':
pt = last_page; break;
default:
pt = odd_page; break;
}
return pt;
}
///////////////////////////////////////////////////////////
// TForm_flags
///////////////////////////////////////////////////////////
TForm_flags::TForm_flags()
{
automagic = dirty = finkr = finkl = memo = newpage = price = FALSE;
shown = enabled = TRUE;
}
// Read from string
// Certified 100%
bool TForm_flags::update(const char* s)
{
CHECK(s, "NULL flags string");
for (; *s; s++) switch(toupper(*s))
{
case 'A':
automagic = TRUE; break;
case 'D':
enabled = FALSE; break;
case 'H':
shown = FALSE; break;
case 'F':
finkl = TRUE; break;
case 'K':
finkr = TRUE; break;
case 'M':
memo = TRUE; break;
case 'N':
newpage = TRUE; break;
case 'U':
price = TRUE; break;
default :
error_box("Unknown form item flag '%c'", *s); break;
}
return TRUE;
}
// Print on stream
// Certified 100%
void TForm_flags::print_on(ostream& out) const
{
TString16 s;
if (automagic) s << "A";
if (!enabled) s << "D";
if (!shown) s << "H";
if (memo) s << "M";
if (newpage) s << "N";
if (finkl) s << "F";
if (finkr) s << "K";
if (price) s << "U";
if (s.not_empty())
out << " FLAGS \"" << s << '"' << endl;
}
///////////////////////////////////////////////////////////
// TForm_item
///////////////////////////////////////////////////////////
TForm_item::TForm_item(TPrint_section* section)
: _section(section), _x(-1), _y(-1), _width(0),
_height(0),_effective_height(0), _id(0), _ofs(0),
_temp(FALSE)
{}
void TForm_item::copy_to_form_item(TForm_item* fi) const
{
fi->_flag = _flag; fi->_group = _group;
/* come copiarlo facendo una cosa orrenda...
fi->_special.destroy();
specials().restart();
int items = special_items();
for (int k = 0; k < items; k++)
{
THash_object* ho = specials().get_hashobj();
fi->_special.add(ho->key(),ho->obj());
}
*/
fi->_special = _special; // sarebbe utile avere un "operator =" per i TAssoc_array
fi->_temp = _temp; fi->_id = _id;
fi->_x = _x; fi->_y = _y;
fi->_width = _width; fi->_height = _height;
fi->_effective_height = _effective_height;
fi->_ofs = _ofs; fi->_prompt = _prompt;
fi->_desc = _desc; fi->_col_head = _col_head;
/* Anche qui... copia uno alla volta
items = _message.items();
for (k = 0; k < items; k++)
fi->_message.add(_message.row(k),k);
*/
fi->_message = _message; // sarebbe utile avere un "operator =" per i TString_array
}
TObject* TForm_item::dup() const
{
TForm_item * fi = new TForm_item(_section);
copy_to_form_item(fi);
return fi;
}
bool TForm_item::parse_head(TScanner& scanner)
{
_id = scanner.integer();
if (_id == 0) // Temporary
_id = _section->fields()+1;
_width = scanner.integer();
if (_width > 0)
_height = scanner.integer();
return TRUE;
}
void TForm_item::print_on(ostream& out) const
{
out << class_name() << ' ' << id();
if (_width > 0)
{
out << ' ' << _width;
if (_height > 0)
out << ' ' << _height;
}
out << "\nBEGIN\n";
print_body(out);
out << "END\n" << endl;
}
void TForm_item::print_body(ostream& out) const
{
out << " KEY \"" << _desc << "\"\n";
if (_y >= 0)
out << " PROMPT " << _x << ' ' << _y << " \"" << _prompt << "\"\n";
if (_group.ones())
out << " GROUP " << _group << "\n";
out << _flag;
if (_message.items() == 1)
{
const TToken_string& m = _message.row(0);
if (!m.empty_items())
out << " MESSAGE " << m << endl;
}
if (_special.items() > 0)
{
TAssoc_array& aa = specials();
aa.restart();
THash_object* op;
while ((op = aa.get_hashobj()) != NULL)
{
TToken_string& t = (TToken_string&)op->obj();
TString typ(t.get(0));
TString val(t.get(1));
TString des(t.get(2));
out << " SPECIAL " << typ << " " << op->key()
<< " \"" << val << "\" \"" << des << "\"\n";
}
}
}
bool TForm_item::parse_item(TScanner& scanner)
{
if (scanner.key() == "PR")
{
_x = scanner.integer();
_y = scanner.integer();
_prompt = scanner.string();
return TRUE;
}
if (scanner.key() == "FL")
return _flag.update(scanner.string());
if (scanner.key() == "ME")
{
TFixed_string m(scanner.line());
m.strip_spaces();
int n = 0;
if (m.left(5) == "EMPTY")
{
n = 1;
m.ltrim(5);
}
if (!m.blank())
message(n).add(m);
return TRUE;
}
if (scanner.key() == "KE")
{
_desc = scanner.string();
return TRUE;
}
if (scanner.key() == "GR")
{
_group.set(scanner.line());
return TRUE;
}
if (scanner.key() == "SP")
{
TToken_string val(scanner.pop());
TString16 var = scanner.pop();
val.add(scanner.string());
val.add(scanner.string());
_special.add(var,val);
return TRUE;
}
yesnofatal_box("Unknown symbol in item '%s': '%s'",
(const char*)key(), (const char*)scanner.token());
return FALSE;
}
bool TForm_item::parse(TScanner& scanner)
{
bool ok = parse_head(scanner);
if (ok && scanner.popkey() != "BE")
ok = yesnofatal_box("Missing BEGIN in form item %s", (const char*)key());
while (ok && scanner.popkey() != "EN")
ok = parse_item(scanner);
return ok;
}
bool TForm_item::read_from(const TRectype& prof)
{
CHECK(prof.num() == LF_RFORM, "Il record deve essere del file LF_RFORM");
bool changed = FALSE;
int i = prof.get_int("X");
if (_x != i)
{
_x = i;
changed = TRUE;
}
i = prof.get_int("Y");
if (_y != i)
{
_y = i;
changed = TRUE;
}
i = prof.get_int("LEN");
if (_width != i)
{
_width = i;
changed = TRUE;
}
i = prof.get_int("HGT");
if (_height != i)
{
_height = i;
changed = TRUE;
}
TString p(prof.get("PROMPT"));
if (p.not_empty())
{
if (p[0] == '\xFE') p.cut(0);
const int l = p.len();
if (l > 0 && p[l-1] == '\xFF')
{
p[l-1] = ' ';
p << '\0';
}
_prompt = p;
changed = TRUE;
}
const bool s = prof.get_bool("ATTIVO");
if (_flag.shown != s)
{
_flag.shown = s;
changed = TRUE;
}
TToken_string special(prof.get("SPECIAL"),'\n');
special.rtrim();
const int sp_items = special.items();
for (i = 0; i < sp_items; i++)
{
TToken_string sp(special.get(i), '$');
TString key(sp.get(0));
TString val(sp.get(1));
if (!_special.is_key(key))
{
error_box("Variabile speciale non presente nel profilo: %s",
(const char*)key);
continue;
}
TToken_string& tt = (TToken_string&)_special[key];
tt.add(val,1);
// forza riscrittura su memo
if (tt.items() == 3) tt.add("X");
}
return TRUE;
}
void TForm_item::print_on(TRectype& prof)
{
CHECK(prof.num() == LF_RFORM, "Il record deve essere del file LF_RFORM");
prof.put("ID", id());
prof.put("X", _x);
prof.put("Y", _y);
prof.put("LEN", width());
prof.put("HGT", height());
if (_prompt.empty()) _prompt << '\xFE' << '\0';
const int l = _prompt.len();
const char c = _prompt[l-1];
if (c==' ') _prompt[l-1]='\xFF';
prof.put("PROMPT", _prompt);
prof.put("ATTIVO", shown() ? "X" : " ");
// specials: se e' stato cambiato, la tokenstring del valore contiene
// una X alla fine (campo 3)
{
TToken_string special(128,'\n');
_special.restart();
for (int i = 0; i < _special.items(); i++)
{
THash_object* o = _special.get_hashobj();
TString key(o->key());
TToken_string& tt = (TToken_string&)o->obj();
if (tt.items() == 4)
{
TToken_string sp(key,'$');
TString val(tt.get(1));
sp.add(val);
special.add(sp);
}
}
special.rtrim();
prof.put("SPECIAL", special);
}
}
// @doc EXTERNAL
// @mfunc Abilita/Disabilita il campo
void TForm_item::enable(
bool on) // @parm Operazione da svolgere sul campo:
// @flag TRUE | Il campo viene abiliato
// @flag FALSE | Il campo viene disabiliato
// @comm Viene automaticamente setta se il campo diventi visibile o nascosto (chiama <mf TForm_item::show>)
{
_flag.enabled = on;
show(on);
}
void TForm_item::set_special_value(const char* s, const char* val)
{
TToken_string& tt = (TToken_string&) _special[s];
tt.add(val,1);
if (tt.items()==3) tt.add("X");
}
const char* TForm_item::get_special_item(const char* s, int n) const
{
TAssoc_array& sp = (TAssoc_array&)_special;
if (sp.is_key(s))
{
TToken_string& tt = (TToken_string&) sp[s];
return tt.get(n);
} else return "";
}
void TForm_item::string_at(int x, int y, const char* s)
{
if (shown())
{
if (section().columnwise()) x += _ofs;
TPrintrow& row = section().row(y-1); // Seleziona riga di stampa
if (_width > 0 && strlen(s) > (word)_width) // Tronca testo se necessario
{
TString& tmp = get_tmp_string();
tmp.strncpy(s, _width);
s = tmp;
}
row.put(s, x-1); // Stampa testo
}
}
TToken_string& TForm_item::message(int m)
{
TToken_string* t = (TToken_string*)_message.objptr(m);
if (t == NULL)
{
t = new TToken_string(16);
_message.add(t, m);
}
return *t;
}
// @doc EXTERNAL
// @mfunc Manda il messaggio al campo <p dest>
void TForm_item::send_message(
const TString& cmd, // @parm Messaggio di comando
TForm_item& des) const // @parm Campo a cui destinare il messaggio
{
if (cmd == "ADD" || cmd == "INC")
{
if (form().message_add_enabled())
{
const real n((cmd[0] == 'I') ? "1.0" : get());
real r(des.get());
r += n;
des.set(r.string());
}
} else if (cmd == "COPY") {
des.set(get());
} else if (cmd == "APPEND") {
TString256 val = des.get();
if (val.not_empty()) val << ' ';
val << get();
des.set(val);
} else if (cmd == "RESET") {
des.set("");
} else if (cmd == "DISABLE") {
des.disable();
} else if (cmd == "ENABLE") {
des.enable();
} else if (cmd == "HIDE") {
des.hide();
} else if (cmd == "SHOW") {
des.show();
} else if (cmd == "SUB") {
const real n(get());
real r(des.get());
r -= n;
des.set(r.string());
} else if (cmd[0] == '"') {
TString256 val(cmd);
val.strip("\"");
des.set(val);
} else
error_box("Unknown message in item '%s': '%s'",
(const char*)key(), (const char*)cmd);
}
TForm_item& TForm_item::find_field(const TString& id) const
{
if (isdigit(id[0])) // Field in the same section
{
TForm_item& des = section().find_field(atoi(id));
return des;
}
const int freccia = id.find("->");
const pagetype pt = (freccia==2) ? char2page(id[1]) : section().page_type() ;
char se;
int id_num;
int pos_id;
if (freccia >= 0)
{
pos_id=freccia+2;
id_num=atoi(id.mid(pos_id));
se = id[0];
} else {
id_num=0;
se = section().section_type();
pos_id=0;
}
if (id_num) // id numerico: campo semplice
{
TForm_item& des = form().find_field(se, pt, id_num);
return des;
} else { // id stringa : campo sezione
TForm_item& des = form().find_field(se, pt, id.mid(pos_id));
return des;
}
}
// il parametro num serve per identificare il messaggio nelle listbox...
bool TForm_item::do_message(int num)
{
TToken_string& messaggio = message(num);
if (messaggio.empty_items())
return FALSE;
TToken_string msg(16, ',');
for (const char* m = messaggio.get(0); m; m = messaggio.get())
{
msg = m;
if (*m == '_')
form().validate(*this, msg);
else
{
const TString80 cmd(msg.get()); // Get command
const TString80 id = msg.get(); // Get destination
if (id.right(1) == "@")
{
const byte group = atoi(id);
// Send the message to all fields in local and upper sections with the given group
send_message_to_group(cmd,group,section(),&section());
}
else
{
TForm_item& des = find_field(id);
send_message(cmd, des);
}
}
}
return TRUE;
}
void TForm_item::send_message_to_group(const char * cmd,byte id,const TPrint_section & section, const TPrint_section *starting_section)
{
TForm_item * f ;
// look into local section
for(word i = 0; i < section.fields(); i++)
{
f = &section.field(i);
if (f->in_group(id))
send_message(cmd,*f);
}
// look into the section above ("father" )
if (section.section_above() && section.section_above()!=starting_section) {
send_message_to_group(cmd,id,*section.section_above(),&section);
}
// look into sections beside ("brothers" )
for (int j = 0; j < section.subsections(); j++) {
const TPrint_section &bs=section.subsection(j)->printsection();
if (&bs!=starting_section) {
send_message_to_group(cmd,id,section.subsection(j)->printsection(),&section);
}
}
}
bool TForm_item::update()
{
if (_prompt.right(1) == "#")
{
TString prompt(_prompt);
for (int i = prompt.len()-2; i >= 0; i--)
if (prompt[i] != '#') break;
prompt.cut(i+1);
string_at(x(), _y, prompt);
}
else string_at(x(), _y, _prompt);
return TRUE;
}
void TForm_item::print_on(TToken_string& row) const
{
row.cut(0);
row.add(id());
row.add(key());
row.add(_y);
row.add(_x);
row.add(shown() ? " " : "X");
if (form().edit_level() > 1)
{
const long fu = _group.first_one();
if (fu > 0) row.add(fu);
else row.add(" ");
}
}
const TString& TForm_item::picture() const
{
NFCHECK("Can't get the picture of a generic form item!");
return EMPTY_STRING;
}
void TForm_item::set_picture(const char*)
{
NFCHECK("Can't set the picture of a generic form item!");
}
TToken_string& TForm_item::memo_info()
{
NFCHECK("Can't get a memo of a generic form item!");
return (TToken_string &) EMPTY_STRING;
}
short TForm_item::x()
{
if (_section == NULL || !_section->columnwise())
return _x;
return _section->tab(_x-1) + _section->ofspc();
}
///////////////////////////////////////////////////////////
// TForm_subsection
///////////////////////////////////////////////////////////
TForm_subsection::TForm_subsection(TPrint_section* s, const char* nm)
: TForm_item(s), _ssec(&(s->form()), s->section_type(), s->page_type()),
_file_id(-1), _name(nm), _condexpr(NULL),
_title_section(NULL),_qtitle_section(NULL),_title_type(type_notitle),_show_title(FALSE)
{
_ssec.set_subsection_above(this);
}
TForm_subsection::~TForm_subsection()
{
if (_condexpr) delete _condexpr;
// _title_section e _qtitle_section sono puntatori a subsection contenute nel corpo, quindi non vanno deallocati
}
TObject* TForm_subsection::dup() const
{
TForm_subsection* fs = new TForm_subsection(_section);
copy_to_form_item(fs);
fs->_ssec = _ssec;
fs->_name = _name;
fs->_file_id = _file_id;
fs->_title_type = _title_type;
fs->_show_title=_show_title;
if (_condexpr)
fs->_condexpr=new TExpression((const char *)_condexpr);
else
fs->_condexpr=NULL;
if (_title_section)
fs->_title_section=(TForm_subsection* )_title_section->dup();
else
fs->_title_section=NULL;
if (_qtitle_section)
fs->_qtitle_section=(TForm_subsection* )_qtitle_section->dup();
else
fs->_qtitle_section=NULL;
return fs;
}
int TForm_subsection::fileid()
{
return _file_id;
}
// restituisce la condizione della sottosezione
const char * TForm_subsection::condition()
{
if (_condexpr)
return (const char *)_condexpr->string();
else
return NULL;
}
// imposta la condizione della sottosezione
void TForm_subsection::setcondition(const char* cond,TTypeexp type)
{
if (_condexpr)
{
if (_file_id != -1)
printsection().set_subs_cond(_file_id,cond,_condexpr->string());
delete _condexpr;
}
_condexpr=new TExpression(cond,type);
}
// imposta la sottosezione titolo
void TForm_subsection::set_title_section(TForm_subsection* s)
{
if (_title_section) delete _title_section;
_title_section=s;
}
// imposta la sottosezione titolo di coda
void TForm_subsection::set_qtitle_section(TForm_subsection* s)
{
if (_qtitle_section) delete _qtitle_section;
_qtitle_section=s;
}
void TPrint_section::print_title()
{
TPrinter& pr = printer();
if (pr.current_row() > pr.headersize()+1)
if (word(height()) > pr.rows_left())
pr.formfeed();
word last_printed_row=0;
const word maxs=(word)subsections() ;
for (word s = 0; s < (word)maxs ;s++)
{
TForm_subsection &ssec=*subsection(s);
for (; last_printed_row < (word)ssec.y() -1;last_printed_row++)
pr.print(titlerow(last_printed_row));
if (ssec.shown())
ssec.printsection().print_title();
}
for (; last_printed_row < (word)height() ;last_printed_row++)
pr.print(titlerow(last_printed_row));
}
void TPrint_section::set_subs_cond(int file,const char *newcond,const char * oldcond)
{
TForm_subsection * s;
s=(TForm_subsection * )(_subsections.first_item());
while (s) {
TString newsubcond(s->condition());
if (file!=-1 && s->fileid()==file && newsubcond.not_empty()) {
// there's another file group subsection below....
newsubcond=newsubcond.mid(strlen(oldcond));
newsubcond.insert(newcond);
s->setcondition(newsubcond,_strexpr);
}
s=(TForm_subsection * )(_subsections.succ_item()) ;
}
}
// ritorna l'indirizzo della prima sottosezione condizionale di livello superiore alla corrente
TForm_subsection *TForm_subsection::upper_conditional() const
{
if (section().subsection_above())
{
if (section().subsection_above()->_condexpr && section().subsection_above()->_file_id>0)
return section().subsection_above();
else
return section().subsection_above()->upper_conditional();
} else
return NULL;
}
// Esegue una post visita dell'albero delle subsection, stampando tutte le section "Titolo"
bool TForm_subsection::print_titles()
{
if (section().subsection_above())
section().subsection_above()->print_titles();
bool ok=TRUE;
// print the title
if (_title_section != NULL && _title_section->_show_title)
{
if ( shown() && _title_section->shown() )
{
_title_section->printsection().print_title();
}
_title_section->show_title(FALSE);
}
return ok;
}
bool TForm_subsection::print_qtitle()
{
bool ok=TRUE;
// print the title
if (_qtitle_section != NULL)
{
if (shown() && _qtitle_section->shown())
{
print_titles();
_qtitle_section->printsection().print_title();
}
}
return ok;
}
bool TForm_subsection::parse(TScanner& s)
{
_section->add_subsection(this);
name(s.pop());
//_width = s.integer(); // ...unused
//_x = s.integer(); // ...unused
_y = s.integer(); // posizione rispetto ai campi della sezione "padre"
_height = s.integer(); // minima altezza (primo "header")
_ssec.parse_head(s);
s.popkey();
if (s.key() == "FI") // FI_LE su cui iterare con next_match
{
_file_id = name2log(s.pop());
if (s.popkey() == "GR" || s.key() == "BY")
{
// GR_OUP or BY group : gestione dei raggruppamenti o big skip
TString e;
TForm_subsection * uppersec=upper_conditional();
e = s.line();
if (uppersec && uppersec->_file_id==_file_id)
{
// se anche la sezione soprastante
const TString& eu = uppersec->_condexpr->string();
if (e != eu)
{
e.insert("+");
if (e != eu.right(e.len()))
e.insert(eu); // Aggiungo espressione precedente
else
e = eu; // Inutile aggiungere espressione gi<67> presente
}
}
_condexpr = new TExpression(e,_strexpr);
_bigskip = s.key() == "BY";
} else
s.push();
} else {
if (s.key() == "NU") // NU_MERIC CONDITION di gestione della sezione
_condexpr = new TExpression(s.line(),_numexpr); //
else if (s.key() == "ST") // ST_RING CONDITION di gestione della sezione
_condexpr = new TExpression(s.line(),_strexpr); //
else if (s.key() == "HE") // sottosezione HE_ADER (titolo), stampa solo se altr sotto sez verranno stampati
{
_title_type=type_title;
if (section().subsection_above())
section().subsection_above()->set_title_section(this);
}
else if (s.key() == "FO") // sottosezione FO_OOTER (titolo di coda), stampato solo se altr sotto sez verranno stampati
{
_title_type=type_qtitle;
if (section().subsection_above())
section().subsection_above()->set_qtitle_section(this);
}
else if (s.key() != "GR") // GR_OUP section (raggruppamento puro)
s.push();
}
if (s.popkey() == "FL")
_flag.update(s.string());
else s.push();
return(_ssec.parse_body(s)) ;
}
// nel caso di subsection viene chiamata la set_body anzich<63> la update
bool TForm_subsection::update()
{
return TRUE;
}
bool TForm_subsection::print_body(sec_print_mode showfields)
{
bool at_newpage=(atnewpage() || printer().rows_left() < (word)minheight());
bool ok = FALSE;
TCursor* cur = form().cursor();
TRelation* rel = (TRelation* )form().relation();
set_effective_height(0); // resetta l'altezza della sottosezione al suo "minimo"
if (!enabled() )
return FALSE;
if (is_title())
{
show_title(TRUE);
showfields=printmode_title ; // calcola e bufferizza ora, rimanda la stampa dopo ...
}
if (!shown())
showfields = printmode_noprint;
if (cur == NULL || (_file_id == -1 && _condexpr==NULL)) // ...unused
ok = _ssec.update_and_print(showfields,at_newpage);
else if (_file_id == -1 && _condexpr!=NULL) // subsection condizionale
{
if ((bool)(_section->eval_expr(*_condexpr,_file_id)))
ok = _ssec.update_and_print(showfields,at_newpage);
}
else
{
_ssec.set_repeat_count(0);
if (_condexpr) { // sottosezione di raggruppamenti su file
int i = 0;
TString group_expr = _section->eval_expr(*_condexpr,_file_id).as_string();
bool again=TRUE;
while (again && group_expr==_section->eval_expr(*_condexpr,_file_id).as_string())
{
form().match_result(_file_id);
if (!_bigskip || i==0)
{
ok |= _ssec.update_and_print(showfields,at_newpage);
_ssec.set_repeat_count(++i);
}
if (form().next_match_done(_file_id))
{
again=form().last_match_result(_file_id); // continue if there WAS a match
} else {
again=cur->next_match(_file_id) ;
form().match_result(_file_id,again); // store if a match occoured
}
at_newpage=(atnewpage() || printer().rows_left() < (word)minheight());
}
// _ssec.set_repeat_count(0);
} else { // sottosezione di file
int i = 0;
if (cur->is_first_match(_file_id))
{
bool again;
do {
form().match_result(_file_id);
ok |= _ssec.update_and_print(showfields,at_newpage);
_ssec.set_repeat_count(++i);
if (form().next_match_done(_file_id))
again=form().last_match_result(_file_id);
else
again= cur->next_match(_file_id);
at_newpage=(atnewpage() || printer().rows_left() < (word)minheight());
} while (again);
ok |= (_ssec.repeat_count()>0); // (ovvero, sempre true: se c'e' un first match)
}
// _ssec.set_repeat_count(0);
}
}
return ok;
}
// @mfunc Abilita (default) o disabilita la stampa di tutti i campi della sottosezione
/*void TForm_subsection::show(bool on)
{
TForm_item::show(on);
for (unsigned int i = 0; i < _ssec.fields(); i++)
_ssec.field(i).show(on);
}
// @mfunc Abilita (default) o disabilita la valutazione e la stampa di tutti i campi della sottosezione
void TForm_subsection::enable(bool on)
{
TForm_item::enable(on);
for (unsigned int i = 0; i < _ssec.fields(); i++)
_ssec.field(i).enable(on);
} */
///////////////////////////////////////////////////////////
// TForm_string
///////////////////////////////////////////////////////////
TForm_string::TForm_string(TPrint_section* section)
: TForm_item(section), _memo("",'\n')
{}
TObject* TForm_string::dup() const
{
TForm_string* fs = new TForm_string(_section);
copy_to_form_item(fs);
fs->_str = _str;
fs->_picture = _picture;
fs->_field = _field;
fs->_memo = _memo;
return fs;
}
bool TForm_string::parse_item(TScanner& scanner)
{
if (scanner.key() == "FI") // FIELD reference
{
TFieldref* fr = new TFieldref(scanner.line(), 0);
_field.add(fr);
return TRUE;
}
if (scanner.key() == "PI") // PICTURE def
{
set_picture(scanner.string());
return TRUE;
}
return TForm_item::parse_item(scanner);
}
bool TForm_string::set(const char* s)
{
_str = s;
return TRUE;
}
const char* TForm_string::get() const
{ return _str; }
// Se un campo e' abilitato ed ha almeno un riferimento su file leggilo
bool TForm_string::read()
{
const bool ok = enabled();
if (ok)
{
if (_field.items() != 0)
{
const char* s = "";
// !?!?!?!!
const TRelation* r = (TRelation* )form().relation();
CHECK(r, "Can't read from null relation");
for (int i = 0; i < _field.items() && *s == '\0'; i++)
s = field(i).read(*r);
set(s);
}
}
return ok;
}
void TForm_string::put_paragraph(const char* s)
{
if (hidden()) return;
const int h = height();
if (h > 1)
{
TString lines;
if (_prompt.not_empty())
lines = _prompt;
lines << s;
TParagraph_string p(lines, width());
for (int i=0; (s = p.get()) != NULL && i < h; i++)
string_at(x(), _y+i, s);
_effective_height = i;
TForm_subsection *subsec= section().subsection_above();
if (subsec)
{
// aggiorno l'altezza effettiva della sottosezione
if (effective_height() > 1)
{
// il campo si <20> "espanso"
const int last_y=effective_height()+y()-1;
if (last_y > subsec->height())
subsec->set_effective_height(last_y);
}
}
}
else
{
if (_prompt.empty())
string_at(x(), _y, s);
else
string_at(-1 , _y, s);
}
}
void TForm_string::apply_format(TString& s) const
{
TString tmp(s);
if (!picture().blank())
{
TToken_string delim(4, ','); // Stringa con i due delimitatori
const char * pic = picture(); // Picture senza delimitatori
if (pic[0] == '(') // Se ci sono i delimitatori ...
{
const int bra = picture().find(')');
if (bra > 0) // ... cerca la parentesi chiusa
{
delim = picture().sub(1, bra); // memorizza delimitatori
pic += bra+1; // toglili dalla picture
}
}
if (strcmp(class_name(),"DATA")==0 && s.empty())
tmp ="";
else
tmp.picture(pic, s); // riempi la stringa col valore pitturato
if (!delim.empty_items()) // Aggiungi delimitatori
{
TString16 d(delim.get(0));
const int ld = d.len();
if (ld > 0) // Se il primo delimitatore e' valido ...
{
for (int spc = 0;s[spc]==' ' ; spc++) ;
if (spc < ld)
{
TString16 spazi;
spazi.spaces(ld - spc);
tmp.insert(spazi,0);
spc = ld;
}
tmp.overwrite(d,spc - ld);
}
d = delim.get();
if (d.not_empty()) // Se il secondo delimitatore e' valido ...
tmp << d; // ... aggiungilo alla fine
}
s = tmp;
}
}
bool TForm_string::update()
{
if (read()) // valuta il campo
{
TForm_item::update();
// esegue i messaggi
const int n = (_message.objptr(1) != NULL && *get()=='\0' ? 1 : 0);
do_message(n);
// prende il campo e lo stampa
TString s(get());
apply_format(s);
put_paragraph(s);
}
return TRUE;
}
const char* TForm_string::example() const
{
TString& prova = get_tmp_string();
prova = "XXXXXXXXXXXXXXXXXXXXXXXXXX";
apply_format(prova);
const int w = width();
if (prova.size() > w && w > 0)
prova.cut(w);
return prova;
}
///////////////////////////////////////////////////////////
// TForm_number
///////////////////////////////////////////////////////////
class TForm_number : public TForm_string
{
protected: // TForm_string
virtual const char* class_name() const { return "NUMERO"; }
virtual bool parse_head(TScanner& scanner);
virtual bool update();
//virtual int height() const { return 0; }
protected:
int decimals() const { return _height; }
public:
void real2currency(const real& r, TString& str) const;
virtual TObject* dup() const;
void set_decimals(int d) { _height = d; }
virtual const char* example() const;
virtual void set_picture(const char* p);
virtual void apply_format(TString& s) const;
virtual void put_paragraph(const char * s);
TForm_number(TPrint_section* section) : TForm_string(section) {}
virtual ~TForm_number() {}
};
bool TForm_number::parse_head(TScanner& scanner)
{
return TForm_item::parse_head(scanner);
}
TObject* TForm_number::dup() const
{
TForm_number *fn = new TForm_number(_section);
copy_to_form_item(fn);
return fn;
}
void TForm_number::put_paragraph(const char* s)
{
if (hidden()) return;
int gap = 0;
if (section().columnwise())
{
const int w = width();
const int l = strlen(s);
if (w>l) gap = w-l;
}
if (_prompt.empty())
string_at(x()+gap, _y, s);
else
string_at(-1, _y, s); // se ha il prompt stampa all'ultima posizione raggiunta
}
void TForm_number::real2currency(const real& r, TString& str) const
{
TCurrency c(r);
c.set_price(_flag.price != 0);
const TExchange* oe = form().output_exchange();
if (oe && !c.get_exchange().same_value_as(*oe))
c.change_value(*oe);
const TString& pic = picture();
const int piclen = pic.len();
const bool dotted = pic.empty() || pic.find('.') >= 0;
str = c.string(dotted);
const int w = width();
if (w > piclen)
str.right_just(w);
}
bool TForm_number::update()
{
if (read()) // valuta il campo
{
TForm_item::update();
real n = get(); // Trasforma la stringa in numero reale
// Arrotonda intelligentemente il numero
int round_dec = decimals();
if (round_dec == 0 && width() > 9 && form().magic_currency()) // Magic currency?
round_dec = TCurrency::get_firm_dec();
n.round(round_dec);
if (_message.items() > 0)
{
const int nm = (_message.objptr(1) != NULL && n.is_zero()) ? 1 : 0;
do_message(nm);
n = get(); // Il numero potrebbe essere cambiato dal messaggio!
n.round(round_dec);
}
bool print = TRUE;
if (n.is_zero())
{
char sep = picture().find('E') >= 0 ? '.' :',';
int comma = picture().find(sep);
if (comma < 0 )
comma = picture().len();
print = comma > 0 && picture()[comma-1] == '@';
}
if (print)
{
TString80 print_string;
bool app_for = TRUE; // Apply format?
if (form().magic_currency())
{
const bool b1 = picture() == "." || (picture().len() >= 9 && picture().find(',') < 0);
const bool b2 = width() >= 9 && decimals() == 0;
if (b1 || b2)
{
real2currency(n, print_string);
app_for = FALSE; // La stringa <20> gi<67> belle che formattata!
}
}
if (app_for)
{
print_string = n.string();
apply_format(print_string);
}
put_paragraph(print_string);
}
}
return TRUE;
}
void TForm_number::apply_format(TString& s) const
{
if (!picture().blank())
{
real n(s);
TToken_string delim(4, ','); // Stringa con i due delimitatori
TString pic(picture()); // Picture senza delimitatori
int maxlen = -1;
if (pic[0] == '(') // Se ci sono i delimitatori ...
{
const int bra = pic.find(')');
if (bra > 0) // ... cerca la parentesi chiusa
{
delim = pic.sub(1, bra); // memorizza delimitatori
pic.ltrim(bra + 1); // toglili dalla picture
}
}
const int at = pic.find('@');
if (at > 0)
{
const int len = atoi(&pic[at+1]);
if (len > 0)
{
maxlen = len;
pic.cut(at);
}
}
s=n.string(pic); // riempi la stringa col valore pitturato
if (maxlen >= 0 && maxlen < s.size())
s.cut(maxlen);
if (!delim.empty_items()) // Aggiungi delimitatori
{
TString16 d(delim.get(0));
const int ld = d.len();
if (ld > 0) // Se il primo delimitatore e' valido ...
{
for (int spc = 0;s[spc]==' ' ; spc++) ;
if (spc < ld)
{
TString16 spazi;
spazi.spaces(ld - spc);
s.insert(spazi,0);
spc = ld;
}
s.overwrite(d,spc - ld);
}
d = delim.get();
if (d.not_empty()) // Se il secondo delimitatore e' valido ...
s << d; // ... aggiungilo alla fine
}
}
else
{
real n(s);
s = n.stringa(width(), decimals());
}
}
void TForm_number::set_picture(const char *p)
{
TForm_string::set_picture(p);
const int comma = picture().find(',');
if (comma > 0)
set_decimals(picture().len() - comma -1);
}
const char* TForm_number::example() const
{
TString& s = get_tmp_string();
s = "1234567890.123456";
apply_format(s);
return s;
}
///////////////////////////////////////////////////////////
// TForm_currency
///////////////////////////////////////////////////////////
class TForm_currency : public TForm_number
{
TForm_item* _driver;
protected: // TForm_string
virtual const char* class_name() const { return "VALUTA"; }
virtual bool parse_head(TScanner& scanner);
virtual bool parse_item(TScanner& scanner);
virtual bool update();
virtual const char* get() const;
// @cmember Manda il messaggio al campo <p dest>
virtual void send_message(const TString& cmd, TForm_item& dest) const;
public:
virtual TObject* dup() const;
virtual TCurrency get_currency() const;
TForm_currency(TPrint_section* section) : TForm_number(section), _driver(NULL) {}
virtual ~TForm_currency() {}
};
bool TForm_currency::parse_head(TScanner& scanner)
{
return TForm_item::parse_head(scanner);
}
bool TForm_currency::parse_item(TScanner& scanner)
{
if (scanner.key() == "DR")
{
_driver = &find_field(scanner.pop());
return TRUE;
}
return TForm_number::parse_item(scanner);
}
TObject* TForm_currency::dup() const
{
TForm_currency *fn = new TForm_currency(_section);
copy_to_form_item(fn);
return fn;
}
const char* TForm_currency::get() const
{
const char* val = TForm_string::get();
return val;
}
TCurrency TForm_currency::get_currency() const
{
const TString& codval = _driver ? _driver->get() : form().get_curr_codval();
const real n(get());
return TCurrency(n, codval, ZERO, _exchange_undefined, _flag.price != 0);
}
bool TForm_currency::update()
{
if (read()) // valuta il campo
{
TForm_item::update();
if (_message.items() > 0)
{
const int nm = (_message.objptr(1) != NULL && real::is_null(get())) ? 1 : 0;
do_message(nm);
}
if (!real::is_null(get()))
{
TCurrency curr = get_currency();
if (!_driver)
{
const TExchange* oe = form().output_exchange();
if (oe != NULL && !curr.get_exchange().same_value_as(*oe))
curr.change_value(*oe);
}
// Niente apply_format(), la picture viene ignorata per i TForm_currency
TString80 v;
const TString& pic = picture();
if (pic.find("LETTERE") >= 0)
{
v = get();
apply_format(v);
const int slash = v.rfind('/');
TString16 tail;
for (int i = v.len()-1; i > 0 && !isalnum(v[i]); i--)
{
tail << v[i];
v.cut(i);
}
const int zeroes_needed = curr.decimals();
if (zeroes_needed > 0)
{
int zeroes_missing = 0;
if (slash >= 0)
{
const int decimals_already_there = v.len() - slash - 1;
zeroes_missing = zeroes_needed - decimals_already_there;
}
else
{
v << '/';
zeroes_missing = zeroes_needed;
}
for ( ; zeroes_missing > 0; zeroes_missing--)
v << '0';
}
else
{
if (slash >= 0)
v.cut(slash);
}
v << tail;
}
else
{
const bool dotted = pic.empty() || pic.find('.') > 0;
v = curr.string(dotted);
if (pic.right(3) == "^^^") // 770 only: to be improved
{
const int dec = curr.decimals();
if (dec == 0)
v.rtrim(3+dotted);
else
v.rtrim(dec+1);
}
const int w = width() - (_section->columnwise() ? _prompt.len() : 0);
if (w > v.len())
v.right_just(w);
}
put_paragraph(v);
}
else
{
const TString& pic = picture();
if (pic.right(1)[0] == '@')
{
TString80 v;
const int w = width() - (_section->columnwise() ? _prompt.len() : 0);
int d = 0;
if (_driver)
{
const TCurrency z(ZERO, _driver->get(), ZERO, _exchange_base, _flag.price != 0);
d = z.decimals();
}
else
{
const TExchange* oe = form().output_exchange();
if (oe != NULL)
{
const TCurrency z(ZERO, *oe, _flag.price != 0);
d = z.decimals();
}
else
d = TCurrency::get_firm_dec(_flag.price != 0);
}
if (d > 0)
{
v.format("%*.*lf", w, d, 0.0);
v.replace('.', ',');
}
else
v.format("%*d", w, 0);
put_paragraph(v);
}
else
put_paragraph("");
}
}
return TRUE;
}
void TForm_currency::send_message(const TString& cmd, TForm_item& dest) const
{
if (cmd == "ADD")
{
TCurrency total;
if (dest.class_name() != class_name()) // La destinazione non e' un TForm_currency
{
const real n = dest.get();
total.set_num(n);
}
else
total = ((TForm_currency&)dest).get_currency();
total += get_currency();
dest.set(total.get_num().string());
}
else
TForm_number::send_message(cmd, dest);
}
///////////////////////////////////////////////////////////
// TForm_date
///////////////////////////////////////////////////////////
class TForm_date : public TForm_string
{
TString16 _format;
protected:
virtual const char* class_name() const { return "DATA"; }
virtual bool read();
virtual bool set(const char*);
bool set(const TDate& d);
virtual bool parse_item(TScanner& scanner);
virtual void print_body(ostream& out) const;
virtual void print_on(TMask& m);
virtual void read_from(const TMask& m);
virtual bool read_from(const TRectype& rform);
virtual void print_on(TRectype& rform);
public:
virtual TObject* dup() const;
void set_format(const char* f) { _format = f; }
virtual bool edit(TMask& m);
virtual const char* example() const;
TForm_date(TPrint_section* section);
virtual ~TForm_date() {}
};
TForm_date::TForm_date(TPrint_section* section)
: TForm_string(section), _format("1444-")
{}
TObject* TForm_date::dup() const
{
TForm_date* fd = new TForm_date(_section);
copy_to_form_item(fd);
fd->_format = _format;
return fd;
}
bool TForm_date::read()
{
bool ok = TForm_string::read();
if (ok && !get()[0] && automagic())
set(printer().getdate());
return ok;
}
void TForm_date::print_body(ostream& out) const
{
TForm_string::print_body(out);
out << " FORMAT \"" << _format << "\"\n";
}
bool TForm_date::parse_item(TScanner& scanner)
{
if (scanner.key() == "FO")
{
_format = scanner.string();
return TRUE;
}
return TForm_string::parse_item(scanner);
}
bool TForm_date::read_from(const TRectype& prof)
{
bool changed = TForm_string::read_from(prof);
const TString& df = prof.get("DATEFORM");
if (df.not_empty() && df != _format)
{
_format = df;
changed = TRUE;
}
return changed;
}
void TForm_date::print_on(TRectype& prof)
{
TForm_string::print_on(prof);
prof.put("DATEFORM", _format);
}
bool TForm_date::set(const char* s)
{
const TDate da(s);
return set(da);
}
bool TForm_date::set(const TDate& da)
{
TFormatted_date d(da); d.set_format(_format);
TForm_string::set(d.string());
return TRUE;
}
void TForm_date::print_on(TMask& m)
{
const TDate dd(TODAY);
TFormatted_date d(dd); d.set_format(_format);
m.set(F_DEXAMPLE, d.string());
m.set(F_DFORMAT, _format.mid(0,1));
m.set(F_DDAY, _format.mid(1,1));
m.set(F_DMONTH, _format.mid(2,1));
m.set(F_DYEAR, _format.mid(3,1));
m.set(F_DSEP, _format.mid(4,1));
TForm_string::print_on(m);
}
void TForm_date::read_from(const TMask& m)
{
TForm_string::read_from(m);
// adjust format string
_format[0] = m.get(F_DFORMAT)[0];
_format[1] = m.get(F_DDAY )[0];
_format[2] = m.get(F_DMONTH )[0];
_format[3] = m.get(F_DYEAR )[0];
_format[4] = m.get(F_DSEP )[0];
_format[5] = '\0';
}
bool TForm_date::edit(TMask& m)
{
return TForm_string::edit(m);
}
const char* TForm_date::example() const
{
const TDate dd(TODAY);
TFormatted_date d(dd); d.set_format(_format);
TString& s = get_tmp_string();
s = d.string();
return s;
}
///////////////////////////////////////////////////////////
// TForm_list
///////////////////////////////////////////////////////////
class TForm_list : public TForm_string
{
TToken_string _codes;
TToken_string _values;
protected:
virtual const char* class_name() const { return "LISTA"; }
virtual bool parse_item(TScanner& scanner);
virtual void print_on(TMask& m);
virtual void read_from(const TMask& m);
virtual void print_body(ostream& out) const;
virtual bool update();
public:
virtual TObject* dup() const;
TForm_list(TPrint_section* section);
virtual ~TForm_list() {}
};
TForm_list::TForm_list(TPrint_section* section)
: TForm_string(section)
{}
TObject* TForm_list::dup() const
{
TForm_list* fl = new TForm_list(_section);
copy_to_form_item(fl);
fl->_codes = _codes;
fl->_values = _values;
return fl;
}
bool TForm_list::parse_item(TScanner& scanner)
{
if (scanner.key() == "IT")
{
TToken_string s(scanner.string());
_codes.add(s.get());
_values.add(s.get());
while (scanner.popkey() == "ME")
{
TFixed_string m(scanner.line());
m.strip_spaces();
message(_values.items()-1).add(m);
}
scanner.push();
return TRUE;
}
return TForm_string::parse_item(scanner);
}
void TForm_list::print_on(TMask& m)
{
TForm_string::print_on(m);
TSheet_field& s = (TSheet_field&)m.field(F_ITEMS);
s.reset();
_codes.restart(); _values.restart();
for (int i = 0; i < _codes.items(); i++)
{
TToken_string& row = s.row(i);
row = _codes.get();
row.add(_values.get());
row.add(message(i));
}
// s.force_update();
}
void TForm_list::read_from(const TMask& m)
{
TForm_string::read_from(m);
TSheet_field& s = (TSheet_field&)m.field(F_ITEMS);
_codes = _values = "";
for (int i = 0; i < s.items(); i++)
{
TToken_string& row = s.row(i);
_codes.add(row.get(0));
_values.add(row.get());
message(i) = row.get();
}
}
void TForm_list::print_body(ostream& out) const
{
TForm_string::print_body(out);
TToken_string& cod = (TToken_string&)_codes; // Trick to skip const
TToken_string& val = (TToken_string&)_values;
int i = 0;
TString c(cod.get(0));
TString v(val.get(0));
for (; c[0]; c = cod.get(), v = val.get(), i++)
{
out << " ITEM \"" << c;
if (v.not_empty()) out << '|' << v;
out << '"';
const char* m = ((TForm_list*)this)->message(i);
if (*m) out << " MESSAGE " << m;
out << endl;
}
}
bool TForm_list::update()
{
bool ok = TRUE;
if (!read()) return ok;
const TString& val =get();
int pos = _codes.get_pos(val);
if (pos < 0)
{
TString def= _codes.get(0);
def.trim();
if (val == def) pos = 0; // Test default (first & empty) value
else
{
ok = yesno_box("Il campo '%s' non puo' valere '%s': continuare ugualmente",
(const char*)key(), (const char*)val);
set(_codes.get(pos = 0));
}
}
if (ok)
{
do_message(pos);
if (!hidden())
{
const char* c = _values.get(pos);
if (c == NULL) c = val;
if (c) string_at(x(), _y, c);
}
}
return ok;
}
///////////////////////////////////////////////////////////
// TForm_group
///////////////////////////////////////////////////////////
class TForm_group : public TForm_item
{
protected:
virtual const char* class_name() const { return "GRUPPO"; }
virtual bool update() { return TRUE; }
public:
TForm_group(TPrint_section* section) : TForm_item(section) {};
virtual ~TForm_group() {}
};
///////////////////////////////////////////////////////////
// TGraphic_section
///////////////////////////////////////////////////////////
class TGraphic_section : public TPrint_section
{
TString _back;
protected:
// @cmember Crea un campo della classe specificata
virtual TForm_item* create_item(const TString& s);
virtual bool update();
public:
void append(const char* s) { _back << s; }
TGraphic_section(TForm* f, pagetype pt) : TPrint_section(f, 'G', pt) {}
virtual ~TGraphic_section() {}
};
class TForm_picture : public TForm_item
{
TFieldref _field;
protected:
virtual const char* class_name() const { return "FIGURA"; }
virtual bool parse_item(TScanner& scanner);
virtual bool update();
public:
TForm_picture(TPrint_section* section) : TForm_item(section) {}
virtual ~TForm_picture() {}
};
class TForm_line : public TForm_item
{
protected:
virtual const char* class_name() const { return "LINEA"; }
virtual bool update();
public:
TForm_line(TGraphic_section* section) : TForm_item(section) {}
virtual ~TForm_line() {}
};
class TForm_box : public TForm_item
{
protected:
virtual const char* class_name() const { return "BOX"; }
virtual bool update();
public:
TForm_box(TGraphic_section* section) : TForm_item(section) {}
virtual ~TForm_box() {}
};
bool TForm_picture::parse_item(TScanner& scanner)
{
if (scanner.key() == "FI") // FIELD reference
{
_field = scanner.line();
return TRUE;
}
return TForm_item::parse_item(scanner);
}
bool TForm_picture::update()
{
TFilename i;
if (_field.ok())
{
const TRelation* r = form().relation();
if (r)
{
TToken_string list(_field.read(*r), '\n');
FOR_EACH_TOKEN(list, tok)
{
i = tok;
const int pos = i.find('|');
if (pos >= 0)
i.cut(pos);
if (stricmp(i.ext(), "bmp") == 0)
{
i.replace('\\', '/');
i.trim();
break;
}
else
i.cut(0);
}
}
else
NFCHECK("Can't read picture from NULL relation");
}
else
i = _prompt;
i.custom_path();
bool ok = i.not_empty() && i.exist();
if (ok)
{
i << ',' << _x << ',' << _y << ',' << (_x+width()-1) << ',' << (_y+height()-1);
if (section().section_type() == 'G')
{
i.insert("i{", 0); i << '}';
((TGraphic_section&)section()).append(i);
}
else
{
i.insert("@F[", 0); i << ']';
TPrintrow& row = section().row(_y-1);
row.put(i);
}
}
return ok;
}
bool TForm_line::update()
{
int spessore = 1;
char codice = 'l';
for (int j = _prompt.len()-1; j >= 0; j--)
{
switch (_prompt[j])
{
case 'B':
case 'b':
spessore = 3; break;
case 'R':
case 'r':
codice = 'r'; break;
default:
break;
}
}
// Calcola la vera coordinata y della linea
const int y = _y >= 0 ? _y : (printer().formlen()+_y+1);
TString80 i;
i << 'W' << spessore << codice
<< '{' << _x << ',' << y << ','
<< (_x+width()-1) << ',' << (y+height()-1) << '}';
((TGraphic_section&)section()).append(i);
return TRUE;
}
bool TForm_box::update()
{
TString80 i;
const int w = _prompt[0] == '@' ? 3 : 1;
i << 'W' << w << "b{" << _x << ',' << _y << ','
<< (_x+width()-1) << ',' << (_y+height()-1) << '}';
((TGraphic_section&)section()).append(i);
return TRUE;
}
TForm_item* TGraphic_section::create_item(const TString& typ)
{
TForm_item* fff = NULL;
if (typ.compare("LINEA", 2, TRUE) == 0)
fff = new TForm_line(this); else
if (typ.compare("BOX", 2, TRUE) == 0)
fff = new TForm_box(this); else
if (typ.compare("FIGURA", 2, TRUE) == 0)
fff = new TForm_picture(this);
return fff;
}
bool TGraphic_section::update()
{
_back.cut(0);
const bool ok = TPrint_section::update();
int index;
switch(page_type())
{
case even_page : index = 1; break;
case first_page: index = 2; break;
case last_page : index = 3; break;
default : index = 0; break;
}
printer().setbackground(_back, index);
return ok;
}
///////////////////////////////////////////////////////////
// TPrint_section
///////////////////////////////////////////////////////////
TMask* TPrint_section::_msk = NULL;
word TPrint_section::height() const
{
word h = _height;
if (subsection_above() && (word)subsection_above()->effective_height() > h)
{
h = subsection_above()->effective_height();
}
if (short(h) < 0) // Can't write h < 0!
{
if (section_type() == 'F')
{
h += printer().formlen();
if (short(h) < 0) // Still < 0 ?? get out...
h = 0;
}
else
{
h = _rows.items();
if (h == 0)
h = 0xFFFF - _height + 1; // Same as abs(_height)
}
}
return h;
}
TExpression & TPrint_section::eval_expr(TExpression & expr,int defaultfile_id)
{
for (int j = 0; j < expr.numvar(); j++)
{ // scansione delle variabili dell'espressione di rvalue
TString var= expr.varname(j);
if (var[0]=='#')
{ // riferimento ad un campo del form
var.ltrim(1);
TForm_item &fi= find_field(atoi(var));
expr.setvar(j, fi.get()); // il valore corrente del campo viene settato nell'espressione
}
else
{ // riferimento ad un campo di file
TFieldref fr = TFieldref(var, 0);
int fileno=fr.file();
// choose logical file number
fileno= (fileno==0) ? (defaultfile_id>0 ? defaultfile_id : 0): fileno;
expr.setvar(j, fr.read( form().relation()->lfile(fileno).curr() ) ); // il valore corrente del campo viene settato nell'espressione
}
}
return expr;
}
TPrint_section::TPrint_section(TForm* f, char st, pagetype pt, TForm_subsection* father)
: _height(0), _form(f), _sec_type(st), _page_type(pt), _dirty(FALSE),
_upsection(father), _repeat_count(0), _ofspc(0), _ofsvr(0), _nfld(0), _temp(0),
_columnwise(FALSE)
{
reset_tabs();
}
TPrint_section::~TPrint_section()
{
if (_msk)
{
delete _msk;
_msk = NULL;
}
}
TForm_item* TPrint_section::create_item(const TString& s)
{
TForm_item* f = NULL;
if (s.compare("STRINGA", 2, TRUE) == 0)
f = new TForm_string(this); else
if (s.compare("NUMERO", 2, TRUE) == 0)
f = new TForm_number(this); else
if (s.compare("VALUTA", 2, TRUE) == 0)
f = new TForm_currency(this); else
if (s.compare("DATA", 2, TRUE) == 0)
f = new TForm_date(this); else
if (s.compare("LISTA", 2, TRUE) == 0)
f = new TForm_list(this); else
if (s.compare("GRUPPO", 2, TRUE) == 0)
f = new TForm_group(this); else
if (s.compare("SECTION", 2, TRUE) == 0)
f = new TForm_subsection(this); else
if (s.compare("FIGURA", 2, TRUE) == 0)
f = new TForm_picture(this);
return f;
}
void TPrint_section::change_field(int n, TForm_item* f)
{
_item.add(f,n);
}
void TPrint_section::insert_field(int n, TForm_item* f)
{
_item.insert(f,n);
}
void TPrint_section::add_field(TForm_item* f)
{
_item.add(f);
}
inline int TPrint_section::subsections()const
{
return _subsections.items();
}
inline TForm_subsection* TPrint_section::subsection(int n) const
{
return (TForm_subsection* )_subsections.objptr(n);
}
inline void TPrint_section::add_subsection(TForm_subsection* s)
{
_subsections.add(s);
}
const TPrint_section& TPrint_section::copy(const TPrint_section& ps)
{
_msk = ps._msk; _height = ps._height; _ofspc = ps._ofspc;
_ofsvr = ps._ofsvr; _nfld = ps._nfld; _dirty = ps._dirty;
_temp = ps._temp; _form = ps._form;
_sec_type = ps._sec_type; _page_type = ps._page_type;
_item = ps._item;
// subsections
_upsection = ps._upsection; _repeat_count = ps._repeat_count; _subsections=ps._subsections;
// columnwise
_columnwise = ps._columnwise;
for (int i = 0; i < MAXCOLUMNS; i++) _tab[i] = ps._tab[i];
return ps;
}
TPrintrow& TPrint_section::row(int num)
{
TPrintrow* pr = (TPrintrow*)_rows.objptr(num);
if (pr == NULL)
{
pr = new TPrintrow;
_rows.add(pr, num);
}
return *pr;
}
TPrintrow& TPrint_section::titlerow(int num)
{
TPrintrow* pr = (TPrintrow*)_titlerows.objptr(num);
if (pr == NULL)
{
pr = new TPrintrow;
_titlerows.add(pr, num);
}
return *pr;
}
void TPrint_section::reset_tabs()
{
for (int i = 0; i < MAXCOLUMNS; i++)
_tab[i] = -1;
}
int TPrint_section::tab(int col)
{
int ret = -1;
if (_columnwise)
{
if (_tab[0] == -1 && fields())
{
_tab[0] = 2;
{
int extraoff=0;
// compute column offset
_nfld = 0;
short maxcolreached = 0,mincolreached = MAXCOLUMNS+1;
for (word i = 0; i < fields(); i++)
{
if (!field(i).is_section() && field(i).shown())
{
const int curr_col=field(i)._x;
CHECKD (curr_col >=0 && curr_col < MAXCOLUMNS, "Colonna ammessa e non concessa: ", field(i)._x);
_tab[curr_col] = field(i)._width + 1; // one is for separation
if (curr_col < mincolreached) mincolreached = curr_col;
if (curr_col > maxcolreached) maxcolreached = curr_col;
_nfld++;
}
}
// cumulate offsets
if (_upsection)
{
if (mincolreached<=MAXCOLUMNS && mincolreached>0)
{
// print section of a subsection: extra offset
extraoff=_upsection->section().tab(mincolreached-1);
for (i = 1 ; i < (word)mincolreached; i++)
{
_tab[i]=_upsection->section()._tab[i];
}
if (extraoff== _tab[mincolreached-1])
extraoff=0;
else
extraoff-=_upsection->section().tab(0);
}
}
int last = 0;
for (i = mincolreached ; i <= (word)maxcolreached; i++)
{
if (_tab[i - 1] != -1)
last = i - 1;
if (_tab[i] != -1)
_tab[i] += _tab[last]+extraoff;
}
}
}
// se manca la colonna, vai a prendere quella immediatamente prima
while (_tab[col] == -1 && col > 0)
col--;
ret = _tab[col];
}
return ret;
}
word TPrint_section::subs_height() const
{
TForm_subsection *fss;
word h=0;
if (subsections())
{
fss=subsection(0);
h=subsection(0)->minheight();
h+=subsection(0)->printsection().subs_height(); // ricorsione...
}
return h;
}
void TPrint_section::offset(int& x, int& y)
{
if (x >= 0)
{
if (_columnwise) x = tab(x-1) + _ofspc;
x += form().offset_x();
}
if (y >= 0)
y += form().offset_y() + (_height * _repeat_count);
}
TForm_item* TPrint_section::parse_item(const TString& s)
{
TForm_item* f = create_item(s);
#ifdef DBG
if (f == NULL)
yesnofatal_box("Tipo di campo del form non riconosciuto: '%s'", (const char*)s);
#endif
return f;
}
TForm_item* TPrint_section::parse_item(TScanner& scanner)
{
return parse_item(scanner.key());
}
bool TPrint_section::parse_head(TScanner& scanner)
{
_height = scanner.integer();
scanner.integer();scanner.integer(); // Eat offset X and Y of Print_section if present
if (scanner.popkey() == "CO") // COLUMNWISE attribute
_columnwise = TRUE;
else if (scanner.key() == "NO") // NORMAL (no COLUMNWISE) attribute
_columnwise = FALSE;
else
{
if (section_above())
_columnwise = section_above()->_columnwise;
else
_columnwise = FALSE;
scanner.push();
}
return TRUE;
}
bool TPrint_section::parse_body(TScanner& scanner)
{
while (scanner.popkey() != "EN")
{
TForm_item *fi = parse_item(scanner);
if (fi == NULL) return FALSE;
if (fi->parse(scanner))
{
_item.add(fi);
} else
return FALSE;
}
return TRUE;
}
bool TPrint_section::parse(TScanner& scanner)
{
if (parse_head(scanner))
return parse_body(scanner);
return FALSE;
}
// Azzera tutte le righe della sezione di stampa
void TPrint_section::reset()
{
for (int i = _rows.last(); i >= 0; i--)
{
if (_height > 0xF000)
_rows.destroy(i);
else
row(i).reset();
}
}
// Aggiorna tutti i campi
bool TPrint_section::update()
{
bool ok = TRUE;
reset();
for (word i = 0; i < fields(); i++)
{
if (!field(i).is_section())
{
const bool esito = field(i).update();
if (!esito) ok = FALSE;
}
}
return ok;
}
TForm_item* TPrint_section::exist_field(short id) const
{
TForm_item* f = find_field_everywhere(id,this);
return f;
}
TForm_item& TPrint_section::find_field(short id) const
{
TForm_item* f = exist_field(id);
if (f) return *f;
yesnofatal_box("Can't find item with id %d", id);
return field(0);
}
// Ricerca i campi verso l'alto:
// prima la sezione attuale, poi le sezioni sopra
TForm_item *TPrint_section::find_field_everywhere(short id,const TPrint_section *starting_section) const
{
TForm_item * f ;
for(word i = 0; i < fields(); i++)
{
f = &field(i);
if (f->id() == id) return f;
}
// look into the section above ("father" )
if (section_above() && section_above()!=starting_section) {
f=section_above()->find_field_everywhere(id,this);
if (f)
return f;
}
// look into sections beside ("brothers" )
for (int j = 0; j < subsections(); j++)
{
const TPrint_section &bs=subsection(j)->printsection();
if (&bs!=starting_section) {
f=bs.find_field_everywhere(id,this);
if (f)
return f;
}
}
return NULL;
}
TForm_item* TPrint_section::exist_field(const char *sec_name) const
{
TForm_item* f = find_field_everywhere(sec_name,this);
return f;
}
TForm_item& TPrint_section::find_field(const char *sec_name) const
{
TForm_item* f = exist_field(sec_name);
if (f) return *f;
yesnofatal_box("Can't find subsection '%s'", sec_name);
return field(0);
}
// Ricerca i campi verso il basso:
// prima la sezione attuale, poi le sottosezioni
TForm_item *TPrint_section::find_field_everywhere(const char *sec_name,const TPrint_section *starting_section) const
{
// search here
for (int j = 0; j < subsections(); j++) {
const char *n=subsection(j)->name();
if (strcmp(n,sec_name)==0)
return subsection(j);
}
// search down
for (j = 0; j < subsections(); j++) {
TForm_item *it=subsection(j)->printsection().find_field_everywhere(sec_name,starting_section);
if (it)
return it;
}
return NULL;
}
///////////////////////////////////////////////////////////
// TForm
///////////////////////////////////////////////////////////
// classe per le informazioni sugli skip dei file del cursore del form
class TForm_skip_info : public TObject
{
protected:
virtual TObject * dup() const;
public :
bool _match_result;
int _match_number;
~TForm_skip_info(){};
TForm_skip_info();
};
TObject * TForm_skip_info ::dup() const
{
TForm_skip_info *p=new TForm_skip_info;
p->_match_result=_match_result;
p->_match_number=_match_number;
return p;
}
TForm_skip_info::TForm_skip_info()
{
_match_result=FALSE;
_match_number=0;
}
TForm_editor& TForm::editor() const
{ return (TForm_editor&)main_app(); }
//
bool TForm::parse_use(TScanner& scanner)
{
const int logicnum = scanner.integer();
const char* tab = NULL;
if (logicnum > 0)
_relation = new TRelation(logicnum);
else
{
tab = scanner.pop();
_relation = new TRelation(tab);
}
int key = 1; // key number
if (scanner.popkey() == "KE")
key = scanner.integer();
else
scanner.push();
if (scanner.popkey() == "BY" || scanner.key() == "FI") // file sorted or filtered
{
if (scanner.key() == "BY" ) { // "sort BY": user-defined sort
TToken_string ordexpr(parse_sortexpr(scanner));
_cursor = new TSorted_cursor(_relation, ordexpr,"", key);
} else {
TToken_string filter(parse_filter(scanner));
_cursor = new TCursor(_relation,filter, key);
}
} else {
scanner.push();
_cursor = new TCursor(_relation,"", key);
}
if (scanner.popkey() == "FI") // "FIlter" : sorted defined by the user
{
TToken_string filter(parse_filter(scanner));
_cursor->setfilter(filter);
} else {
scanner.push();
}
return TRUE;
}
bool TForm::parse_join(TScanner& scanner)
{
TString16 j(scanner.pop()); // File or table
int to = 0;
if (scanner.popkey() == "TO") // TO keyword
{
const char* n = scanner.pop();
to = name2log(n);
}
else scanner.push();
return parse_join_param(scanner,_relation,j,to);
}
bool TForm::parse_join_param(TScanner& scanner,TRelation * rel, TString16 j, int to )
{
int key = 1;
if (scanner.popkey() == "KE")
key = scanner.integer();
else scanner.push();
int alias = 0;
if (scanner.popkey() == "AL")
alias = scanner.integer();
else scanner.push();
TToken_string exp(80);
if (scanner.pop() == "INTO")
{
exp=parse_filter(scanner);
}
if (exp.empty())
yesnofatal_box("JOIN senza espressioni INTO");
if (isdigit(j[0]))
rel->add(atoi(j), exp, key, to, alias); // join file
else
rel->add(j, exp, key, to, alias); // join table
return TRUE;
}
bool TForm::parse_sortedjoin(TScanner& scanner)
{
TToken_string filter,sortexp;
TString16 j(scanner.pop()); // File or table
if (scanner.popkey() == "BY" )
{
sortexp=parse_sortexpr(scanner);
} else scanner.push();
if (scanner.popkey() == "FI" ) {
filter=parse_filter(scanner);
} else scanner.push();
if (filter.empty() && sortexp.empty())
yesnofatal_box("Sort senza espressioni di ordinamento o filtri");
TRelation * sortrel=new TRelation(atoi(j));
while (ok() && scanner.popkey() != "JO" )
{
if (scanner.key() == "US") // USING keyword
{
TString16 subj(scanner.pop()); // File or table
parse_join_param(scanner,sortrel,subj,atoi(j));
} else
yesnofatal_box("Token non riconosciuto in SORT:%s",scanner.key());
}
int to = 0;
if (scanner.popkey() == "TO") // TO keyword
{
const char* n = scanner.pop();
to = name2log(n);
}
else scanner.push();
int key = 1;
if (scanner.popkey() == "KE")
key = scanner.integer();
else scanner.push();
int alias = 0;
if (scanner.popkey() == "AL")
alias = scanner.integer();
else scanner.push();
TToken_string exp(80);
if (scanner.pop() == "INTO")
{
const char* r = scanner.pop();
while (strchr(r, '=') != NULL)
{
exp.add(r);
r = scanner.pop();
}
}
if (exp.empty())
yesnofatal_box("JOIN senza espressioni INTO");
scanner.push();
TSortedfile *sf= new TSortedfile(atoi(j),sortrel,sortexp,filter,key);
_relation->add((TLocalisamfile *)sf, exp, key, to, alias,FALSE); // join table
return TRUE;
}
TToken_string TForm::parse_filter(TScanner& scanner)
{
TToken_string filter;
const char* r = scanner.pop();
while (strchr(r, '=') != NULL)
{
filter.add(r);
r = scanner.pop();
}
scanner.push();
return filter;
}
TToken_string TForm::parse_sortexpr(TScanner& scanner)
{
TToken_string sortexp;
TToken_string se(scanner.line(),' ');
const char * c;
while (c=se.get())
if (*c!='\0')
sortexp.add(c);
return sortexp;
}
TRelation_description& TForm::rel_desc() const
{
CHECK(_rel_desc, "No relation description");
return *_rel_desc;
}
bool TForm::parse_description(TScanner& scanner)
{
if (edit_level() > 0)
{
CHECK(_rel_desc == NULL, "Can't parse descriptions two times");
_rel_desc = new TRelation_description(*_relation);
}
bool ok = scanner.popkey() == "DE";
if (ok)
{
if (edit_level() > 0)
{
scanner.popkey(); // eat BEGIN
TFieldref fld;
while (scanner.pop() != "END")
{
fld = scanner.token();
_rel_desc->set_cur_file(fld.file());
if (fld.name() == "*")
_rel_desc->file_desc(scanner.string());
else
_rel_desc->set_field_description(fld.name(), scanner.string());
}
}
else
{
while (scanner.line() != "END");
ok = FALSE;
}
}
else scanner.push();
return ok;
}
void TForm::print_description(ostream& out) const
{
out << "DESCRIPTION\nBEGIN\n";
out << rel_desc();
out << "END\n" << endl;
}
bool TForm::parse_general(TScanner &scanner)
{
bool ok = scanner.popkey() == "GE";
if (ok)
{
while (scanner.pop() != "END")
{
if (scanner.key() == "OF") // Offsets
{
_x = scanner.integer();
_y = scanner.integer();
}
if (scanner.key() == "FO") // Font name
_fontname = scanner.string();
if (scanner.key() == "SI") // Font size
_fontsize = scanner.integer();
if (scanner.key() == "CA") // Carattere di posizionamento
_char_to_pos = scanner.string()[0];
if (scanner.key() == "IN") // Riga e colonna del posizionamento iniziale
{
_ipx = scanner.integer();
_ipy = scanner.integer();
}
if (scanner.key() == "FI") // Riga e colonna del posizionamento finale
_fpx = scanner.integer();
if (scanner.key() == "GR") // Carattere di fincatura
set_fincatura(scanner.string());
if (scanner.key() == "PA") // Numero di pagine fisso
_npages=scanner.integer();
if (scanner.key() == "VA") // Valuta/Divisa impiegata
{
_curr_codval=scanner.string(); // DA ELIMINARE
}
extended_parse_general(scanner); // Parse non-standard parameters
}
} else scanner.push();
return (ok);
}
void TForm::print_general(ostream& out) const
{
out << "GENERAL\nBEGIN\n";
out << " OFFSET " << _x << " " << _y << "\n";
out << " FONT " << "\"" << _fontname << "\"\n";
out << " SIZE " << _fontsize << "\n" ;
if (_char_to_pos != '\0')
{
out << " CARATTERE \"" << _char_to_pos << "\"\n" ;
out << " INIZIO_POS " << _ipx << " " << _ipy << "\n";
out << " FINE_POS " << _fpx << "\n";
}
out << " GRID \"" << _fink << "\"\n";
out << "END\n" << endl;
}
// @doc EXTERNAL
// @mfunc Controlla se esiste una sezione di stampa
//
// @rdesc Ritorna la <c TPrint_section> trovata o creata
TPrint_section* TForm::exist(
char s, // @parm Indica in quale parte deve cercare:
//
// @flag F | Tra i footers
// @flag G | Tra gli sfondi
// @flag H | Tra gli headers
// @flag B | Tra i bodies (default)
pagetype t, // @parm Tipo di pagina (vedi <t pagetype>)
bool create) // @parm Indica se creare la sezione nel caso non esista
{
TArray* a;
switch (toupper(s))
{
case 'F':
a = &_foot; break;
case 'G':
a = &_back; break;
case 'H':
a = &_head; break;
default:
a = &_body; break;
}
TPrint_section* sec = (TPrint_section*)a->objptr(t);
if (sec == NULL && create)
{
sec = (s == 'G') ? new TGraphic_section(this, t) : new TPrint_section(this, s, t);
a->add(sec, t);
}
return sec;
}
TForm_item* TForm::exist_field(char s, pagetype t, short id) const
{
const TPrint_section* ps = ((TForm*)this)->exist(s, t);
CHECKD(ps, "Can't find section for field ", id);
return ps->exist_field(id);
}
TForm_subsection* TForm::exist_field(char s, pagetype t, const char *section) const
{
const TPrint_section* ps = ((TForm*)this)->exist(s, t);
CHECKS(ps, "Can't find section for field ", section);
return (TForm_subsection*)ps->exist_field(section);
}
TForm_item& TForm::find_field(char s, pagetype t, short id) const
{
const TPrint_section* ps = ((TForm*)this)->exist(s, t);
CHECKD(ps, "Can't find section for field ", id);
return ps->find_field(id);
}
TForm_subsection& TForm::find_field(char s, pagetype t, const char *section) const
{
const TPrint_section* ps = ((TForm*)this)->exist(s, t);
CHECKS(ps, "Can't find section for field ", section);
return (TForm_subsection&)ps->find_field(section);
}
TPrint_section& TForm::section(char s, pagetype pos)
{
TPrint_section* sec = exist(s, pos, TRUE);
return *sec;
}
TPrint_section& TForm::section(char s, word pagenum)
{
pagetype pt = odd_page;
if (pagenum == 0 && exist(s, last_page))
pt = last_page;
if (pagenum == 1 && exist(s, first_page))
pt = first_page;
if (pt == odd_page && (pagenum & 0x1) == 0 && exist(s, even_page))
pt = even_page;
return section(s, pt);
}
// @doc EXTERNAL
// @mfunc Rilegge la sezione specificata
//
// @rdesc Ritorna se ce l'ha fatta
bool TForm::reread(
char sec, // @parm Sezione da rileggere
pagetype p, // @parm Posizione della pagina
bool force) // @parm Forza rilettura anche se nessun campo e' cambiato
{
TPrint_section* s = exist(sec,p);
bool ok = force;
if (s != NULL)
for (word j = 0; j < s->fields(); j++)
ok |= s->field(j).dirty();
if (s != NULL && ok)
{
s->destroy_fields(); // Distrugge tutti gli items...
// ...si posiziona nel file sorgente alla sezione opportuna...
TFilename n(_name); n.ext("frm");
TScanner scanner(n);
bool ok = FALSE;
while (!ok)
{
while (TRUE) // ...scans searching for a section...
{
const TString& key = scanner.popkey();
if (key == "SE" || key == "") // ..if section or end of file...
break;
}
const char secr = scanner.popkey()[0]; // Section name (GRAPH, HEAD, BODY, FOOT)
if (secr=='\0') break;
const pagetype pr = char2page(scanner.popkey()[0]); // Section type (odd, even, first, last)
if (secr==sec && pr==p) ok = TRUE; // L'ha trovata...
}
// ...riesegue la parse della sezione leggendo dal file sorgente
if(ok && s->parse(scanner))
{
// Legge le modifiche su archivio e poi e' finita.
s->set_dirty(FALSE);
TLocalisamfile rprof(LF_RFORM);
const char sez[3] = {sec,p+'0','\0'};
rprof.zero();
rprof.put("TIPOPROF", _name);
rprof.put("CODPROF", _code);
rprof.put("SEZ", sez);
const TRectype filter(rprof.curr());
for (int err = rprof.read(_isgteq); err == NOERR && rprof.curr() == filter; err = rprof.next())
{
const short id = rprof.get_int("ID");
if (id == 0)
{
TPrint_section& se = section(sec, p);
se.read_from(rprof.curr());
}
else
{
TForm_item& item = find_field(sec, p, id);
item.read_from(rprof.curr());
}
}
set_compulsory_specials();
}
}
return ok;
}
///////////////////////////////////////////////////////////
// TForm
///////////////////////////////////////////////////////////
// @doc EXTERNAL
// @mfunc Cambia il formato di tutte le date nel form
//
// @rdesc Ritorna sempre TRUE
bool TForm::ps_change_date_format(
TPrint_section& s, // @parm Sezione nella quale modificare le date
const char* f) // @parm Nuovo formato delle date
// @comm Ha le stesse funzioni di <mf TForm::change_date_format>, ma per <c TPrint_section>,
// all'uopo di chiamarla con ricorsiva insistenza
{
for (word i = 0; i < s.fields(); i++)
{
TForm_item& fi = s.field(i);
if (fi.is_section())
{
TPrint_section& ps = ((TForm_subsection&)fi).printsection();
ps_change_date_format(ps, f);
}
else if (strcmp(fi.class_name(), "DATA") == 0)
{
((TForm_date&)fi).set_format(f);
if (!s.dirty()) s.set_dirty();
if (!fi.dirty()) fi.set_dirty();
}
}
return TRUE;
}
// @doc EXTERNAL
// @mfunc Cambia il formato di tutti i numeri nel form
//
// @rdesc Ritorna sempre TRUE
bool TForm::ps_change_number_format(
TPrint_section& s, // @parm Sezione nella quale modificare i numeri
int w, // @parm Dimensione massima del fomato numerico
int dec, // @parm Numero di decimali
const char* p) // @parm Picture del nuovo formato
// @comm Ha le stesse funzioni di <mf TForm::change_number_format>, ma per <c TPrint_section>,
// all'uopo di chiamarla con ricorsiva insistenza
{
for (word i = 0; i < s.fields(); i++)
{
TForm_item& fi = s.field(i);
if (fi.is_section())
{
TPrint_section& ps = ((TForm_subsection&)fi).printsection();
ps_change_number_format(ps, w, dec, p);
}
else if (strcmp(fi.class_name(), "NUMERO") == 0)
{
TForm_number& fn = (TForm_number&)fi;
fn.width() = w;
fn.set_decimals(dec);
fn.set_picture(p);
if (!s.dirty()) s.set_dirty();
if (!fn.dirty()) fn.set_dirty();
}
}
return TRUE;
}
void TForm::change_date_format(const char* f)
{
char secs[] = { "FHGB" };
char ptyp[] = { "LOEF" };
TPrint_section* ps;
for (int sc = 0; sc < 4; sc++)
for (int pt = 0; pt < 4; pt++)
if ((ps = exist(secs[sc], char2page(ptyp[pt]), FALSE)) != NULL)
ps_change_date_format(*ps, f);
}
void TForm::change_number_format(int w, int dec, const char* p)
{
char secs[] = { "FHGB" };
char ptyp[] = { "LOEF" };
TPrint_section* ps;
for (int sc = 0; sc < 4; sc++)
for (int pt = 0; pt < 4; pt++)
if ((ps = exist(secs[sc], char2page(ptyp[pt]), FALSE)) != NULL)
ps_change_number_format(*ps, w, dec, p);
}
// @doc EXTERNAL
// @mfunc Effettua l'update della sezione grafica background
//
// @rdesc Ritorna la lunghezza della pagina da stampare
word TForm::set_background(
word p, // @parm Numero pagina
bool u) // @parm Indica se aggiornare lo sfondo nella stampante corrente
// @xref <mf TForm::set_header> <mf TForm::set_body> <mf TForm::set_footer>
{
word len = 0;
if (u && _back.items())
{
TPrint_section& graph = section('G', p);
graph.update();
len = printer().formlen();
}
return len;
}
// @doc EXTERNAL
// @mfunc Effettua l'update della sezione header
//
// @rdesc Ritorna l'altezza dell'header settato
word TForm::set_header(
word p, // @parm Numero pagina
bool u) // @parm Indica se cambiare l'eventuale header o solo ritornare l'altezza
// @xref <mf TForm::set_background> <mf TForm::set_body> <mf TForm::set_footer>
{
TPrinter& pr = printer();
pr.resetheader();
TPrint_section& head = section('H', p);
if (u) head.update();
else
{
head.reset();
pr.headerlen(head.height());
}
for (word j = 0; j < head.height(); j++)
pr.setheaderline(j, head.row(j));
return head.height();
}
// @doc EXTERNAL
// @mfunc Effettua l'update della sezione body e la sua stampa su Printer
//
// @rdesc Ritorna l'altezza del body settato
word TForm::set_body(
word p, // @parm Numero pagina
bool u) // @parm Indica se effettuare l'update (TRUE) o fare il reset (FALSE)
// @xref <mf TForm::set_background> <mf TForm::set_header> <mf TForm::set_footer>
{
TPrint_section& body = section('B', p);
if (u) body.update_and_print(printmode_normal);
else body.reset();
return body.height();
}
TPrint_section * TPrint_section::section_above() const
{
if (_upsection)
return &_upsection->section();
return NULL;
}
// @doc EXTERNAL
// @mfunc Compone e stampa tutte le righe della sezione (valida in caso di BODY)
// ritorna se c'e' stata una valutazione
bool TPrint_section::update_and_print(const sec_print_mode show_fields, bool new_page)
{
bool ok=FALSE;
TPrinter& pr = printer();
word last_printed_row=0;
reset();
if (show_fields == printmode_normal
&& pr.current_row() > pr.headersize()+1
&& new_page)
{
pr.formfeed();
}
int repeat_count=0; // numero di sottosezioni stampate o numero di stampe della stessa sottosezione
int last_hpos=0;
for (word i = 0; i < fields(); i++)
{
if (!field(i).is_section())
{
// compose rows using "simple" fields
field(i).update();
}
else
{
last_hpos=min(word(field(i).y()-1), height());
// found a subsection
TForm_subsection & ss=(TForm_subsection & )field(i);
last_printed_row=print_rows(show_fields,last_printed_row,last_hpos);
// process subsection
if (ss.enabled())
ok |= ss.print_body(show_fields) ;
}
} // ... loop for each field
const word hgt = height();
if (print_rows(show_fields,last_printed_row,hgt) > 0 && show_fields==printmode_normal)
ok = TRUE;
// print footers
if (subsection_above()!=NULL && !subsection_above()->is_title() && ok)
subsection_above()->print_qtitle();
return ok;
}
word TPrint_section::print_rows(const sec_print_mode show_fields, word from, word to)
{
TPrinter& pr = printer();
if (show_fields!=printmode_noprint && to>from)
{
// print preceeding rows:are all those rows which have Y coord <= than subsection's Y
if (subsection_above()!=NULL && !subsection_above()->is_title())
{
// find some to print: print titles.....
if (show_fields == printmode_normal)
subsection_above()->print_titles();
}
if (pr.current_row() > pr.headersize()+1)
if ((to-from+1) > pr.rows_left() && show_fields==printmode_normal )
pr.formfeed();
for (word j = from; j < to ;j++)
switch (show_fields)
{
case printmode_normal:
pr.print(row(j)); break; // print to printer
default:
_titlerows.add(row(j),j); break; // print to buffer
}
return to;
}
return from;
}
// @doc EXTERNAL
// @mfunc Effettua l'update della sezione footer
//
// @rdesc Ritorna l'altezza del footer settato
word TForm::set_footer(
word p, // @parm Numero pagina
bool u) // @parm Indica se cambiare l'eventuale footer corrente!!!
// @xref <mf TForm::set_background> <mf TForm::set_header> <mf TForm::set_body>
{
TPrinter& pr = printer();
pr.resetfooter();
TPrint_section& foot = section('F', p);
if (u) foot.update();
else
{
foot.reset();
pr.footerlen(foot.height());
}
for (word j = 0; j < foot.height(); j++)
pr.setfooterline(j, foot.row(j));
return foot.height();
}
void TForm::header_handler(TPrinter& p)
{
TForm& f = *_cur_form;
if (f.firstpage_is_lastpage())
{
f.set_background(1, TRUE);
f.set_header(1, TRUE);
f.set_footer(0, FALSE);
}
else
{
const word page = f.page(p);
f.set_background(page, TRUE);
f.set_header(page, TRUE);
f.set_footer(page, FALSE);
}
}
void TForm::footer_handler(TPrinter& p)
{
TForm& f = *_cur_form;
if (f.firstpage_is_lastpage())
{
f.set_footer(0, TRUE);
}
else
{
const word currp = f.page(p);
f.set_footer(currp, TRUE);
if (currp)
f.set_header(f.next_page(p), FALSE);
}
}
// @doc EXTERNAL
// @mfunc Ritorna se la prima pagina coincide conl'ultima
bool TForm::firstpage_is_lastpage() const
{
return _first_eq_last;
}
// @doc EXTERNAL
// @mfunc Ritorna il numero di pagina correntemente in stampa
//
// @rdesc Se <md _TForm::lastpage> e' TRUE (sta stampando l'ultima pagina)
// ritorna 0, altrimenti ritorna il numero della pagina corrente da stampare
// (chiam <mf TPrinter::getcurrentepage>).
word TForm::page(
const TPrinter& p) const // @parm Operazione corrente di stampa
{
return _lastpage || fixed_pages() && p.getcurrentpage()==_npages ? 0 : p.getcurrentpage();
}
word TForm::next_page(
const TPrinter& p) const // @parm Operazione corrente di stampa
{
return _lastpage || fixed_pages() && p.getcurrentpage()+1==_npages ? 0 : p.getcurrentpage()+1;
}
// @doc EXTERNAL
// @mfunc Effettua il posizionamento manuale del modulo
void TForm::arrange_form()
// @comm Nota: siccome si scrive direttamente sulla porta, sarebbe necessario
// mandare una stringa di reset alla stampante, o per lo meno far si' che
// ogni volta che si fa il posizionamento il font col quale scrive sia sempre
// lo stesso. Tutto cio' non e' possibile con la generica solo testo, o meglio
// ad ogni stampa col posizionamento e' necessario che la stampante sia resettata.
// <nl>Riassumendo, come regola generale, i posizionamenti devono essere fatti con il
// font di default della stampante (tipicamente 10 cpi). Accade pero' (con la generica
// solo testo) che rimanga settato l'ultimo font, di conseguenza quando si effettua una
// seconda stampa con posizionamento, stampera' tali caratteri in 17"! Per questo
// motivo e' necessario settare a 17 cpi, almeno la prima volta, la stampante!.
// <nl>Quindi, per ovviare a tutto cio, visto che <mf TForm::arange_form> ha senso solo su
// stampanti ad aghi, che le stampanti ad aghi possono andare in emulazione EPSON o IBM,
// che il codice per settare il font draft 17cpi e' lo stesso sia per EPSON che IBM
// CHR(15), allora prima del posizionamento scrivo il chr(15) sulla stampante!
{
/*
int i, x;
TString str_pos;
TMask m("ba2100c");
// _ipy viene assunto uguale per entrambi i posizionamneti
str_pos = "\017"; // Questo e' 15 in ottale...
for (i=1; i < _ipy; i++) str_pos << "\n";
os_open_spool_row(printer().printername());
os_spool_row(str_pos);
os_close_spool_row();
str_pos = ""; //Azzera la stringa di posizionamento
for (i=1; i < _ipx; i++) str_pos << " "; //Aggiunge gli spazi necessari...
if (_ipx > 0)
str_pos << _char_to_pos; // aggiunge il primo carattere di posizionamento...
x = _fpx - _ipx ; // calcola quanti spazi aggiungere...
for (i=1; i < x; i++) str_pos << " ";
if (_fpx > 0)
str_pos << _char_to_pos; // aggiunge il secondo carattere di posizionamento
str_pos << '\r';
// TString bspc; bspc.fill('\b',str_pos.len()); // Questi servono per tornare indietro...
do
{
os_open_spool_row(printer().printername());
os_spool_row(str_pos);
os_close_spool_row();
} while (m.run() == K_ESC); // cicla sulla stampa posizionamento...
printer().set_offset(-(_ipy-1), printer().get_column_offset());
*/
}
long TForm::records() const
{
const long r = cursor() ? cursor()->items() : 0;
return r;
}
// @doc EXTERNAL
// @mfunc Genera automaticamente la sezione grafica con colonne fincate
//
// @rdesc Ritorna FALSE se non c'e' il body per quella pagina
bool TForm::genera_fincatura(
pagetype p, // @parm Posizione della pagina (vedi <t pagetype>)
int y1, // @parm Prima y per le righe verticali
int y2, // @parm Ultima y per le righe verticali
const int* rows) // @parm Array di posizioni riga con 0 per finire
{
TPrint_section* body = exist('B', p);
if (body == NULL) return FALSE;
body->reset_tabs();
bool istemp = exist('G', p) == NULL;
TGraphic_section* grs = (TGraphic_section*)exist('G', p, TRUE);
grs->temp() = istemp;
int j = 0, start = 999, end = 0, wlast = 0;
int cols[MAXCOLUMNS];
for (word k = grs->fields(); k > 0; k--)
if (grs->field(k-1).temp())
grs->destroy_field(k-1);
for (int i = 0; i < (int)body->fields(); i++)
{
TForm_item& f = body->field(i);
if (!f.shown() || f.is_section())
continue;
int x = f.x();
if (x < start) start = x;
if (x > end) { end = x; wlast = f.width(); }
cols[j++] = f.finkl() ? -x : x;
}
// inner lines
for (i = 0; i < j; i++)
{
if (cols[i] != start && cols[i] > 0)
{
TForm_line* l = new TForm_line(grs);
l->set_x(cols[i]-1);
l->y() = (word)y1;
l->id() = -1;
l->width() = 1;
l->height() = (int)(y2 - y1 + 1);
l->set("@R");
l->temp() = TRUE;
grs->add_field(l);
}
}
// box around
if (start != 999 && end != 0)
{
TForm_box* l = new TForm_box(grs);
l->set_x(start-1);
l->y() = (word)y1;
l->id() = -1;
l->width() = (int)(end + wlast - start + 2);
l->height() = (int)(y2 - y1 + 1);
l->set("@B@R");
l->temp() = TRUE;
grs->add_field(l);
}
// horizontal lines
if (start != 999 && end != 0)
for (i = 0; rows[i]; i++)
{
TForm_line* l = new TForm_line(grs);
l->set_x(start-1);
l->y() = (word)rows[i];
l->id() = -1;
l->width() = (int)(end + wlast - start + 2);
l->height() = 1;
l->set("@R");
l->temp() = TRUE;
grs->add_field(l);
}
return TRUE;
}
// @doc EXTERNAL
// @mfunc Genera le righe di intestazione colonna alla riga indicata, vale per COLUMNWISE
//
// @rdesc Ritorna FALSE se non esiste body (o non e' COLUMNWISE) o se non esiste l'header
bool TForm::genera_intestazioni(
pagetype p, // @parm Posizione della pagina (vedi <t pagetype>)
short y) // @parm Riga dell'header in cui vanno inserite
// @comm I form_items di intestazione vengono aggiunti alla sezione header di tipo <p p> con ID -1
{
TPrint_section* body = exist('B', p);
if (body == NULL || !body->columnwise())
return FALSE;
TPrint_section* header = exist('H', p);
if (header == NULL)
return FALSE;
body->reset_tabs();
// Elimina eventuali campi temporanei precedenti
for (int k = header->fields()-1; k >= 0; k--)
if (header->field(k).temp())
header->destroy_field(k);
const word items = body->fields();
TForm_string* s;
for (word j=0;j<items;j++)
{// Scans all body items to print, and append header items...
TForm_item& fi = body->field(j);
if (!fi.shown() || fi.is_section())
continue;
char align='\0';
if (fi.col_head()[0]=='@')
{
switch (fi.col_head()[1])
{
case 'C': // centered
case 'c':
align='c';
break;
case 'R': // right just
case 'r':
align='r';
break;
default: // left just
align='l';
break;
}
}
// Paragraph_string has as many items as lines needed...
TParagraph_string prompts(fi.col_head().mid(align ? 2:0),fi.width());
TString p;
for (int c=0;c < prompts.items(); c++)
{
p = prompts.get(c);
switch (align)
{
case 'c':
p.center_just(fi.width());
break;
case 'r':
p.right_just(fi.width());
break;
default:
break;
}
s = new TForm_string(header);
s->id() = -1;
s->set_x(fi.x());
s->y() = y+c;
s->set_prompt(p);
s->temp() = TRUE;
header->add_field(s);
}
}
return TRUE;
}
/*
void TForm::remove_temp_items(char sec, pagetype p)
{
TPrint_section* s = exist(sec,p);
if (s!=NULL)
{
const word items = s->fields();
for (word j=0;j<items; j++)
{
if (s->field(j).temp())
s->destroy_field(j,FALSE);
}
s->field_array().pack();
}
}
void TForm::put_examples(char sez, pagetype p)
{
TPrint_section* s = exist(sez,p);
if (s!=NULL)
{
const word items = s->fields();
for (word i=0;i<items;i++)
{
TForm_item& fi = s->field(i);
if (fi.fields()!=0) continue;
if (fi.memo())
fi.set(fi.memo_info());
else
if (fi.prompt().empty())
{
if (fi.class_name() == "DATA")
{
const TDate d(TODAY);
fi.set(d);
}
else
if (fi.class_name() == "NUMERO")
{
fi.set_prompt(fi.example());
fi.temp() = TRUE;
}
else
fi.set(fi.key());
}
}
}
}
void TForm::remove_examples(char sez, pagetype p)
{
TPrint_section* s = exist(sez,p);
if (s!=NULL)
{
const word items = s->fields();
for (word i=0;i<items;i++)
{
TForm_item& fi = s->field(i);
if (fi.fields()!=0) continue;
if (fi.memo())
fi.set("");
else
if (fi.class_name() == "NUMERO" && fi.temp())
{
fi.set_prompt("");
fi.temp() = FALSE;
}
}
}
}
*/
bool TForm::has_subsections()
{
const TPrint_section& b = section('B', odd_page);
return b.subsections() > 0 ;
}
// @doc EXTERNAL
// @mfunc Stampa gli items da <p form> a <p to>
//
// @rdesc Ritorna se ha effettuato correttamente la stampa
bool TForm::print(
long from, // @parm Primo item da stampare (default 0l)
long to) // @parm Ultimo da stampare (se <lt>0 stampa fino alla fine del file, default -1l)
// @comm Se i parametri di posizionamento sono settati e cosi' pure gli offset genera un <f error_box>.
{
_cur_form = this;
if ((_char_to_pos != '\0' || ((_ipx +_ipy+_fpx) != 0)) && // Se i parametri di posizionamento sono settati e
(_x != 0 || _y != 0)) // cosi' pure gli offset genera un errore.
{
error_box("Non e' possibile settare contemporaneamente gli offset"
" e i parametri di posizionamento del modulo.");
return FALSE;
}
TPrinter& pr = printer();
if (_frompage) pr.set_from_page(_frompage);
if (_topage) pr.set_to_page(_topage);
if (_char_to_pos != '\0' || (_ipx +_ipy+_fpx) != 0) // Effettua il posizionamento del form...
{
if (_arrange && pr.printtype() == winprinter)
arrange_form();
}
else
pr.set_offset(_y,_x);
pr.setheaderhandler(header_handler); // Setta handlers
pr.setfooterhandler(footer_handler);
if (!pr.is_generic())
{
for (pagetype t = odd_page; t <= last_page; t = pagetype(t+1))
{
if (height(t)> (word)pr.formlen())
{
TString s("La lunghezza totale della sezione ");
switch ( t )
{
case odd_page:
s << "standard"; break;
case even_page:
s << "pagine pari"; break;
case first_page:
s << "prima pagina"; break;
case last_page:
s << "ultima pagina"; break;
default:
break;
}
s << " eccede la lunghezza reale del foglio.";
message_box(s);
}
}
}
else
{
pr.formlen(height());
}
if (_fontsize != 0)
pr.set_char_size(_fontsize); // Set font name and size
if (_fontname.not_empty())
pr.set_fontname(_fontname); // according to current form
const bool was_open = pr.isopen();
set_last_page(FALSE); // non e' l'ultima pagina
set_background(1, TRUE);
if (!was_open && !pr.open())
return FALSE;
do_events();
long lastrec= records()-1;
if (to < 0) to = lastrec;
// controlla i casi di stampa
_first_eq_last=FALSE;
if (!fixed_pages() && !has_subsections() && set_body(1,FALSE) * word(to-from+1) <= pr.formlen()- set_header(1,FALSE) - set_footer(0,FALSE))
// tutta la stampa sta in una pagina
_first_eq_last=TRUE;
// if (to == lastrec) to--; // l'ultima pagina <20> gestita come caso particolare
bool ok = TRUE;
for (long i = from; i <= to && ok;)
{
if (pr.frozen())
break;
if (from < 0)
to = from;
else if (cursor())
{
*cursor()=i;
match_result();
}
if (pr.current_row() > pr.headersize()+1)
{
const word h = set_body(page(pr), FALSE);
if (h > pr.rows_left())
{
pr.formfeed();
// quanto resta da stampare sta nell'ultima pagina
if (!fixed_pages() && !has_subsections() && set_body(0,FALSE) * word(to-i+1) <= pr.formlen()- set_header(1,FALSE) - set_footer(0,FALSE))
{
while (i <= to && from >= 0) // stampa l'ultima pagina
{
set_last_page(TRUE);
set_background(0, TRUE);
set_header(0, TRUE);
if (cursor())
{
*cursor() = i;
set_body(0, TRUE);
}
i++;
}
break;
}
}
}
set_body(page(pr), TRUE);
if (cursor())
{
if (next_match_done())
i=cursor()->pos();
else
i++;
}
else
i++;
} // fine ciclo di stampa
while (fixed_pages() && page(pr) % _npages !=0)
{
pr.formfeed();
/*
static TPrintrow empty_line;
pr.print(empty_line);
*/
pr.skip(1); // No static when possible
}
if (from >= 0)
{
if (!_lastpage)
{
TPrint_section* last_foot = exist('F', last_page, FALSE);
if (last_foot != NULL)
{
const word lfh = last_foot->height();
const word left = pr.rows_left() + pr.footersize();
if (lfh > left) // Se l'ultimo footer e' troppo grande ...
pr.formfeed(); // Stampa il footer normale
pr.footerlen(lfh); // Fondamentale!
}
set_last_page(TRUE);
}
pr.formfeed();
}
if (!was_open)
pr.close();
pr.setheaderhandler(NULL);
pr.setfooterhandler(NULL);
return ok;
}
/*bool TForm::print(
long from, // @parm Primo item da stampare (default 0l)
long to) // @parm Ultimo da stampare (se <lt>0 stampa fino alla fine del file, default -1l)
// @comm Se i parametri di posizionamento sono settati e cosi' pure gli offset genera un <f error_box>.
{
_cur_form = this;
if ((_char_to_pos != '\0' || ((_ipx +_ipy+_fpx) != 0)) && // Se i parametri di posizionamento sono settati e
(_x != 0 || _y != 0)) // cosi' pure gli offset genera un errore.
{
error_box("Non e' possibile settare contemporaneamente gli offset"
" e i parametri di posizionamento del modulo.");
return FALSE;
}
TPrinter& pr = printer();
if (_frompage) pr.set_from_page(_frompage);
if (_topage) pr.set_to_page(_topage);
if (_char_to_pos != '\0' || (_ipx +_ipy+_fpx) != 0) // Effettua il posizionamento del form...
{
if (_arrange && pr.printtype() == winprinter)
arrange_form();
}
else
pr.set_offset(_y,_x);
pr.setheaderhandler(header_handler); // Setta handlers
pr.setfooterhandler(footer_handler);
if (!pr.is_generic())
{
for (pagetype t = odd_page; t <= last_page; t = pagetype(t+1))
{
if (height(t)> (word)pr.formlen())
{
TString s("La lunghezza totale della sezione ");
switch ( t )
{
case odd_page:
s << "standard"; break;
case even_page:
s << "pagine pari"; break;
case first_page:
s << "prima pagina"; break;
case last_page:
s << "ultima pagina"; break;
default:
break;
}
s << " eccede la lunghezza reale del foglio.";
message_box(s);
}
}
}
else
{
pr.formlen(height());
}
pr.set_char_size(_fontsize); // Set font name and size
pr.set_fontname(_fontname); // according to current form
const bool was_open = pr.isopen();
set_last_page(FALSE); // non e' l'ultima pagina
set_background(1, TRUE);
if (!was_open && !pr.open())
return FALSE;
do_events();
long lastrec= records()-1;
if (to < 0) to = lastrec;
if (to == lastrec) to--; // l'ultima pagina <20> gestita come caso particolare
bool ok = TRUE;
for (long i = from; i <= to && ok;)
{
if (from < 0) to = from;
else if (cursor())
*cursor()=i;
match_result();
if (pr.current_row() > pr.headersize()+1)
{
const word h = set_body(page(pr), FALSE);
if (h > pr.rows_left()) {
pr.formfeed();
}
}
set_body(page(pr), TRUE);
if (cursor()) {
if (next_match_done())
i=cursor()->pos();
else
i++;
}
}
if (i >= lastrec && from >= 0) // stampa l'ultima pagina (garantisce il footer diverso)
{
set_last_page(TRUE);
set_background(0, TRUE);
set_header(0, TRUE);
if (cursor() && i == lastrec) {
*cursor() = i;
set_body(0, TRUE);
}
pr.formfeed();
}
if (!was_open)
pr.close();
pr.setheaderhandler(NULL);
pr.setfooterhandler(NULL);
return ok;
} */
void TForm::print_section(ostream& out, char s) const
{
for (pagetype t = odd_page; t <= last_page; t = pagetype(t+1))
{
const TPrint_section* sec = ((TForm*)this)->exist(s, t);
if (sec && sec->ok() && !sec->temp())
{
const char* name;
switch (s)
{
case 'F':
name = "FOOTER"; break;
case 'G':
name = "GRAPHICS"; break;
case 'H':
name = "HEADER"; break;
default :
name = "BODY"; break;
}
out << "SECTION " << name;
out << *sec;
out << "END\n" << endl;
}
}
}
// funzione di validazione delle macro
bool TForm::validate(TForm_item &cf, TToken_string &s)
{
const TString code(s.get(0)); // prende il primo parametro, il codice del messaggio
TString valore;
if (code=="_ISAMREAD")
{
// lettura generica di un file del database
// sintassi: _ISAMREAD,<file>,<espressione input>[!<espressione input>!...],{<campo file>|<espressione output>[!<espressione output>!...]}
// dove: <file> <20> il numero logico del file o il nome della tabella
// <espressione input> <20> un'espressione del tipo <campo file>=<espressione campi form>
// <espressione campi form> <20> un'espressione di costanti numeriche, stringhe e valori di campi della form (indicati con il loro numero preceduto da #)
// <espressione output> <20> un'espressione del tipo <campo form o gruppo>=<campo file> (se <20> un gruppo deve essere seguito da @) oppure solo <campo file> (il campo della form <20> quello corrente)
int i, j, poseq, posrv, itms;
pagetype pt;
char sec;
TLocalisamfile *file;
TString f_code(s.get()); // prende il codice del file da leggere
if (atoi(f_code) != 0) file= new TLocalisamfile(atoi(f_code)); // se il codice <20> numerico allora <20> un file
else file= new TTable(f_code); // altrimenti <20> una tabella
file->zero(); // vuota il record corrente del file
TToken_string in(s.get(), '!');
for (i=0; i<in.items(); i++)
{ // scansione sugli elementi dell'input
TString curr(in.get(i));
poseq= curr.find("=="); // divide la stringa corrente in lvalue e rvalue
if (poseq== -1)
{
poseq= curr.find('=');
if (poseq != -1) posrv= poseq+1;
}
else
posrv= poseq+2;
TString fld(curr.left(poseq)); // preleva il nome del campo del file alla sinistra dell'uguale
TString expr(curr.mid(posrv)); // preleva l'espressione di assegnamento alla destra dell'uguale
TExpression rval(expr, _strexpr);
for (j=0; j<rval.numvar(); j++)
{ // scansione delle variabili dell'espressione di rvalue
TString var= rval.varname(j);
if (var[0]=='#') var.ltrim(1); // rimuove dalla stringa il primo carattere
TForm_item &fi= cf.find_field(var);
rval.setvar(j, fi.get()); // il valore corrente del campo viene settato nell'espressione
}
file->put(fld, rval.as_string()); // scrive il risultato dell'espressione nel campo del file
}
if (file->read()== NOERR)
{ // tenta una lettura del file
TToken_string out(s.get(), '!');
for (i=0; i<out.items(); i++)
{ // scansione sugli elementi dell'output
TString curr(out.get(i));
poseq= curr.find("=="); // divide la stringa corrente in lvalue e rvalue
if (poseq== -1)
{
poseq= curr.find('=');
if (poseq != -1) posrv= poseq+1;
}
else
posrv= poseq+2;
if (poseq== -1)
{
const TString &dat= file->get(curr); // preleva il nome del campo del file e lo legge dal record
cf.set(dat);
}
else
{
TString fld(curr.left(poseq)); // preleva il nome del campo del form alla sinistra dell'uguale
const TString &dat= file->get(curr.mid(posrv)); // preleva il nome del campo del file alla destra dell'uguale e lo legge dal record
if (fld[0]=='#') fld.ltrim(1);
if (fld.right(1)== "@")
{ // se c'<27> la a-commerciale <20> un gruppo
if (fld.find("->") != -1)
{ // se nel gruppo c'<27> la freccia si riferisce ad un'altra sezione
sec= fld[0];
if (fld[1] != '-') pt= char2page(fld[1]);
else pt= even_page;
itms= section(sec, pt).fields();
}
else
{ // altrimenti si riferisce alla sezione corrente
sec= cf.section().section_type();
pt= cf.section().page_type();
itms= cf.section().fields();
}
for (j=0; j<itms; j++)
{ // per ogni campo della sezione specificata (o sottointesa)...
TForm_item &fi= section(sec, pt).field(j);
fi.set(dat);
}
}
else
{
TForm_item &fi= cf.find_field(fld);
fi.set(dat);
}
}
}
}
delete file;
return TRUE;
// fine _ISAMREAD
}
if (code== "_TABLEREAD")
{
// lettura generica di un campo di una tabella
// sintassi: _TABLEREAD,<tabella>,<chiave>,<campo file>
// dove: <tabella> nome tabella da leggere
// <chiave> costante stringa o riferimento a campo della form (preceduto da '#') da usare come chiave di ricerca
// <campo file> identificativo del campo da leggere dalla tabella
TTable tab(s.get()); // prende il nome della tabella
tab.zero(); // vuota il record corrente della tabella
TString in(s.get()); // prende il valore o il campo da usare come codice di ricerca
if (in[0]== '#')
{
in.ltrim(1);
TForm_item &fi= cf.find_field(in);
in= fi.get();
}
tab.put("CODTAB", in); // setta la chiave nella tabella
if (tab.read()== NOERR)
{
const TString &fld= s.get(); // prende il nome del campo da leggere...
valore = tab.get(fld);
cf.set(valore);
}
return TRUE;
} // fine _TABLEREAD
if (code== "_ALIGN")
{
// allineamento della posizione di un campo rispetto ad un altro
// sintassi: _ALIGN,<campo form>[,<allineamento>][,<allineamento>...]
// dove: <campo form> <20> il campo della form (preceduto da '#') da cui prendere l'allineamento
// <allineamento> <20> uno dei seguenti valori:
// TOP allinea sulla riga d'inizio
// MIDDLE allinea al centro (effettivo)
// BOTTOM allinea sulla riga di fine (effettiva, non preimpostata)
// LEFT allinea sulla colonna d'inizio
// RIGHT allinea sulla colonna di fine
TString in(s.get());
if (in[0]== '#') in.ltrim(1);
TForm_item &fi= cf.find_field(in);
int i= 2;
for (const char * cmd = s.get(); cmd != NULL; cmd = s.get())
{ // Calcola la nuova posizione
TString align(cmd);
if (align[0]=='!')
align.ltrim(1);
if (align== "TOP") cf.y()= fi.y();
else
if (align== "MIDDLE") cf.y()= fi.y()+ fi.effective_height()/2;
else
if (align== "BOTTOM") cf.y()= fi.y()+ (fi.effective_height() ? fi.effective_height()-1 : 0);
else
if (align== "LEFT") cf.set_x(fi.x());
else
if (align== "RIGHT") cf.set_x(fi.x()+ fi.width());
}
// altrimenti stampa la stringa cosi' com'e'
return TRUE;
} // fine _ALIGN
if (code== "_PAGENO") // Messaggio per stampare il numero di pagina corrente
{
TString16 pg; pg << int(printer().getcurrentpage() );
cf.set(pg);
return TRUE;
}
if (code== "_TODAY")// Messaggio per stampare la data di oggi
{
TString16 dt(TDate(TODAY).string());
cf.set(dt);
return TRUE;
}
if (code== "_NUMEXPR" || code== "_STREXPR")
{
// Messaggio per la valutazione di espressioni numeriche e stringhe
int comma = s.find(',');
TExpression rval(s.mid(comma+1),code[1]=='N' ? _numexpr:_strexpr,TRUE);
cf.section().eval_expr(rval);
if (!rval.error())
cf.set(rval.as_string());
return TRUE;
}
if (code== "_DITTA")
{
// lettura dei dati della ditta
// sintassi: _DITTA,{<campo relazione>|<macro>}
// dove: <campo relazione> <20> un riferimento alla relazione di gestione dei dati della ditta (es. 113@->DENCOM <20> la denominazione del comune di residenza della ditta)
// <macro> <20> uno delle macro seguenti:
// !RAGSOC ragione sociale
// !IND indirizzo (fiscale se c'<27>, oppure di residenza)
// !NUM numero civico (fiscale se c'<27>, oppure di residenza)
// !CAP CAP (fiscale se c'<27>, oppure di residenza)
// !COM comune (fiscale se c'<27>, oppure di residenza)
// !PROV provincia (fiscale se c'<27>, oppure di residenza)
// !IVA partita iva
// !CF codice fiscale
// !TEL numero di telefono (con prefisso)
// !FAX numero di fax (con prefisso)
// !REGSOC numero di registrazione presso il Tribunale
// !CCIAA numero di registrazione presso la camera di commercio
// nota: la relazione della ditta <20> cos<6F> strutturata:
// %NDITTE (9) Dati ditte
// + %ANAGR (6) Anagrafica generale (indirizzo, ecc.)
// + %COMUNI (113@) Comune di residenza
// + %COMUNI (213@) Comune di residenza fiscale
TLocalisamfile firm(LF_NDITTE);
TLocalisamfile anag(LF_ANAG);
firm.put("CODDITTA",main_app().get_firm());
firm.read();
anag.put("TIPOA",firm.get("TIPOA"));
anag.put("CODANAGR",firm.get("CODANAGR"));
anag.read();
TString in(s.get());
if (in[0]=='!') {
in.ltrim(1);
bool _fisc= anag.get("INDRF").not_empty();
if (in=="RAGSOC")
valore = anag.get("RAGSOC");
if (in=="IND") {
if (_fisc)
valore = anag.get("INDRF");
else
valore = anag.get("INDRES");
}
if (in=="NUM") {
if (_fisc)
valore = anag.get("CIVRF");
else
valore = anag.get("CIVRES");
}
if (in=="CAP") {
if (_fisc)
valore = anag.get("CAPRF");
else
valore = anag.get("CAPRES");
}
/*if (in=="COM") {
if (_fisc)
valore = _firmrel.lfile(-213).get("DENCOM");
else
valore = _firmrel.lfile(-113).get("DENCOM");
}
if (in=="PROV") {
if (_fisc)
valore = _firmrel.lfile(-213).get("PROVCOM");
else
valore = _firmrel.lfile(-113).get("PROVCOM");
}*/
if (in=="IVA")
valore = anag.get("PAIV");
if (in=="CF")
valore = anag.get("COFI");
if (in=="TEL") {
valore = anag.get("PTEL");
valore << "/" << anag.get("TEL");
}
if (in=="FAX") {
valore = anag.get("PFAX");
valore << "/" << anag.get("FAX");
}
/*if (in=="REGSOC") {
valore = _firmrel[LF_UNLOC].get("REGTRIB");
valore << " Vol. " << _firmrel[LF_UNLOC].get("VOLTRIB");
valore << " Fasc. " << _firmrel[LF_UNLOC].get("FASCTRIB");
}
if (in=="CCIAA") {
valore = _firmrel[LF_UNLOC].get("NUMCCIAA");
valore << " del " << _firmrel[LF_UNLOC].get("DATAICCIAA");
} */
} else {
TFieldref fref(s.get(), 0);
valore = fref.read(anag.curr());
}
cf.set(valore);
return TRUE;
}
return TRUE;
}
void TForm::print_on(ostream& out) const
{
if (relation())
{
out << *relation() << "\nEND" << endl;
print_description(out);
}
print_general(out);
print_section(out, 'G');
print_section(out, 'H');
print_section(out, 'B');
print_section(out, 'F');
out << "END" << endl;
}
word TForm::height(word page)
{
const pagetype t = (page == 1) ? first_page : ((page & 0x1) ? odd_page : even_page);
word h = 0;
if (_back.items() == 0)
{
if (_head.items() && exist('H', t) != NULL)
h += section('H', page).height();
if (_body.items() && exist('B', t) != NULL)
h += section('B', page).height();
if (_foot.items() && exist('F', t) != NULL)
h += section('F', page).height();
}
else
h = printer().formlen();
return h;
}
// @doc EXTERNAL
// @mfunc Legge un profilo
//
// @rdesc Ritorna se e' riuscito nell'operazione:
// @flag TRUE | E' riuscito a leggere il prfilo
// @flag FALSE | Non ha letto il profilo
bool TForm::read_profile()
// @comm Per la lettura del profilo procede leggendo prima la definizione del
// profilo base e successivamente le modifiche relative.
{
TLocalisamfile prof(LF_FORM);
TLocalisamfile rprof(LF_RFORM);
prof.zero();
prof.put("TIPOPROF",_name);
prof.put("CODPROF",_code);
if (prof.read(_isequal) == NOERR)
{
rprof.zero();
rprof.put("TIPOPROF", _name);
rprof.put("CODPROF", _code);
const TRectype filter(rprof.curr());
TString set("HGBF");
for (int err = rprof.read(_isgteq); err == NOERR && rprof.curr() == filter; err = rprof.next())
{
// controllo lingua per codici profilo
char cl = rprof.curr().get("CODPROF").right(1)[0];
char cp = _code.right(1)[0];
// stop se il codice letto e' di un profilo EC in lingua e
// il corrente e' ec non in lingua
if (!isdigit(cl) && cl != cp) break;
const TString& s = rprof.get("SEZ");
const char sec = s[0];
if (set.find(sec)<0) continue; // Se non fa parte di una sezione standard la salta
const pagetype pt = char2page(s[1]);
const short id = rprof.get_int("ID");
if (id == 0)
{
TPrint_section& se = section(sec, pt);
se.read_from(rprof.curr());
}
else
{
TForm_item& item = find_field(sec, pt, id);
item.read_from(rprof.curr());
}
}
if (_code.not_empty()&& !_isnew)
{
_x = prof.get_int("OFFX");
_y = prof.get_int("OFFY");
_fontname = prof.get("FONTNAME");
_fontsize = prof.get_int("FONTSIZE");
_char_to_pos = prof.get("CTP")[0];
_ipx = prof.get_int("IPX");
_ipy = prof.get_int("IPY");
_fpx = prof.get_int("FPX");
set_fincatura(prof.get("GRID"));
}
}
return TRUE;
}
bool TForm::write_profile()
{
const char sechar[4] = { 'B', 'F', 'G', 'H' };
get_compulsory_specials();
TLocalisamfile form(LF_FORM);
form.zero();
form.put("TIPOPROF",_name);
form.put("CODPROF",_code);
if (form.read(_isequal,_lock) == NOERR)
{
if (_dirty)
{
form.put("OFFY",_y);
form.put("OFFX",_x);
form.put("FONTNAME",_fontname);
form.put("FONTSIZE",_fontsize);
form.put("CTP",_char_to_pos);
form.put("IPX", _ipx);
form.put("IPY", _ipy);
form.put("FPX", _fpx);
form.put("GRID", _fink);
form.rewrite();
_dirty=FALSE;
}
}
TLocalisamfile rform(LF_RFORM);
TRectype& cur = rform.curr();
int err = NOERR;
for (int sn = 0; sn < 4 && err == NOERR; sn++) // For each section
{
const char sc = sechar[sn];
for (pagetype pt = odd_page; pt <= last_page; pt = pagetype(pt+1)) // For each section type
{
TPrint_section* sec = exist(sc, pt);
if (sec != NULL && sec->dirty())
{
const char codsez[3] = { sc, pt+'0', '\0' };
cur.zero();
cur.put("TIPOPROF", name());
cur.put("CODPROF", code());
cur.put("SEZ", codsez);
sec->print_on(cur);
sec->set_dirty(FALSE);
err = _isnew ? rform.write() : rform.rewrite();
if (err != NOERR)
err = _isnew ? rform.rewrite() : rform.write();
for (word i = 0; i < sec->fields() && err == NOERR; i++)
{
TForm_item& fi = sec->field(i);
if (fi.dirty())
{
fi.print_on(cur);
err = _isnew ? rform.write() : rform.rewrite();
if (err != NOERR)
err = _isnew ? rform.rewrite() : rform.write();
fi.set_dirty(FALSE);
}
}
}
}
}
form.reread(_unlock);
if (err != NOERR)
return error_box("Errore di salvataggio profilo: %d", err);
return TRUE;
}
void TForm::init()
{
_npages=0;
_relation= NULL;
_cursor= NULL;
_rel_desc= NULL;
_isnew= FALSE;
_fontname= "";
_fontsize= 0;
_x= 0;
_y= 0;
_char_to_pos= '\0';
_ipx= 0;
_ipy= 0;
_fpx= 0;
_arrange= TRUE;
set_fincatura("+++++++++-|");
set_fink_mode(TRUE);
_dirty= FALSE;
_msg_add_enabled = TRUE;
_magic_currency = FALSE;
_exchange = NULL;
}
// @doc EXTERNAL
// @mfunc Carica il form dal file specificato
void TForm::read(
const char* name, // @parm Nome del profilo di stampa da leggere
const char* code, // @parm Codice del profilo di stampa da leggere
int lev, // @parm Permessi di stampa
const char* desc) // @parm Descrizione del formato da leggere
{
_name= name;
_code= code;
_editlevel= lev;
_desc= desc;
if (_code.not_empty())
{
// extract base form name
TLocalisamfile forms(LF_FORM);
forms.zero();
forms.put("TIPOPROF", _name);
forms.put("CODPROF", _code);
_isnew = forms.read() != NOERR;
if (_isnew)
{
// create new form
forms.put("TIPOPROF", _name);
forms.put("CODPROF", _code);
forms.put("DESC", _desc);
forms.put("OFFY",_y);
forms.put("OFFX",_x);
forms.put("FONTNAME",_fontname);
forms.put("FONTSIZE",_fontsize);
forms.put("CTP", _char_to_pos);
forms.put("IPX", _ipx);
forms.put("IPY", _ipy);
forms.put("FPX", _fpx);
forms.put("GRID", _fink);
forms.write();
}
else
if (forms.status() == NOERR)
{
_desc = forms.get("DESC");
if (desc && *desc && _desc != desc ) // Controlla se la descrizione e' diversa, in questo caso l'aggiorna
{
forms.reread(_lock);
forms.put("DESC",desc);
forms.rewrite();
}
}
}
// read base form
TFilename n(_name); n.ext("frm");
n.custom_path();
if (!n.exist())
fatal_box("Il form '%s' non esiste.",(const char*)n);
TScanner scanner(n);
bool ok = TRUE;
if (scanner.popkey() == "US") // Parse relation
{
ok = parse_use(scanner);
while (ok && scanner.popkey() == "JO" || scanner.key() == "SO")
{
if (scanner.key() == "JO")
ok = parse_join(scanner);
else // join a sorted file
{
ok= parse_sortedjoin(scanner);
}
}
parse_description(scanner); // Parse description
}
else scanner.push();
if (ok) parse_general(scanner); // Parse general
while (ok)
{
if (scanner.popkey() != "SE") // SECTION or END
break;
const char sec = scanner.popkey()[0]; // Section name (GRAPH, HEAD, BODY, FOOT)
const pagetype p = char2page(scanner.popkey()[0]); // Section type (odd, even, first, last)
TPrint_section* ps = exist(sec, p, TRUE); // Create section
ok = ps->parse(scanner); // Parse section
}
if (_code.not_empty())
read_profile(); // read from LF_RFORM file
set_compulsory_specials();
TPrinter& pr = printer();
pr.set_offset(_y,_x);
if (_fontname.not_empty())
{
pr.set_char_size(_fontsize);
pr.set_fontname(_fontname);
}
else
{
_fontname = pr.fontname();
_fontsize = pr.get_char_size();
}
set_fink_mode(TRUE);
}
void TForm::set_compulsory_specials()
{
const char sechar[3] = { 'B', 'F', 'H' };
for (int sn = 0; sn < 3; sn++)
{
const char sc = sechar[sn];
for (pagetype pt = odd_page; pt <= last_page; pt = pagetype(pt+1))
{
const TPrint_section* sec = exist(sc, pt);
if (sec != NULL && sec->columnwise())
{
const word fields = sec->fields();
for (word i = 0; i < fields; i++)
{
TForm_item& fi = sec->field(i);
if (fi.special_items() > 0)
{
fi.set_col_head(fi.get_special_value("INTESTAZIONE"));
fi.ofs() = (short)atoi(fi.get_special_value("OFFSET"));
const TString& fnk = fi.get_special_value("FINCATURA");
if (fnk.not_empty())
{
fi.set_finkl(fnk[0]!='X'); // !finkl significa fincatura abilitata
fi.set_finkr(fnk[1]!='X'); // !finkr significa fincatura abilitata
}
}
}
}
}
}
}
void TForm::get_compulsory_specials()
{
const char sechar[3] = { 'B', 'F', 'H' };
for (int sn = 0; sn < 3; sn++)
{
const char sc = sechar[sn];
for (pagetype pt = odd_page; pt <= last_page; pt = pagetype(pt+1))
{
TPrint_section* sec = exist(sc, pt);
if (sec != NULL)
{
const word fields = sec->fields();
const bool col_wise = sec->columnwise();
for (word i = 0; col_wise && i < fields; i++)
{
TForm_item& fi = sec->field(i);
if (fi.special_items()>0)
{
fi.set_special_value("INTESTAZIONE", fi.col_head());
fi.set_special_value("OFFSET", format("%d",fi.ofs()));
TString fnk(fi.finkl()? " " : "X");
fnk << (fi.finkr() ? " " : "X");
fi.set_special_value("FINCATURA",fnk);
}
}
}
}
}
}
void TForm::set_fincatura(const char* s)
{
_fink = s; _fink.cut(11);
printer().set_fincatura(_fink);
}
void TForm::set_fink_mode(bool f)
{
printer().set_fink_mode(f);
}
bool TForm::get_fink_mode()
{
return printer().get_fink_mode();
}
// @cmember Indica se ignorare il prossimo skip del ciclo sul file
void TForm::match_result(int file,int val)
{
if (file==0)
file=cursor()->file().num();
if (val <0)
_skip_info.destroy(file);
else
{
TForm_skip_info info;
if (next_match_done(file))
info._match_number=((TForm_skip_info &)_skip_info[file])._match_number;
if (val)
info._match_number++;
info._match_result= val != 0;
_skip_info.add(info,file);
}
}
// @cmember Indica se ignorare (default) o non ignorare il prossimo skip del ciclo sul file
bool TForm::last_match_result(int file)
{
if (file==0)
file=cursor()->file().num();
if (next_match_done(file))
return ((TForm_skip_info &)_skip_info[file])._match_result;
return fatal_box("Tryed to get result of a never executed skip in file %d",file);
}
// @mfunc Memorizza l'avvenuto next_match sul file passato
bool TForm::next_match_done(int file)
{
if (file==0)
file=cursor()->file().num();
return _skip_info.objptr(file)!=NULL;
}
// @mfunc Indica l'avvenuto next_match sul file passato
int TForm::matches_done(int file)
{
if (file==0)
file=cursor()->file().num();
if (next_match_done(file))
return ((TForm_skip_info &)_skip_info[file])._match_number;
return 0;
}
void TForm::set_output_exchange(const char* codval, real exchange, exchange_type et)
{
if (_exchange == NULL)
_exchange = new TExchange;
_exchange->set(codval, exchange, et);
}
TForm::TForm()
{
init();
_frompage=_topage=0;
_magic_currency = FALSE;
}
TForm::TForm(const char* name, const char* code, int lev, const char* desc)
{
init();
read(name, code, lev, desc);
_frompage=_topage=0;
_magic_currency = FALSE;
}
TForm::~TForm()
{
if (_cursor)
{
delete _cursor;
delete _relation;
if (_rel_desc)
delete _rel_desc;
}
if (_exchange)
delete _exchange;
}