#include #include #include #include #include #include #include #include #include /////////////////////////////////////////////////////////// // 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); val.strip("\""); 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 /////////////////////////////////////////////////////////// void TPrint_section::init(const char* name, TForm* f) { _name = name; _form = f; } TPrint_section::TPrint_section(const char* name, TForm* f) : _heigth(0) { init(name, 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 = main_app().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 = main_app().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 = main_app().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) { _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(); _head.init("HEADER", this); _body.init("BODY", this); _foot.init("FOOTER", this); 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; } }