// $Id: relapp.cpp,v 1.1.1.1 1994-08-12 10:52:05 alex Exp $ #include #include #include #include #include #include #if XVT_OS == XVT_OS_WIN extern "C" { #include } #endif /////////////////////////////////////////////////////////// // Array delle chiavi della maschera di ricerca /////////////////////////////////////////////////////////// class TChiave : public TObject { enum { MAX = 16 }; int _pos[MAX]; byte _num; public: void add(int p); int pos(byte n) const { return (n >= _num) ? -1 : _pos[n]; } byte items() const { return _num; } TChiave() : _num(0) {} virtual ~TChiave() {} }; void TChiave::add(int p) { CHECKD(_num < MAX, "Too many fields in key : field n.", p); _pos[_num++] = p; } class TKey_array : public TArray { const TMask* _mask; public: TKey_array(const TMask* m); virtual ~TKey_array() {} TChiave& key(byte k); }; TChiave& TKey_array::key(byte k) { k--; TChiave* chiave = (TChiave*)objptr(k); if (chiave == NULL) { chiave = new TChiave; add(chiave, k); } return *chiave; } TKey_array::TKey_array(const TMask* m) : _mask(m) { const byte keys = m->num_keys(); for (int f = 0; f < m->fields(); f++) { TMask_field& c = m->fld(f); if (c.in_key(0)) for (byte k = 1; k <= keys; k++) if (c.in_key(k)) key(k).add(f); } } /////////////////////////////////////////////////////////// // TRelation_application /////////////////////////////////////////////////////////// TRelation_application::TRelation_application() : _mask(NULL), _maskeys(NULL), _search_id(-1), _lnflag(FALSE) {} TRelation_application::~TRelation_application() { if (_maskeys) delete _maskeys; } void TRelation_application::setkey() { if (has_filtered_cursor()) { TEdit_field* f = (TEdit_field*) get_search_field(); TCursor* cur = f->browse()->cursor(); cur->setkey(); return; } file().setkey(1); } // what - meaning // 0 - nop // 1 - first // 2 - last // 3 - both void TRelation_application::set_limits(byte what) { if (has_filtered_cursor()) { TEdit_field* f = (TEdit_field*) get_search_field(); CHECK(f, "Manca il campo di ricerca"); TCursor* cur = f->browse()->cursor(); if (cur) { cur->setkey(); f->browse()->do_input(TRUE); if (cur->items() == 0) _first = _last = -1; else { if (what & 0x1) { *cur = 0; _first = cur->file()->recno(); } if (what & 0x2) { *cur = cur->items() - 1; _last = cur->file()->recno(); } } return; } } file().setkey(1); if (what & 0x1) { if (file().empty()) _first = 1; else { file().first(); _first = file().recno(); } } if (what & 0x2) { if (file().empty()) _last = 1; else { file().last(); _last = file().recno(); } } } bool TRelation_application::create() { TApplication::create(); const bool ok = user_create(); if (ok) { write_enable(); _mask = get_mask(MODE_QUERY); filter(); _maskeys = new TKey_array(_mask); set_limits(); dispatch_e_menu(BAR_ITEM(1)); } return ok; } bool TRelation_application::menu(MENU_TAG m) { if (m == BAR_ITEM(1)) return main_loop(); return TRUE; } bool TRelation_application::destroy() { user_destroy(); return TApplication::destroy(); } void TRelation_application::set_fixed() { TString s(16); for (const char* f = _fixed.get(0); f && *f; f = _fixed.get()) { s = f; const int u = s.find('='); const int id = atoi(s.left(u)); _mask->disable(id); const char* val = s.mid(u+1); if (*val) _mask->set(id, val); } } void TRelation_application::enable_query() { const bool query = _mask->mode() == MODE_QUERY; const byte numkeys = _maskeys->items(); for (byte k = 1; k <= numkeys; k++) { const TChiave& chiave = _maskeys->key(k); for (int i = 0; i < chiave.items(); i++) { const int num = chiave.pos(i); TMask_field& c = _mask->fld(num); const bool has_query = c.has_query(); if (k == 1) { // THIS should have been fixed // if (!query && has_query) c.check(STARTING_CHECK); c.enable(query); } if (has_query) ((TEdit_field&)c).enable_check(query); } } set_fixed(); } void TRelation_application::set_toolbar(bool all) { const int mode = _mask->mode(); int pos; if (all) { pos = _mask->id2pos(DLG_SAVEREC); if (pos >= 0) _mask->fld(pos).enable(mode != MODE_QUERY); pos = _mask->id2pos(DLG_DELREC); if (pos >= 0) { bool enabdel = mode == MODE_MOD; if (enabdel) { TRelation& r = *get_relation(); const TRecnotype oldpos = r.lfile()->recno(); enabdel = !protected_record(r.curr()); if (r.lfile()->recno() != oldpos) r.lfile()->readat(oldpos); } _mask->fld(pos).enable(enabdel); } /* const bool full = !file().empty() && _first != -1; pos = _mask->id2pos(DLG_FIRSTREC); if (pos >= 0) _mask->fld(pos).enable(full); pos = _mask->id2pos(DLG_LASTREC); if (pos >= 0) _mask->fld(pos).enable(full); pos = _mask->id2pos(DLG_STOPREC); if (pos >= 0) _mask->fld(pos).enable(full); */ } enable_query(); /* const TRecnotype rpos = file().recno(); pos = _mask->id2pos(DLG_PREVREC); if (pos >= 0) _mask->fld(pos).enable(mod && rpos != _first); pos = _mask->id2pos(DLG_NEXTREC); if (pos >= 0) _mask->fld(pos).enable(mod && rpos != _last); */ } int TRelation_application::set_mode(int mode) { static int _mode = NO_MODE; const int m = ((TMaskmode)mode == NO_MODE) ? (int) MODE_QUERY : mode; _mask->set_mode(m); if (mode == _mode) { set_toolbar(FALSE); // Fast buttons update } else { set_toolbar(TRUE); // Full buttons update _mode = mode; } const char* t = ""; switch(mode) { case MODE_QUERY : t = "Ricerca"; break; case MODE_MOD : t = "Modifica"; break; case NO_MODE : t = "Ricerca/Inserimento"; break; case MODE_INS : t = "Inserimento"; break; default : break; } xvt_statbar_set(t); return _mode; } bool TRelation_application::autonum(TMask* m, bool rec) { TToken_string k(get_next_key()); for (const char* n = k.get(0); n && *n; n = k.get()) { const short id = atoi(n); if (id < 1) break; const char* val = k.get(); TMask_field& f = m->field(id); if (rec || f.get().empty()) f.set(val); if (rec) f.autosave(get_relation()); } return k.not_empty(); } void TRelation_application::query_mode(bool pre_ins) { TMask* old = _mask; const bool changing = changing_mask(MODE_QUERY) || old == NULL; if (changing && old) old->close_modal(); _mask = get_mask(MODE_QUERY); if (changing) { if (old) _mask->open_modal(); if (_maskeys) delete _maskeys; _maskeys = new TKey_array(_mask); set_limits(); } _mask->reset(); if (pre_ins) { set_mode(NO_MODE); autonum(_mask, FALSE); init_query_insert_mode(*_mask); } else { set_mode(MODE_QUERY); init_query_mode(*_mask); } } void TRelation_application::insert_mode() { if (test_key(1, FALSE) == FALSE) { if (!autonum(_mask, FALSE)) { query_insert_mode(); return; } } const bool changing = changing_mask(MODE_INS); TFilename workname; workname.temp("rim.$$"); if (changing) { _mask->set_workfile(workname); _mask->save(); _mask->close_modal(); } _mask = get_mask(MODE_INS); if (changing) { _mask->reset(); _mask->set_workfile(workname); _mask->load(); ::remove(workname); _mask->open_modal(); delete _maskeys; _maskeys = new TKey_array(_mask); } set_mode(MODE_INS); init_insert_mode(*_mask); } bool TRelation_application::modify_mode() { int err = get_relation()->read(_isequal, _testandlock); if (err != NOERR) { if (err == _islocked) message_box("I dati sono gia' in uso ad un altro utente"); else error_box("Impossibile leggere i dati: errore %d", err); query_mode(); return FALSE; } const bool changing = changing_mask(MODE_MOD); if (changing) { _mask->close_modal(); } _mask = get_mask(MODE_MOD); set_mode(MODE_MOD); err = read(*_mask); if (changing) _mask->open_modal(); if (err != NOERR) { error_box("Errore di caricamento dati nella maschera %d", err); query_mode(); return FALSE; } get_relation()->save_status(); init_modify_mode(*_mask); return TRUE; } TMask_field* TRelation_application::get_search_field() const { if (_search_id > 0) return &_mask->field(_search_id); const TChiave& k = _maskeys->key(1); for (int i = 0; i < k.items(); i++) { TMask_field* f = &_mask->fld(k.pos(i)); if (f->required()) return f; } return NULL; } bool TRelation_application::search_mode() { if (_mask->mode() != MODE_QUERY) query_mode(); TMask_field* f = get_search_field(); if (f) if (f->on_key(K_F9)) if (find(1)) return modify_mode(); return FALSE; } bool TRelation_application::test_key(byte k, bool err) { const TChiave& chiave = _maskeys->key(k); bool onereq = FALSE, onefill = FALSE; for (int i = 0; i < chiave.items(); i++) { const int num = chiave.pos(i); TMask_field& c = _mask->fld(num); if (c.required()) { onereq = TRUE; if (c.get().empty()) { if (err) { _mask->first_focus(-c.dlg()); error_box("Manca un valore indispensabile"); } return FALSE; } } else if (k == 1 && !onereq && !onefill && c.get().not_empty()) onefill = TRUE; } if (k == 1 && !onereq && !onefill) { if (err) error_box("Manca un valore indispensabile"); return FALSE; } return TRUE; } // Guy: doesn't change fields bool TRelation_application::find(byte k) { const byte numkeys = _maskeys->items(); if (k == 0) { for (k = 1; k <= numkeys && !test_key(k, FALSE); k++); if (k > numkeys) return test_key(1, TRUE); } file().setkey(k); file().zero(); const TChiave& chiave = _maskeys->key(k); for (int i = 0; i < chiave.items(); i++) { const TMask_field& c = _mask->fld(chiave.pos(i)); c.autosave(get_relation()); } const int err = file().read(_isequal); return err == NOERR; } bool TRelation_application::save(bool check_dirty) { static bool was_dirty = FALSE; int err = NOERR; const int mode = _mask->mode(); if (check_dirty) { const int dirty = _mask->dirty(); if (mode == MODE_QUERY) { const bool cont = !dirty || yesno_box("Annullare i dati inseriti?"); return cont; } if (!dirty && !was_dirty) { if (mode == MODE_MOD) { get_relation()->restore_status(); get_relation()->lfile()->reread(_unlock); // Unlock main file } return TRUE; } const KEY k = yesnocancel_box("Registrare le modifiche?"); if (k == K_ESC) { was_dirty = TRUE; return FALSE; } if (k == K_NO) { get_relation()->restore_status(); get_relation()->lfile()->reread(_unlock); // Unlock main file was_dirty = FALSE; return TRUE; } if (_mask->last_key() == K_ESC || _mask->last_key() == K_QUIT) { _mask->get_mask_fields(); if (!_mask->check_fields()) // Exit with ESC didn't check values { _mask->first_focus(-_mask->fld(_mask->focus_field()).dlg()); was_dirty = TRUE; return FALSE; } } } was_dirty = FALSE; if (mode == MODE_INS) { bool changed = TRUE; while (changed) { err = write(*_mask); if (err == _isreinsert) changed = autonum(_mask, TRUE); else changed = FALSE; } if (err == NOERR) { get_relation()->save_status(); set_limits(); get_relation()->restore_status(); } } else err = rewrite(*_mask); switch(err) { case NOERR: break; case _isreinsert: warning_box("Esiste gia' un documento con la stessa chiave"); break; default: error_box("Impossibile registrare i dati: errore %d", err); break; } return err == NOERR; } int TRelation_application::read(TMask& m) { const TRelation *r = get_relation(); m.autoload(r); return NOERR; } int TRelation_application::write(const TMask& m) { TRelation *r = get_relation(); r->zero(); m.autosave(r); r->write(); return r->status(); } int TRelation_application::rewrite(const TMask& m) { TRelation *r = get_relation(); r->zero(); m.autosave(r); r->rewrite(); return r->status(); } bool TRelation_application::remove() { CHECK(_mask->mode() == MODE_MOD, "You can call remove in MODE_MOD only"); TRelation *r = get_relation(); r->restore_status(); if (protected_record(r->curr())) return message_box("Registrazione non eliminabile"); if (yesno_box("Confermare l'eliminazione")) { r->restore_status(); const int err = r->remove(); if (err == NOERR) set_limits(); else return error_box("Errore di cancellazione"); } return TRUE; } bool TRelation_application::main_loop() { long recins = -1; query_mode(); _mask->open_modal(); KEY k; // Provoca l'autopremimento per il messaggio di LINK if (_lnflag) _mask->send_key(K_SHIFT_ENTER, 0); do { // Seleziona il cursore a freccia set_cursor(TASK_WIN, CURSOR_ARROW); // Dis/abilita cambio ditta enable_menu_item(M_FILE_NEW, (_mask->mode() == MODE_QUERY)); k = _mask->run(); // Seleziona il cursore a clessidra se necessario if (k != K_QUIT && k != K_F9) set_cursor(TASK_WIN, CURSOR_WAIT); switch (k) { case K_ESC: if (save(TRUE)) { if (_mask->query_mode()) { _mask->reset(); set_fixed(); } else query_mode(); } if (_lnflag) k = K_QUIT; break; case K_QUIT: if (save(TRUE)) { if (_mask->mode() == MODE_MOD && _autoins_caller.not_empty()) recins = file().recno(); } else k = K_ENTER; break; case K_ENTER: if (find(0)) modify_mode(); else insert_mode(); break; case K_SAVE: if (save(FALSE)) { if (_autoins_caller.not_empty() || _lnflag) { recins = file().recno(); k = K_QUIT; } else modify_mode(); } break; case K_INS: if (_mask->mode() == MODE_QUERY) insert_mode(); else if (save(TRUE)) query_mode(TRUE); break; case K_DEL: { if (remove()) query_mode(); } break; case K_F9: if (save(TRUE)); search_mode(); break; default: if (save(TRUE)) { setkey(); int err = ~NOERR; switch (k) { case K_HOME: err = file().readat(_first, _testandlock); break; case K_NEXT: err = file().reread(); err = file().next(_testandlock); break; case K_PREV: err = file().reread(); err = file().prev(_testandlock); break; case K_END: err = file().readat(_last, _testandlock); break; default: break; } if (err == NOERR || err == _islocked) modify_mode(); else query_mode(); } break; } } while (k != K_QUIT); if (_mask->is_open()) _mask->close_modal(); _mask->set_mode(NO_MODE); if (recins > 0 && _autoins_caller.not_empty()) { TMessage msg(_autoins_caller, MSG_AI, format("%ld", recins)); msg.send(); } return k != K_QUIT; } bool TRelation_application::filter() { TMailbox mail; TMessage* msg = mail.next_s(MSG_FS); if (msg) { _mask = get_mask(MODE_MOD); TToken_string body(msg->body()); short id = body.get_int(); while (id > 0) { _search_id = id; TEdit_field& f = (TEdit_field&)_mask->field(id); TCursor* cur = f.browse()->cursor(); TRectype& rec = cur->curr(); rec.zero(); TString80 t; const char* s; while((s = body.get()) != NULL) { t = s; const int u = t.find('='); if (u < 0) { id = atoi(t); break; } _fixed.add(t); const short fid = atoi(t.left(u)); const TFieldref* campo = _mask->field(fid).field(); if (campo != NULL) campo->write(t.mid(u+1), rec); } cur->filter("", &rec, &rec); if (s == NULL) id = 0; } } mail.restart(); msg = mail.next_s(MSG_AI); if (msg) _autoins_caller = msg->from(); mail.restart(); msg = mail.next_s(MSG_LN); if (msg) { TToken_string body(msg->body()); const int key = body.get_int(); const int max = _mask->fields(); // _autoins_caller = msg->from(); _lnflag = TRUE; const char* v = body.get(); for (int i = 0; i < max && v != NULL; i++) { TMask_field& f = _mask->fld(i); if (f.active() && f.dlg() > 0 && f.in_key(key)) { const TString s(v); _fixed.add(format("%d=%s", f.dlg(), (const char*) s)); v = body.get(); } } } return TRUE; }