campo-sirio/include/relapp.cpp

867 lines
17 KiB
C++
Executable File

// $Id: relapp.cpp,v 1.1.1.1 1994-08-12 10:52:05 alex Exp $
#include <mailbox.h>
#include <sheet.h>
#include <urldefid.h>
#include <relapp.h>
#include <utility.h>
#include <xvtility.h>
#if XVT_OS == XVT_OS_WIN
extern "C" {
#include <statbar.h>
}
#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;
}