#include #include #include #include #include #include #include #include #include #include #include /////////////////////////////////////////////////////////// // TRelation_application /////////////////////////////////////////////////////////// TRelation_application::TRelation_application() : _mask(NULL), _search_id(-1), _lnflag(0), _autodelete(0), _navigating(false) { } TRelation_application::~TRelation_application() { } TCursor& TRelation_application::get_filtered_cursor() const { const TEdit_field& f = get_search_field(); return *f.browse()->cursor(); } void TRelation_application::setkey() { if (has_filtered_cursor()) get_filtered_cursor().setkey(); else file().setkey(1); } void TRelation_application::set_key_filter() { TString rf = get_user_read_filter(); rf.trim(); if (rf.not_empty()) { TString expr; for (int f = _mask->fields()-1; f >= 0; f--) { TMask_field& fld= _mask->fld(f); if (fld.is_edit() && fld.in_key(0)) { TBrowse* b = ((TEdit_field&)fld).browse(); if (b && b->cursor()->relation()->lfile().num() == get_relation()->lfile().num()) { expr = b->get_filter(); if (expr.find(rf) < 0) { if (expr.not_empty()) { expr.insert("(", 0); expr << ")&&(" << rf << ')'; } else expr = rf; b->set_filter(expr); } } } } } } // @doc INTERNAL // @mfunc Setta i limiti void TRelation_application::set_limits( byte what) // @parm tipo di limite da assegnare al record // @comm I limiti possibili sono: // @flag 0 | Nessuna operazione // @flag 1 | Primo record // @flag 2 | Ultimo record // @flag 3 | Entrambi { if (has_filtered_cursor()) { const TEdit_field& f = get_search_field(); if (f.browse() != NULL) f.browse()->do_input(true); TCursor& cur = get_filtered_cursor(); cur.setkey(); if (cur.items() > 0) { if (what & 0x1) { cur = 0; _first = cur.file().recno(); } if (what & 0x2) { cur = cur.items() - 1; _last = cur.file().recno(); } } else _first = _last = -1; } else { setkey(); if (!file().empty()) { if (what & 0x1) { if (file().first() == NOERR) _first = file().recno(); } if (what & 0x2) { if (file().last() == NOERR) _last = file().recno(); } } else _first = _last = -1; } } void TRelation_application::set_find_button() { // Ricalcola posizioni bootoni di navigazione con la vecchia toolbar WINDOW bar = _mask->toolbar(); if (bar != NULL_WIN) xvt_toolbar_realize(_mask->toolbar()); else // Non c'e' la nuova relapbar { int pos = _mask->id2pos(DLG_FINDREC); if (pos >= 0 && _mask->id2pos(DLG_FIRSTREC) >= 0) //se e' un bottone pentapartito... { TButton_field& f_find = (TButton_field &)_mask->fld(pos); RCT rct_base; f_find.get_rect(rct_base); const int bwidth = (rct_base.right - rct_base.left); const int bheight = (rct_base.bottom - rct_base.top); if (bwidth > 3*bheight/2) // Controllo se ho gia' ridimensionato i bottoni in precedenza { int bx = bwidth / 3; int by = bheight / 2; RCT r = rct_base; r.left += bx; r.right -= bx; if (!NATIVE_CONTROLS) { r.left -= 2; r.right += 2; } f_find.set_rect(r); // Ridimensiona il bottone centrale di ricerca if (!NATIVE_CONTROLS) { bx += 5; by += 3; // Aggiusta dimensioni bottoni sussidiari } pos = _mask->id2pos(DLG_FIRSTREC); if (pos >= 0) { r = rct_base; r.top = r.bottom - by; r.right = r.left + bx; _mask->fld(pos).set_rect(r); } pos = _mask->id2pos(DLG_PREVREC); if (pos >= 0) { r = rct_base; r.bottom = r.top + by; r.right = r.left + bx; _mask->fld(pos).set_rect(r); } pos = _mask->id2pos(DLG_NEXTREC); if (pos >= 0) { r = rct_base; r.bottom = r.top + by; r.left = r.right - bx; _mask->fld(pos).set_rect(r); } pos = _mask->id2pos(DLG_LASTREC); if (pos >= 0) { r = rct_base; r.top = r.bottom - by; r.left = r.right - bx; _mask->fld(pos).set_rect(r); } } } } } bool TRelation_application::create() { bool ok = user_create(); if (ok) { write_enable(); _mask = get_mask(MODE_QUERY); filter(); set_key_filter(); set_limits(); } return ok ? TSkeleton_application::create() : ok; } bool TRelation_application::destroy() { user_destroy(); return TSkeleton_application::destroy(); } void TRelation_application::set_fixed() { TToken_string s(256, '='); for (const char* f = _fixed.get(0); f && *f; f = _fixed.get()) { s = f; const int id = s.get_int(0); s = s.get(); if (s.not_empty()) _mask->set(id, s); if (_lnflag < 2) _mask->disable(id); } } void TRelation_application::enable_query() { const bool query = _mask->query_mode(); const bool keyon = query || get_relation()->status() == _isreinsert; for (int i = _mask->fields() - 1; i >= 0; i--) { TMask_field& c = _mask->fld(i); if (c.in_key(0) && c.enabled_default()) { if (c.in_key(1)) c.enable(keyon); if (c.is_edit()) { TEdit_field& e = (TEdit_field&)c; if (e.browse() != NULL) e.enable_check(query); } } } set_fixed(); } void TRelation_application::set_toolbar() { const int mode = _mask->mode(); const bool can_edit_some = user_can_write(NULL); int pos = _mask->id2pos(DLG_SAVEREC); if (pos >= 0) { bool enabsave=mode != MODE_QUERY; if (enabsave) enabsave = user_can_write(get_relation()); _mask->fld(pos).enable(enabsave); } pos = _mask->id2pos(DLG_DELREC); if (pos >= 0) { bool enabdel = (mode == MODE_QUERY && can_edit_some) || (mode == MODE_MOD); if (enabdel && mode == MODE_MOD) { TRelation& r = *get_relation(); const TRecnotype oldpos = r.lfile().recno(); enabdel = !protected_record(r); if (r.lfile().recno() != oldpos) r.lfile().readat(oldpos); } _mask->fld(pos).enable(enabdel); } pos = _mask->id2pos(DLG_FINDREC); if (pos >= 0) { _mask->fld(pos).enable(_lnflag == 0); const long recno = get_relation()->lfile().recno(); const bool enable_next_prev = _mask->edit_mode(); const bool can_nav = _lnflag == 0 && _curr_transaction != TRANSACTION_LINK; pos = _mask->id2pos(DLG_FIRSTREC); if (pos >= 0) _mask->fld(pos).enable(can_nav && (enable_next_prev ? _first != recno : _first > 0)); pos = _mask->id2pos(DLG_PREVREC); if (pos >= 0) _mask->fld(pos).enable(can_nav && enable_next_prev && _first > 0 && _first != recno); pos = _mask->id2pos(DLG_NEXTREC); if (pos >= 0) _mask->fld(pos).enable(can_nav && enable_next_prev && _last > 0 && _last != recno); pos = _mask->id2pos(DLG_LASTREC); if (pos >= 0) _mask->fld(pos).enable(can_nav && (enable_next_prev ? _last != recno : _last > 0)); } pos = _mask->id2pos(DLG_NEWREC); if (pos >= 0) { bool enabins = (mode == MODE_QUERY || _lnflag == 0) && can_edit_some; _mask->fld(pos).enable(enabins); } set_find_button(); enable_query(); } void TRelation_application::update_navigation_bar() { if (_mask->query_mode()) { set_limits(); set_toolbar(); } } bool TRelation_application::save_and_new() const { return false; } int TRelation_application::set_mode(int mode) { static int _mode = NO_MODE; if (mode < NO_MODE) mode = _mode; const int m = ((TMaskmode)mode == NO_MODE) ? (int) MODE_QUERY : mode; _mask->set_mode(m); set_toolbar(); _mode = mode; const char* t = ""; switch(mode) { case MODE_QUERY: t = TR("Ricerca"); break; case MODE_MOD: t = TR("Modifica"); break; case NO_MODE: t = TR("Ricerca/Inserimento"); break; case MODE_INS: t = TR("Inserimento"); break; default: break; } xvtil_statbar_set(t, TRUE); return _mode; } // @doc INTERNAL // @mfunc Permette di autonumerare un record // // @rdesc Ritorna se e' riuscito a creare una nuova autonumerazione: // // @flag TRUE | La chiave non e' vuota // @flag FALSE | Non e' riuscito ad autonumerare il documento bool TRelation_application::autonum( TMask* m, // @parm Maschera a cui applicare l'autonumerazione bool rec) // @parm Indica se registrare la chiave anche sul record corrente { TToken_string k; if (!get_next_key(k)) { k = get_next_key(); /* if (k.not_empty()) NFCHECK("La 'const char* get_next_key()' verra' sostituita dalla 'bool get_next_key(TToken_string&)'"); */ } if (!rec && !m->query_mode()) m->reset(); _renum_message = ""; for (const char* n = k.get(0); n && *n; n = k.get()) { const short id = atoi(n); CHECKD (id > 0 && m->id2pos(id) >= 0, "Identificatore di autonumerazione errato: ", id); const char* val = k.get(); TMask_field& f = m->field(id); if (rec || f.empty()) f.set(val); if (rec) ((TEditable_field&)f).autosave(*get_relation()); if (_renum_message.empty() || f.in_key(1)) _renum_message.format("L'elemento e' stato registrato con :\n %s = %s", (const char *) f.prompt(), (const char *) f.get()); } return k.not_empty(); } // @doc EXTERNAL // @mfunc Entra in modo di ricerca void TRelation_application::query_mode( bool pre_ins) // @parm Indica in quale modo andare: // // @flag TRUE | Entra in modo MODE_QUERY_INSERT // @flag FALSE | Entra in modo MODE_QUERY (default) { TMask* old = _mask; const bool was_open = old != NULL && old->is_open(); const bool changing = changing_mask(MODE_QUERY); if (changing && was_open) old->close_modal(); _mask = get_mask(MODE_QUERY); if (changing) { if (was_open) _mask->open_modal(); set_limits(); } _mask->set_mode(pre_ins ? MODE_QUERYINS : MODE_QUERY); _mask->reset(); _mask->disable_page(1); // Nasconde pagine inutili if (pre_ins) { set_mode(NO_MODE); init_query_insert_mode(*_mask); enable_query(); } else { set_mode(MODE_QUERY); init_query_mode(*_mask); enable_query(); // Aggiorna bottoni di ricerca: utile soprattutto per ve0 che imposta CODNUM if (has_filtered_cursor()) { set_limits(); set_toolbar(); } } } void TRelation_application::insert_mode() { bool try_auto = true; if (_mask->query_mode()) try_auto = !test_key(1, FALSE); if (try_auto && !autonum(_mask, FALSE)) { query_insert_mode(); return; } TRelation* r = get_relation(); r->zero(); _mask->autosave(*r); if (!user_can_write(r)) { warning_box(FR("L'utente %s non puo' inserire in questo archivio"), (const char*)user()); return; } const bool changing = changing_mask(MODE_INS); TFilename workname; workname.temp("msk"); 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(); } else _mask->enable_page(1); set_mode(MODE_INS); r->zero(); // Azzera tutta la relazione! _mask->load_defaults(); init_insert_mode(*_mask); // ....possibilmente spostare questa chiamata ..... if (_curr_transaction == TRANSACTION_INSERT) ini2insert_mask(); } bool TRelation_application::modify_mode() { TRelation* rel = get_relation(); if (!user_can_read(rel)) { warning_box(TR("I dati non sono accessibili per l'utente %s"), (const char*)user()); query_mode(); return FALSE; } const TReclock block = user_can_write(rel) ? _testandlock : _nolock; int err = rel->read(_isequal, block); if (err != NOERR) { if (err == _islocked) message_box(TR("I dati sono gia' usati da un altro programma")); else error_box(FR("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); if (changing) _mask->open_modal(); else _mask->enable_page(1); set_mode(MODE_MOD); err = read(*_mask); if (err != NOERR) { query_mode(); return FALSE; } rel->save_status(); init_modify_mode(*_mask); // ....possibilmente spostare questa chiamata ..... // Forse deve essere fatta prima della init_modify_mode()! if (_curr_transaction == TRANSACTION_MODIFY) ini2insert_mask(); return TRUE; } TEdit_field& TRelation_application::get_search_field() const { short id = _search_id; if (id <= 0 || !_mask->field(id).shown()) { for (int i = _mask->fields()-1; i >= 0; i--) { const TMask_field& f = _mask->fld(i); if (f.is_edit() && f.in_key(1) && f.shown()) { id = f.dlg(); break; } } } return _mask->efield(id); } bool TRelation_application::search_mode() { if (_mask->mode() != MODE_QUERY) query_mode(); TEdit_field* prima = &get_search_field(); while (prima) { if (prima->on_key(K_F9)) { if (find(1)) return modify_mode(); else break; } TMask_field* dopo = &_mask->focus_field(); if (dopo != prima && dopo->is_edit() && dopo->in_key(0)) prima = (TEdit_field*)dopo; else break; } return FALSE; } HIDDEN bool delete_handler(TMask_field& f, KEY k) { if (k == K_TAB && f.focusdirty() && !f.empty()) { TMask& m = f.mask(); const bool finale = *f.prompt() == 'A'; const int pos = m.id2pos(f.dlg()); if (pos >= 3) { const TMask_field& e = m.fld(pos - 3); if (e.is_edit() && e.get().blank()) { const short id = e.dlg() - (finale ? 200 : 100); const TRelation_application& app = (TRelation_application&)main_app(); const TMask_field& orig = app.curr_mask().field(id); bool req = orig.required(); if (!req && orig.is_edit()) { const TEdit_field& e = (TEdit_field&)orig; req = e.validate_func() == 12; } if (req) { TString str; str << (finale ? TR("A ") : TR("Da ")) << orig.prompt(); return f.error_box(FR("Specificare anche il valore %s"), (const char*)str); } } } if (finale && !f.get().blank()) { const TMask_field& p = m.fld(pos - 1); TString80 prec = p.get(); TString80 curr = f.get(); bool ok; switch (p.class_id()) { case CLASS_REAL_FIELD: ok = real(prec) <= real(curr); break; case CLASS_DATE_FIELD: ok = TDate(prec) <= TDate(curr); break; default : ok = prec <= curr; break; } if (!ok) return f.error_box(FR("Inserire un valore non inferiore a '%s'"), (const char*)prec); } } return TRUE; } int TRelation_application::delete_mode() { TEdit_field& fld = get_search_field(); TBrowse* brw = fld.browse(); if (brw) { brw->do_input(TRUE); TCursor& cur = *brw->cursor(); TToken_string head(brw->head()); head.insert("@1|", 0); TToken_string items(brw->items()); items.insert(" |", 0); int tab1 = 0, tab2 = 0, y = 0; // Nuovo modo basato sugli input TToken_string inplist = brw->get_input_fields(); if (inplist.not_empty()) { FOR_EACH_TOKEN(inplist, tok) { if (*tok != '"' && strchr(tok, '@') == NULL) { TMask_field& e = _mask->field(short(atoi(tok))); if (e.active()) { const int len = strlen(e.prompt()); if (len > tab1) tab1 = len; const int size = e.size(); if (size > tab2) tab2 = size; y++; } } } } tab1 += 5; tab2 += tab1+2; cur = 0L; TCursor_sheet sht(&cur, items, TR("Eliminazione"), head, 0x4, y); y = -1; // Posizione del campo precedente TString prompt; // Prompt del campo corrente const short delta = 100; FOR_EACH_TOKEN(inplist, tok) { if (*tok != '"' && strchr(tok, '@') == NULL) { TMask_field& e = _mask->field(short(atoi(tok))); if (!e.active()) continue; const short id = e.dlg()+delta; prompt = "Da "; prompt << e.prompt(); sht.add_static(DLG_NULL, 0, prompt, 1, ++y); TString16 flags; if (e.automagic()) flags << 'A'; if (e.roman()) flags << 'M'; if (e.right_justified()) flags << 'R'; if (e.uppercase()) flags << 'U'; if (e.zerofilled()) flags << 'Z'; switch (e.class_id()) { case CLASS_DATE_FIELD: { TDate_field& d1 = sht.add_date(id, 0, "", tab1, y, flags); TDate_field& d2 = sht.add_date(id+delta, 0, "A ", tab2, y, flags); d1.set_handler(delete_handler); d2.set_handler(delete_handler); } break; case CLASS_REAL_FIELD: { TReal_field& r1 = sht.add_number(id, 0, "", tab1, y, e.size(), flags); TReal_field& r2 = sht.add_number(id+delta, 0, "A ", tab2, y, e.size(), flags); r1.set_handler(delete_handler); r2.set_handler(delete_handler); } break; default: { TEdit_field& e1 = sht.add_string(id, 0, "", tab1, y, e.size(), flags); TEdit_field& e2 = sht.add_string(id+delta, 0, "A ", tab2, y, e.size(), flags); e1.set_handler(delete_handler); e2.set_handler(delete_handler); } break; } if (y == 0) sht.first_focus(id); } } sht.open_modal(); KEY tasto; bool keep_running = TRUE; while (keep_running) { tasto = sht.run(); if (tasto == K_ENTER) { TRectype rec_from(cur.curr()), rec_to(cur.curr()); rec_from.zero(); rec_to.zero(); TToken_string fldlist = brw->get_input_field_names(); TString80 str; int fi = 0; for (TString80 tok = inplist.get(fi); tok.not_empty(); tok = inplist.get(), fi++) { const TString16 fn = fldlist.get(fi); const TFieldref fr(fn, 0); if (*tok == '"') { str = tok; str.ltrim(1); str.rtrim(1); fr.write(str, rec_from); fr.write(str, rec_to); } else { const short id = short(atoi(tok)); if (sht.id2pos(id+delta) >= 0) { str = sht.get(id+delta); if (str.not_empty()) fr.write(str, rec_from); str = sht.get(id+2*delta); if (str.not_empty()) fr.write(str, rec_to); } else { str = _mask->get(id); fr.write(str, rec_from); fr.write(str, rec_to); } } } if (rec_from.empty() && rec_to.empty()) { sht.check(-1); } else { const long totit = cur.items(); cur.freeze(TRUE); cur.curr() = rec_from; cur.read(); while (cur.pos() < totit && cur.curr() <= rec_to) { sht.check(cur.pos()); ++cur; } cur.freeze(FALSE); } } else { keep_running = FALSE; if (tasto == K_DEL && sht.checked() == 0) { error_box(TR("Non e' stato selezionato nessun elemento")); sht.select(0); keep_running = TRUE; } } } sht.close_modal(); if (tasto == K_DEL) { long deleting = sht.checked(); TString msg; msg.format(FR("Confermare l'eliminazione di %d elementi"), deleting); bool can_delete = yesno_box(msg); if (can_delete && deleting > 100) { msg.insert(TR("ATTENZIONE: "), 0); can_delete = yesno_box(msg); } if (can_delete) { TWait_cursor hourglass; long skipped = 0; // Record non cancellati perche' protetti cur.freeze(TRUE); // Congelo il cursore altrimenti si riaggiorna troppo for (long pos = sht.items()-1; deleting > 0; pos--) { if (sht.checked(pos)) { cur = pos; brw->do_output(); bool can_delete = FALSE; if (find(1)) { TRelation& r = *get_relation(); _autodelete = 0x3; if (!protected_record(r)) { if (modify_mode()) { r.restore_status(); can_delete = remove(); } query_mode(); } _autodelete = FALSE; } if (!can_delete) skipped++; deleting--; } } cur.freeze(FALSE); set_limits(); // Riaggiorno il numero del primo/ultimo record if (skipped > 0) { warning_box(FR("%ld elementi non sono stati cancellati in quanto protetti."), skipped); query_mode(); } } } } else { if (search_mode()) _autodelete = TRUE; } return TRUE; } // @doc INTERNAL // @mfunc Controlla se una chiave e' completa ed esiste su file // // @rdesc Ritorna se la chave esiste sul file bool TRelation_application::test_key( word k, // @parm Chiave da ricercare bool err) // @parm Indica se visualizzare eventuali errori occorsi { bool onereq = FALSE, onefill = FALSE; for (TEditable_field* e = _mask->get_key_field(k, TRUE); e != NULL; e = _mask->get_key_field(k, FALSE)) { if (e->required() && e->shown()) { onereq = TRUE; if (e->empty()) { if (err) { TString msg(80); msg = TR("Manca un valore indispensabile per la ricerca."); #ifdef DBG msg << "\nChiave " << int(k) << " - Campo " << e->dlg(); const TFieldref* fr = e->field(); if (fr != NULL) { msg << " - " << fr->name(); if (fr->to() > 0) msg << '[' << fr->from() << ',' << fr->to() << ']'; } #endif error_box(msg); _mask->first_focus(-e->dlg()); } return FALSE; } } else /* if (k == 1 && !onereq && !onefill && c.get().not_empty()) */ if (!onereq && !onefill && e->is_edit() && !e->empty()) onefill = TRUE; } if (k == 1 && !onereq && !onefill) { if (err) error_box(TR("Manca un valore indispensabile per la ricerca")); return FALSE; } return onefill || onereq; } bool TRelation_application::find(word k) { if (k == 0) { for (k = 1; k <= MAX_KEYS && !test_key(k, FALSE); k++); if (k > MAX_KEYS) return test_key(1, TRUE); } file().setkey(k); file().zero(); for (TEditable_field* e = _mask->get_key_field(k, TRUE); e; e = _mask->get_key_field(k, FALSE)) { if (e->shown()) // Ignora campi invisibili e->autosave(*get_relation()); } const int err = file().read(_isequal); return err == NOERR; } void TRelation_application::edit_cancel() { if (_mask->mode() == MODE_MOD) { TRelation* rel = get_relation(); rel->restore_status(); rel->lfile().reread(_unlock); // Unlock main file } } bool TRelation_application::save(bool check_dirty) { static bool was_dirty = FALSE; int pos = _mask->id2pos(DLG_SAVEREC); if (pos < 0 || !_mask->fld(pos).active()) { edit_cancel(); return true; } int err = NOERR; const int mode = _mask->mode(); if (check_dirty) { const short dirty = _mask->dirty(); if (mode == MODE_QUERY) { const bool cont = !dirty || yesno_box(TR("Annullare i dati inseriti?")); return cont; } if (!dirty && !was_dirty) { edit_cancel(); return true; } const KEY last = _mask->last_key(); const bool annulla = last == K_ESC || last == K_QUIT || last == K_F9; const bool errore = dirty && _mask->field(dirty).dirty() > 1; KEY k; if (errore) { if (annulla) { TString w; TMask_field& df = _mask->field(dirty); if (df.is_edit()) w = ((TEdit_field&)df).get_warning(); if (w.blank()) { w = df.prompt(); if (!w.blank()) { w.trim(); w << ' ' << TR("inconsistente."); } } if (w.blank()) w = TR("Campo inconsistente."); w << '\n'; switch (last) { case K_ESC: w << TR("Si desidera annullare?"); break; case K_QUIT: w << TR("Si desidera uscire?"); break; default: w << TR("Si desidera continuare?"); break; } k = yesno_box(w) ? K_NO : K_ESC; if (k == K_ESC) _mask->first_focus(-dirty); } else k = K_ESC; } else k = yesnocancel_box(TR("Si desidera registrare?")); if (k == K_ESC || k == K_NO) { edit_cancel(); was_dirty = false; return k == K_NO; } if (annulla) { TMask_field& ff = _mask->focus_field(); if (ff.focusdirty() && ff.is_edit()) // I need simulate tab on the current field! { if (!ff.on_key(K_TAB)) { _mask->first_focus(-ff.dlg()); was_dirty = TRUE; return FALSE; } } if (!_mask->check_fields()) // Exit with ESC didn't check values { // check_fields sets the focus on the blocking field _mask->first_focus(-_mask->focus_field().dlg()); was_dirty = TRUE; return FALSE; } } } was_dirty = FALSE; TWait_cursor hourglass; if (mode == MODE_INS) { bool changed = TRUE; bool changed_key = FALSE; while (changed) { err = write(*_mask); if (err == _isreinsert) { changed = autonum(_mask, TRUE); if (!changed) { _mask->disable_starting_check(); enable_query(); // Abilita chiave 1 per rinumerazione manuale } else changed_key = TRUE; } else changed = FALSE; } if (err == NOERR) { if (changed_key) message_box(_renum_message); get_relation()->save_status(); set_limits(); get_relation()->restore_status(); } } else { get_relation()->restore_status(); err = rewrite(*_mask); } switch(err) { case NOERR: _recins = get_relation()->lfile().recno(); mask2mail(*_mask); break; case _isreinsert: warning_box(TR("Esiste gia' un elemento con la stessa chiave")); break; default: error_box(FR("Impossibile registrare i dati: errore %d"), err); break; } return err == NOERR; } int TRelation_application::read(TMask& m) { const TRelation &r = *get_relation(); /* Metodo VECCHIO! const int max = m.fields(); for (int i = 0; i < max; i++) { if (m.fld(i).is_sheet()) { TSheet_field& f = (TSheet_field&)m.fld(i); if (f.record() && !f.external_record()) f.record()->read(*f.putkey(r)); } } */ if (m.sheets() > 0) // Metodo Salvatempo { FOR_EACH_MASK_SHEET(m, i, s) { if (s->record() && !s->external_record()) s->record()->read(*s->putkey(r)); } } m.autoload(r); return NOERR; } int TRelation_application::write(const TMask& m) { TRelation &r = *get_relation(); m.autosave(r); r.curr().set_creation_info(); // write relation and all independent sheets int err=r.write(); /* const int max = m.fields(); for (int i = 0; i < max; i++) { if (m.fld(i).is_sheet()) { TSheet_field& f = (TSheet_field& )m.fld(i); if (f.record() && !f.external_record()) err|=f.record()->write(FALSE); } } */ FOR_EACH_MASK_SHEET(m, i, s) { if (s->record() && !s->external_record()) err |= s->record()->write(false); } return err; } int TRelation_application::rewrite(const TMask& m) { TRelation& r = *get_relation(); m.autosave(r); r.curr().set_modify_info(); // rewrite relation and all independent sheets r.rewrite(); int err=r.status(); /* const int max = m.fields(); for (int i = 0; i < max; i++) { if (m.fld(i).is_sheet()) { TSheet_field& f = (TSheet_field&)m.fld(i); if (f.record()&& !f.external_record()) err|=f.record()->write(TRUE); } } */ FOR_EACH_MASK_SHEET(m, i, s) { if (s->record() && !s->external_record()) err |= s->record()->write(true); } return err; } // @doc INTERNAL // @mfunc Cancella il record corrente // // @rdesc Ritorna se il record e' stato eliminato bool TRelation_application::relation_remove() // @comm Se la maschera e' in MODE_MOD non e' possibile cancellare il record e viene // emesso un di errore. { CHECK(_mask->edit_mode(), "You can call remove in edit mode only"); TRelation& r = *get_relation(); r.restore_status(); if (protected_record(r)) return message_box(TR("Elemento non eliminabile")); if (_curr_transaction == TRANSACTION_DELETE || yesno_box(TR("Confermare l'eliminazione"))) { r.restore_status(); const bool ok = remove(); if (ok || is_transaction()) set_limits(); else { const int err = r.status(); if (err != NOERR) // Succede nei remove con richiesta di conferma all'utente return error_box(FR("Errore di cancellazione %d"), err); } } return TRUE; } bool TRelation_application::protected_record(TRelation &r) { if (user_can_delete(&r)) return protected_record(r.curr()); return true; } bool TRelation_application::remove() { int err = get_relation()->remove(); if (err == NOERR) { const int maxf = _mask->fields(); for (int i = 0; i < maxf; i++) { const TMask_field& mf = _mask->fld(i); if (mf.is_sheet()) { TSheet_field& f = (TSheet_field&)mf; if (f.record()&& !f.external_record()) err |= f.record()->remove(); } } } if (err == NOERR) { _mask->set_mode(NO_MODE); mask2mail(*_mask); } return err == NOERR; } bool TRelation_application::firm_change_enabled() const { bool ok = TApplication::firm_change_enabled(); ok &= (_mask == NULL || _mask->query_mode()) && _lnflag == 0; return ok; } void TRelation_application::main_loop() { KEY k; do { // ciclo delle transazioni _recins = -1; // imposta la maschera in query mode query_mode(); _mask->open_modal(); // Provoca l'autopremimento per il messaggio di LINK if (_lnflag) { if (_trans_counter < _ntransactions) { // la transazione è sul .ini : la imposta nelle variabili _curr_transaction... if (load_transaction()) { // la transazione necessita di autopremimento _autodelete = _curr_transaction == TRANSACTION_DELETE; if (_curr_transaction == TRANSACTION_INSERT ) _mask->send_key(K_CTRL+'N', 0); else _mask->send_key(K_AUTO_ENTER, 0); } } else // la transazione non è sul .ini { _mask->send_key(K_AUTO_ENTER, 0); } } if (is_transaction()) ini2query_mask(); do { const bool change = firm_change_enabled(); // Dis/abilita cambio ditta enable_menu_item(M_FILE_NEW, change); if (_mask->edit_mode()) { if (_autodelete) { const int pos = _mask->id2pos(DLG_DELREC); if (pos >= 0 && _mask->fld(pos).active()) _mask->send_key(K_CTRL+'E', 0); else error_box(TR("Elemento non eliminabile.")); _autodelete = FALSE; } } k = _mask->run(); switch (k) { case K_ESC: if (save(TRUE)) query_mode(); if ((_autoins_caller.full() || is_transaction()) && _curr_trans_mode != TM_REMAIN) k = K_QUIT; break; case K_QUIT: if (!save(TRUE)) k = K_ENTER; break; case K_F1: dispatch_e_menu(M_HELP_CONTENTS); break; case K_F2: dispatch_e_menu(M_FILE_ABOUT); break; case K_ENTER: if (_lnflag && _curr_transaction != TRANSACTION_RUN) { if (find(1)) { if (_curr_transaction == TRANSACTION_INSERT) _curr_transaction = TRANSACTION_MODIFY; modify_mode(); } else { if (_curr_transaction == TRANSACTION_MODIFY) _curr_transaction = TRANSACTION_INSERT; insert_mode(); } } else { if (find(0)) modify_mode(); else insert_mode(); } if (_curr_trans_mode == TM_AUTOMATIC) _mask->send_key(K_CTRL+'R', 0); break; case K_SAVE: if (save(FALSE)) { if ((_autoins_caller.full() || is_transaction()) && _curr_trans_mode != TM_REMAIN) { k = K_QUIT; } else { if (save_and_new()) { if (_mask->insert_mode()) insert_mode(); else query_mode(); } else { const TMask_field & f = _mask->focus_field(); _mask->first_focus(-f.dlg(), false); modify_mode(); } } } break; case K_INS: if (_mask->query_mode() || save(TRUE)) { const bool trovato = _mask->query_mode() && test_key(1, FALSE) && find(1); if (trovato) { if (is_transaction()) _curr_transaction=TRANSACTION_MODIFY; else warning_box(TR("Elemento gia' presente")); modify_mode(); } else insert_mode(); } if (_curr_trans_mode == TM_AUTOMATIC) _mask->send_key(K_CTRL+'R', 0); break; case K_DEL: if (_mask->query_mode()) { delete_mode(); } else { if (relation_remove()) { query_mode(); if (_autoins_caller.not_empty() || is_transaction()) { if (_lnflag) _recins = 0; k = K_QUIT; } } } break; case K_F9: if (_mask->query_mode() || 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(); if (has_filtered_cursor()) { TCursor& cur = get_filtered_cursor(); cur.curr() = file().curr(); cur.read(); ++cur; file().curr() = cur.curr(); err = get_relation()->read(_isequal, _testandlock); } else err = file().next(_testandlock); break; case K_PREV: file().reread(); if (has_filtered_cursor()) { TCursor& cur = get_filtered_cursor(); cur.curr() = file().curr(); cur.read(); --cur; file().curr() = cur.curr(); err = get_relation()->read(_isequal, _testandlock); } else err = file().prev(_testandlock); break; case K_END: err = file().readat(_last, _testandlock); break; default: break; } if (err == NOERR || err == _islocked) { _navigating = true; modify_mode(); _navigating = false; } else query_mode(); } break; } } while (k != K_QUIT); if (_mask->is_open()) _mask->close_modal(); _mask->set_mode(NO_MODE); if (autoins_caller().not_empty() && _recins >= 0) { NFCHECK("Obsolete LINK message calling convention"); TString16 num; num.format("%ld", _recins); TMessage msg(autoins_caller(), _lnflag ? MSG_LN : MSG_AI, num); msg.send(); } if (is_transaction()) { TConfig ini(_trans_ini.row(_trans_counter), "Transaction"); ini.set("Record", _recins); if (_recins >= 0) { ini.set("Result", "OK"); ini.set("Error", "0"); edit_mask2ini(); } else { const int err = get_relation()->status(); ini.set("Result", err == NOERR ? "CANCEL" : "ERROR"); ini.set("Error", err); } } _trans_counter++; } while ( _trans_counter < _ntransactions); } bool TRelation_application::filter() { if (parse_command_line()) return true; 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->setfilter(""); cur->setregion(rec, rec, 0x2); 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(); _autoins_caller = msg->from(); _lnflag = TRUE; TString str, tmp; const char* v = body.get(); for (int i = 0; v != NULL && i < _mask->fields(); i++) { TMask_field& f = _mask->fld(i); if (f.active() && f.dlg() > 0 && f.in_key(key)) { str = v; tmp.format("%d=", f.dlg()); str.insert(tmp, 0); _fixed.add(str); v = body.get(); } } } mail.restart(); msg = mail.next_s(MSG_ED); if (msg) { TToken_string body(msg->body()); const int key = body.get_int(); _autoins_caller = msg->from(); _lnflag = 2; TAssoc_array field_values; const char * s; TString t, v; while((s = body.get()) != NULL) { t = s; const int u = t.find('='); CHECKS(u > 0, "Invalid edit message ", (const char *) body); if (u > 0) { v = t.mid(u + 1); t.cut(u); field_values.add(t, v); } } for (int i = 0; i < _mask->fields(); i++) { TMask_field& f = _mask->fld(i); const TFieldref * field = f.field(); if (field && f.in_key(key)) { TString16 field_name(field->name()); const int from = field->from(); const int to = field->to(); if (to >= 0) field_name << "[" << (from + 1); const TString * v = (const TString *) field_values.objptr(field_name); TString val; if (v == NULL && to >= 0) { v = (const TString *)field_values.objptr(field->name()); if (v) val = v->sub(from, to); } else if (v) val = *v; if (v) { t.format("%d=", f.dlg()); val.insert(t, 0); _fixed.add(val); } } } } return TRUE; } void TRelation_application::set_link(TMask & m, const char * keyexpr) { CHECK(keyexpr != NULL, "Invalid expression"); TToken_string body(keyexpr); const int key = body.get_int(); _lnflag = TRUE; const char* v = body.get(); TString16 tmp; const int max = m.fields(); for (int i = 0; i < max && v != NULL; i++) { TMask_field& f = m.fld(i); if (f.active() && f.dlg() > 0 && f.in_key(key)) { TString s(v); tmp.format("%d=", f.dlg()); s.insert(tmp, 0); _fixed.add(s); v = body.get(); } } } bool TRelation_application::parse_command_line() { _trans_ini.destroy(); _trans_counter=0; _curr_transaction = ""; _curr_trans_mode = 'I'; TFilename ini; for (int i = argc()-1; i > 0; i--) { ini = argv(i); if ((ini[0] == '-' || ini[0] == '/') && (ini[1] == 'I' || ini[1] == 'i')) { ini.ltrim(2); CHECK(!ini.blank(),"Manca l'indicazione della transazione. Il nome va indicato di seguito al -i, senza interporre spaziatura."); if (ini.find('*')>=0) { // metachars: list_files(ini, _trans_ini); } else _trans_ini.add(ini); break; } } _ntransactions= _trans_ini.items(); _lnflag = _ntransactions>0; return _lnflag != 0; } // il valore di ritorno indica se attivare l'"automagia" (spedizione dei tasti e // precaricamento della maschera) bool TRelation_application::load_transaction() { bool retv = FALSE; if (_trans_counter < _ntransactions) { TConfig cnf(_trans_ini.row(_trans_counter), "Transaction"); _curr_transaction = cnf.get("Action"); _curr_transaction.upper(); _curr_trans_mode = toupper(cnf.get("Mode")[0]); _curr_trans_from = cnf.get("From"); const long firm = cnf.get_long("Firm"); if (firm > 0) { bool ok = set_firm(firm); if (ok) _mask->on_firm_change(); else error_box(FR("La ditta %ld non esiste"), firm); } if (_curr_transaction == TRANSACTION_RUN) retv = false; // Ho gia' finito qui: basta il cambio ditta else retv = true; // Attiva automagia } return retv; } void TRelation_application::on_firm_change() { TApplication::on_firm_change(); if (_mask != NULL) { set_limits(0x3); } } void TRelation_application::ini2query_mask() { if (is_transaction()) { TString8 n; n.format("%d", get_relation()->lfile().num()); TConfig ini(_trans_ini.row(_trans_counter), n); ini2mask(ini, *_mask, TRUE); } } void TRelation_application::ini2insert_mask() { if (is_transaction()) { TString8 n; n.format("%d", get_relation()->lfile().num()); TConfig ini(_trans_ini.row(_trans_counter), n); ini2mask(ini, *_mask, FALSE); } } void TRelation_application::ini2mask(TConfig& ini, TMask& m, bool query) { const TString16 defpar = ini.get_paragraph(); TString tmp; _fixed.cut(0); for (int f = m.fields()-1; f >= 0; f--) { TMask_field& campo = m.fld(f); const TFieldref* fref = campo.field(); if (fref) { if (!query || campo.in_key(0)) { const TString& str = fref->read(ini, defpar); if (str.not_empty()) { campo.set(str); if (query) { tmp.format("%d=%s", campo.dlg(), (const char *) str); _fixed.add(tmp); } } } } else { if (!query && campo.is_sheet()) { TSheet_field &sheet=(TSheet_field &)campo; ini2sheet(ini, sheet); } } } ini.set_paragraph(defpar); if (query) set_fixed(); } void TRelation_application::edit_mask2ini() { if (_trans_ini.row(_trans_counter).not_empty()) { TString8 head; head.format("%d", get_relation()->lfile().num()); TConfig ini(_trans_ini.row(_trans_counter), head); mask2ini(*_mask, ini); } } void TRelation_application::ini2sheet(TConfig& ini,TSheet_field &sheet) { if (sheet.record() != NULL) { const int lognum = sheet.record()->logic_num(); const TMask& sm = sheet.sheet_mask(); // scrive le righe nello sheet associato TString16 defpar; for (int r = 1; ;r++) { defpar.format("%d,%d", lognum, r); if (ini.set_paragraph(defpar)) { TToken_string& row = sheet.row(r-1); for (int sf = sm.fields()-1; sf >= 0; sf--) { TMask_field& campo = sm.fld(sf); const TFieldref* fref = campo.field(); if (fref) { const TString& str = fref->read(ini, defpar); row.add(str, sheet.cid2index(campo.dlg())); } } sheet.check_row(r-1); } else break; } } } void TRelation_application::sheet2ini(TSheet_field &sheet,TConfig& ini) { if (sheet.record() != NULL) { const int lognum = sheet.record()->logic_num(); const TMask& sm = sheet.sheet_mask(); // scrive le righe degli sheet associati TString16 defpar; TString str; int r; for (r = 1 ; r <= sheet.items(); r++) { defpar.format("%d,%d", lognum, r); TMask_field* fkey; sheet.restart_key(); while ((fkey = sheet.get_key(str))) { ini.set(str, fkey->get(), defpar); } TToken_string& row = sheet.row(r-1); const char* value; int i; for (i = 0, value = row.get(0); value; i++, value = row.get()) { const TMask_field& campo = sm.field(FIRST_FIELD+i); const TFieldref* fr = campo.field(); if (fr) { if (value == NULL || *value == '\0') value = " "; // ini.set(fr->name(), value, defpar); fr->write(ini, defpar, value); } } } for (r = sheet.items()+1; ; r++) { defpar.format("%d,%d", lognum, r); if (ini.set_paragraph(defpar)) ini.remove_all(); else break; } } } void TRelation_application::mask2ini(const TMask& m, TConfig& ini) { ini.set("Firm", get_firm(), "Transaction"); int year, release, tag, patch; if (get_version_info(year, release, tag, patch)) { TString80 ver; ver.format("%d %d.%d-%d", year, release, tag, patch); ini.set("Version", ver); } const TLocalisamfile& lfile = get_relation()->lfile(); TString16 defpar; defpar.format("%d", lfile.num()); ini.set_paragraph(defpar); switch (lfile.num()) { case LF_TAB: case LF_TABCOM: case LF_TABGEN: { const TString& tabname = lfile.curr().get("COD"); ini.set("COD", tabname, defpar); } break; } for (int f = 0; f < m.fields(); f++) { TMask_field& campo = m.fld(f); if (campo.shown()) { const TFieldref* fr = campo.field(); if (fr) { if (campo.empty()) fr->write(ini, defpar, " "); else { if (campo.class_id() == CLASS_DATE_FIELD && campo.right_justified()) { const TDate d(campo.get()); fr->write(ini, defpar, d.string(ANSI)); } else fr->write(ini, defpar, campo.get()); } } else if (campo.is_sheet()) { TSheet_field &sheet=(TSheet_field &)campo; sheet2ini(sheet,ini); // It's virtual } } } ini.set_paragraph(defpar); // Reimposta paragrafo standard } bool TRelation_application::mask2mail(const TMask& m) { TWait_cursor hourglass; bool ok = _curr_trans_from.empty() && ::can_dispatch_transaction(get_relation()->curr()); if (ok) { TFilename ininame; ininame.temp(); if (ok) // Test qualunque per usare {} { TConfig ini(ininame, "Transaction"); const char* action = ""; char mode[2] = { TM_AUTOMATIC, '\0' }; switch (m.mode()) { case NO_MODE: action = TRANSACTION_DELETE; break; case MODE_MOD: action = TRANSACTION_MODIFY; break; default: action = TRANSACTION_INSERT; break; } ini.set("Action", action); ini.set("Mode", mode); mask2ini(m, ini); } ok = ::dispatch_transaction(get_relation()->curr(), ininame); ::remove(ininame); } return ok; }