#include #include #include #include #include #include #include #include #include #include "../mg/anamag.h" /////////////////////////////////////////////////////////// // TBrowse_button /////////////////////////////////////////////////////////// TBrowse_button::TBrowse_button(TEdit_field* f) : _fld(f) { } TBrowse_button::~TBrowse_button() { } // Certified 100% TEditable_field& TBrowse_button::field(short id) const { if (id > 0) { TMask_field& f = _fld->mask().field(id); CHECKD(f.is_editable(), "Can't use in a browse the field ", id); return (TEditable_field&)f; } return *_fld; } /////////////////////////////////////////////////////////// // TList_sheet /////////////////////////////////////////////////////////// // Certified 100% TList_sheet::TList_sheet(TEdit_field* f, const char* caption, const char* head) : TBrowse_button(f), _row(-1), _caption(caption), _head(head) { } // Certified 100% TList_sheet::~TList_sheet() { } // Certified 100% void TList_sheet::parse_input(TScanner& scanner) { _inp_id.add(scanner.pop()); } // Certified 100% void TList_sheet::parse_item(TScanner& scanner) { _data.add(new TToken_string(scanner.string())); } // Certified 100% void TList_sheet::parse_output(TScanner& scanner) { _out_id.add(scanner.pop()); } // il numero di riga selezionata int TList_sheet::do_input() { if (_inp_id.empty_items()) return -2; // List empty! _inp_id.restart(); TToken_string rowsel(80); for (const char* fld = _inp_id.get(); fld; fld = _inp_id.get()) { if (*fld == '"') { rowsel.add(fld+1); if (rowsel.not_empty()) rowsel.cut(rowsel.len()-1); } else { const short id = field().atodlg(fld); if (id > 0) { const TMask_field& f = field(id); if (f.class_id() == CLASS_ZOOM_FIELD) { const TZoom_field& z = (TZoom_field&)f; rowsel.add(z.get_first_line()); } else rowsel.add(f.get()); } else rowsel.add(""); } } TString fd, it; for (int i = 0 ; i < _data.items(); i++) { TToken_string& ts =_data.row(i); ts.restart(); const char * item; for (item = rowsel.get(0); item ; item = rowsel.get()) { it = item; it.trim(); fd = ts.get(); fd.trim(); if (fd != it) break; } if (!item) return i; } return -1; // Value not found! } // Certified 50% void TList_sheet::do_output(CheckTime t) { if (_row < 0 || t == FINAL_CHECK) return; _out_id.restart(); TToken_string& rowsel = _data.row(_row); rowsel.restart(); for (const char* fld = _out_id.get(); fld; fld = _out_id.get()) { const short id = field().atodlg(fld); TMask_field& f = field(id); const char* val = rowsel.get(); if (t != STARTING_CHECK || f.field() == NULL) { const bool hit = f.get() != val; f.set(val); if (hit && field().dlg() != id) { f.on_hit(); if (t == RUNNING_CHECK) f.check(); } } } } // Certified 100% KEY TList_sheet::run() { TArray_sheet sci(3, 3, -3, -3, _caption, _head); sci.rows_array() = _data; _row = do_input(); sci.select(_row); const KEY k = sci.run(); switch (k) { case K_ENTER: _row = (int)sci.selected(); do_output(); break; default: break; } return k; } // Certified 100% bool TList_sheet::check(CheckTime t) { _row = do_input(); bool passed = _row != -1; if (passed) do_output(t); else { switch(field().check_type()) { case CHECK_SEARCH: passed = true; break; default: break; } } return passed; } /////////////////////////////////////////////////////////// // TBrowse /////////////////////////////////////////////////////////// // Certified 100% TBrowse::TBrowse(TEdit_field* f, TRelation* r, int key, const char* filter) : TBrowse_button(f), _relation(r), _cursor(new TCursor (r, "", key)), _filter(filter), _secondary(false), _alt_browse(NULL), _custom_filter_handler(NULL) { custom_cursor(); } // Certified 100% TBrowse::TBrowse(TEdit_field* f, TCursor* c) : TBrowse_button(f), _relation(NULL), _cursor(c), _secondary(false), _alt_browse(NULL), _custom_filter_handler(NULL) { custom_cursor(); } // Certified 100% TBrowse::~TBrowse() { // Se e' stato usato il primo costruttore devo distruggere la relazione ed il cursore if (_relation) { delete _cursor; delete _relation; } if (_alt_browse) delete _alt_browse; } static bool descr_filter_handler(TMask_field& f, KEY k) { if (k == K_SPACE) { TString expr; if (!f.get().empty()) // Filtro attivato! { const short id = f.dlg()-500; TString e = f.mask().get(id); // Espressione regolare e.strip("\"'"); // Tolgo caratteri che potrebbero dare problemi if (!e.blank()) expr << "(DESCR+DESCRAGG)" << "?=\"" << e << '"'; if (expr.empty()) f.reset(); } ((TBrowse_sheet&) f.mask()).add_custom_filter(expr); } return true; } void TBrowse::custom_cursor() { TRelation * relation = _relation == NULL ? _cursor->relation() : _relation; int logicnum = relation->lfile().num(); switch(logicnum) { case LF_ANAMAG : if (_cursor->key() == 2 && ini_get_bool(CONFIG_DITTA, "Main", "CUSTOM_SEARCH_" TOSTRING(LF_ANAMAG), false, 2)) { delete _cursor; _cursor = new TSorted_cursor(relation, ANAMAG_DESCR "|" ANAMAG_DESCRAGG "[1,50]", "", 2); set_custom_filter_handler(descr_filter_handler); } break; default: break; } } void TBrowse::custom_display() { switch(_cursor->file().num()) { case LF_ANAMAG: if (_cursor->key() == 2 && ini_get_bool(CONFIG_DITTA, "Main", "CUSTOM_SEARCH_" TOSTRING(LF_ANAMAG), false, 2)) { TToken_string & it = (TToken_string &) items(); if (it.find(ANAMAG_DESCRAGG) < 0) { const char * s = it.get(0); for (int i = 0; s && *s; s = it.get(++i)) if (strcmp(s, ANAMAG_DESCR) == 0) { add_display_field("Descrizione aggiuntiva@50", ANAMAG_DESCRAGG, i + 1); break; } } } break; case LF_TABMOD: { _cursor->file().zero(); // Azzera il record corrente in modo da impostare "MOD" const TString& mod =_cursor->curr().get("MOD"); const word cod = dongle().module_name2code(mod); field().set_module(cod); } break; default: break; } } // Certified 100% void TBrowse::parse_display(TScanner& scanner) { const char* s = scanner.string(); _head.add(dictionary_translate_header(s)); s = scanner.line(); _items.add(s); } void TBrowse::parse_input(TScanner& scanner) { const char* s = scanner.pop(); _inp_fn.add(s); s = scanner.pop(); if (*s == '"') // Constant string { scanner.push(); TString& str = scanner.line(); _inp_id.add(str); } else // Field on the mask { CHECKS(_inp_id.get_pos(s) < 0, "Duplicate input field ", s); _inp_id.add(s); if (scanner.popkey() == "SE") _inp_id << '@'; // Special FILTERing field else scanner.push(); } } void TBrowse::parse_output(TScanner& scanner) { const char* s = scanner.pop(); #ifdef DBG field().atodlg(s); #endif _out_id.add(s); s = scanner.pop(); _out_fn.add(s); _secondary = false; } bool TBrowse::parse_copy(const TString& what, const TBrowse& b) { const bool all = what == "AL"; if (all || what == "US") { set_insert(b.get_insert()); _filter = b.get_filter(); if (!field().has_warning() && b.field().has_warning()) field().set_warning(b.field().get_warning()); if (!all) return true; } if (all || what == "IN") { _inp_id = b._inp_id; _inp_fn = b._inp_fn; if (!all) return true; } if (all || what == "DI") { _head = b._head; _items = b._items; if (!all) return true; } if (all || what == "OU") { _out_id = b._out_id; _out_fn = b._out_fn; _secondary = b.field().has_check(); } return true; } void TBrowse::parse_join(TScanner& scanner) { TString80 j(scanner.pop()); // File or table CHECKS(_relation, "Can't join to NULL relation ", (const char*)j); int to; if (scanner.popkey() == "TO") // TO keyword { const char* t = scanner.pop(); to = name2log(t); } else { to = 0; // _relation->lfile()->num(); 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(); } } scanner.push(); #ifdef DBG if (exp.empty()) yesnofatal_box("JOIN senza espressioni INTO"); #endif if (isdigit(j[0])) _relation->add(atoi(j), exp, key, to, alias); // join file else { #ifdef DBG if (j.len() > 4) yesnofatal_box("'%s' non e' una tabella valida: %d", (const char*)j); else #endif _relation->add(j, exp, key, to, alias); // join table } } void TBrowse::parse_insert(TScanner& scanner) { const TString& key = scanner.popkey(); _insert.cut(0); if (key != "NO") { _insert << key[0] << scanner.line(); _insert.trim(); } } // Ritorna il numero di inputs senza contare quelli che funzionano solo da filtro int TBrowse::input_fields() { int inp = 0; for (const char* fld = _inp_id.get(0); fld; fld = _inp_id.get()) { if (*fld != '"' && strchr(fld, '@') == NULL) { TMask_field& f = field(field().atodlg(fld)); if (f.active() && f.is_editable()) inp++; } } return inp; } const char* TBrowse::get_input_fields() const { return _inp_id; } const char* TBrowse::get_input_field_names() const { return _inp_fn; } void TBrowse::add_input_field(const char * id, const char * name, const int pos, bool select) { TString strid(id) ; if (select) strid << '@'; if (pos < 0 || pos >= _items.items()) { _inp_id.add(strid); _inp_fn.add(name); } else { _inp_id.insert_at(strid, pos); _inp_fn.insert_at(name, pos); } } void TBrowse::remove_display_field(const int pos) { if (pos < 0) { _head.cut(0); _items.cut(0); } else { _head.destroy(pos); _items.destroy(pos); } } void TBrowse::copy_input(const TBrowse * b) { if (b) { _inp_id = b->_inp_id; _inp_fn = b->_inp_fn; } } void TBrowse::copy_display(const TBrowse* b) { if (b) b->get_display_fields(_head, _items); } void TBrowse::copy_output(const TBrowse * b) { if (b) { _out_id = b->_out_id; _out_fn = b->_out_fn; } } void TBrowse::add_display_field(const char * hd, const char * name, const int pos) { if (pos < 0 || pos >= _items.items()) { _head.add(dictionary_translate_header(hd)); _items.add(name); } else { _head.insert_at(dictionary_translate_header(hd), pos); _items.insert_at(name, pos); } } void TBrowse::remove_input_field(const int pos) { if (pos < 0) { _inp_id.cut(0); _inp_fn.cut(0); } else { _inp_id.destroy(pos); _inp_fn.destroy(pos); } } void TBrowse::add_output_field(const char * id, const char * name, const int pos) { if (pos < 0 || pos >= _items.items()) { _out_id.add(id); _out_fn.add(name); } else { _out_id.insert_at(id, pos); _out_fn.insert_at(name, pos); } } void TBrowse::remove_output_field(const int pos) { if (pos < 0) { _out_id.cut(0); _out_fn.cut(0); } else { _out_id.destroy(pos); _out_fn.destroy(pos); } } const char* TBrowse::get_output_fields() const { return _out_id; } const char* TBrowse::get_output_field_names() const { return _out_fn; } // @doc INTERNAL // @mfunc Ritorna il numero di campi non vuoti e non filtrati // // @rdesc Numero di campi non vuoti e non filtrati int TBrowse::do_input( bool filter) // @parm Indica se effettuare il filtro sulla selezione // @comm Questa funzione serve ai { int ne = 0; if (_inp_id.empty()) return ne; _cursor->file(0).zero(); // was cur.zero() che non va bene per le tabelle di modulo TRectype& cur = _cursor->curr(); TRectype filtrec(cur); _inp_id.restart(); _inp_fn.restart(); TString val; // Value to output bool tofilter = false; for (const char* fld = _inp_id.get(); fld; fld = _inp_id.get()) { const TFieldref fldref(_inp_fn.get(), 0); // Output field if (*fld == '"') { val = (fld+1); if (val.not_empty()) val.rtrim(1); tofilter = filter; } else { const TMask_field* campf = NULL; if (*fld == '-') { TSheet_field* sheet = field().mask().get_sheet(); if (sheet != NULL) { const short id = atoi(fld+1); campf = &sheet->mask().field(id); } } else { const short id = field().atodlg(fld); campf = &field(id); } if (campf != NULL) { const TMask_field& f = *campf; val = f.get(); switch (f.class_id()) { case CLASS_REAL_FIELD: // Cerco di allineare correttamente i campi interi salvati parzialmente su codtab if (fldref.to() > 1 && f.size() > 1 && val.full() && ((TReal_field&)f).decimals() == 0 && fldref.name() == "CODTAB") { const int len = fldref.len(cur); if (f.size() == len && val.len() < len) val.right_just(len); } break; case CLASS_DATE_FIELD: if (f.right_justified()) { const TDate d(val); val = d.string(ANSI); } break; default: break; } const bool filter_flag = strchr(fld, '@') != NULL; tofilter = filter && filter_flag; if (f.is_edit() && val.not_empty() && !filter_flag) ne++; // Increment not empty fields count } } fldref.write(val, *_cursor->relation()); if (tofilter) { const int len = fldref.len(cur); if (val.len() < len && cur.type(fldref.name()) == _alfafld) val.rpad(len, '~'); fldref.write(val, filtrec); } } if (!filter) return ne; TString work(_filter.size()); bool filter_update = false; for (int i = 0; _filter[i]; i++) { if (_filter[i] == '"') { do { work << _filter[i++]; } while (_filter[i] && _filter[i] != '"'); work << '"'; if (!_filter[i]) break; } else if (_filter[i] == '#') { if (_filter[++i] == '-') { TString val; TSheet_field* sheet = field().mask().get_sheet(); if (sheet != NULL) { const short id = atoi(&_filter[++i]); val = sheet->mask().field(id).get(); } work << '"' << val << '"'; } else work << '"' << field(atoi(&_filter[i])).get() << '"'; while (isspace(_filter[i])) i++; while (isdigit(_filter[i])) i++; i--; } else { work << _filter[i]; if (_filter[i] == '-' && _filter[i + 1] == '>') filter_update = true; } } _cursor->relation()->mask2rel(field().mask()); _cursor->setfilter(work, filter_update); _cursor->setregion(filtrec, filtrec); return ne; } static TBit_array s_checked; static short s_checking = 0; void TBrowse::do_output(CheckTime t) { if (t == FINAL_CHECK) return; const bool master = s_checking == 0; if (master) { s_checking = field().dlg(); s_checked.reset(); // Rendo intoccabili i campi del MIO output for (const char* fld = _out_id.get(0); fld && *fld; fld = _out_id.get()) { const short id = field().atodlg(fld); s_checked.set(id); } } TString sum; TToken_string flds(24, '+'); const TRelation& relation = *_cursor->relation(); TBit_array spotted; _out_fn.restart(); const char* fld; for (fld = _out_id.get(0); fld && *fld; fld = _out_id.get()) { const short id = field().atodlg(fld); TMask_field& f = field(id); flds = _out_fn.get(); bool do_that = t != STARTING_CHECK || f.field() == NULL || (f.mask().mode() == MODE_INS && !f.in_key(0)); if (do_that && main_app().class_id() == CLASS_RELATION_APPLICATION) { // Considera a parte l'inizializzazione delle transazioni! // Non sovrascrivere con degli output campi che potrebbero essere riempiti dal .ini if (!f.empty() && f.field() != NULL) { const TMask& m = f.mask(); if (!m.is_running() && m.get_sheet() == NULL) // Maschera principale chiusa { const TRelation_application& ra = (const TRelation_application&)main_app(); if (ra.is_transaction()) do_that = false; } } } if (do_that) { sum.cut(0); for(const char* fr = flds.get(0); fr; fr = flds.get()) { if (*fr == '"') { sum << (fr+1); sum.rtrim(1); } else { const TFieldref fld(fr, 0); sum << fld.read(relation); } } bool hit = false; if (master) { f.set(sum); hit = id != s_checking; // Il mio handler viene fatto nella on_key } else { if (!s_checked[id]) { f.set(sum); s_checked.set(id); hit = true; } } spotted.set(id, hit); } } for (fld = _out_id.get(0); fld && *fld; fld = _out_id.get()) { const short id = field().atodlg(fld); if (spotted[id]) { TMask_field& f = field(id); f.check(); f.on_hit(); } } if (master) s_checking = 0; } void TBrowse::do_clear(CheckTime t) { const bool master = s_checking == 0; if (master) { s_checking = field().dlg(); s_checked.reset(); // Rendo intoccabili i campi del MIO input for (const char* fld = _inp_id.get(0); fld && *fld; fld = _inp_id.get()) { if (isdigit(*fld)) { const short id = field().atodlg(fld); s_checked.set(id); } } } for (TString16 fld = _out_id.get(0); fld.not_empty(); fld = _out_id.get()) { const short id = field().atodlg(fld); TMask_field& f = field(atoi(fld)); if (f.field() == NULL && field().dlg() != id && !s_checked[id] && _inp_id.get_pos(fld) < 0) { f.reset(); s_checked.set(id); f.on_hit(); f.check(t); } } if (master) s_checking = 0; } bool TBrowse::do_link(bool insert) { bool ok = false; TString app; if (_insert.starts_with("MTB", true)) _cursor->file().get_relapp(app); else app = _insert.mid(1); if (app.find('#') >= 0) { const TString w(app); app = ""; for (const char* f = w; *f; f++) { if (*f == '#') { const int id = atoi(++f); app << field(id).get(); while (isspace(*f)) ++f; while (isdigit(*f)) ++f; if (*f) app << ' ' << *f; else break; } else app << *f; } } TFilename msg; msg.temp("msg"); app << " /i" << msg; if (insert) { TConfig ini(msg, "Transaction"); ini.set("Action", TRANSACTION_RUN); } else { TConfig ini(msg, "Transaction"); ini.set("Action", TRANSACTION_LINK); TString8 paragraph; paragraph << _cursor->file().num(); ini.set_paragraph(paragraph); // Uso sempre la chiave 1 per collegarmi agli altri programmi const TRelation& rel = *_cursor->relation(); const RecDes& recd = rel.curr().rec_des(); // Descrizione del record della testata const KeyDes& kd = recd.Ky[0]; // Elenco dei campi della chiave 1 TString inp_val; for (int i = 0; i < kd.NkFields; i++) { const int nf = kd.FieldSeq[i] % MaxFields; const RecFieldDes& rf = recd.Fd[nf]; const TFieldref fldref(rf.Name, 0); inp_val = fldref.read(rel); fldref.write(ini, paragraph, inp_val); } } TExternal_app a(app); a.run(); field().mask().set_focus(); if (msg.not_empty()) { TConfig ini(msg, "Transaction"); _rec = ini.get_long("Record"); if (_rec > 0 || !insert) // Modifica o cancellazione _cursor->update(); // Forza ricalcolo cursore if (_rec >= 0) { _cursor->file().readat(_rec); ok = _cursor->ok(); if (ok) { rec_cache(_cursor->file().num()).notify_change(); // Svuota eventule cache do_output(); } } ::remove(msg); } return ok; } TToken_string& TBrowse::create_siblings(TToken_string& siblings) const { siblings = ""; // Azzera la lista dei campi associati TBit_array key(4); // Elenco delle chiavi gia' utilizzate key.set(_cursor->key()); TString fn; // Nome campo // Scorre la lista dei campi di output int n = 0; TToken_string& outid = (TToken_string&)_out_id; for (const char* i = outid.get(0); i; i = outid.get(), n++) { const short id = field().atodlg(i); const TEditable_field& f = field(id); if (!f.active() || !f.is_edit()) // Scarta i campi non editabili continue; const TEdit_field& e = (const TEdit_field&)f; const TBrowse* b = e.browse(); if (b == NULL) continue; // Scarta i campi senza ricerca const TCursor* c = b->cursor(); // Considera ricerche sullo stesso file ma con chiave diversa if (c->file().num() == _cursor->file().num() && (key[c->key()] == false || id == field().dlg())) { _out_fn.get(n, fn); // Legge nome del campo su file int pos = ((TToken_string&)_items).get_pos(fn); // Determina header corrispondente if (pos < 0) // Se non lo trova identico ... { const int q = fn.find('['); if (q > 0) { fn.cut(q); pos = ((TToken_string&)_items).get_pos(fn); // ... ritenta senza parentesi } } if (pos >= 0) { siblings.add(id); TString80 h; _head.get(pos, h); siblings.add(h); const int et = siblings.find('@'); if (et > 0) siblings.cut(et); key.set(c->key()); // Marca la chiave come usata } } } return siblings; } KEY TBrowse::run() { const TString& val = field().get(); if (val.starts_with("*")) { TFuzzy_browse fb(&field(), cursor()->key()); const KEY k = fb.run(); if (k == K_ENTER) { do_input(true); _cursor->read(_isgteq); do_output(); } return k; } else if (val.starts_with("%") && _alt_browse) { const KEY k = _alt_browse->run(); if (k == K_ENTER) { do_input(true); _cursor->read(_isgteq); do_output(); } return k; } begin_wait(); do_input(true); _cursor->read(_isgteq); TString caption = _cursor->file().description(); if (caption.blank()) caption = TR("Selezione"); KEY k = K_ESC; long selected = 0; TToken_string siblings, vals; create_siblings(siblings); { byte buttons = 0; if (_insert.not_empty()) { // Mette il bottone di gestione, a meno che ... if (_cursor->items() == 0) buttons = 2; // Non mette il bottone collega se non ci sono elementi else buttons = 3; if (_insert[0] == 'M' || _insert[0] == 'R') { const TString& maskname = field().mask().source_file(); if (maskname.mid(2,2).compare("tb", 2, true) == 0 && field().in_key(0)) { const char* tabname = _cursor->file().name(); if (maskname.mid(4, 3).compare(tabname, 3, true) == 0) buttons = 0; } } } for (const char* i = _inp_id.get(0); i; i = _inp_id.get()) { if (*i != '\0' && *i != '"' && strchr(i, '@') == NULL) { const short id = field().atodlg(i); const TEditable_field& f = field(id); if (f.active() && f.is_editable()) { vals.add(i); vals.add(f.get()); vals.add((int)f.dirty()); } } } end_wait(); TBrowse_sheet s(_cursor, _items, caption, _head, buttons, field(), siblings, _custom_filter_handler); k = s.run(); selected = s.selected(); } switch (k) { case K_ESC: case K_QUIT: break; case K_CTRL+'G': *_cursor = selected; k = do_link(false) ? K_ENTER : K_ESC; break; case K_INS: k = do_link(true) ? K_ENTER : K_ESC; break; case K_ENTER: *_cursor = selected; do_output(); break; default: { for (const char* i = vals.get(0); i && *i; i = vals.get()) { const short id = field().atodlg(i); TEditable_field& f = field(id); f.set(vals.get()); f.set_dirty(vals.get_int()); } } if (k >= K_CTRL) // Scatta la ricerca su di una chiave alternativa { TMask& m = field().mask(); const int tag = k - K_CTRL - K_F1; const short id = siblings.get_int(tag * 2); TEdit_field& ef = m.efield(id); ef.set_focus(); k = K_F9; if (m.is_running()) m.send_key(k, id, &ef); //m.send_key(k, id); } break; } return k; } void TBrowse::set_cursor(TCursor* c) { if (_cursor != NULL) delete _cursor; _cursor = c ; } bool TBrowse::check(CheckTime t) { bool passed = true; if (_secondary == true && t != RUNNING_CHECK) return true; CheckType chk = field().check_type(); // Se ho la ricerca alternativa ed il campo comincia per % ... if (t == RUNNING_CHECK) { const TString& magic = field().get(); if (magic[0] == '*' && cursor()->key() > 1) { TFuzzy_browse fb(&field(), cursor()->key()); if (fb.check(t)) { if (chk == CHECK_NONE) // Se trovo la chiave forzo gli output (RAGSOC in righe prima nota) chk = CHECK_NORMAL; } else return false; } else if (magic[0] =='%' && _alt_browse != NULL) { if (_alt_browse->check(t)) { if (chk == CHECK_NONE) // Se trovo la chiave forzo gli output (RAGSOC in righe prima nota) chk = CHECK_NORMAL; } else return false; } } if (chk != CHECK_NONE) { const TMaskmode mode = (TMaskmode)field().mask().mode(); if (chk == CHECK_REQUIRED && (t == STARTING_CHECK || mode == MODE_QUERY)) chk = CHECK_NORMAL; const int ne = do_input(true); if (ne || chk == CHECK_REQUIRED) { passed = _cursor->test() == NOERR; if (t != FINAL_CHECK) { if (passed) { _cursor->repos(); do_output(t); if (t == STARTING_CHECK && field().dirty() > 1) field().set_dirty(true); } else { if (chk == CHECK_SEARCH) { passed = true; } else { do_clear(t); if (!field().mask().query_mode() && field().check_enabled()) field().set_dirty(3); } } } else { if (chk == CHECK_SEARCH) passed = true; } } else { if (chk == CHECK_SEARCH) passed = true; else { if (t != FINAL_CHECK) do_clear(t); } } } return passed; } bool TBrowse::empty_check() { if (field().mask().query_mode() || field().check_type() != CHECK_REQUIRED) return true; else return do_input() > 0; } bool TBrowse::set_alt_browse(int altkey) { if (_alt_browse) delete _alt_browse; if (altkey > 2) _alt_browse = new TAlternative_browse(&field(), altkey); return altkey > 2; } /////////////////////////////////////////////////////////// // TFile_select /////////////////////////////////////////////////////////// TFile_select::TFile_select(TEdit_field* ef, const char* filter) : TBrowse_button(ef), _filter(filter) { } void TFile_select::parse_input(TScanner& scanner) { scanner.pop(); } void TFile_select::parse_output(TScanner& scanner) { scanner.pop(); } KEY TFile_select::run() { TFilename path; path = field().get(); if (path.full() && _filter.find('.') > 0 && !_filter.ends_with(".*")) path.ext(_filter.ext()); FILE_SPEC fs; xvt_fsys_convert_str_to_fspec(path, &fs); bool good = xvt_dm_post_file_open(&fs, field().prompt()) == FL_OK; if (good) { xvt_fsys_convert_fspec_to_str(&fs, path.get_buffer(), path.size()); good = _filter.blank() || xvt_str_match(path.name(), _filter, false); if (good) field().set(path); else field().error_box(FR("Il nome del file non corrisponde a %s"), _filter.get_buffer()); } return good ? K_ENTER : K_ESC; } bool TFile_select::check(CheckTime ct) { const TFilename name = field().get(); if (ct != STARTING_CHECK && name.empty() && field().check_type() == CHECK_REQUIRED) return false; bool ok = _filter.empty() || xvt_str_match(name, _filter, false); if (ok && field().roman()) // Must exist ok = name.exist(); return ok; } /////////////////////////////////////////////////////////// // TDir_select /////////////////////////////////////////////////////////// TDir_select::TDir_select(TEdit_field* ef) : TBrowse_button(ef) { } void TDir_select::parse_input(TScanner& scanner) { scanner.pop(); } void TDir_select::parse_output(TScanner& scanner) { scanner.pop(); } KEY TDir_select::run() { DIRECTORY savedir; xvt_fsys_get_dir(&savedir); DIRECTORY dir; xvt_fsys_convert_str_to_dir(field().get(), &dir); bool good = xvt_dm_post_dir_sel(&dir) == FL_OK; xvt_fsys_set_dir(&savedir); if (good) { TFilename path; xvt_fsys_convert_dir_to_str(&dir, path.get_buffer(), path.size()); field().set(path); } return good ? K_ENTER : K_ESC; } bool TDir_select::check(CheckTime ct) { const TFilename name = field().get(); if (ct != STARTING_CHECK && name.empty() && field().check_type() == CHECK_REQUIRED) return false; bool ok = true; if (field().roman()) // Must exist ok = name.exist(); return ok; } /////////////////////////////////////////////////////////// // TProfile_select /////////////////////////////////////////////////////////// TProfile_select::TProfile_select(TEdit_field* ef) : TBrowse_button(ef) { } void TProfile_select::parse_input(TScanner& scanner) { scanner.pop(); } void TProfile_select::parse_output(TScanner& scanner) { scanner.pop(); } HIDDEN int get_profile_desc(TConfig& cfg, void* jolly) { const int num = atoi(cfg.get_paragraph()); if (num > 0) { TString_array& p = *(TString_array*)jolly; TToken_string* str = new TToken_string; str->format("%4d", num); str->add(cfg.get("Description")); p.add(str); } return false; } int TProfile_select::get_descriptions(TString_array& a) const { TFilename profname; field().mask().make_profile_name(profname); TConfig prof(profname); a.destroy(); prof.for_each_paragraph(get_profile_desc, &a); a.sort(); return a.items(); } KEY TProfile_select::run() { TArray_sheet p(3, 3, -3, -3, TR("Profili"), HR("Codice@6R|Descrizione@60"), 0x6, 2); const short id = DLG_USER+1; TEdit_field& prompt = p.add_string(id, 0, PR("Salva con nome "), 1, 0, 60); p.add_button(DLG_SAVEREC, PR("~Registra"), K_CTRL+'r', TOOL_SAVEREC); prompt.set(field().get()); TMask& m = field().mask(); TFilename profname; m.make_profile_name(profname); bool running = true; KEY key; while (running) { p.destroy(); TString_array& a = p.rows_array(); get_descriptions(a); p.field(DLG_SAVEREC).enable(a.items()>0); FOR_EACH_ARRAY_ROW_BACK(a, r, row) if (field().get() == row->get(1)) break; if (r) p.select(r); key = p.run(); switch(key) { case K_ENTER: { const int num = p.row().get_int(0); TString16 para; para << m.load_profile(num); prompt.set(p.row().get(1)); running = false; } break; case K_CTRL+'r': { const TString& name = p.get(id); FOR_EACH_ARRAY_ROW_BACK(a, r, row) if (r != p.selected() && name == row->get(1)) break; if (r < 0) { const int num = p.row().get_int(0); m.save_profile(num, name); running = false; } else error_box("Esiste gia' un profilo di nome\n%s", (const char*)name); } break; case K_INS: { const TString& name = p.get(id); if (!name.blank()) { FOR_EACH_ARRAY_ROW_BACK(a, r, row) if (name == row->get(1)) break; if (r < 0) { TString16 para; para << m.save_profile(-1, name); field().set(name); running = false; } else error_box("Esiste gia' un profilo di nome\n%s", (const char*)name); } else error_box("E' necessario dare un nome al profilo"); } break; case K_DEL: { TString16 para; para << p.row().get_int(0); const TString desc = p.row().get(1); TConfig prof(profname, para); if (yesno_box("Confermare la cancellazione del profilo %s\n%s", (const char*)para, (const char*)desc)) prof.remove_all(); } break; default: running = false; break; } } field().set(prompt.get()); return key; } bool TProfile_select::check(CheckTime ct) { switch (ct) { case STARTING_CHECK: { TMask& m = field().mask(); TFilename name; m.make_profile_name(name); TString16 para; para << m.load_profile(); TConfig ini(name, para); field().set(ini.get("Description")); } break; case RUNNING_CHECK: if (!field().empty()) { const TString& name = field().get(); TString_array a; get_descriptions(a); FOR_EACH_ARRAY_ROW_BACK(a, r, row) { if (name == row->get(1)) { field().mask().load_profile(row->get_int(0)); break; } } if (r < 0) return field().error_box("Profilo inesistente"); } break; case FINAL_CHECK: if (!field().active()) { TMask& m = field().mask(); m.save_profile(); } break; default: break; } return true; } /////////////////////////////////////////////////////////// // TReport_select /////////////////////////////////////////////////////////// TReport_select::TReport_select(TEdit_field* ef, const char* classe) : TBrowse_button(ef), _classe(classe) { } void TReport_select::parse_input(TScanner& scanner) { scanner.pop(); } void TReport_select::parse_output(TScanner& scanner) { scanner.pop(); } KEY TReport_select::run() { TFilename path = field().get(); if (select_custom_file(path, "rep", _classe)) { path = path.name(); path.ext(""); field().set(path); } return path.not_empty() ? K_ENTER : K_ESC; } bool TReport_select::check(CheckTime ct) { TFilename name = field().get(); if (ct != STARTING_CHECK && name.empty() && field().check_type() == CHECK_REQUIRED) return false; bool ok = true; if (field().roman()) // Must exist ok = name.custom_path(); return ok; } /////////////////////////////////////////////////////////// // TFuzzy_browse /////////////////////////////////////////////////////////// static TFuzzy_browse* _curr_fbrowse = NULL; TCursor& TFuzzy_browse::cursor() { TBrowse& b = *field().browse(); TCursor& c = *b.cursor(); if (_altfld.empty()) { const RecDes& rd = c.curr().rec_des(); CHECKD(_altkey > 0 && _altkey <= rd.NKeys, "Invalid browse key ", _altkey); const KeyDes& kd = rd.Ky[_altkey-1]; const int mf = kd.FieldSeq[kd.NkFields-1] % MaxFields; _altfld = rd.Fd[mf].Name; _outfld = "RAGSOC"; TToken_string outfields = b.get_output_fields(); const int outpos = outfields.get_pos(field().dlg()); if (outpos >= 0) { outfields = b.get_output_field_names(); outfields.get(outpos, _outfld); } } return c; } static void clean_string(TString& str) { char* d = str.get_buffer(); for (const char* s = d; *s; s++) if (*s < '\0' || isalnum(*s)) *d++ = *s; *d = '\0'; str.upper(); } TRecnotype TFuzzy_browse::find(const TString& raw_val) { const TBrowse& b = *field().browse(); TCursor& c = cursor(); TString80 magic_val = raw_val; clean_string(magic_val); c = 0L; TRecnotype recno = -1; TRectype& curr = c.curr(); curr.put(_altfld, magic_val); recno = c.read(); if (recno >= 0 && curr.get(_altfld).starts_with(magic_val)) return recno; recno = -1; const int testlen = magic_val.len()+1; if (testlen > 3) { double best = 0.66; for (c = 0L; c.ok(); ++c) { TString80 val = curr.get(_altfld); clean_string(val); for (int i = val.find(magic_val[0], 0); i >= 0; i = val.find(magic_val[0], i+1)) { double n = xvt_str_fuzzy_compare(val.mid(i, testlen), magic_val); n -= i*0.01; if (n > best) { best = n; recno = c.pos(); if (n >= 1.0) break; } } } } if (recno >= 0) c = recno; return recno; } bool TFuzzy_browse::check(CheckTime /*t*/) { const TRecnotype recno = find(field().get()); if (recno >= 0) { field().set(cursor().curr().get(_outfld)); return true; } return run() == K_ENTER; } static bool fuzzy_code_handler(TMask_field& f, KEY k) { if (k == K_F2) { f.reset(); k = K_SPACE; } if (k == K_SPACE || k == K_TAB) { const TString& str = ((TEdit_field&)f).get_window_data(); const TRecnotype pos = _curr_fbrowse->find(str); if (pos >= 0) { TSheet& s = (TSheet&)f.mask(); if (k == K_TAB) { f.set(s.row(pos).get(0)); s.post_select(pos); } else s.select(pos); } } return true; } KEY TFuzzy_browse::run() { const TBrowse& b = *field().browse(); TCursor& c = cursor(); TString caption = c.file().description(); if (caption.blank()) caption = TR("Selezione"); TToken_string fields, head; b.get_display_fields(head, fields); TCursor_sheet sheet(&c, fields, caption, head, 0, 2); TEdit_field& e = sheet.add_string(field().dlg(), 0, field().prompt(), 1, 1, field().size(), "U"); e.set_handler(fuzzy_code_handler); _curr_fbrowse = this; TString80 val = field().get(); val.strip("*"); e.set(val); e.on_key(K_SPACE); sheet.first_focus(e.dlg()); const KEY k = sheet.run(); _curr_fbrowse = NULL; if (k == K_ENTER) { c = sheet.selected(); field().set(c.curr().get(_outfld)); } return k; } TFuzzy_browse::TFuzzy_browse(TEdit_field* ef, int altkey) : TBrowse_button(ef), _altkey(altkey) { } /////////////////////////////////////////////////////////// // TAlternative_browse /////////////////////////////////////////////////////////// static TBit_array _alternative_bits; static bool alternative_filter(const TRelation* rel) { const TRecnotype recno = rel->file().recno(); return _alternative_bits[recno]; } TCursor& TAlternative_browse::cursor() { if (_cursor == NULL) { TBrowse& b = *field().browse(); TCursor& c = *b.cursor(); const RecDes& rd = c.curr().rec_des(); const KeyDes& kd = rd.Ky[_altkey-1]; const int mf = kd.FieldSeq[kd.NkFields-1] % MaxFields; _altfld = rd.Fd[mf].Name; _outfld = "RAGSOC"; TToken_string outfields = b.get_output_fields(); const int outpos = outfields.get_pos(field().dlg()); if (outpos >= 0) { outfields = b.get_output_field_names(); outfields.get(outpos, _outfld); } _cursor = new TCursor(c.relation(), "", _altkey); _alternative_bits.reset(); const TRecnotype old = c.pos(); for (c = 0L; c.ok(); ++c) { if (c.curr().get(_altfld).full()) _alternative_bits.set(c.file().recno()); } _cursor->set_filterfunction(alternative_filter); _cursor->items(); _cursor->freeze(); c = old; } return *_cursor; } static bool alternative_code_handler(TMask_field& f, KEY k) { if (k == K_F2) { f.reset(); k = K_SPACE; } if (k == K_SPACE || k == K_TAB) { const TString& str = ((TEdit_field&)f).get_window_data(); const TRecnotype pos = _curr_fbrowse->find(str); if (pos >= 0) { TSheet& s = (TSheet&)f.mask(); if (k == K_TAB) { f.set(s.row(pos).get(0)); s.post_select(pos); } else s.select(pos); } } return true; } KEY TAlternative_browse::run() { const TBrowse& b = *field().browse(); TCursor& c = cursor(); TString caption = c.file().description(); if (caption.blank()) caption = TR("Selezione"); TToken_string fields, head; b.get_display_fields(head, fields); const int pos = fields.get_pos(_altfld); const int sz = c.curr().length(_altfld); if (pos > 0) { fields.destroy(pos); fields.insert_at(_altfld, 0); TString80 h; head.get(pos, h); head.destroy(pos); head.insert_at(h, 0); } else { fields.insert_at(_altfld, 0); TString80 h; h << "Cod.Alt.@" << sz; head.insert_at(h, 0); } TCursor_sheet sheet(&c, fields, caption, head, 0, 2); TEdit_field& e = sheet.add_string(field().dlg(), 0, head.before('@'), 1, 1, sz, "U"); e.set_handler(alternative_code_handler); _curr_fbrowse = this; TString80 val = field().get(); val.strip("%"); e.set(val); e.on_key(K_SPACE); sheet.first_focus(e.dlg()); const KEY k = sheet.run(); _curr_fbrowse = NULL; if (k == K_ENTER) { c = sheet.selected(); field().set(c.curr().get(_outfld)); } return k; } TAlternative_browse::TAlternative_browse(TEdit_field* ef, int altkey) : TFuzzy_browse(ef, altkey), _cursor(NULL) { } TAlternative_browse::~TAlternative_browse() { if (_cursor) delete _cursor; }