#include #include #include #include #include #include #include #include #include "..\ba\ba2100.h" static TForm* _form = NULL; static TForm& form() { CHECK(_form, "Can't print NULL form"); return *_form; } /////////////////////////////////////////////////////////// // TForm_flags /////////////////////////////////////////////////////////// struct TForm_flags : public TObject { bool automagic : 1; bool enabled : 1; bool shown : 1; protected: void print_on(ostream& out) const; public: TForm_flags(); void print_on(TMask& m); void read_from(const TMask& m); bool update(const char* s); }; TForm_flags::TForm_flags() { automagic = FALSE; shown = enabled = TRUE; } bool TForm_flags::update(const char* s) { for (; *s; s++) switch(toupper(*s)) { case 'A': automagic = TRUE; break; case 'D': enabled = FALSE; break; case 'H': shown = FALSE; break; default : error_box("Unknown form item flag '%c'", *s); break; } return TRUE; } void TForm_flags::print_on(ostream& out) const { TString16 s; if (automagic) s << "A"; if (!enabled) s << "D"; if (!shown) s << "H"; if (s.not_empty()) out << " FLAGS \"" << s << '"' << endl; } void TForm_flags::print_on(TMask& m) { m.set(F_DISABLED, enabled ? " " : "X"); m.set(F_HIDDEN, shown ? " " : "X"); m.set(F_AUTOMAGIC, automagic ? "X" : " "); } void TForm_flags::read_from(const TMask& m) { shown = !m.get_bool(F_HIDDEN); enabled = !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, _height; TString _prompt; virtual void print_on(ostream& out) const; virtual void print_body(ostream& out) const; int width() const { return _width; } int height() const { return _height; } bool shown() const { return _flag.shown; } bool hidden() const { return !_flag.shown; } bool enabled() const { return _flag.enabled; } bool disabled() const { return !_flag.enabled; } 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(); virtual void print_on(TMask& m); virtual void read_from(const TMask& m); bool edit(TMask& m); TPrint_section* section() const { return _section; } bool in_group(byte g) const { return g == 0 || _group[g]; } const TString& key() const { return _desc; } void print_on(TToken_string& row) const; void show(bool on = TRUE) { _flag.shown = on; } void hide() { show(FALSE); } void enable(bool on = TRUE); void disable() { enable(FALSE); } TForm_item(TPrint_section* section); virtual ~TForm_item() {} }; TForm_item::TForm_item(TPrint_section* section) : _section(section), _x(-1), _y(-1), _width(0), _height(0) {} bool TForm_item::parse_head(TScanner& scanner) { _width = scanner.integer(); if (_width) _height = scanner.integer(); return TRUE; } void TForm_item::print_on(ostream& out) const { out << class_name(); 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 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") { TFixed_string 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; } 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; } void TForm_item::enable(bool on) { _flag.enabled = on; show(on); } 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") { TString80 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] == '"') { TString80 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) { TToken_string& messaggio = message(num); if (messaggio.empty()) return FALSE; TToken_string msg(16, ','); for (const char* m = messaggio.get(0); m; m = messaggio.get()) { msg = m; const TString16 cmd = msg.get(); // Get command const word id = msg.get_int(); // Get destination group // Send the message to all fields with the given group for (word i = 0; i < section()->fields(); i++) { TForm_item& des = section()->field(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::print_on(TToken_string& row) const { row = class_name(); row.add(_y); row.add(_x); const long fu = _group.first_one(); if (fu > 0) row.add(fu); else row.add(" "); row.add(key()); } void TForm_item::print_on(TMask& m) { 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); m.set(F_HEIGHT, _height); _flag.print_on(m); for (int g = 1; g <= 12; g++) m.set(F_GROUP+g, _group[g] ? "X" : " "); } void TForm_item::read_from(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)); _height = atoi(m.get(F_HEIGHT)); _flag.read_from(m); _group.reset(); for (int g = 1; g <= 12; g++) _group.set(g, m.get_bool(F_GROUP+g)); } bool TForm_item::edit(TMask& m) { m.reset(); if (m.insert_mode()) m.enable(F_CLASS); else print_on(m); const bool dirty = (m.run() == K_ENTER) && m.dirty(); if (m.insert_mode()) m.disable(F_CLASS); else if (dirty) read_from(m); return dirty; } /////////////////////////////////////////////////////////// // TForm_string /////////////////////////////////////////////////////////// class TForm_string : public TForm_item { TString _str, _picture; TArray _field; protected: virtual const char* class_name() const { return "STRINGA"; } virtual void print_body(ostream& out) const; virtual void print_on(TMask& m); virtual void read_from(const TMask& m); virtual bool parse_item(TScanner&); virtual bool read(); 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[i]; } void put_paragraph(const char* s); public: TForm_string(TPrint_section* section) : TForm_item(section) {} virtual ~TForm_string() {} }; 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::print_on(TMask& m) { TForm_item::print_on(m); for (int i = 0; i < 2; i++) if (i < _field.items()) { TString80 f; f << field(i); m.set(i == 0 ? F_FIELD : F_FIELD2, f); } m.set(F_PICTURE, _picture); } void TForm_string::read_from(const TMask& m) { TForm_item::read_from(m); _picture = m.get(F_PICTURE); for (int i = 0; i < 2; i++) { const TString& f = m.get(i == 0 ? F_FIELD : F_FIELD2); if (f.not_empty()) _field.add(new TFieldref(f, 0), i); else _field.destroy(i); } } 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 (enabled() && _field.items()) { 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 (height() > 1) { TParagraph_string p(s, width()); int i = _prompt.not_empty() ? 1 : 0; for (; (s = p.get()) != NULL && i < height(); 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()) { TString80 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 "NUMERO"; } virtual bool parse_head(TScanner& scanner); virtual bool update(); int decimals() const { return height(); } public: TForm_number(TPrint_section* section) : TForm_string(section) {} virtual ~TForm_number() {} }; bool TForm_number::parse_head(TScanner& scanner) { _width = 0; _height = scanner.integer(); return TRUE; } bool TForm_number::update() { TForm_item::update(); if (read()) { const char* s = get(); real n(s); n.round(decimals()); 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 "DATA"; } virtual bool read(); virtual bool set(const char*); bool set(const TDate& d); public: TForm_date(TPrint_section* section); virtual ~TForm_date() {} }; TForm_date::TForm_date(TPrint_section* section) : TForm_string(section) {} bool TForm_date::read() { bool ok = TForm_string::read(); if ((!ok || !get()[0]) && automagic()) { set(main_app().printer().getdate()); ok = TRUE; } return ok; } bool TForm_date::set(const char* s) { const TDate d(s); TForm_string::set(d.string((width() == 8) ? 2 : 4)); return TRUE; } bool TForm_date::set(const TDate& d) { TForm_string::set(d.string((width() == 8) ? 2 : 4)); return TRUE; } /////////////////////////////////////////////////////////// // 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: TForm_list(TPrint_section* section); virtual ~TForm_list() {} }; 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()); TString m(80); while (scanner.popkey() == "ME") { 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); _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) { 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 parse_head(TScanner&) { return TRUE; } virtual bool update() { return TRUE; } public: TForm_group(TPrint_section* section) : TForm_item(section) {}; virtual ~TForm_group() {} }; /////////////////////////////////////////////////////////// // TPrint_section /////////////////////////////////////////////////////////// TMask* TPrint_section::_msk = NULL; TPrint_section::TPrint_section(TForm* f) : _height(0), _form(f) {} TPrint_section::~TPrint_section() { if (_msk) { delete _msk; _msk = NULL; } } const TPrint_section& TPrint_section::copy(const TPrint_section& ps) { _item = ps._item; _height = ps._height; return ps; } 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(const TString& s) { if (s == "ST") return new TForm_string(this); if (s == "NU") return new TForm_number(this); if (s == "DA") return new TForm_date(this); if (s == "LI") return new TForm_list(this); if (s == "GR") return new TForm_group(this); CHECKS(NULL, "Campo di stampa sconosciuto: ", (const char*)s); return NULL; } TForm_item* TPrint_section::parse_item(TScanner& scanner) { return parse_item(scanner.key()); } bool TPrint_section::parse(TScanner& scanner) { _height = scanner.integer(); while (scanner.popkey() != "EN") { TForm_item *fi = parse_item(scanner); if (!fi) return FALSE; if (fi->parse(scanner)) _item.add(fi); else return FALSE; } return TRUE; } void TPrint_section::reset() { for (word i = 0; i < height(); i++) row(i).reset(); } bool TPrint_section::update() { bool ok = TRUE; reset(); for (word i = 0; i < fields(); i++) { const bool esito = field(i).update(); if (!esito) ok = FALSE; } #ifdef DBG const int l = last()-1; if (l >= (int)_height) warning_box("Sezione troppo lunga: %d > %d", l+1, _height); #endif return ok; } bool TPrint_section::edit(const char* title) { TMask m("ba2100s"); m.set_caption(title); m.set(F_HEIGHT, _height); if (m.run() == K_ESC) return FALSE; bool dirty = m.dirty() != 0; if (dirty) _height = m.get_int(F_HEIGHT); TArray_sheet a(-1, -1, 0, 0, title, "Tipo@8|Riga|Col.|Gr.|Descrizione@40", 0xE); for (word i = 0; i < fields(); i++) { TToken_string* s = new TToken_string(128); field(i).print_on(*s); a.add(s); } KEY k; do { k = a.run(); i = (word)a.selected(); if (k == K_ENTER || k == K_INS && _msk == NULL) _msk = new TMask("ba2100f"); switch(k) { case K_ENTER: _msk->set_mode(MODE_MOD); if (field(i).edit(*_msk)) { field(i).print_on(a.row(i)); dirty = TRUE; } break; case K_INS: { _msk->set_mode(MODE_INS); TForm_string dummy(this); if (dummy.edit(*_msk)) { const TString& c = _msk->get(F_CLASS).left(2); TForm_item* item = parse_item(c); item->read_from(*_msk); _item.insert(item, i); TToken_string s(128); item->print_on(s); a.insert(s, i); dirty = TRUE; } } break; case K_DEL: if (yesno_box("Confermare la cancellazione")) { _item.destroy(i, TRUE); a.destroy(i); dirty = TRUE; } break; default: break; } } while (k != K_ESC); return dirty; } void TPrint_section::print_on(ostream& out) const { out << ' ' << _height << endl; for(word i = 0; i < fields(); i++) out << field(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(); _relation = new TRelation(tab); } int key = 1; if (scanner.popkey() == "KE") key = scanner.integer(); else scanner.push(); _cursor = new TCursor(_relation, "", key); 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(); 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(); 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; } TPrint_section* TForm::exist(char s, pagetype t, bool create) { TArray* a = NULL; switch (s) { case 'H': a = &_head; break; case 'F': a = &_foot; break; default: a = &_body; break; } TPrint_section* sec = (TPrint_section*)a->objptr(t); if (sec == NULL && create) { sec = new TPrint_section(this); a->add(sec, t); } return sec; } TPrint_section& TForm::section(char s, word p) { pagetype pos = odd_page; if (p == 0 && exist(s, last_page)) pos = last_page; if (p == 1 && exist(s, first_page)) pos = first_page; if (pos == 0 && (p & 0x1) == 0 && exist(s, even_page)) pos = even_page; TPrint_section* sec = exist(s, pos, TRUE); return *sec; } word TForm::set_header(word p, bool u) { TPrinter& printer = main_app().printer(); printer.resetheader(); TPrint_section& head = section('H', p); if (u) head.update(); else { head.reset(); printer.headerlen(head.height()); } for (word j = 0; j < head.height(); j++) printer.setheaderline(j, head.row(j)); return head.height(); } word TForm::set_body(word p, bool u) { TPrint_section& body = section('B', p); if (u) body.update(); else body.reset(); if (u) { TPrinter& printer = main_app().printer(); for (word j = 0; j < body.height(); j++) printer.print(body.row(j)); } return body.height(); } word TForm::set_footer(word p, bool u) { TPrinter& printer = main_app().printer(); printer.resetfooter(); TPrint_section& foot = section('F', p); if (u) foot.update(); else { foot.reset(); printer.footerlen(foot.height()); } for (word j = 0; j < foot.height(); j++) printer.setfooterline(j, foot.row(j)); return foot.height(); } void TForm::header_handler(TPrinter& p) { const word page = form().page(p); form().set_header(page, TRUE); form().set_footer(page, FALSE); } void TForm::footer_handler(TPrinter& p) { const word page = form().page(p); form().set_footer(page, TRUE); if (page) form().set_header(page+1, FALSE); } word TForm::page(const TPrinter& p) const { return _lastpage ? 0 : p.getcurrentpage(); } long TForm::records() const { const long r = _cursor ? _cursor->items() : 0; return r; } // Stampa gli items dal from a to // se to < 0 stampa fino alla fine del file bool TForm::print(long from, long to) { _form = this; // setta il form corrente _lastpage = FALSE; TPrinter& printer = main_app().printer(); printer.setheaderhandler(header_handler); printer.setfooterhandler(footer_handler); printer.formlen(height()); const bool was_open = printer.isopen(); if (!was_open && !printer.open()) return FALSE; if (to < 0) to = records()-1; bool ok = TRUE; for (long i = from; i <= to && ok; i++) { if (from < 0) to = from; else if (_cursor) *_cursor = i; const word h = set_body(page(printer), FALSE); if (h > printer.rows_left()) printer.formfeed(); set_body(page(printer), TRUE); } if (i > records()) { if (exist('H', last_page) || exist('B', last_page) || exist('F', last_page)) { _lastpage = TRUE; set_header(0, TRUE); set_body(0, TRUE); printer.formfeed(); } } if (!was_open) printer.close(); _form = NULL; // resetta form 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()) { const char* name = s == 'H' ? "HEADER" : (s == 'F' ? "FOOTER" : "BODY"); out << "SECTION " << name << ' ' << int(t); out << *sec; out << "END\n" << endl; } } } void TForm::print_on(ostream& out) const { if (relation()) out << *relation() << endl; print_section(out, 'H'); print_section(out, 'B'); print_section(out, 'F'); out << "END" << endl; } word TForm::height() { word h = 0; if (_head.items()) h += section('H', 1).height(); if (_body.items()) h += section('B', 1).height(); if (_foot.items()) h += section('F', 1).height(); return h; } TForm::TForm(const char* name) : _name(name), _relation(NULL), _cursor(NULL) { const CURSOR oldcur = get_cursor(TASK_WIN); set_cursor(TASK_WIN, CURSOR_WAIT); _name.ext("frm"); TScanner scanner(_name); bool ok = TRUE; if (scanner.popkey() == "US") { ok = parse_use(scanner); while (ok && scanner.popkey() == "JO") ok = parse_join(scanner); } while (ok) { scanner.popkey(); const char sec = toupper(scanner.key()[0]); if (sec <= ' ' || sec == 'E') break; const pagetype p = (pagetype)scanner.integer(); TPrint_section* ps = exist(sec, p, TRUE); ok = ps->parse(scanner); } set_cursor(TASK_WIN, oldcur); } TForm::~TForm() { if (_cursor) { delete _cursor; delete _relation; } }