campo-sirio/include/relapp.cpp
guy 4759abb8f4 applicat.cpp Aggiunto metodo pre_create per inizializzazioni di basso livello
golem.cpp     Migliorata gestione degli hook agli handler di finestra
msksheet.cpp  Eliminati molti sfarfallamenti duante cambio focus
relapp.cpp    Corretta gestione messaggio ED
sheet.cpp     Corretto posizionamento iniziale su righe disabilitate
xvtility.cpp  Migliorata gestione dell'event hook.


git-svn-id: svn://10.65.10.50/trunk@3328 c028cbd2-c16b-5b4b-a496-9718f37d4682
1996-08-05 09:43:06 +00:00

1001 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 == 1)
_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 | Il campo chiave non e' vuoto
// @flag FALSE | Non e' riuscii ad autonumerare il campo chiave
bool TRelation_application::autonum(
TMask* m, // @parm Maschera a cui applicare l'autonumerazione
bool rec) // @parm Indica se registrare il 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
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();
}
}
}