campo-sirio/include/form.cpp

1064 lines
21 KiB
C++
Executable File

#include <ctype.h>
#include <stdlib.h>
#include <applicat.h>
#include <mask.h>
#include <form.h>
#include <relation.h>
#include <sheet.h>
#include <utility.h>
#include <bagn003.h>
///////////////////////////////////////////////////////////
// TForm_flags
///////////////////////////////////////////////////////////
struct TForm_flags : public TObject
{
bool automagic : 1;
bool disabled : 1;
bool hidden : 1;
protected:
void print_on(ostream& out) const;
public:
TForm_flags();
void to_mask(TMask& m) const;
void from_mask(const TMask& m);
bool update(const char* s);
};
TForm_flags::TForm_flags()
{
hidden = automagic = disabled = FALSE;
}
bool TForm_flags::update(const char* s)
{
for (; *s; s++) switch(toupper(*s))
{
case 'A': automagic = TRUE; break;
case 'D': disabled = TRUE; break;
case 'H': hidden = TRUE; break;
default : error_box("Unknown form item flag '%c'", *s); break;
}
return TRUE;
}
void TForm_flags::print_on(ostream& out) const
{
TString s(4);
if (automagic) s << "A";
if (disabled) s << "D";
if (hidden) s << "H";
if (s.not_empty()) out << " FLAGS \"" << s << '"' << endl;
}
void TForm_flags::to_mask(TMask& m) const
{
m.set(F_DISABLED, disabled ? "X" : " ");
m.set(F_HIDDEN, hidden ? "X" : " ");
m.set(F_AUTOMAGIC, automagic ? "X" : " ");
}
void TForm_flags::from_mask(const TMask& m)
{
hidden = m.get_bool(F_HIDDEN);
disabled = m.get_bool(F_DISABLED);
automagic = m.get_bool(F_AUTOMAGIC);
}
///////////////////////////////////////////////////////////
// TForm_item
///////////////////////////////////////////////////////////
class TForm_item : public TObject
{
TPrint_section* _section;
TString _desc;
TForm_flags _flag;
TBit_array _group;
TArray _message;
protected:
int _x, _y, _width, _heigth;
TString _prompt;
virtual void print_on(ostream& out) const;
virtual void print_body(ostream& out) const;
virtual void to_mask(TMask& m) const;
virtual void from_mask(const TMask& m);
int width() const { return _width; }
int heigth() const { return _heigth; }
bool hidden() const { return _flag.hidden; }
bool disabled() const { return _flag.disabled; }
bool automagic() const { return !_flag.automagic; }
virtual bool parse_head(TScanner&);
virtual bool parse_item(TScanner&);
virtual const char* get() const { return _prompt; }
virtual bool set(const char* s) { _prompt = s; return TRUE; }
TToken_string& message(int m = 0);
void send_message(const TString& cmd, TForm_item* dest) const;
bool do_message(int m = 0);
void string_at(int x, int y, const char* s);
public:
virtual bool parse(TScanner&);
virtual bool update();
bool edit(TMaskmode mode);
TPrint_section* section() const { return _section; }
bool in_group(byte g) const { return g == 0 || _group[g]; }
const TString& key() const { return _desc; }
void to_row(TToken_string& row) const;
void show(bool on = TRUE) { _flag.hidden = !on; }
void hide() { show(FALSE); }
void enable(bool on = TRUE);
void disable() { enable(FALSE); }
TForm_item(TPrint_section* section);
};
TForm_item::TForm_item(TPrint_section* section)
: _section(section), _x(-1), _y(-1), _width(0), _heigth(0)
{}
bool TForm_item::parse_head(TScanner& scanner)
{
_width = scanner.integer();
if (_width) _heigth = scanner.integer();
return TRUE;
}
void TForm_item::print_on(ostream& out) const
{
out << class_name();
if (_width > 0)
{
out << ' ' << _width;
if (_heigth > 0)
out << ' ' << _heigth;
}
out << "\nBEGIN\n";
print_body(out);
out << "END\n" << endl;
}
void TForm_item::print_body(ostream& out) const
{
if (_y >= 0)
out << " PROMPT " << _x << ' ' << _y << " \"" << _prompt << "\"\n";
if (_desc.not_empty())
out << " KEY \"" << _desc << "\"\n";
if (_group.ones())
out << " GROUP " << _group << "\n";
out << _flag;
if (_message.items() == 1)
{
const char* m = (TToken_string&)_message[0];
out << " MESSAGE " << m << endl;
}
}
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")
{
TString m(scanner.line());
m.strip_spaces();
message(0).add(m);
return TRUE;
}
if (scanner.key() == "KE")
{
_desc = scanner.string();
return TRUE;
}
if (scanner.key() == "GR")
{
_group.set(scanner.line());
return TRUE;
}
error_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 = error_box("Missing BEGIN in form item %s", (const char*)key());
while (ok && scanner.popkey() != "EN")
ok = parse_item(scanner);
return ok;
}
void TForm_item::enable(bool on)
{
_flag.disabled = !on;
if (on) show();
else hide();
}
void TForm_item::string_at(int x, int y, const char* s)
{
if (hidden()) return;
TPrintrow& row = _section->row(y-1); // Seleziona riga di stampa
if (_width > 0 && strlen(s) > (word)_width) // Tronca testo se necessario
{
strncpy(__tmp_string, s, width());
__tmp_string[width()] = '\0';
s = __tmp_string;
}
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;
}
void TForm_item::send_message(const TString& cmd, TForm_item* des) const
{
if (cmd == "ADD" || cmd == "SUM" || cmd == "INC")
{
const real n((cmd[0] != 'I') ? get() : "1.0");
real r(des->get());
r += n;
des->set(r.string());
} else
if (cmd == "COPY")
{
des->set(get());
} else
if (cmd == "APPEND")
{
TString val(80);
val = des->get();
if (val.not_empty()) val << ' ';
val << get();
des->set(val);
} 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 == "RESET")
{
des->set("");
} else
if (cmd[0] == '"')
{
TString val(&cmd[1]);
val.cut(val.len()-1);
des->set(val);
} else
error_box("Unknown message in item '%s': '%s'",
(const char*)key(), (const char*)cmd);
}
bool TForm_item::do_message(int num)
{
if (message(num).empty()) return FALSE;
TToken_string msg(16, ',');
TString cmd(8);
const char* m;
message(num).restart();
while ((m = message(num).get()) != NULL)
{
msg = m;
cmd = msg.get(); // Get command
TFixed_string str(msg.get());
const word id = atoi(str); // Get destination id
// Send the message to all fields with the given group
for (int i = 0; i < section()->items(); i++)
{
TForm_item* des = section()->item(i);
if (des->in_group(id))
send_message(cmd, des);
}
}
return TRUE;
}
bool TForm_item::update()
{
string_at(_x, _y, _prompt);
do_message();
return TRUE;
}
void TForm_item::to_row(TToken_string& row) const
{
row = class_name();
row.add(key());
}
void TForm_item::to_mask(TMask& m) const
{
m.set(F_CLASS, class_name());
m.set(F_KEY, key());
m.set(F_X, _x);
m.set(F_Y, _y);
m.set(F_PROMPT, _prompt);
m.set(F_WIDTH, _width);
_flag.to_mask(m);
TString g;
g << _group;
m.set(F_GROUP, g);
}
void TForm_item::from_mask(const TMask& m)
{
_desc = m.get(F_KEY);
_x = atoi(m.get(F_X));
_y = atoi(m.get(F_Y));
_prompt = m.get(F_PROMPT);
_width = atoi(m.get(F_WIDTH));
TString flag;
if (m.get(F_AUTOMAGIC) == "X") flag << "A";
if (m.get(F_HIDDEN) == "X") flag << "H";
_flag.update(flag);
}
bool TForm_item::edit(TMaskmode mode)
{
TMask m("bagn003", mode);
if (mode == MODE_INS)
{
m.enable(0);
m.show();
}
to_mask(m);
const bool dirty = (m.run() == K_ENTER) && m.dirty();
if (dirty) from_mask(m);
return dirty;
}
///////////////////////////////////////////////////////////
// TForm_string
///////////////////////////////////////////////////////////
class TForm_string : public TForm_item
{
TString _str, _picture;
TArray _field;
protected:
virtual const char* class_name() const { return "STRING"; }
virtual void print_body(ostream& out) const;
virtual void to_mask(TMask& m) const;
virtual void from_mask(const TMask& m);
virtual bool parse_item(TScanner&);
virtual bool update();
const char* get() const;
bool set(const char*);
const TString& picture() const { return _picture; }
TFieldref* field(int i) const { return (TFieldref*)_field.objptr(i); }
void put_paragraph(const char* s);
bool read();
public:
TForm_string(TPrint_section* section) : TForm_item(section) {}
};
bool TForm_string::parse_item(TScanner& scanner)
{
if (scanner.key() == "FI")
{
TFieldref* fr = new TFieldref(scanner.line(), 0);
_field.add(fr);
return TRUE;
}
if (scanner.key() == "PI")
{
_picture = scanner.string();
return TRUE;
}
return TForm_item::parse_item(scanner);
}
void TForm_string::print_body(ostream& out) const
{
TForm_item::print_body(out);
if (_picture.not_empty())
out << " PICTURE \"" << _picture << "\"" << endl;
for (int i = 0; i < _field.items(); i++)
out << " FIELD " << *field(i) << endl;
}
void TForm_string::to_mask(TMask& m) const
{
TForm_item::to_mask(m);
TString f(24); f << *field(0);
m.set(F_FIELD, f);
m.set(F_PICTURE, _picture);
}
void TForm_string::from_mask(const TMask& m)
{
TForm_item::from_mask(m);
_picture = m.get(F_PICTURE);
*field(0) = m.get(F_FIELD);
}
bool TForm_string::set(const char* s)
{
_str = s;
if (width()) _str.cut(width());
return TRUE;
}
const char* TForm_string::get() const
{ return _str; }
bool TForm_string::read()
{
if (_field.items() && !disabled())
{
const char* s = "";
for (int i = 0; i < _field.items(); i++)
{
s = field(i)->read(section()->form()->relation());
if (*s) break;
}
set(s);
return TRUE;
}
return FALSE;
}
void TForm_string::put_paragraph(const char* s)
{
if (hidden()) return;
if (heigth() > 1)
{
TParagraph_string p(s, width());
int i = _prompt.not_empty() ? 1 : 0;
for (; (s = p.get()) != NULL && i < heigth(); i++)
string_at(_x, _y+i, s);
}
else string_at(-1, _y, s);
}
bool TForm_string::update()
{
TForm_item::update();
if (read())
{
if (_picture.not_empty())
{
TString p;
p.picture(_picture, get());
put_paragraph(p);
} else put_paragraph(get());
}
return TRUE;
}
///////////////////////////////////////////////////////////
// TForm_number
///////////////////////////////////////////////////////////
class TForm_number : public TForm_string
{
protected:
virtual const char* class_name() const { return "NUMBER"; }
virtual bool parse_head(TScanner& scanner);
virtual bool update();
public:
TForm_number(TPrint_section* section) : TForm_string(section) {}
};
bool TForm_number::parse_head(TScanner& scanner)
{
_width = 0;
_heigth = scanner.integer();
return TRUE;
}
bool TForm_number::update()
{
TForm_item::update();
if (read())
{
real n(get());
n.round(heigth());
const char* s = n.string(picture());
put_paragraph(s);
}
return TRUE;
}
///////////////////////////////////////////////////////////
// TForm_date
///////////////////////////////////////////////////////////
class TForm_date : public TForm_string
{
protected:
virtual const char* class_name() const { return "DATE"; }
virtual bool set(const char*);
public:
TForm_date(TPrint_section* section);
};
TForm_date::TForm_date(TPrint_section* section)
: TForm_string(section)
{
if (automagic())
{
TDate oggi(TODAY);
set(oggi.string());
}
}
bool TForm_date::set(const char* s)
{
TDate d(s);
bool ok = d.ok();
if (ok)
ok = TForm_string::set(d.string((width() == 8) ? 2 : 4));
return ok;
}
///////////////////////////////////////////////////////////
// TForm_list
///////////////////////////////////////////////////////////
class TForm_list : public TForm_string
{
TToken_string _codes;
TToken_string _values;
protected:
virtual const char* class_name() const { return "LIST"; }
virtual bool parse_item(TScanner& scanner);
virtual void print_body(ostream& out) const;
virtual bool update();
public:
TForm_list(TPrint_section* section);
};
TForm_list::TForm_list(TPrint_section* section)
: TForm_string(section)
{}
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")
{
TString 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_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;
int pos = _codes.get_pos(get());
if (pos < 0)
{
TString k(_codes.get(0));
ok = error_box("Il campo '%s' non puo' valere '%s': assumo '%s'",
(const char*)key(), get(), (const char*)k);
set(k);
pos = 0;
}
do_message(pos);
if (!hidden())
{
if (_prompt.not_empty())
{
int found = -1;
for (int i = 0; found < pos && _prompt[i]; i++)
if (_prompt[i] != ' ') found++;
if (found == pos)
{
char c[2] = { _prompt[i], '\0' };
string_at(_x+i, _y, c);
}
else error_box("Non trovo l'elemento %d in '%s'", (const char*)_prompt);
}
else
{
const char* c = _values.get(pos);
if (c == NULL) c = get();
if (c) string_at(_x, _y, c);
}
}
return ok;
}
///////////////////////////////////////////////////////////
// TPrint_section
///////////////////////////////////////////////////////////
TPrint_section::TPrint_section(const char* name, TForm* f)
: _name(name), _heigth(0), _form(f)
{}
TPrintrow& TPrint_section::row(int num)
{
TPrintrow* pr = (TPrintrow*)objptr(num);
if (!pr)
{
pr = new TPrintrow;
add(pr, num);
}
return *pr;
}
TForm_item* TPrint_section::parse_item(TScanner& scanner)
{
if (scanner.key() == "ST")
return new TForm_string(this);
if (scanner.key() == "NU")
return new TForm_number(this);
if (scanner.key() == "DA")
return new TForm_date(this);
if (scanner.key() == "LI")
return new TForm_list(this);
error_box("Elemento sconosciuto nella sezione %s: %s",
(const char*)_name, (const char*)scanner.token());
return NULL;
}
bool TPrint_section::parse(TScanner& scanner)
{
_heigth = scanner.integer();
set_cursor(TASK_WIN, CURSOR_WAIT);
while (scanner.popkey() != "EN")
{
TForm_item *fi = parse_item(scanner);
if (!fi) return FALSE;
if (fi->parse(scanner))
_item.add(fi);
else
return FALSE;
}
set_cursor(TASK_WIN, CURSOR_ARROW);
return TRUE;
}
bool TPrint_section::update()
{
destroy();
const int last = _item.items();
bool ok = TRUE;
for (int i = 0; i < last; i++)
{
bool esito = ((TForm_item&)_item[i]).update();
if (!esito) ok = FALSE;
}
i = items();
if (i < _heigth) row(_heigth-1);
else if (i > _heigth)
ok = warning_box("Sezione %s troppo lunga: %d > %d",
(const char*)_name, i, _heigth);
return ok;
}
bool TPrint_section::edit(int mode)
{
TString title(40);
title = "Campi della sezione "; title << _name;
TArray_sheet a(-1, -1, 0, 0, title, "Tipo@6|Descrizione@40", 0x8);
for (int i = 0; i < items(); i++)
{
TToken_string s(64);
item(i)->to_row(s);
a.add(s);
}
bool dirty = FALSE;
while (a.run() == K_ENTER)
{
i = (int)a.selected();
const bool spork = item(i)->edit((TMaskmode)mode);
if (spork)
{
dirty = TRUE;
item(i)->to_row(a.row(i));
}
}
return dirty;
}
void TPrint_section::print_on(ostream& out) const
{
out << "\nPAGE " << _name << ' ' << _heigth << '\n' << endl;
for(int i = 0; i < items(); i++)
out << *item(i);
}
///////////////////////////////////////////////////////////
// TForm
///////////////////////////////////////////////////////////
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();
if (strlen(tab) > 4)
return error_box("'%s' non e' una tabella valida: %d", tab);
_relation = new TRelation(tab);
}
int key = 1;
if (scanner.popkey() == "KE")
{
key = scanner.integer();
if (key < 1)
{
error_box("Chiave non valida '%s': uso 1",
(const char*)scanner.token());
key = 1;
}
}
else scanner.push();
_cursor = new TCursor(_relation, "", key);
return TRUE;
}
bool TForm::parse_join(TScanner& scanner)
{
TString 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();
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())
error_box("JOIN senza espressioni INTO");
}
scanner.push();
if (isdigit(j[0]))
_relation->add(atoi(j), exp, key, to, alias); // join file
else
_relation->add(j, exp, key, to, alias); // join table
return TRUE;
}
bool TForm::set_header()
{
TPrinter& printer = MainApp()->printer();
printer.resetheader();
const bool ok = _head.update();
int last = _head.last();
for (int j = 0; j <= last; j++)
printer.setheaderline(j, _head.row(j));
return ok;
}
bool TForm::set_footer()
{
TPrinter& printer = MainApp()->printer();
printer.resetfooter();
const bool ok = _foot.update();
int last = _foot.last();
for (int j = 0; j <= last; j++)
printer.setfooterline(j, _foot.row(j));
return ok;
}
// Stampa gli items dal from a to
// se to < 0 stampa fino alla fine del file
bool TForm::print(long from, long to)
{
TPrinter& printer = MainApp()->printer();
const bool was_open = printer.isopen();
if (!was_open && !printer.open())
return FALSE;
if (to < 0) to = _cursor->items()-1;
bool ok = set_header() && set_footer();
for (long i = from; i <= to && ok; i++)
{
if (from < 0) to = from;
else *_cursor = i;
ok &= _body.update();
if (!ok) ok = yesno_box("Stampo ugualmente");
if (!ok) break;
const word last = _body.last()+1;
if (last < printer.rows() && last > printer.rows_left())
ok = printer.formfeed();
for (word j = 0; j < last && ok; j++)
ok = printer.print(_body.row(j));
}
if (!was_open)
printer.close();
return ok;
}
void TForm::print_on(ostream& out) const
{
out << *_cursor->relation() << endl;
if (_head.items()) out << _head;
if (_body.items()) out << _body;
if (_foot.items()) out << _foot;
out << "ENDPAGE" << endl;
}
bool TForm::edit(int mode, int section)
{
bool dirty = FALSE;
switch (section)
{
case 0: dirty = _head.edit(mode); break;
case 2: dirty = _foot.edit(mode); break;
default: dirty = _body.edit(mode); break;
}
if (dirty && yesno_box("Salvare le modifiche?"))
{
set_cursor(TASK_WIN, CURSOR_WAIT);
TFilename bak(_name); bak.ext("bak");
rename(_name, bak);
ofstream out(_name);
print_on(out);
set_cursor(TASK_WIN, CURSOR_ARROW);
}
return dirty;
}
TForm::TForm(const char* name)
: _name(name),
_head("HEADER", this), _body("BODY", this), _foot("FOOTER", this)
{
_name.ext("frm");
TScanner scanner(_name);
bool ok = FALSE;
if (scanner.popkey() == "US")
ok = parse_use(scanner);
CHECKS(ok, "Missing USE in form: ", name);
while (ok && scanner.popkey() == "JO")
ok = parse_join(scanner);
scanner.push();
while (scanner.popkey() == "PA")
{
scanner.pop();
if (scanner.token() == "HEADER") _head.parse(scanner); else
if (scanner.token() == "BODY") _body.parse(scanner); else
if (scanner.token() == "FOOTER") _foot.parse(scanner);
}
}
TForm::~TForm()
{
if (_cursor)
{
delete _cursor;
delete _relation;
}
}