campo-sirio/include/relapp.cpp
simona 5738d45526 Modifica alla documentazione
git-svn-id: svn://10.65.10.50/trunk@3563 c028cbd2-c16b-5b4b-a496-9718f37d4682
1996-09-10 10:43:17 +00:00

1003 lines
21 KiB
C++
Executable File

#include <mailbox.h>
#include <sheet.h>
#include <urldefid.h>
#include <relapp.h>
#include <utility.h>
#define STRICT
#define XVT_INCL_NATIVE
#include <xvtility.h>
#if XVT_OS == XVT_OS_WIN
#include <windows.h>
#endif
///////////////////////////////////////////////////////////
// TRelation_application
///////////////////////////////////////////////////////////
TRelation_application::TRelation_application()
: _mask(NULL), _search_id(-1), _lnflag(FALSE)
{ }
TRelation_application::~TRelation_application()
{ }
void TRelation_application::setkey()
{
if (has_filtered_cursor())
{
TEdit_field& f = get_search_field();
TCursor* cur = f.browse()->cursor();
cur->setkey();
return;
}
file().setkey(1);
}
// @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())
{
TEdit_field& f = get_search_field();
TBrowse* b = f.browse();
TCursor* cur = b != NULL ? b->cursor() : NULL;
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();
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()
{
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(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);
}
}
enable_query();
}
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);
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, 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(get_next_key());
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, "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("Il documento 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();
if (pre_ins)
{
set_mode(NO_MODE);
init_query_insert_mode(*_mask);
}
else
{
set_mode(MODE_QUERY);
init_query_mode(*_mask);
}
}
void TRelation_application::insert_mode()
{
if (_mask->query_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("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
{
if (!autonum(_mask, FALSE))
{
query_insert_mode();
return;
}
}
set_mode(MODE_INS);
get_relation()->zero(); // Azzera tutta la relazione!
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 programma");
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);
if (changing)
_mask->open_modal();
set_mode(MODE_MOD);
err = read(*_mask);
if (err != NOERR)
{
query_mode();
return FALSE;
}
get_relation()->save_status();
init_modify_mode(*_mask);
return TRUE;
}
TEdit_field& TRelation_application::get_search_field() const
{
short id = _search_id;
if (id <= 0)
{
const int max = _mask->fields();
for (int i = 0; i < max; i++)
{
const TMask_field& f = _mask->fld(i);
if (f.in_key(1) && f.required())
{
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();
}
TMask_field* dopo = &_mask->focus_field();
prima = (dopo == prima || !dopo->is_edit()) ? NULL : (TEdit_field*)dopo;
}
return FALSE;
}
// @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(
byte 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())
{
onereq = TRUE;
if (e->empty())
{
if (err)
{
error_box("Manca un valore indispensabile per la ricerca");
_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("Manca un valore indispensabile per la ricerca");
return FALSE;
}
return onefill || onereq;
}
bool TRelation_application::find(byte 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;
}
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();
const char* ms = (mode == MODE_MOD) ? "le modifiche" : "i dati inseriti";
if (mode == MODE_QUERY)
{
const bool cont = !dirty || yesno_box("Annullare %s?", ms);
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 last = _mask->last_key();
const bool annulla = last == K_ESC || last == K_QUIT || last == K_F9;
const bool errore = dirty && _mask->field(dirty).dirty() > TRUE;
KEY k;
if (errore)
{
if (annulla)
{
TString w(80);
if (_mask->field(dirty).is_edit())
w = _mask->efield(dirty).get_warning();
if (w.empty())
w = "Campo inconsistente";
w << ": si desidera ";
switch (last)
{
case K_ESC:
w << "annullare?"; break;
case K_QUIT:
w << "uscire?"; break;
default:
w << "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("Registrare %s?", ms);
if (k == K_ESC || k == K_NO)
{
if (mode == MODE_MOD)
{
get_relation()->restore_status();
get_relation()->lfile().reread(_unlock); // Unlock main file
}
was_dirty = FALSE;
return k == K_NO;
}
if (annulla)
{
if (!_mask->check_fields()) // Exit with ESC didn't check values
{
_mask->first_focus(-_mask->focus_field().dlg());
was_dirty = TRUE;
return FALSE;
}
}
}
was_dirty = FALSE;
begin_wait();
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);
}
end_wait();
switch(err)
{
case NOERR:
_recins = get_relation()->lfile().recno();
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();
m.autosave(r);
r.write();
return r.status();
}
int TRelation_application::rewrite(const TMask& m)
{
TRelation& r = *get_relation();
m.autosave(r);
r.rewrite();
return r.status();
}
// @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 <f CHECK> di errore.
{
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 bool ok = remove();
if (ok)
set_limits();
else
return error_box("Errore di cancellazione %d", r->status());
}
return TRUE;
}
bool TRelation_application::remove()
{
const int err = get_relation()->remove();
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;
}
bool TRelation_application::main_loop()
{
_recins = -1;
query_mode();
_mask->open_modal();
KEY k;
// Provoca l'autopremimento per il messaggio di LINK
if (_lnflag) _mask->send_key(K_AUTO_ENTER, 0);
do
{
const bool change = firm_change_enabled();
// Dis/abilita cambio ditta
enable_menu_item(M_FILE_NEW, change);
// Dis/abilita cambio parametri
enable_menu_item(M_FILE_REVERT, change);
k = _mask->run();
switch (k)
{
case K_ESC:
if (save(TRUE))
query_mode();
if (_lnflag)
k = K_QUIT;
break;
case K_QUIT:
if (!save(TRUE))
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())
{
k = K_QUIT;
}
else
{
if (save_and_new())
{
if (_mask->insert_mode())
insert_mode();
else
query_mode();
}
else
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)
{
modify_mode();
warning_box("Documento gia' presente");
}
else
insert_mode();
}
break;
case K_DEL:
if (relation_remove())
query_mode();
if (_autoins_caller.not_empty())
{
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();
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 (autoins_caller().not_empty() && _recins >= 0)
{
TMessage msg(autoins_caller(), _lnflag ? MSG_LN : 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->setfilter("");
cur->setregion(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();
_autoins_caller = msg->from();
_lnflag = TRUE;
const char* v = body.get();
TString80 s;
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))
{
s = v;
_fixed.add(format("%d=%s", f.dlg(), (const char*)s));
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;
TString80 t;
while((s = body.get()) != NULL)
{
t = s;
const int u = t.find('=');
CHECKS(u > 0, "Invalid edit message ", (const char *) body);
if (u > 0)
{
const TString 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)
_fixed.add(format("%d=%s", f.dlg(), (const char*)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();
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))
{
const TString s(v);
_fixed.add(format("%d=%s", f.dlg(), (const char*) s));
v = body.get();
}
}
}