campo-sirio/include/maskfld.cpp
guy 81534d006f Patch level : 10.0
Files correlati     : tutti
Ricompilazione Demo : [ ]
Commento            :
0001213: mappa di login, fuoco
Lla mappa di login si apre ma per poter digitare la password bisogna cliccare sul campo col mouse. Stesso problema richiamando le ricerche, per esempio quella clienti.


git-svn-id: svn://10.65.10.50/trunk@18591 c028cbd2-c16b-5b4b-a496-9718f37d4682
2009-03-23 15:16:49 +00:00

5269 lines
118 KiB
C++
Executable File

#include <automask.h>
#include <colors.h>
#include <controls.h>
#include <diction.h>
#include <execp.h>
#include <expr.h>
#include <msksheet.h>
#include <recarray.h>
#include <recset.h>
#include <relapp.h>
#include <sheet.h>
#include <relation.h>
#include <tabutil.h>
#include <text.h>
#include <urldefid.h>
#include <utility.h>
#include <validate.h>
#include <virtkeyb.h>
#include <nditte.h>
// @doc INTERNAL
// @func HIDDEN void | smart_trim | Elimina gli spazi iniziali e/o finali da un stringa
HIDDEN void smart_trim(
TString & s, // @parm Stringa
byte mode // @parm operazione da effettuare ( 0 = nessuna operazione
// 1 = trimma a sinistra
// 2 = trimma a destra
// 3 = trimma da entrambi i lati
)
{
switch (mode)
{
case 1: s.ltrim(); break;
case 2: s.rtrim(); break;
case 3: s.trim(); break;
default: break;
}
}
///////////////////////////////////////////////////////////
// Field Flags
///////////////////////////////////////////////////////////
// Certified 100%
TMask_field::TField_Flags::TField_Flags()
{
automagic = persistent = FALSE;
enabled = enable_default = TRUE;
shown = show_default = TRUE;
uppercase = rightjust = FALSE;
zerofilled = button = FALSE;
dirty = focusdirty = FALSE;
roman = read_only = FALSE;
firm = ghost = FALSE;
password = FALSE;
trim = 3;
pipeallowed = FALSE;
user = FALSE;
}
// Certified 100%
char TMask_field::TField_Flags::update(const char* f, bool reset)
{
const char * s;
for (s = f; *s; s++)
switch(*s)
{
case '#':
trim = 2; break;
case '@':
trim = 1; break;
case ' ':
case '_':
trim = 0; break;
case '*':
password = !reset; break;
case 'A':
automagic = persistent = !reset; break;
case 'B':
button = !reset; break;
case 'D':
enable_default = enabled = reset; break;
case 'F':
firm = persistent = !reset; break;
case 'G':
ghost = !reset; break;
case 'H':
show_default = shown = reset; break;
case 'I':
break; // reserved for sheetfield insert
case 'L':
read_only = !reset; break;
case 'M':
roman = !reset; break;
case 'P':
persistent = !reset; break;
case 'R':
rightjust = !reset; break;
case 'T':
user = !reset; break;
case 'U':
uppercase = !reset; break;
case 'Z':
zerofilled = !reset; break;
default :
break;
}
return *s;
}
///////////////////////////////////////////////////////////
// TMask_field
///////////////////////////////////////////////////////////
TMask_field::TControl_data TMask_field::_ctl_data;
void TMask_field::TControl_data::reset()
{
_dlg = -1;
_x = _y = -1;
_width = 0;
_height = 1;
_size = 0;
_decimals = 0;
_bmp_up = _bmp_dn = 0;
_prompt.cut(0);
_flags.cut(0);
_park.spaces(256);
_park.cut(0);
}
void TMask_field::update_flags(const char* f, bool reset)
{
_flags.update(f, reset);
show(shown());
enable(enabled());
set_read_only(read_only());
}
TMask_field::TMask_field(TMask* m)
: _mask(m), _groups(NULL), _ctl(NULL)
{ }
// Certified 100%
TMask_field::~TMask_field()
{
if (_ctl) delete _ctl;
if (_groups) delete _groups;
}
// Certified 100%
const char* TMask_field::class_name() const
{ return "Field"; }
// Certified 100%
word TMask_field::class_id() const
{ return CLASS_FIELD; }
// Certified 100%
bool TMask_field::is_kind_of(word cid) const
{ return cid == CLASS_FIELD || TObject::is_kind_of(cid); }
// Certified 100%
bool TMask_field::ok() const
{ return _ctl != NULL; }
// Certified 100%
void TMask_field::parse_head(TScanner&)
{}
short TMask_field::dlg() const
{
return _ctl ? _ctl->id() : _ctl_data._dlg;
}
void TMask_field::highlight() const
{
#ifdef DBG
yesnofatal_box("Can't set the focus to non-operable field %d", dlg());
#endif
}
void TMask_field::set_focus() const
{
#ifdef DBG
yesnofatal_box("Can't set the focus to non-operable field %d", dlg());
#endif
}
void TMask_field::set_justify(bool r)
{
_flags.rightjust = r;
if (_ctl)
_ctl->set_rjust(r);
}
void TMask_field::set_read_only(bool r)
{
_flags.read_only = r && !in_key(1);
if (_ctl)
_ctl->set_read_only(_flags.read_only);
}
// @doc INTERNAL
// Certified 100%
// @mfunc Converte una stringa in un identificatore di campo.
short TMask_field::atodlg(
const char* s) const // @parm stringa da convertire in numero
// @comm In modo DBG controlla anche che sia un numero valido
{
short d = (s && *s) ? atoi(s) : 0;
#ifdef DBG
if (d == 0 || d < -1 || d > 1000)
{
yesnofatal_box("Identificatore non valido nel campo %d: '%s'", _ctl_data._dlg, s);
d = DLG_NULL;
}
#endif
return d;
}
// @doc EXTERNAL
// @mfunc Imposta la posizione
void TMask_field::set_caret_pos(
int pos) // @parm Posizione
{
_ctl->set_caret_pos(pos);
}
// @doc EXTERNAL
// @mfunc Costruisce il campo
void TMask_field::construct(
short id, // @parm Identificatore del campo
const char* prompt, // @parm Prompt del campo
int x, // @parm Posizione in x (in caratteri) del campo nella maschera
int y, // @parm Posizione in y (in caratteri) del campo nella maschera
int len, // @parm Lunghezza del buffer campo
WINDOW parent, // @parm Finestra padre alla quale assegnare il campo
const char* flags, // @parm Flags del campo (default "")
int width, // @parm Lunghezza a video del campo
short bmp_up, // @parm Immagine standard del bottone
short bmp_dn) // @parm Immagine spremuta del bottone
// @parm TScanner& | scanner | File dal quale leggere leggere le informazioni
// @syntax void construct(TScanner& scanner, WINDOW parent);
// @syntax void construct(short id, const char* prompt, int x, int y, int len, WINDOW parent, const char* flags, int width);
//
// @comm E' possibile costruire il campo leggendo direttamente dal file, oppure passare alla funzione
// tutti i parametri necessari alla definizione del campo stesso
{
_ctl_data.reset();
_ctl_data._x = x;
_ctl_data._y = y;
_ctl_data._prompt = prompt;
_ctl_data._size = len;
switch(class_id())
{
case CLASS_REAL_FIELD:
((TReal_field*)this)->set_decimals(width);
_ctl_data._width = len;
break;
case CLASS_BUTTON_FIELD:
case CLASS_BUTTON_TOOL:
_ctl_data._height = len;
_ctl_data._width = width <= 0 ? 12 : width;
_ctl_data._bmp_up = bmp_up;
_ctl_data._bmp_dn = bmp_dn;
break;
case CLASS_MEMO_FIELD:
_ctl_data._height = len;
_ctl_data._width = width;
_ctl_data._size = len * width;
break;
case CLASS_TREE_FIELD:
case CLASS_OUTLOOK_FIELD:
_ctl_data._height = len;
_ctl_data._width = width;
_ctl_data._size = 0;
break;
default:
_ctl_data._width = width == 0 ? len : width;
break;
}
_ctl_data._dlg = id;
_ctl_data._flags = flags;
_flags.update(flags);
create(parent);
}
void TMask_field::construct(TScanner& scanner, WINDOW parent)
{
_ctl_data.reset();
_ctl_data._dlg = atodlg(scanner.pop());
parse_head(scanner);
scanner.popkey(); // BEGIN
#ifdef DBG
if (scanner.key() != "BE")
{
NFCHECK("Testata errata o BEGIN mancante nel campo %d", _ctl_data._dlg);
scanner.push();
}
if (_ctl_data._dlg > 0)
{
const TMask& m = mask();
for (int f = m.fields()-1; f >= 0; f--)
{
const TMask_field& mf = m.fld(f);
if (mf.dlg() == _ctl_data._dlg && mf.parent() == parent)
NFCHECK("Esistono due campi con identificatore %d", _ctl_data._dlg);
}
}
#endif
while(scanner.popkey() != "EN") // END of control
parse_item(scanner);
create(parent);
}
void TMask_field::destroy()
{
if (_ctl != NULL)
_ctl->destroy();
}
void TMask_field::set_group(byte group)
{
if (_groups == NULL)
_groups = new TBit_array;
_groups->set(long(group));
_groups->set(0L);
}
bool TMask_field::parse_item(TScanner& scanner)
{
if (scanner.key() == "PR") // PROMPT
{
_ctl_data._x = scanner.integer();
_ctl_data._y = scanner.integer();
_ctl_data._prompt = dictionary_translate_prompt(scanner.string(), is_editable() ? 0 : -1);
return TRUE;
}
if (scanner.key() == "FL") // FLAGS
{
const char* f = scanner.string();
if (_flags.update(f) == '\0')
_ctl_data._flags << f;
return TRUE;
}
if (scanner.key() == "GR")
{
if (_groups == NULL)
_groups = new TBit_array;
_groups->set(scanner.line());
return TRUE;
}
NFCHECK("'%s' Token non riconosciuto nel campo %d: %s",
(const char*)scanner.token(), (int)dlg(), (const char*)_ctl_data._prompt);
return FALSE;
}
// Certified 100%
WINDOW TMask_field::parent() const
{
CHECK(_ctl, "Can't get the parent of a NULL control");
return _ctl->parent();
}
RCT& TMask_field::get_rect(RCT& r) const
{
if (_ctl) _ctl->get_rect(r);
else memset(&r, 0, sizeof(r));
return r;
}
void TMask_field::set_rect(const RCT& r)
{
if (_ctl) _ctl->set_rect(r);
}
// Certified 100%
// @doc EXTERNAL
// @mfunc Abilita/disabilita il campo (lo rende scrivibile)
void TMask_field::enable(
bool on) // @parm Operazione da svolgere:
//
// @flag TRUE | Abilita il campo (default)
// @flag FALSE | Disabilita il campo
{
_flags.enabled = on;
}
// Certified 100%
void TMask_field::enable_default()
{
const bool ed = _flags.enable_default;
enable(ed);
}
// Certified 100%
// @doc EXTERNAL
// @mfunc Permette di rendere visibile/invisibile un campo
void TMask_field::show(
bool on) // @parm Operazione da svolgere:
//
// @flag TRUE | Rendere visibile il campo (default)
// @flag FALSE | Rendere invisibile il campo
{
if (_ctl)
{
_ctl->show(on);
_flags.shown = on;
}
}
// Certified 100%
void TMask_field::show_default()
{
const bool sd = _flags.show_default;
show(sd);
}
// Certified 100%
bool TMask_field::active() const
{
return is_operable() && enabled() && shown() && !read_only();
}
void TMask_field::set_dirty(byte d)
{
if (_flags.dirty == 3)
{
if (d == FALSE) // Non permette di annullare il dirty dei campi errati
return;
}
#ifdef DBG
if (d == 3)
_flags.dirty = d; // Riga per breakpoint
#endif
_flags.dirty = d;
set_focusdirty(d != 0);
}
// Certified 100%
const char* TMask_field::prompt() const
{
return _ctl ? _ctl->caption() : "";
}
// Certified 100%
void TMask_field::reset()
{
if (!_flags.persistent)
set("");
}
// Certified 100%
void TMask_field::set_prompt(const char* p)
{
if (_ctl) _ctl->set_caption(p);
}
int TMask_field::page() const
{
return _mask->win2page(parent());
}
void TMask_field::set(const char*)
{
// Place holder
}
void TMask_field::set(long n)
{
TString16 s; s << n;
set(s);
}
const TString& TMask_field::get() const
{
return EMPTY_STRING;
}
long TMask_field::get_long() const
{
return atol(get());
}
void TMask_field::set_default(const char*)
{
NFCHECK("Only loadables can have a default");
}
const TString& TMask_field::get_default() const
{
NFCHECK("Only loadables can have a default");
return EMPTY_STRING;
}
const TString & TMask_field::evaluate_field(short id) const
{
if (id == 0)
return get();
const TMask* m = &mask();
if (id < 0)
{
TSheet_field* sh = m->get_sheet();
if (sh != NULL)
{
m = &sh->mask();
id = -id;
}
}
const int pos = m->id2pos(id);
if (pos >= 0)
return m->fld(pos).get();
return EMPTY_STRING;
}
const TString & TMask_field::evaluate_field(const char * s) const
{
if (s && *s)
{
if (s[0] == '#')
s++;
const short id = atoi(s);
return evaluate_field(id);
}
return EMPTY_STRING;
}
// @doc EXTERNAL
// @mfunc Verifica se il campo deve essere sottoposto a check
//
// @rdesc Ritorna il risultato:
//
// @flag TRUE | Se il campo e' da sottoporre a check
// @flag FALSE | Se il campo non e' da sottoporre check
bool TMask_field::to_check(
KEY k, // @parm Tasto da passare al campo come simulazione di inizio controllo
bool checkrun) const // @parm Permette di ritornare TRUE se la maschera e' in start_run() mode
{
bool yes = (k == K_TAB && focusdirty()) || (k == K_ENTER && dirty());
if (!yes && checkrun)
yes = k == K_TAB && !mask().is_running();
return yes;
}
void TMask_field::send_key(KEY k, short to)
{
_mask->send_key(k, to, this);
}
void TMask_field::check_type(CheckType)
{ CHECK(0, "Can't set check type to non-edit field"); }
void TMask_field::set_handler(CONTROL_HANDLER)
{ CHECK(0, "Can't set the handler to a TMask_field"); }
bool TMask_field::on_hit()
{
CHECK(0, "Can't hit non-operable field");
return false;
}
// Certified 100%
bool TMask_field::on_key(KEY key)
{
#ifdef DBG
if (key > (K_CTRL+K_SPACE))
return error_box("Tasto ignorato %d", key);
#endif
return true;
}
#define build_msg() \
char* _msg = _ctl_data._park.get_buffer(256); \
va_list argptr; va_start(argptr,fmt); \
vsprintf(_msg,fmt,argptr);va_end(argptr)
// @doc EXTERNAL
// @mfunc Crea una error-box relativo al campo (chiama <f error_box>)
//
// @rdesc Ritorna sempre FALSE
bool TMask_field::error_box(
const char* fmt, // @parm Formato della stringa da scrivere
...) const // @parmvar Uno o piu' parametri corrispondenti ai codici in <p fmt>
// @comm Se il campo e' uno sheet viene aggiornata la barra di stato, altrimenti
// viene creata una finestra di errore normale.
{
build_msg();
TMask& m = mask();
if (m.is_sheetmask() && !m.is_running())
m.get_sheet()->error_box(_msg);
else
m.post_error_message(_msg, 3);
return false;
}
bool TMask_field::message_box(const char* fmt, ...) const
{
build_msg();
mask().post_error_message(_msg, 1);
return false;
}
// @doc EXTERNAL
// @mfunc Crea una warning-box relativo al campo (chiama <f warning_box>)
//
// @rdesc Ritorna sempre FALSE
bool TMask_field::warning_box(
const char* fmt, // @parm Formato della stringa da scrivere
...) const // @parmvar Uno o piu' parametri corrispondenti ai codici in <p fmt>
// @comm Se il campo e' uno sheet viene aggiornata la barra di stato, altrimenti
// viene creata una finestra di warning normale.
{
build_msg();
if (mask().is_sheetmask() && !mask().is_running())
{
xvt_dm_post_speech(_msg, 1, TRUE);
xvtil_statbar_set(_msg);
beep(1);
}
else
{
mask().post_error_message(_msg, 2);
}
return FALSE;
}
bool TMask_field::yesno_box(const char* fmt, ...) const
{
set_focus();
build_msg();
const bool yes = ::yesno_box("%s", _msg);
set_focus();
return yes;
}
KEY TMask_field::yesnocancel_box(const char* fmt, ...) const
{
set_focus();
build_msg();
const KEY k = ::yesnocancel_box("%s", _msg);
set_focus();
return k;
}
///////////////////////////////////////////////////////////
// TText_field
///////////////////////////////////////////////////////////
// Certified 100%
word TText_field::class_id() const
{ return CLASS_TEXT_FIELD; }
// Certified 100%
bool TText_field::is_kind_of(word cid) const
{ return cid == CLASS_TEXT_FIELD || TMask_field::is_kind_of(cid); }
// Certified 100%
void TText_field::create(WINDOW parent)
{
_ctl = new TText_control(parent, _ctl_data._dlg,
_ctl_data._x, _ctl_data._y,
0, 1,
_ctl_data._flags, _ctl_data._prompt);
}
///////////////////////////////////////////////////////////
// TGroup_field
///////////////////////////////////////////////////////////
// Certified 100%
word TGroup_field::class_id() const
{ return CLASS_GROUPBOX_FIELD; }
TGroup_field::TGroup_field(TMask* mask) : TMask_field(mask)
{
_flags.persistent = TRUE;
}
// _size means _heigth
void TGroup_field::parse_head(TScanner& scanner)
{
_ctl_data._width = scanner.integer();
_ctl_data._size = scanner.integer();
}
void TGroup_field::create(WINDOW parent)
{
_ctl = new TGroupbox_control(parent, _ctl_data._dlg,
_ctl_data._x, _ctl_data._y,
_ctl_data._width, _ctl_data._size,
_ctl_data._flags, _ctl_data._prompt);
}
///////////////////////////////////////////////////////////
// TOperable_field
///////////////////////////////////////////////////////////
TOperable_field::TOperable_field(TMask* m)
: TMask_field(m), _message(NULL), _handler(NULL)
{ }
TOperable_field::~TOperable_field()
{
if (_message)
delete _message;
}
TToken_string* TOperable_field::message(int m, bool crea)
{
TToken_string* msg = _message ? _message->rowptr(m) : NULL;
if (msg == NULL && crea)
{
if (_message == NULL)
_message = new TString_array(2);
msg = new TToken_string(16);
_message->add(msg, m);
}
return msg;
}
bool TOperable_field::parse_item(TScanner& scanner)
{
if (scanner.key() == "HE") // HELP
{
scanner.string(); // Ignored from this version
return true;
}
if (scanner.key() == "ME")
{
const TString& m = scanner.line().trim(); // Togli spazi
message(0, true)->add(m);
return true;
}
return TMask_field::parse_item(scanner);
}
void TOperable_field::set_focus() const
{
mask().set_focus_field(dlg());
_ctl->set_focus();
}
// Certified 100%
bool TOperable_field::is_kind_of(word cid) const
{ return cid == CLASS_OPERABLE_FIELD || TMask_field::is_kind_of(cid); }
void TOperable_field::enable(bool on)
{
TMask_field::enable(on);
if (_ctl) _ctl->enable(on);
}
bool TOperable_field::on_key(
KEY key) // @parm Tasto notificato
{
switch(key)
{
case K_F11:
if (handler(key))
{
TString msg;
msg << TR("Identificatore: ") << dlg() << '\n'
<< TR("Maschera: ") << mask().source_file() << '\n';
if (field() != NULL)
msg << TR("Campo: ") << *field();
message_box(msg);
}
break;
case K_CTRL + K_TAB:
mask().notify_focus_field(dlg());
return handler(key);
default:
return handler(key);
}
return TMask_field::on_key(key);
}
// Certified 50%
HIDDEN void modify_list(bool add, TMask_field& f, TToken_string& msg)
{
#ifdef DBG
if (f.class_id() != CLASS_LIST_FIELD)
{
yesnofatal_box("Can't add/delete items of non list-box field %d", f.dlg());
return;
}
#endif
TList_field& l = (TList_field&)f;
TToken_string item(16);
item = msg.get();
if (add) item.add(msg.get());
item.strip("\"'");
if (add)
l.add_item(item);
else
l.delete_item(item);
}
// Certified 99%
HIDDEN const char* copy_value(TToken_string& msg, const TString& val)
{
int from = msg.get_int()-1;
int to = -1;
if (from < 0) from = 0;
else to = msg.get_int();
return val.sub(from, to);
}
HIDDEN void run_app(TMask& mask, TToken_string& msg)
{
TFilename a;
for (const char* m = msg.get(1); m; m = msg.get())
{
if (a.not_empty())
a << ' ';
for (const char* f = m; *f; f++)
{
if (*f == '#')
{
const int id = atoi(++f);
a << mask.get(id);
break;
}
else
a << *f;
}
}
TExternal_app app(a);
app.run();
mask.set_focus();
}
// Certified 90%
bool TOperable_field::do_message(int num)
{
const int MAX_CMD = 18;
static const char* commands[MAX_CMD] =
{
"ADD", // 0
"CHECK", // 1
"CLEAR", // 2
"CO", // 3
"DEL", // 4
"DIRTY", // 5
"DISABLE", // 6
"ENABLE", // 7
"ENABLEDEF", // 8
"EXIT", // 9
"HIDE", // 10
"NORMAL", // 11
"PUSH", // 12
"REQUIRED", // 13
"RESET", // 14
"RU", // 15
"SHOW", // 16
"TAB", // 17
};
TToken_string* mess = message(num);
if (mess == NULL || mess->empty())
return FALSE;
TToken_string msg(16, ',');
TString256 value;
for (const char* m = mess->get(0); m && *m; m = mess->get())
{
KEY key = 0;
msg = m;
value = msg.get();
const char* dlg = msg.get();
int cmd = -1;
if (isalpha(value[0])) // binary search
{
int f = 0, l = MAX_CMD-1;
while (TRUE)
{
cmd = (f+l)>>1;
const int cmp = strcmp(value, commands[cmd]);
if (cmp == 0) break;
if (cmp > 0) f = cmd+1;
else l = cmd-1;
if (f > l)
{
cmd = -1;
break;
}
}
}
if (cmd == 9) // EXIT
{
mask().stop_run(atoi(dlg));
continue;
} else
if (cmd == 15) // RUN
{
run_app(mask(), msg);
continue;
}
short fld = (dlg && dlg[0] > ' ') ? atodlg(dlg) : 0;
const bool broadcast = dlg && strchr(dlg, '@');
if (broadcast) fld = -fld;
if (value[0] == '"')
value = value.strip("\"'");
else switch (cmd)
{
case 0:
modify_list(TRUE, mask().field(fld), msg);
continue;
case 1:
mask().field(fld).set_dirty();
mask().field(fld).on_key(K_TAB);
continue;
case 2:
mask().disable(fld);
mask().reset(fld);
continue;
case 3:
value = copy_value(msg, get()); break;
case 4:
modify_list(FALSE, mask().field(fld), msg); continue;
case 5:
mask().field(fld).set_dirty(); continue;
case 6:
mask().disable(fld); continue;
case 7:
mask().enable(fld); continue;
case 8:
mask().enable_default(fld); continue;
case 10:
mask().hide(fld); continue;
case 11:
mask().field(fld).check_type(CHECK_NORMAL); continue;
case 12:
mask().field(fld).on_hit(); continue;
case 13:
mask().field(fld).check_type(CHECK_REQUIRED); continue;
case 14:
key = K_F2; break;
case 16:
mask().show(fld); continue;
case 17:
mask().field(fld).on_key(K_TAB); continue;
default:
key = atoi(value);
break;
}
if (key)
{
if (key > 0)
send_key(key, fld);
}
else
{
// Setta a value il campo fld solo se ha un valore diverso da value
if (broadcast)
{
const int max = mask().fields();
for (int i = 0; i < max; i++)
{
TMask_field& f = mask().fld(i);
if (f.in_group((int)-fld))
{
const TString& prev = f.get();
if (value != prev)
{
f.set(value);
if (f.shown() || f.ghost())
f.on_hit();
}
}
}
}
else
{
TMask_field& f = mask().field(fld);
const char* prev = f.get();
if (value != prev)
{
f.set(value);
if (f.shown() || f.ghost())
f.on_hit();
}
}
}
}
return TRUE;
}
void TOperable_field::highlight() const
{
if (_ctl) _ctl->set_focus();
}
bool TOperable_field::handler(KEY k)
{
bool ok = true;
if (_handler)
ok = _handler(*this, k);
return ok;
}
// Certified 90%
bool TOperable_field::on_hit()
{
const bool ok = handler(K_SPACE);
if (ok && has_message())
do_message(0);
return ok;
}
///////////////////////////////////////////////////////////
// TLoadable_field
///////////////////////////////////////////////////////////
bool TLoadable_field::parse_item(TScanner& scanner)
{
if (scanner.key() == "DE") // DEFAULT
{
set_default(scanner.line());
return true;
}
return TOperable_field::parse_item(scanner);
}
// @cmember Ritorna il valore di default del campo
const TString& TLoadable_field::get_default() const
{ return _default; }
// @cmember Imposta il valore di default del campo
void TLoadable_field::set_default(const char* def)
{ _default = def; }
///////////////////////////////////////////////////////////
// Button_field
///////////////////////////////////////////////////////////
TButton_field::TButton_field(TMask* m)
: TOperable_field(m)
{ }
word TButton_field::class_id() const
{ return CLASS_BUTTON_FIELD; }
bool TButton_field::is_kind_of(word cid) const
{ return cid == CLASS_BUTTON_FIELD || TOperable_field::is_kind_of(cid); }
void TButton_field::parse_head(TScanner& scanner)
{
_ctl_data._width = scanner.integer();
if (_ctl_data._width <= 0) _ctl_data._width = 10;
_ctl_data._height = scanner.integer(); // Height
if (_ctl_data._height <= 0) _ctl_data._height = 1;
}
bool TButton_field::parse_item(TScanner& scanner)
{
if (scanner.key() == "PI")
{
const short bmp = (short)scanner.integer();
if (_ctl_data._bmp_up == 0)
_ctl_data._bmp_up = bmp;
else
_ctl_data._bmp_dn = bmp;
return bmp > 0;
}
return TOperable_field::parse_item(scanner);
}
void TButton_field::create(WINDOW parent)
{
_virtual_key = _exit_key = 0;
switch (dlg())
{
case DLG_OK:
if (_ctl_data._prompt.empty() || _ctl_data._prompt == "Conferma")
_ctl_data._prompt = BR("~Conferma", _ctl_data._width);
_exit_key = K_ENTER;
if (_ctl_data._bmp_up == 0 && _ctl_data._prompt == BR("~Conferma", _ctl_data._width))
_ctl_data._bmp_up = BMP_OK;
break;
case DLG_CANCEL:
if (_ctl_data._prompt.empty())
_ctl_data._prompt = BR("Annulla", _ctl_data._width);
_virtual_key = _exit_key = K_ESC;
if (_ctl_data._bmp_up == 0 && _ctl_data._prompt == BR("Annulla", _ctl_data._width))
_ctl_data._bmp_up = BMP_CANCEL;
break;
case DLG_DELREC:
if (_ctl_data._prompt.empty() || _ctl_data._prompt == "Elimina")
_ctl_data._prompt = BR("~Elimina", _ctl_data._width);
_exit_key = K_DEL;
if (_ctl_data._bmp_up == 0 && _ctl_data._prompt == BR("~Elimina", _ctl_data._width))
{
_ctl_data._bmp_up = BMP_DELREC;
_ctl_data._bmp_dn = BMP_DELRECDN;
}
break;
case DLG_PRINT:
if (_ctl_data._prompt.empty() || _ctl_data._prompt == "Stampa")
_ctl_data._prompt = BR("~Stampa", _ctl_data._width);
_exit_key = K_ENTER;
if (_ctl_data._bmp_up <= 0 && _ctl_data._prompt == BR("~Stampa", _ctl_data._width))
_ctl_data._bmp_up = BMP_PRINT;
break;
case DLG_QUIT:
if (_ctl_data._prompt.empty())
_ctl_data._prompt = BR("Fine", _ctl_data._width);
_virtual_key = K_F4;
_exit_key = K_QUIT;
if (_ctl_data._bmp_up <= 0 && _ctl_data._prompt == BR("Fine", _ctl_data._width))
{
_ctl_data._bmp_up = BMP_QUIT;
_ctl_data._bmp_dn = BMP_QUITDN;
}
break;
case DLG_SELECT:
if (_ctl_data._bmp_up <= 0)
_ctl_data._bmp_up = BMP_SELECT;
_exit_key = K_ENTER;
break;
default:
break;
}
_ctl = new TPushbutton_control(parent, _ctl_data._dlg,
_ctl_data._x, _ctl_data._y,
_ctl_data._width+2, _ctl_data._height,
_ctl_data._flags, _ctl_data._prompt,
_ctl_data._bmp_up, _ctl_data._bmp_dn);
TToken_string* mess = message(0);
if (mess)
{
TToken_string msg(mess->get(0), ',');
const TFixed_string m = msg.get(0);
if (m == "EXIT")
{
_exit_key = msg.get_int();
if (_exit_key == 0)
_exit_key = ((TPushbutton_control*)_ctl)->mnemonic();
}
else
{
if (msg.get_int() == 0)
_exit_key = atoi(m);
}
}
if (_virtual_key == 0)
{
const char acc = ((TPushbutton_control*)_ctl)->mnemonic();
_virtual_key = (acc > ' ') ? toupper(acc) : _exit_key;
}
}
bool TButton_field::on_key(KEY key)
{
bool ok = TRUE;
if (key == K_SPACE)
{
if (dlg() != DLG_CANCEL && dlg() != DLG_QUIT)
{
const TMask& m = mask();
if (parent() == m.toolwin())
ok = m.focus_field().on_key(K_TAB);
}
if (ok)
{
if (xvt_vobj_get_attr(NULL_WIN, ATTR_SPEECH_MODE) & (1<<7))
{
TString str = prompt();
str.strip("~");
xvt_dm_post_speech(str, 7, TRUE);
}
ok = on_hit();
if (ok && _exit_key > 0 && !has_message())
mask().stop_run(_exit_key);
}
}
else
ok = TOperable_field::on_key(key);
return ok;
}
void TButton_field::set_bmp(short up, short dn)
{
((TPushbutton_control*)_ctl)->set_bmp(up, dn);
}
void TButton_field::set_bmp(const char * up, const char * dn)
{
((TPushbutton_control*)_ctl)->set_bmp(up, dn);
}
void TButton_field::set_central_icon(unsigned icon)
{
((TPushbutton_control*)_ctl)->set_icon(icon);
}
///////////////////////////////////////////////////////////
// TEditable_field
///////////////////////////////////////////////////////////
TEditable_field::TEditable_field(TMask* m)
: TLoadable_field(m), _field(NULL), _prompt(NULL), _keys(NULL),
_warning(NULL), _drivers(NULL), _userdata(NULL), _validate(NULL)
{ }
TEditable_field::~TEditable_field()
{
if (_prompt) delete _prompt;
if (_field) delete _field;
if (_keys) delete _keys;
if (_validate) delete _validate;
if (_warning) delete _warning;
if (_drivers) delete _drivers;
if (_userdata) delete _userdata;
}
void TEditable_field::set_warning(const char* w)
{
if (_warning)
*_warning = w;
else
_warning = new TString(w);
if (_warning->empty())
{
delete _warning;
_warning = NULL;
}
}
// Certified 100%
const char* TEditable_field::prompt() const
{
return _prompt ? _prompt->caption() : "";
}
void TEditable_field::reset_driver(short id)
{
if (_drivers != NULL)
{
if (id == 0)
_drivers->destroy();
else
{
for (int f = _drivers->last(); f >= 0; f--)
{
const short fid = (short)_drivers->get_long(f);
if (fid == id)
_drivers->destroy(f, true);
}
}
}
}
bool TEditable_field::add_driver(short id)
{
if (id != 0)
{
if (_drivers == NULL)
_drivers = new TPointer_array;
_drivers->add_long(id);
}
return id != 0;
}
TOperable_field* TEditable_field::get_driver(int n, bool test) const
{
TOperable_field* driver = NULL;
if (_drivers != NULL)
{
const short id = (short)_drivers->get_long(n);
if (id != 0)
{
if (id < 0)
{
TSheet_field* sheet = mask().get_sheet();
if (sheet)
{
const int pos = sheet->mask().id2pos(-id);
if (pos >= 0)
driver = (TOperable_field*)&sheet->mask().fld(pos);
}
}
else
{
const int pos = mask().id2pos(id);
if (pos >= 0)
{
driver = (TOperable_field*)&mask().fld(pos);
if (test)
{
TString16 msg; msg.format("CHECK,%d", dlg());
TToken_string* tok = driver->message(0, false);
if (tok == NULL || tok->get_pos(msg) < 0)
driver->message(0, true)->add(msg);
}
}
}
}
}
return driver;
}
TOperable_field* TEditable_field::driver(int n) const
{
return get_driver(n, false);
}
void TEditable_field::test_drivers() const
{
if (_drivers != NULL)
{
for (int i = 0; i < _drivers->items(); i++)
get_driver(i, true);
}
}
// Ritorna il messaggio d'errore associato al campo
const char* TEditable_field::get_warning() const
{ return _warning ? (const char*)*_warning : ""; }
bool TEditable_field::parse_item(TScanner& scanner)
{
const TString& k = scanner.key();
if (k == "FI") // FIELD
{
set_field(scanner.line());
return TRUE;
}
if (k == "KE") // KEY
{
if (_keys == NULL)
_keys = new TBit_array;
_keys->set(scanner.line());
_keys->set(0L);
return TRUE;
}
if (k == "DR") // DRIVENBY
{
TToken_string lista(scanner.line(), ' ');
FOR_EACH_TOKEN(lista, tok)
{
const short id = atoi(tok);
add_driver(id);
}
return TRUE;
}
if (k == "CU") // CUSTOM DATA
{
if (_userdata == NULL)
_userdata = new TToken_string(scanner.string());
else
_userdata->add(scanner.string());
return TRUE;
}
if (scanner.key() == "VA")
{
#ifdef DBG
if (_validate)
return yesnofatal_box("VALIDATE duplicata nel campo %d", _ctl_data._dlg);
#endif
_validate = new TValidation_data;
const char* n = scanner.pop();
_validate->_func = isdigit(*n) ? atoi(n) : -1;
#ifdef DBG
if (_validate->_func < 0)
return yesnofatal_box("Funzione di validazione '%s' errata nel campo %d",
n, _ctl_data._dlg);
#endif
const int nparms = scanner.integer();
#ifdef DBG
if (nparms < 0 || nparms > 100)
return yesnofatal_box("Numero di parametri VALIDATE errato nel campo %d: %d",
_ctl_data._dlg, nparms);
#endif
for (int i = 0; i < nparms; i++)
{
// per risolvere problemi nelle formule
// l'ultimo parametro viene letto fino in fondo alla riga
if (i == nparms-1)
{
TString& str = scanner.line().trim();
if (str[0] == '{' && str.ends_with("}")) // caso speciale di formule tra graffe
{ str.rtrim(1); str.ltrim(1); }
_validate->_parms.add(str);
}
else
_validate->_parms.add(scanner.operand());
}
return TRUE;
}
if (scanner.key() == "WA")
{
const char* msg = dictionary_translate(scanner.string());
set_warning(msg);
return TRUE;
}
return TLoadable_field::parse_item(scanner);
}
void TEditable_field::set_key(byte key)
{
if (_keys == NULL)
_keys = new TBit_array;
_keys->set(long(key));
_keys->set(0L);
}
// Certified 90%
word TEditable_field::last_key() const
{
long u = _keys ? _keys->last_one() : 0;
if (u < 0) u = 0;
return (word)u;
}
// Certified 90%
word TEditable_field::first_key() const
{
if (_keys == NULL)
return 0;
const int last = last_key();
int i;
for (i = 1; i <= last; i++)
if (in_key(i) == TRUE)
break;
return (word)i;
}
// Certified 90%
bool TEditable_field::has_a_common_key(const TMask_field & f) const
{
const int last = last_key();
for (int i = 1; i <= last; i++)
if (in_key(i) && f.in_key(i))
return TRUE;
return FALSE;
}
bool TEditable_field::test_key_complete(bool normal) const
{
TMask& m = mask();
for (int k = 1; k <= MAX_KEYS; k++)
{
if (in_key(k) && m.key_valid(k))
{
bool complete = true;
for (TEditable_field* e = m.get_key_field(k, TRUE); e; e = m.get_key_field(k, FALSE))
{
e->set_focusdirty(FALSE);
if (e->is_edit())
complete &= e->required();
}
if (normal && !complete)
m.set_test_field(dlg());
else
m.stop_run(K_AUTO_ENTER);
return true;
}
}
return false;
}
// Certified 90%
void TEditable_field::reset_key(byte key)
{
if (_keys)
{
_keys->reset(long(key));
if (key == 0 || last_key() == 0)
{
delete _keys; // Se non ci sono piu' chiavi azzera tutto
_keys = NULL;
}
}
}
// @doc EXTERNAL
// @mfunc Chiama l' eventuale funzione di validazione
//
// @rdesc Ritorna il risultato dell funzione di validazione:
//
// @flag TRUE | Se la validata ha avuto successo
// @flag FALSE | Se la validata no ha avuto successo
bool TEditable_field::validate(
KEY k) // @parm Tasto da passare alla funzione di validazione
{
bool ok = true;
if (_validate != NULL)
ok = ::validate(_validate->_func, *this, k, _validate->_parms);
return ok;
}
// Certified 90%
// @doc EXTERNAL
// @mfunc Crea il prompt del controllo
//
// @rdesc Ritorna la lunghezza del prompt creato
word TEditable_field::create_prompt(
WINDOW parent, // @parm Finestra padre alla quale assegnare il prompt del controllo
word width, // @parm Larghezza del controllo
word height) // @parm Altezza del controllo
{
if (_ctl_data._prompt.not_empty())
{
TString flags;
if (hidden()) flags << 'H';
if (height < 3)
{
width = _ctl_data._prompt.len();
word i;
for (i = 0; i < width && _ctl_data._prompt[(int)i] == '@'; i += 2);
width -= i;
_prompt = new TText_control(parent, -1, _ctl_data._x, _ctl_data._y,
0, 1, flags, _ctl_data._prompt);
}
else
{
if (right_justified()) flags << 'R';
_prompt = new TGroupbox_control(parent, -1, _ctl_data._x, _ctl_data._y,
width, height, flags, _ctl_data._prompt);
}
}
return width;
}
void TEditable_field::show(bool on)
{
TOperable_field::show(on);
if (_prompt) _prompt->show(on);
}
void TEditable_field::set_prompt(const char* p)
{
if (_prompt)
_prompt->set_caption(p);
else
NFCHECK("Can't set prompt to control %d", dlg());
}
// Certified 90%
void TEditable_field::set_field(const TString& fr)
{
if (_field != NULL)
{
if (fr.blank())
{
delete _field;
_field = NULL;
}
else
*_field = fr;
}
else
{
if (!fr.blank())
_field = new TFieldref(fr, 0);
}
}
// Certified 100%
// Legge il valore attuale del campo in formato RAW
const TString& TEditable_field::get() const
{
return _str;
}
// Certified 100%
// Aggiusta un valore letto da file in formato RAW
const char* TEditable_field::reformat(const char* data) const
{
return data;
}
// Certified 100%
// Setta il valore RAW e WIN del campo con un valore RAW
void TEditable_field::set(const char* data)
{
_str = reformat(data);
const char* val = raw2win(_str);
set_window_data(val);
const TMask& m = mask();
if (m.is_running() || m.is_sheetmask())
set_dirty();
}
// Certified 100%
// Converte da formato RAW a formato WIN
const char* TEditable_field::raw2win(const char* data) const
{
return reformat(data);
}
// Certified 100%
// Converte da formato WIN a formato RAW
const char* TEditable_field::win2raw(const char* data) const
{
return reformat(data);
}
bool TEditable_field::autosave(TRelation& r)
{
if (_field)
_field->write(get(), r);
return _field != NULL;
}
bool TEditable_field::autoload(const TRelation& r)
{
if (_field)
set(_field->read(r));
return _field != NULL;
}
///////////////////////////////////////////////////////////
// Boolean_field
///////////////////////////////////////////////////////////
TBoolean_field::TBoolean_field(TMask* m)
: TEditable_field(m)
{}
word TBoolean_field::class_id() const
{ return CLASS_BOOLEAN_FIELD; }
bool TBoolean_field::is_kind_of(word cid) const
{ return cid == CLASS_BOOLEAN_FIELD || TEditable_field::is_kind_of(cid); }
void TBoolean_field::create(WINDOW parent)
{
_ctl = new TCheckbox_control(parent, _ctl_data._dlg,
_ctl_data._x, _ctl_data._y, 0,
_ctl_data._flags, _ctl_data._prompt);
}
void TBoolean_field::set_prompt(const char* p)
{
_ctl->set_caption(p);
}
const char* TBoolean_field::reformat(const char* data) const
{
return (data && *data > ' ' && *data != '0' && *data != 'N') ? "X" : "";
}
void TBoolean_field::set_window_data(const char* data)
{
if (_ctl)
((TCheckbox_control*)_ctl)->check(*data > ' ');
}
TString& TBoolean_field::get_window_data()
{
const bool on = _ctl != NULL && ((TCheckbox_control*)_ctl)->checked();
_str = on ? "X" : "";
return _str;
}
bool TBoolean_field::parse_item(TScanner& scanner)
{
if (scanner.key() == "ME")
{
const bool tf = scanner.integer() != 0; // Message TRUE or FALSE
TToken_string* ts = message(tf, TRUE);
ts->add(scanner.line().strip_spaces());
return true;
}
return TEditable_field::parse_item(scanner);
}
bool TBoolean_field::on_hit()
{
const bool ok = handler(K_SPACE);
if (ok)
{
const bool on = get() == "X";
do_message(on);
}
return ok;
}
bool TBoolean_field::on_key(KEY key)
{
switch (key)
{
case K_SPACE:
get_window_data();
set_dirty();
on_hit();
return TRUE;
case K_F2:
if (!read_only())
{
set("");
set_dirty();
}
return TRUE;
default:
return TEditable_field::on_key(key);
}
return FALSE;
}
///////////////////////////////////////////////////////////
// TCheckbutton_field
///////////////////////////////////////////////////////////
// Copiato da TButton::parse_item
void TCheckbutton_field::parse_head(TScanner& scanner)
{
_ctl_data._width = scanner.integer();
if (_ctl_data._width <= 0) _ctl_data._width = 10;
_ctl_data._height = scanner.integer(); // Height
if (_ctl_data._height <= 0) _ctl_data._height = 1;
}
// Copiato da TButton::parse_item
bool TCheckbutton_field::parse_item(TScanner& scanner)
{
if (scanner.key() == "PI")
{
const short bmp = (short)scanner.integer();
if (_ctl_data._bmp_up == 0)
_ctl_data._bmp_up = bmp;
else
_ctl_data._bmp_dn = bmp;
return bmp > 0;
}
return TOperable_field::parse_item(scanner);
}
void TCheckbutton_field::create(WINDOW parent)
{
_ctl = new TCheckbutton_control(parent, _ctl_data._dlg,
_ctl_data._x, _ctl_data._y,
_ctl_data._width+2, _ctl_data._height,
_ctl_data._flags, _ctl_data._prompt,
_ctl_data._bmp_up, _ctl_data._bmp_dn);
}
TCheckbutton_field::TCheckbutton_field(TMask* mask) : TBoolean_field(mask)
{ }
///////////////////////////////////////////////////////////
// TBrowse_button
///////////////////////////////////////////////////////////
TBrowse_button::TBrowse_button(TEdit_field* f)
: _fld(f)
{ }
TBrowse_button::~TBrowse_button()
{
}
// Certified 100%
TEditable_field& TBrowse_button::field(short id) const
{
if (id > 0)
{
TMask_field& f = _fld->mask().field(id);
CHECKD(f.is_editable(), "Can't use in a browse the field ", id);
return (TEditable_field&)f;
}
return *_fld;
}
///////////////////////////////////////////////////////////
// TList_sheet
///////////////////////////////////////////////////////////
// Certified 100%
TList_sheet::TList_sheet(TEdit_field* f, const char* caption, const char* head)
: TBrowse_button(f), _row(-1), _caption(caption), _head(head)
{ }
// Certified 100%
TList_sheet::~TList_sheet()
{ }
// Certified 100%
void TList_sheet::parse_input(TScanner& scanner)
{
_inp_id.add(scanner.pop());
}
// Certified 100%
void TList_sheet::parse_item(TScanner& scanner)
{
_data.add(new TToken_string(scanner.string()));
}
// Certified 100%
void TList_sheet::parse_output(TScanner& scanner)
{
_out_id.add(scanner.pop());
}
// il numero di riga selezionata
int TList_sheet::do_input()
{
if (_inp_id.empty_items())
return -2; // List empty!
_inp_id.restart();
TToken_string rowsel(80);
for (const char* fld = _inp_id.get(); fld; fld = _inp_id.get())
{
if (*fld == '"')
{
rowsel.add(fld+1);
if (rowsel.not_empty()) rowsel.cut(rowsel.len()-1);
}
else
{
const short id = field().atodlg(fld);
if (id > 0)
{
const TMask_field& f = field(id);
if (f.class_id() == CLASS_ZOOM_FIELD)
{
const TZoom_field& z = (TZoom_field&)f;
rowsel.add(z.get_first_line());
}
else
rowsel.add(f.get());
}
else rowsel.add("");
}
}
TString fd, it;
for (int i = 0 ; i < _data.items(); i++)
{
TToken_string& ts =_data.row(i);
ts.restart();
const char * item;
for (item = rowsel.get(0); item ; item = rowsel.get())
{
it = item; it.trim();
fd = ts.get(); fd.trim();
if (fd != it) break;
}
if (!item) return i;
}
return -1; // Value not found!
}
// Certified 50%
void TList_sheet::do_output(CheckTime t)
{
if (_row < 0 || t == FINAL_CHECK)
return;
_out_id.restart();
TToken_string& rowsel = _data.row(_row);
rowsel.restart();
for (const char* fld = _out_id.get(); fld; fld = _out_id.get())
{
const short id = field().atodlg(fld);
TMask_field& f = field(id);
const char* val = rowsel.get();
if (t != STARTING_CHECK || f.field() == NULL)
{
const bool hit = f.get() != val;
f.set(val);
if (hit && field().dlg() != id)
{
f.on_hit();
if (t == RUNNING_CHECK)
f.check();
}
}
}
}
// Certified 100%
KEY TList_sheet::run()
{
TArray_sheet sci(3, 3, -3, -3, _caption, _head);
sci.rows_array() = _data;
_row = do_input();
sci.select(_row);
const KEY k = sci.run();
switch (k)
{
case K_ENTER:
_row = (int)sci.selected();
do_output();
break;
default:
break;
}
return k;
}
// Certified 100%
bool TList_sheet::check(CheckTime t)
{
_row = do_input();
bool passed = _row != -1;
if (passed)
do_output(t);
else
{
switch(field().check_type())
{
case CHECK_SEARCH: passed = TRUE; break;
default: break;
}
}
return passed;
}
///////////////////////////////////////////////////////////
// TBrowse
///////////////////////////////////////////////////////////
// Certified 100%
TBrowse::TBrowse(TEdit_field* f, TRelation* r, int key, const char* filter)
: TBrowse_button(f),
_relation(r), _cursor(new TCursor (r, "", key)),
_filter(filter), _secondary(FALSE)
{}
// Certified 100%
TBrowse::TBrowse(TEdit_field* f, TCursor* c)
: TBrowse_button(f),
_relation(NULL), _cursor(c), _secondary(FALSE)
{}
// Certified 100%
TBrowse::~TBrowse()
{
// Se e' stato usato il primo costruttore devo distruggere la relazione ed il cursore
if (_relation)
{
delete _cursor;
delete _relation;
}
}
// Certified 100%
void TBrowse::parse_display(TScanner& scanner)
{
const char* s = scanner.string();
_head.add(dictionary_translate_header(s));
s = scanner.line();
_items.add(s);
}
void TBrowse::parse_input(TScanner& scanner)
{
const char* s = scanner.pop();
_inp_fn.add(s);
s = scanner.pop();
if (*s == '"') // Constant string
{
scanner.push();
TString& str = scanner.line();
_inp_id.add(str);
}
else // Field on the mask
{
CHECKS(_inp_id.get_pos(s) < 0, "Duplicate input field ", s);
_inp_id.add(s);
if (scanner.popkey() == "SE")
_inp_id << '@'; // Special FILTERing field
else
scanner.push();
}
}
void TBrowse::parse_output(TScanner& scanner)
{
const char* s = scanner.pop();
#ifdef DBG
field().atodlg(s);
#endif
_out_id.add(s);
s = scanner.pop();
_out_fn.add(s);
_secondary = FALSE;
}
bool TBrowse::parse_copy(const TString& what, const TBrowse& b)
{
const bool all = what == "AL";
if (all || what == "US")
{
set_insert(b.get_insert());
_filter = b.get_filter();
if (!field().has_warning() && b.field().has_warning())
field().set_warning(b.field().get_warning());
if (!all) return TRUE;
}
if (all || what == "IN")
{
_inp_id = b._inp_id;
_inp_fn = b._inp_fn;
if (!all) return TRUE;
}
if (all || what == "DI")
{
_head = b._head;
_items = b._items;
if (!all) return TRUE;
}
if (all || what == "OU")
{
_out_id = b._out_id;
_out_fn = b._out_fn;
_secondary = b.field().has_check();
}
return TRUE;
}
void TBrowse::parse_join(TScanner& scanner)
{
TString80 j(scanner.pop()); // File or table
CHECKS(_relation, "Can't join to NULL relation ", (const char*)j);
int to;
if (scanner.popkey() == "TO") // TO keyword
{
const char* t = scanner.pop();
to = name2log(t);
}
else
{
to = 0; // _relation->lfile()->num();
scanner.push();
}
int key = 1;
if (scanner.popkey() == "KE")
key = scanner.integer();
else scanner.push();
int alias = 0;
if (scanner.popkey() == "AL")
alias = scanner.integer();
else scanner.push();
TToken_string exp(80);
if (scanner.pop() == "INTO")
{
const char* r = scanner.pop();
while (strchr(r, '=') != NULL)
{
exp.add(r);
r = scanner.pop();
}
}
scanner.push();
#ifdef DBG
if (exp.empty()) yesnofatal_box("JOIN senza espressioni INTO");
#endif
if (isdigit(j[0]))
_relation->add(atoi(j), exp, key, to, alias); // join file
else
{
#ifdef DBG
if (j.len() > 4)
yesnofatal_box("'%s' non e' una tabella valida: %d", (const char*)j);
else
#endif
_relation->add(j, exp, key, to, alias); // join table
}
}
void TBrowse::parse_insert(TScanner& scanner)
{
const TString& key = scanner.popkey();
_insert.cut(0);
if (key != "NO")
{
_insert << key[0] << scanner.line();
_insert.trim();
}
}
// Ritorna il numero di inputs senza contare quelli che funzionano solo da filtro
int TBrowse::input_fields()
{
int inp = 0;
for (const char* fld = _inp_id.get(0); fld; fld = _inp_id.get())
{
if (*fld != '"' && strchr(fld, '@') == NULL)
{
TMask_field& f = field(field().atodlg(fld));
if (f.active() && f.is_editable())
inp++;
}
}
return inp;
}
const char* TBrowse::get_input_fields() const
{
return _inp_id;
}
const char* TBrowse::get_input_field_names() const
{
return _inp_fn;
}
const char* TBrowse::get_output_fields() const
{
return _out_id;
}
const char* TBrowse::get_output_field_names() const
{
return _out_fn;
}
// @doc INTERNAL
// @mfunc Ritorna il numero di campi non vuoti e non filtrati
//
// @rdesc Numero di campi non vuoti e non filtrati
int TBrowse::do_input(
bool filter) // @parm Indica se effettuare il filtro sulla selezione
// @comm Questa funzione serve ai <c TCursor_sheet>
{
int ne = 0;
if (_inp_id.empty())
return ne;
TRectype& cur = _cursor->curr();
_cursor->file(0).zero(); // was cur.zero() che non va bene per le tabelle di modulo
TRectype filtrec(cur);
_inp_id.restart();
_inp_fn.restart();
TString val; // Value to output
bool tofilter = false;
for (const char* fld = _inp_id.get(); fld; fld = _inp_id.get())
{
if (*fld == '"')
{
val = (fld+1);
if (val.not_empty()) val.rtrim(1);
tofilter = filter;
}
else
{
const TMask_field* campf = NULL;
if (*fld == '-')
{
TSheet_field* sheet = field().mask().get_sheet();
if (sheet != NULL)
{
const short id = atoi(fld+1);
campf = &sheet->mask().field(id);
}
}
else
{
const short id = field().atodlg(fld);
campf = &field(id);
}
if (campf != NULL)
{
const TMask_field& f = *campf;
val = f.get();
if (f.class_id() == CLASS_DATE_FIELD && f.right_justified())
{
const TDate d(val);
val = d.string(ANSI);
}
const bool filter_flag = strchr(fld, '@') != NULL;
tofilter = filter && filter_flag;
if (f.is_edit() && val.not_empty() && !filter_flag)
ne++; // Increment not empty fields count
}
}
const TFieldref fldref(_inp_fn.get(), 0); // Output field
fldref.write(val, *_cursor->relation());
if (tofilter)
{
const int len = fldref.len(cur);
if (val.len() < len && cur.type(fldref.name()) == _alfafld)
val.rpad(len, '~');
fldref.write(val, filtrec);
}
}
if (!filter)
return ne;
TString work(_filter.size());
bool filter_update = FALSE;
for (int i = 0; _filter[i]; i++)
{
if (_filter[i] == '"')
{
do
{
work << _filter[i++];
} while (_filter[i] && _filter[i] != '"');
work << '"';
if (!_filter[i]) break;
}
else
if (_filter[i] == '#')
{
if (_filter[++i] == '-')
{
TString val;
TSheet_field* sheet = field().mask().get_sheet();
if (sheet != NULL)
{
const short id = atoi(&_filter[++i]);
val = sheet->mask().field(id).get();
}
work << '"' << val << '"';
}
else
work << '"' << field(atoi(&_filter[i])).get() << '"';
while (isspace(_filter[i])) i++;
while (isdigit(_filter[i])) i++;
i--;
}
else
{
work << _filter[i];
if (_filter[i] == '-' && _filter[i + 1] == '>')
filter_update = true;
}
}
_cursor->setfilter(work, filter_update);
_cursor->setregion(filtrec, filtrec);
return ne;
}
static TBit_array s_checked;
static short s_checking = 0;
void TBrowse::do_output(CheckTime t)
{
if (t == FINAL_CHECK)
return;
const bool master = s_checking == 0;
if (master)
{
s_checking = field().dlg();
s_checked.reset();
// Rendo intoccabili i campi del MIO output
for (const char* fld = _out_id.get(0); fld && *fld; fld = _out_id.get())
{
const short id = field().atodlg(fld);
s_checked.set(id);
}
}
TString sum;
TToken_string flds(24, '+');
const TRelation& relation = *_cursor->relation();
TBit_array spotted;
_out_fn.restart();
const char* fld;
for (fld = _out_id.get(0); fld && *fld; fld = _out_id.get())
{
const short id = field().atodlg(fld);
TMask_field& f = field(id);
flds = _out_fn.get();
bool do_that = t != STARTING_CHECK || f.field() == NULL || (f.mask().mode() == MODE_INS && !f.in_key(0));
if (do_that && main_app().class_id() == CLASS_RELATION_APPLICATION)
{
// Considera a parte l'inizializzazione delle transazioni!
// Non sovrascrivere con degli output campi che potrebbero essere riempiti dal .ini
if (!f.empty() && f.field() != NULL)
{
const TMask& m = f.mask();
if (!m.is_running() && m.get_sheet() == NULL) // Maschera principale chiusa
{
const TRelation_application& ra = (const TRelation_application&)main_app();
if (ra.is_transaction())
do_that = false;
}
}
}
if (do_that)
{
sum.cut(0);
for(const char* fr = flds.get(0); fr; fr = flds.get())
{
if (*fr == '"')
{
sum << (fr+1);
sum.rtrim(1);
}
else
{
const TFieldref fld(fr, 0);
sum << fld.read(relation);
}
}
bool hit = FALSE;
if (master)
{
f.set(sum);
hit = id != s_checking; // Il mio handler viene fatto nella on_key
}
else
{
if (!s_checked[id])
{
f.set(sum);
s_checked.set(id);
hit = TRUE;
}
}
spotted.set(id, hit);
}
}
for (fld = _out_id.get(0); fld && *fld; fld = _out_id.get())
{
const short id = field().atodlg(fld);
if (spotted[id])
{
TMask_field& f = field(id);
f.check();
f.on_hit();
}
}
if (master)
s_checking = 0;
}
void TBrowse::do_clear(CheckTime t)
{
const bool master = s_checking == 0;
if (master)
{
s_checking = field().dlg();
s_checked.reset();
// Rendo intoccabili i campi del MIO input
for (const char* fld = _inp_id.get(0); fld && *fld; fld = _inp_id.get())
{
if (isdigit(*fld))
{
const short id = field().atodlg(fld);
s_checked.set(id);
}
}
}
for (TString16 fld = _out_id.get(0); fld.not_empty(); fld = _out_id.get())
{
const short id = field().atodlg(fld);
TMask_field& f = field(atoi(fld));
if (f.field() == NULL && field().dlg() != id &&
!s_checked[id] && _inp_id.get_pos(fld) < 0)
{
f.reset();
s_checked.set(id);
f.on_hit();
f.check(t);
}
}
if (master)
s_checking = 0;
}
bool TBrowse::do_link(bool insert)
{
bool ok = FALSE;
TString app;
if (_insert[0] == 'M')
{
TString nm(_insert.mid(1));
if (nm.compare("tb", 2, TRUE) == 0) // Programma gestione tabelle
_cursor->file().get_relapp(app);
else // Programma generico di browse/edit
app.format("ba3 -3 %s %d", (const char*)nm, _cursor->file().num());
}
else
{
app = _insert.mid(1);
}
if (app.find('#') >= 0)
{
TString w(app);
app = "";
for (const char* f = w; *f; f++)
{
if (*f == '#')
{
const int id = atoi(++f);
app << field(id).get();
while (isspace(*f)) ++f;
while (isdigit(*f)) ++f;
if (*f)
app << ' ' << *f;
else
break;
}
else
app << *f;
}
}
TFilename msg; msg.temp("msg");
app << " /i" << msg;
if (insert)
{
TConfig ini(msg, "Transaction");
ini.set("Action", TRANSACTION_RUN);
}
else
{
TConfig ini(msg, "Transaction");
ini.set("Action", TRANSACTION_LINK);
TString8 paragraph; paragraph << _cursor->file().num();
ini.set_paragraph(paragraph);
// Uso sempre la chiave 1 per collegarmi agli altri programmi
const TRelation& rel = *_cursor->relation();
const RecDes& recd = rel.curr().rec_des(); // Descrizione del record della testata
const KeyDes& kd = recd.Ky[0]; // Elenco dei campi della chiave 1
TString inp_val;
for (int i = 0; i < kd.NkFields; i++)
{
const int nf = kd.FieldSeq[i] % MaxFields;
const RecFieldDes& rf = recd.Fd[nf];
const TFieldref fldref(rf.Name, 0);
inp_val = fldref.read(rel);
fldref.write(ini, paragraph, inp_val);
}
}
TExternal_app a(app);
a.run();
field().mask().set_focus();
if (msg.not_empty())
{
TConfig ini(msg, "Transaction");
_rec = ini.get_long("Record");
if (_rec > 0 || !insert) // Modifica o cancellazione
_cursor->update(); // Forza ricalcolo cursore
if (_rec >= 0)
{
_cursor->file().readat(_rec);
ok = _cursor->ok();
if (ok)
{
rec_cache(_cursor->file().num()).notify_change(); // Svuota eventule cache
do_output();
}
}
::remove(msg);
}
return ok;
}
TToken_string& TBrowse::create_siblings(TToken_string& siblings)
{
siblings = ""; // Azzera la lista dei campi associati
TBit_array key(4); // Elenco delle chiavi gia' utilizzate
key.set(_cursor->key());
TString fn; // Nome campo
// Scorre la lista dei campi di output
int n = 0;
for (const char* i = _out_id.get(0); i; i = _out_id.get(), n++)
{
const short id = field().atodlg(i);
const TEditable_field& f = field(id);
if (!f.active() || !f.is_edit()) // Scarta i campi non editabili
continue;
const TEdit_field& e = (const TEdit_field&)f;
const TBrowse* b = e.browse();
if (b == NULL)
continue; // Scarta i campi senza ricerca
const TCursor* c = b->cursor();
// Considera ricerche sullo stesso file ma con chiave diversa
if (c->file().num() == _cursor->file().num() &&
(key[c->key()] == FALSE || id == field().dlg()))
{
fn = _out_fn.get(n); // Legge nome del campo su file
int pos = _items.get_pos(fn); // Determina header corrispondente
if (pos < 0) // Se non lo trova identico ...
{
const int q = fn.find('[');
if (q > 0)
{
fn.cut(q);
pos = _items.get_pos(fn); // ... ritenta senza parentesi
}
}
if (pos >= 0)
{
siblings.add(id);
const char* h = _head.get(pos);
siblings.add(h);
const int et = siblings.find('@');
if (et > 0) siblings.cut(et);
key.set(c->key()); // Marca la chiave come usata
}
}
}
return siblings;
}
KEY TBrowse::run()
{
begin_wait();
do_input(TRUE);
_cursor->read(_isgteq);
TString caption = _cursor->file().description();
if (caption.blank())
caption = TR("Selezione");
KEY k = K_ESC;
long selected = 0;
TToken_string siblings, vals;
create_siblings(siblings);
{
byte buttons = 0;
if (_insert.not_empty())
{
// Mette il bottone di gestione, a meno che ...
if (_cursor->items() == 0)
buttons = 2; // Non mette il bottone collega se non ci sono elementi
else
buttons = 3;
if (_insert[0] == 'M' || _insert[0] == 'R')
{
const TString& maskname = field().mask().source_file();
if (maskname.mid(2,2).compare("tb", 2, TRUE) == 0 && field().in_key(0))
{
const char* tabname = _cursor->file().name();
if (maskname.mid(4, 3).compare(tabname, 3, TRUE) == 0)
buttons = 0;
}
}
}
for (const char* i = _inp_id.get(0); i; i = _inp_id.get())
{
if (*i != '\0' && *i != '"' && strchr(i, '@') == NULL)
{
const short id = field().atodlg(i);
const TEditable_field& f = field(id);
if (f.active() && f.is_editable())
{
vals.add(i);
vals.add(f.get());
vals.add((int)f.dirty());
}
}
}
end_wait();
TBrowse_sheet s(_cursor, _items, caption, _head, buttons, field(), siblings);
k = s.run();
selected = s.selected();
}
switch (k)
{
case K_ESC:
case K_QUIT:
break;
case K_CTRL+'G':
*_cursor = selected;
k = do_link(FALSE) ? K_ENTER : K_ESC;
break;
case K_INS:
k = do_link(TRUE) ? K_ENTER : K_ESC;
break;
case K_ENTER:
*_cursor = selected;
do_output();
break;
default:
{
for (const char* i = vals.get(0); i && *i; i = vals.get())
{
const short id = field().atodlg(i);
TEditable_field& f = field(id);
f.set(vals.get());
f.set_dirty(vals.get_int());
}
}
if (k >= K_CTRL) // Scatta la ricerca su di una chiave alternativa
{
TMask& m = field().mask();
const int tag = k - K_CTRL - K_F1;
const short id = siblings.get_int(tag * 2);
TEdit_field& ef = m.efield(id);
ef.set_focus();
k = K_F9;
if (m.is_running())
m.send_key(k, id);
}
break;
}
return k;
}
bool TBrowse::check(CheckTime t)
{
bool passed = TRUE;
if (_secondary == TRUE && t != RUNNING_CHECK)
return TRUE;
CheckType chk = field().check_type();
if (chk != CHECK_NONE)
{
const TMaskmode mode = (TMaskmode)field().mask().mode();
if (chk == CHECK_REQUIRED && (t == STARTING_CHECK || mode == MODE_QUERY))
chk = CHECK_NORMAL;
const int ne = do_input(TRUE);
if (ne || chk == CHECK_REQUIRED)
{
passed = _cursor->test() == NOERR;
if (t != FINAL_CHECK)
{
if (passed)
{
_cursor->repos();
do_output(t);
}
else
{
if (chk == CHECK_SEARCH)
{
passed = TRUE;
}
else
{
do_clear(t);
if (!field().mask().query_mode() && field().check_enabled())
field().set_dirty(3);
}
}
}
else
{
if (chk == CHECK_SEARCH)
passed = TRUE;
}
}
else
{
if (chk == CHECK_SEARCH)
passed = TRUE;
else
{
if (t != FINAL_CHECK)
do_clear(t);
}
}
}
return passed;
}
bool TBrowse::empty_check()
{
if (field().mask().query_mode() || field().check_type() != CHECK_REQUIRED)
return TRUE;
else
return do_input() > 0;
}
///////////////////////////////////////////////////////////
// TFile_select
///////////////////////////////////////////////////////////
TFile_select::TFile_select(TEdit_field* ef, const char* filter)
: TBrowse_button(ef), _filter(filter)
{ }
void TFile_select::parse_input(TScanner& scanner)
{
scanner.pop();
}
void TFile_select::parse_output(TScanner& scanner)
{
scanner.pop();
}
KEY TFile_select::run()
{
TFilename path;
path = field().get();
if (path.full() && _filter.find('.') > 0 && !_filter.ends_with(".*"))
path.ext(_filter.ext());
FILE_SPEC fs; xvt_fsys_convert_str_to_fspec(path, &fs);
bool good = xvt_dm_post_file_open(&fs, field().prompt()) == FL_OK;
if (good)
{
xvt_fsys_convert_fspec_to_str(&fs, path.get_buffer(), path.size());
good = _filter.blank() || xvt_str_match(path.name(), _filter, false);
if (good)
field().set(path);
else
field().error_box(FR("Il nome del file non corrisponde a %s"), _filter.get_buffer());
}
return good ? K_ENTER : K_ESC;
}
bool TFile_select::check(CheckTime ct)
{
const TFilename name = field().get();
if (ct != STARTING_CHECK && name.empty() &&
field().check_type() == CHECK_REQUIRED)
return false;
bool ok = _filter.empty() || xvt_str_match(name, _filter, false);
if (ok && field().roman()) // Must exist
ok = name.exist();
return ok;
}
///////////////////////////////////////////////////////////
// TDir_select
///////////////////////////////////////////////////////////
TDir_select::TDir_select(TEdit_field* ef) : TBrowse_button(ef)
{ }
void TDir_select::parse_input(TScanner& scanner)
{
scanner.pop();
}
void TDir_select::parse_output(TScanner& scanner)
{
scanner.pop();
}
KEY TDir_select::run()
{
DIRECTORY savedir;
xvt_fsys_get_dir(&savedir);
DIRECTORY dir;
xvt_fsys_convert_str_to_dir(field().get(), &dir);
bool good = xvt_dm_post_dir_sel(&dir) == FL_OK;
xvt_fsys_set_dir(&savedir);
if (good)
{
TFilename path;
xvt_fsys_convert_dir_to_str(&dir, path.get_buffer(), path.size());
field().set(path);
}
return good ? K_ENTER : K_ESC;
}
bool TDir_select::check(CheckTime ct)
{
const TFilename name = field().get();
if (ct != STARTING_CHECK && name.empty() &&
field().check_type() == CHECK_REQUIRED)
return false;
bool ok = true;
if (field().roman()) // Must exist
ok = name.exist();
return ok;
}
///////////////////////////////////////////////////////////
// TProfile_select
///////////////////////////////////////////////////////////
TProfile_select::TProfile_select(TEdit_field* ef)
: TBrowse_button(ef)
{ }
void TProfile_select::parse_input(TScanner& scanner)
{
scanner.pop();
}
void TProfile_select::parse_output(TScanner& scanner)
{
scanner.pop();
}
HIDDEN int get_profile_desc(TConfig& cfg, void* jolly)
{
const int num = atoi(cfg.get_paragraph());
if (num > 0)
{
TString_array& p = *(TString_array*)jolly;
TToken_string* str = new TToken_string;
str->format("%4d", num);
str->add(cfg.get("Description"));
p.add(str);
}
return FALSE;
}
int TProfile_select::get_descriptions(TString_array& a) const
{
TFilename profname;
field().mask().make_profile_name(profname);
TConfig prof(profname);
a.destroy();
prof.for_each_paragraph(get_profile_desc, &a);
a.sort();
return a.items();
}
KEY TProfile_select::run()
{
TArray_sheet p(3, 3, -3, -3, TR("Profili"), HR("Codice@6R|Descrizione@60"), 0x6, 2);
const short id = DLG_USER+1;
TEdit_field& prompt = p.add_string(id, 0, PR("Salva con nome "), 1, 0, 60);
p.add_button(DLG_SAVEREC, PR("~Registra"), K_CTRL+'r', TOOL_SAVEREC);
prompt.set(field().get());
TMask& m = field().mask();
TFilename profname; m.make_profile_name(profname);
bool running = TRUE;
KEY key;
while (running)
{
p.destroy();
TString_array& a = p.rows_array();
get_descriptions(a);
p.field(DLG_SAVEREC).enable(a.items()>0);
FOR_EACH_ARRAY_ROW_BACK(a, r, row)
if (field().get() == row->get(1)) break;
if (r)
p.select(r);
key = p.run();
switch(key)
{
case K_ENTER:
{
const int num = p.row().get_int(0);
TString16 para; para << m.load_profile(num);
prompt.set(p.row().get(1));
running = FALSE;
}
break;
case K_CTRL+'r':
{
const TString& name = p.get(id);
FOR_EACH_ARRAY_ROW_BACK(a, r, row)
if (r != p.selected() && name == row->get(1)) break;
if (r < 0)
{
const int num = p.row().get_int(0);
m.save_profile(num, name);
running = FALSE;
}
else
error_box("Esiste gia' un profilo di nome\n%s",
(const char*)name);
}
break;
case K_INS:
{
const TString& name = p.get(id);
if (!name.blank())
{
FOR_EACH_ARRAY_ROW_BACK(a, r, row)
if (name == row->get(1)) break;
if (r < 0)
{
TString16 para; para << m.save_profile(-1, name);
field().set(name);
running = FALSE;
}
else
error_box("Esiste gia' un profilo di nome\n%s",
(const char*)name);
}
else
error_box("E' necessario dare un nome al profilo");
}
break;
case K_DEL:
{
TString16 para; para << p.row().get_int(0);
const TString desc = p.row().get(1);
TConfig prof(profname, para);
if (yesno_box("Confermare la cancellazione del profilo %s\n%s",
(const char*)para, (const char*)desc))
prof.remove_all();
}
break;
default:
running = FALSE;
break;
}
}
field().set(prompt.get());
return key;
}
bool TProfile_select::check(CheckTime ct)
{
switch (ct)
{
case STARTING_CHECK:
{
TMask& m = field().mask();
TFilename name; m.make_profile_name(name);
TString16 para; para << m.load_profile();
TConfig ini(name, para);
field().set(ini.get("Description"));
}
break;
case RUNNING_CHECK:
if (!field().empty())
{
const TString& name = field().get();
TString_array a;
get_descriptions(a);
FOR_EACH_ARRAY_ROW_BACK(a, r, row)
{
if (name == row->get(1))
{
field().mask().load_profile(row->get_int(0));
break;
}
}
if (r < 0)
return field().error_box("Profilo inesistente");
}
break;
case FINAL_CHECK:
if (!field().active())
{
TMask& m = field().mask();
m.save_profile();
}
break;
default:
break;
}
return TRUE;
}
///////////////////////////////////////////////////////////
// TReport_select
///////////////////////////////////////////////////////////
TReport_select::TReport_select(TEdit_field* ef, const char* classe)
: TBrowse_button(ef), _classe(classe)
{ }
void TReport_select::parse_input(TScanner& scanner)
{
scanner.pop();
}
void TReport_select::parse_output(TScanner& scanner)
{
scanner.pop();
}
KEY TReport_select::run()
{
TFilename path = field().get();
if (select_custom_file(path, "rep", _classe))
{
path = path.name();
path.ext("");
field().set(path);
}
return path.not_empty() ? K_ENTER : K_ESC;
}
bool TReport_select::check(CheckTime ct)
{
TFilename name = field().get();
if (ct != STARTING_CHECK && name.empty() &&
field().check_type() == CHECK_REQUIRED)
return false;
bool ok = true;
if (field().roman()) // Must exist
ok = name.custom_path();
return ok;
}
///////////////////////////////////////////////////////////
// TEdit_field
///////////////////////////////////////////////////////////
TEdit_field::TEdit_field(TMask* mask)
: TEditable_field(mask), _check(CHECK_NONE),
_forced(FALSE), _check_enabled(FALSE), _browse(NULL)
{ }
TEdit_field::~TEdit_field()
{
if (_browse) delete _browse;
}
word TEdit_field::class_id() const
{ return CLASS_EDIT_FIELD; }
void TEdit_field::set_len(short w)
{
}
void TEdit_field::set_width(short width, short dwidth)
{
RCT rect;
get_rect(rect);
rect.right= rect.left+width;
set_rect(rect);
}
void TEdit_field::parse_head(TScanner& scanner)
{
_ctl_data._size = scanner.integer();
#ifdef DBG
if (_ctl_data._size <= 0)
{
_ctl_data._size = 8;
NFCHECK("Il campo %d ha dimensione nulla: uso %d",
_ctl_data._dlg, _ctl_data._size);
}
#endif
_ctl_data._width = scanner.integer();
if (_ctl_data._width == 0)
_ctl_data._width = _ctl_data._size;
}
const TBrowse* TEdit_field::parse_browse(TScanner& scanner) const
{
const TBrowse* b = NULL;
const int pos = mask().id2pos(scanner.integer());
if (pos >= 0)
{
const TMask_field& f = mask().fld(pos);
if (f.is_edit())
b = ((TEdit_field&)f).browse();
}
return b;
}
bool TEdit_field::set_selector(char s, const TString& str)
{
#ifdef DBG
if (_browse)
NFCHECK("%cSELECT duplicato nel campo %d", s, _ctl_data._dlg);
#endif
if (_browse == NULL)
{
switch (s)
{
case 'D': _browse = new TDir_select(this); break;
case 'F': _browse = new TFile_select(this, str); break;
case 'P': _browse = new TProfile_select(this); set_default("NONE"); break;
case 'R': _browse = new TReport_select(this, str); break;
default: break;
}
_check_enabled = _browse != NULL;
}
return _browse != NULL;
}
bool TEdit_field::parse_item(TScanner& scanner)
{
if (scanner.key() == "PI") // PICTURE
{
_picture = scanner.string();
return TRUE;
}
if (scanner.key() == "CH")
{
const TString& ct = scanner.popkey();
if (ct == "NO") _check = CHECK_NORMAL; else
if (ct == "RE") _check = CHECK_REQUIRED; else
if (ct == "FO") { _check = CHECK_REQUIRED; _forced = TRUE; } else
if (ct == "SE") _check = CHECK_SEARCH;
else _check = CHECK_NONE;
return TRUE;
}
if (scanner.key() == "US") // USE
{
#ifdef DBG
if (_browse != NULL)
return yesnofatal_box("USE duplicata nel campo %d", dlg());
#endif
int key = 1;
TRelation* r = NULL;
TString16 tablename = scanner.pop();
const int logicnum = table2logic(tablename);
if (logicnum > 0)
{
TFilename f = prefix().get_filename(logicnum); f.ext("dbf");
if (f.exist()) // Controlla l'esistenza del file
{
switch (logicnum)
{
case LF_TABGEN:
case LF_TABCOM:
case LF_TAB:
case LF_TABMOD:
r = new TRelation(tablename);
break;
default:
r = new TRelation(logicnum);
tablename.cut(0);
}
}
}
else
error_box("Il campo %d usa il file o tabella non valida %s",
dlg(), (const char*)tablename);
if (scanner.popkey() == "KE")
{
key = scanner.integer();
#ifdef DBG
if (key < 1 || key > MAX_KEYS)
{
yesnofatal_box("Chiave %d non valida nella USE del campo %d", key, dlg());
key = 1;
}
#endif
}
else scanner.push();
TString filter;
if (scanner.popkey() == "SE")
filter = (const char*)scanner.line();
else
scanner.push();
if (r != NULL)
{
_browse = new TBrowse(this, r, key, filter); // create browse with no filter ...
// ... complete relation by parsing all Join items ...
while (scanner.popkey() == "JO")
{
if (browse())
browse()->parse_join(scanner);
else
scanner.line();
}
scanner.push();
if (tablename.full())
{
tablename.insert("MTB", 0);
browse()->set_insert(tablename);
}
_check_enabled = TRUE;
}
else
{
while (scanner.popkey() == "JO")
scanner.line();
scanner.push();
}
return TRUE;
}
if (scanner.key() == "CO") // Copyuse
{
const TString8 what(scanner.popkey());
const TBrowse* b = parse_browse(scanner);
if (b)
{
if (what == "US" || what == "AL")
{
if (_browse == NULL)
_browse = new TBrowse(this, b->cursor());
else
NFCHECK("COPY USE e USE nel campo %d", _ctl_data._dlg);
}
if (_browse)
{
_check_enabled = TRUE;
return browse()->parse_copy(what, *b);
}
}
else
NFCHECK("Il campo %d non puo' copiare la browse da chi non ce l'ha", _ctl_data._dlg);
}
if (scanner.key() == "SH") // SHEET
{
#ifdef DBG
if (_browse)
NFCHECK("SHEET duplicato nel campo %d", _ctl_data._dlg);
#endif
_browse = new TList_sheet(this, _ctl_data._prompt, scanner.string());
_check_enabled = TRUE;
return TRUE;
}
if (scanner.key() == "FS") // FSELECT
{
return set_selector('F', scanner.string());
}
if (scanner.key() == "DS") // DSELECT
{
return set_selector('D', EMPTY_STRING);
}
if (scanner.key() == "PS") // PSELECT
{
return set_selector('P', EMPTY_STRING);
}
if (scanner.key() == "RS") // RSELECT
{
return set_selector('R', scanner.string());
}
if (scanner.key() == "IT") // ITEM
{
#ifdef DBG
if (sheet() == NULL)
return yesnofatal_box("ITEM senza SHEET nel campo %d", _ctl_data._dlg);
else
#endif
sheet()->parse_item(scanner);
return TRUE;
}
if (scanner.key() == "IN")
{
if (_browse)
_browse->parse_input(scanner);
else
scanner.line();
return TRUE;
}
if (scanner.key() == "DI")
{
if (browse())
browse()->parse_display(scanner);
else
scanner.line();
return TRUE;
}
if (scanner.key() == "OU")
{
if (_browse)
_browse->parse_output(scanner);
else
scanner.line();
return TRUE;
}
if (scanner.key() == "AD")
{
if (browse())
browse()->parse_insert(scanner);
else
scanner.line();
return TRUE;
}
if (scanner.key() == "ME")
{
TString& l = scanner.line().strip_spaces();
int m = 0;
if (l[0] == '0')
{
l.ltrim(1);
l.ltrim();
m = 1;
}
message(m, TRUE)->add(l);
return TRUE;
}
return TEditable_field::parse_item(scanner);
}
void TEdit_field::set_background()
{
COLOR c = NORMAL_BACK_COLOR;
if (enabled())
{
int status = required() ? 1 : 0;
if (read_only())
status |= 2;
switch (status)
{
case 1:
if (!same_color(NORMAL_BACK_COLOR, REQUIRED_BACK_COLOR))
c = REQUIRED_BACK_COLOR;
break;
case 2:
c = blend_colors(DISABLED_BACK_COLOR, NORMAL_BACK_COLOR, 0.5);
break;
case 3:
c = blend_colors(DISABLED_BACK_COLOR, REQUIRED_BACK_COLOR, 0.5);
break;
default:
break;
}
}
((TField_control*)_ctl)->set_back_color(c);
if (_browse)
((TField_control*)_ctl)->show_button(active());
}
void TEdit_field::check_type(CheckType c)
{
_check = c;
set_background();
}
void TEdit_field::set_read_only(bool r)
{
if (r != read_only())
{
TMask_field::set_read_only(r);
const bool ok = r == read_only();
if (ok)
{
set_background();
if (_browse != NULL && _browse->is_browse())
{
TToken_string out_ids(((TBrowse*)_browse)->get_output_fields());
TMask& m = mask();
FOR_EACH_TOKEN(out_ids, fld)
m.field(atoi(fld)).set_read_only(r);
}
}
}
}
// Filtro magico sulle ditte esistenti
HIDDEN bool firm_filter(const TRelation* rel)
{
const long firm = rel->curr().get_long(NDT_CODDITTA);
return prefix().exist(firm);
}
void TEdit_field::create(WINDOW parent)
{
const int len = create_prompt(parent, 0, 0);
_size = _ctl_data._size;
_ctl_data._x += len;
if (_browse) // Decide se attivare o meno il bottone di ricerca
_ctl_data._flags << 'B';
if (_ctl_data._prompt.find("@g") >= 0 || _ctl_data._prompt.find("@G") >= 0)
{
_ctl_data._flags << '{';
_ctl_data._x += len;
}
if (_ctl_data._prompt.find("@b") >= 0 || _ctl_data._prompt.find("@B") >= 0)
_ctl_data._flags << '}';
_ctl = new TField_control(parent, _ctl_data._dlg,
_ctl_data._x, _ctl_data._y,
_ctl_data._width, _ctl_data._size,
_ctl_data._flags, "");
if (_browse && !enabled_default())
((TField_control*)_ctl)->show_button(false);
if (_browse && validate_func() == 24)
{
TCursor* cursor = browse()->cursor();
if (cursor)
{
const int logicnum = cursor->file().num();
if (logicnum == LF_NDITTE)
cursor->set_filterfunction(firm_filter);
}
}
if (required())
check_type(CHECK_REQUIRED); // Force color change
}
const char* TEdit_field::reformat(const char* str) const
{
TString& s = _ctl_data._park;
s = str;
const byte trim_mode = _flags.trim;
smart_trim(s, trim_mode);
if (s.not_empty())
{
word len = s.len();
if (len > size())
{
#ifdef DBG
yesnofatal_box("Campo %d troppo lungo: %s > %d", dlg(), str, _size);
#endif
s.cut(len = size());
}
if (_flags.zerofilled)
{
if (len > 0 && len < size())
{
if (isdigit(s[0]) && real::is_natural(s))
s.right_just(size(), '0');
}
const char* w;
for (w = (const char*)s; *w == '0'; w++) ;
if (*w == '\0')
s.cut(0);
}
if (_flags.rightjust && !(trim_mode & 1) && !s.blank())
s.right_just(size());
if (_flags.uppercase)
s.upper();
}
return s;
}
const char* TEdit_field::raw2win(const char* raw) const
{
return reformat(raw);
}
const char* TEdit_field::win2raw(const char* win) const
{
return reformat(win);
}
void TEdit_field::set_window_data(const char* data)
{
_ctl->set_caption(data);
}
void TEdit_field::autoselect(bool on)
{
_ctl->autoselect(on);
}
TString& TEdit_field::get_window_data()
{
_str = win2raw(_ctl->caption());
return _str;
}
// Certified 90%
bool TEdit_field::on_hit()
{
const int vf = validate_func();
if (vf >= 0)
{
if (vf == AUTOEXIT_FUNC || vf == NUMCALC_FUNC || vf == STRCALC_FUNC || vf == 21)
{
const bool ok = validate(K_TAB); // Check validation expression
if (!ok) return FALSE;
}
}
const bool ok = handler(K_TAB);
if (ok && has_message())
{
if (empty() && message(1))
do_message(1);
else
do_message(0);
}
return ok;
}
// @doc EXTERNAL
// @mfunc Mostra un messaggio di errore di default per il campo
//
// @rdesc Ritorna sempre FALSE
bool TEdit_field::default_error_box() const
// @comm Se il campo non possiede un warning particolare chiama la <f error_box>
// indicando genericamente che il valore immesso non e' valido, altrimenti
// riporta il warning associato al campo
{
if (!has_warning())
{
const TString p(prompt());
if (isalnum(p[0]))
{
const TString val(get());
error_box(TR("Valore non valido per %s: %s"), (const char*)p, (const char*)val);
}
else
error_box(TR("Valore non valido: %s"), (const char*)get());
}
else
error_box(get_warning());
return FALSE;
}
bool TEdit_field::autosave(TRelation& r)
{
if (_flags.user)
_str = user();
return TEditable_field::autosave(r);
}
bool TEdit_field::on_key(KEY key)
{
const int vf = validate_func();
switch(key)
{
case K_CTRL+K_TAB:
set_focusdirty(FALSE);
break;
case K_TAB:
/*
if (vf >= 0 && (vf == AUTOEXIT_FUNC || vf == NUMCALC_FUNC || vf == STRCALC_FUNC))
set_focusdirty(); // Forza validate
*/
if (to_check(K_TAB, TRUE))
{
if (class_id() == CLASS_EDIT_FIELD) // Altrimenti l'ha gia' fatto
{
const TString& raw = get_window_data();
set_window_data(raw2win(raw));
}
bool ok = validate(key); // Check validation expression
if (!ok)
{
if (has_warning())
default_error_box();
return FALSE;
}
TMask& m = mask();
const bool query = m.query_mode();
const bool vuoto = empty();
if (_browse)
{
if (browse())
{
// if (check_enabled() && (!query || forced()) && vf != 21)
if (check_enabled() && vf != 21)
{
if (!query || forced())
ok = _browse->check();
else
_browse->check();
}
}
else
{
ok = query || _browse->check(); // Check consistency
}
}
if (ok)
ok = on_hit();
else
{
if (vuoto)
ok = TRUE;
else
default_error_box();
}
if (ok)
{
set_focusdirty(FALSE);
if (query && m.is_running() && in_key(0))
test_key_complete();
}
else
set_focusdirty(!vuoto);
return ok;
}
else
{
TMask& m = mask();
bool ok = handler(K_TAB);
if (ok && m.query_mode() && m.is_running() && in_key(0))
test_key_complete();
return ok;
}
break;
case K_ENTER:
// if (field() != NULL || mask().mode() == NO_MODE)
{
bool ok = validate(K_ENTER); // Check validation expression
if (!ok)
{
if (has_warning())
default_error_box();
return FALSE;
}
if (!mask().query_mode() /* || forced() */)
{
ok = !(check_type() == CHECK_REQUIRED && empty());
// check consistency
if (ok && _browse)
{
if (browse())
{
if (ok && check_enabled() && vf != 21) // 21 = NOT_EMPTY_CHECK_FIELD
{
if (dirty()) ok = browse()->check(FINAL_CHECK); // Check consistency
else ok = browse()->empty_check();
}
}
else
ok = _browse->check(FINAL_CHECK);
}
if (!ok) return default_error_box();
}
}
break;
case K_F2:
if (!read_only())
set("");
break;
case K_F9:
if (!read_only())
{
if (check_enabled())
{
if (focusdirty())
get_window_data();
KEY k = K_ESC;
if (_browse) k = _browse->run();
else beep();
if (k != K_F9)
set_focus();
if (k == K_ENTER)
{
bool ok = TRUE;
set_dirty();
// Controlla i validate che non vengono fatti da on_hit
const int vf = validate_func();
if (vf >= 0 && vf != AUTOEXIT_FUNC && vf != NUMCALC_FUNC &&
vf != STRCALC_FUNC && vf != 21)
{
ok = validate(K_TAB);
if (!ok && has_warning())
default_error_box();
}
// Esegue handler
if (ok)
ok = on_hit();
if (ok)
{
TMask & m = mask();
if (m.is_running())
{
set_focusdirty(FALSE); // Evita doppia esecuzione handlers!
if (m.query_mode() && in_key(0))
test_key_complete();
if (m.is_running())
{
set_focusdirty(FALSE);
send_key(K_TAB, 0); // Passa al campo successivo
}
}
}
return ok;
}
else
return FALSE;
}
else
if (_browse == NULL && has_button())
{
if (focusdirty())
get_window_data();
return handler(K_F9);
}
}
break;
case K_F12:
if (has_virtual_keyboard())
{
TVirtual_keyboard keyboard(*this);
get_window_data();
keyboard.run();
}
return true;
break;
case K_CTRL+K_SPACE:
set_dirty(TRUE);
return handler(K_SPACE);
default:
break;
}
return TEditable_field::on_key(key);
}
// @mfunc Controlla se il campo ha la necessita' di eseguire una ricerca sul cursore o
// sulla tabella associata al momento della sua inizializzazione
//
// @rdesc Ritorna TRUE se il campo ha un TArray_sheet associato oppure un TCursor_sheet
// con check_type non nullo.
bool TEdit_field::has_check() const
{
bool ok = FALSE;
if (_browse)
ok = browse() == NULL || check_type() != CHECK_NONE;
return ok;
}
bool TEdit_field::check(CheckTime t)
{
bool ok = TRUE;
if (check_enabled() || (t == STARTING_CHECK && shown()))
{
if (_browse && validate_func() != 21)
ok = _browse->check(t);
}
return ok;
}
void TEdit_field::set_query_button(TBrowse_button * brw)
{
if (_browse)
delete _browse;
_browse=brw;
}
// @doc EXTERNAL
void TEdit_field::enable(bool on)
{
TEditable_field::enable(on);
set_background();
}
// @mfunc Permette di abilitare/disabilitare un check di un campo
void TEdit_field::enable_check(
bool on) // @parm Operazione da svolgere
//
// @flag TRUE | Abilita il check del campo (default)
// @flag FALSE | Disabilita il check del campo
{
_check_enabled = on;
((TField_control*)_ctl)->show_button(on && active());
}
///////////////////////////////////////////////////////////
// Date_field
///////////////////////////////////////////////////////////
TDate_field::TDate_field(TMask* m) : TEdit_field(m)
{ }
word TDate_field::class_id() const
{ return CLASS_DATE_FIELD; }
// Certified 100%
bool TDate_field::is_kind_of(word cid) const
{ return cid == CLASS_DATE_FIELD || TEdit_field::is_kind_of(cid); }
void TDate_field::create(WINDOW w)
{
// Elimina il flag R che si interpreta come salva in formato ANSI
_ctl_data._flags.strip("AR");
TEdit_field::create(w);
if (automagic())
{
TDate d(TODAY);
set(d.string());
}
}
void TDate_field::parse_head(TScanner&)
{
_ctl_data._size = _ctl_data._width = 10;
}
// @doc EXTERNAL
// @mfunc Permette di formattare la data secondo i flag correnti
//
// @rdesc Ritorna la data formattata
const char* TDate_field::win2raw(
const char* datum) const // @parm Stringa contenenete la data da formattare
// @comm Permette di gestire anche alcuni date particolari come:
//
// @flag IERI | Inserisce la data del giorno precedente a quella del sistema
// @flag OGGI | Inserisce la data del sistema
// @flag DOMANI | Inserisce la data del giorno successivo a quella del sistema
// @flag PRIMO | Primo giorno dell'anno (01-01-aa)
// @flag PASQUA | Giorno di pasqua
// @flag ANGELO | Lunedi' dell'angelo
// @flag NATALE | Giorno di natale (25-12-aa)
// @flag ULTIMO | Ultimo giorno dell'anno (31-12-aa)
{
TString& s = _ctl_data._park;
s = datum; s.trim();
if (s.not_empty())
{
if (isdigit(s[0]) && s.len() < 10)
{
long d;
int m, y;
const int items = sscanf(s, "%ld-%d-%d", &d, &m, &y);
switch(items)
{
case 1:
d = atoi(s.left(2));
m = atoi(s.mid(2, 2));
y = atoi(s.mid(4));
break;
case 2:
y = 0;
break;
case 3:
break;
default:
d = 0;
break;
}
if (d > 0)
{
if (m <= 0 || y <= 0)
{
const TDate oggi(TODAY);
if (m <= 0)
m = oggi.month();
if (y <= 0)
y = oggi.year();
}
if (y < 100)
y += (y <= 10) ? 2000 : 1900;
s.format("%02d-%02d-%4d", int(d), m, y);
}
}
else
{
bool ok = TRUE;
TDate g(TODAY);
s.upper();
if (s[0] == 'I') // "IERI"
{
--g;
} else
if (s[0] == 'D') // "DOMANI"
{
++g;
} else
if (s.starts_with("PO")) // "POSDOMANI"
{
g += 2;
} else
if (s.starts_with("PA")) // s == "PASQUA"
{
g.set_easter();
} else
if (s.starts_with("AN")) // s == "ANGELO"
{
g.set_easter();
++g;
} else
if (s[0] == 'A') // s == "ALTROIERI"
{
g -= 2;
} else
if (s[0] == 'P') // s == "PRIMO"
{
g.set_month(1);
g.set_day(1);
} else
if (s[0] == 'N') // s == "NATALE"
{
g.set_month(12);
g.set_day(25);
} else
if (s[0] == 'U') //s == "ULTIMO"
{
g.set_month(12);
g.set_day(31);
} else
if (s[0] != 'O') // s != "OGGI"
ok = FALSE;
if (ok)
s = g.string();
}
}
return s;
}
const char* TDate_field::reformat(const char* str) const
{
TString& s = _ctl_data._park;
s = str;
if (s.len() == 8)
s = TDate(str).string();
else
if (s.blank())
s.cut(0);
return s;
}
const char* TDate_field::raw2win(
const char* datum) const // @parm Stringa contenenete la data da formattare
{
return reformat(datum);
}
bool TDate_field::on_key(KEY key)
{
if (to_check(key))
{
const TString& data = get_window_data();
if (data.not_empty()) // data not empty
{
if (!TDate::isdate(data))
{
error_box("Data errata o formato non valido");
return FALSE;
}
else
set_window_data(data);
}
}
else
{
if (key == K_F9 && browse() == NULL)
{
RCT rct; get_rect(rct);
TDate olddate;
const TString& data = get_window_data();
if (TDate::isdate(data))
olddate = TDate(data);
long ansidate = olddate.date2ansi();
ansidate = xvt_dm_post_choose_date(parent(), &rct, ansidate);
const TDate newdate(ansidate);
if (newdate != olddate)
set(newdate.string());
return true;
}
if (_ctl->is_edit_key(key))
{
const bool ok = isalnum(key) || key == '-';
if (!ok) beep();
return ok;
}
}
return TEdit_field::on_key(key);
}
bool TDate_field::autosave(TRelation& r)
{
if (field())
{
const char* td = get();
if (right_justified())
{
TDate d(td);
td = d.string(ANSI);
}
field()->write(td, r);
return TRUE;
}
return FALSE;
}
///////////////////////////////////////////////////////////
// Real_field
///////////////////////////////////////////////////////////
TReal_field::TReal_field(TMask* m) : TEdit_field(m)
{ }
word TReal_field::class_id() const
{ return CLASS_REAL_FIELD; }
// Certified 100%
bool TReal_field::is_kind_of(word cid) const
{ return cid == CLASS_REAL_FIELD || TEdit_field::is_kind_of(cid); }
void TReal_field::create(WINDOW w)
{
_ctl_data._flags.strip("AFM");
if (!roman())
_ctl_data._flags << 'R'; // Forza l'allineamento a destra per i numeri
TEdit_field::create(w);
if (_flags.firm)
{
TMask_field::set(prefix().get_codditta());
}
else
if (automagic())
TMask_field::set(TDate(TODAY).year());
}
bool TReal_field::parse_item(TScanner& scanner)
{
if (scanner.key() == "PI") // PICTURE
{
_picture = scanner.string();
if (_decimals == 0)
{
if (_picture[0] == '.')
_decimals = atoi(&_picture[1]);
else
{
const int comma = _picture.find(',');
if (comma >= 0)
_decimals = _picture.len() - comma - 1;
}
}
return TRUE;
}
return TEdit_field::parse_item(scanner);
}
const char* TReal_field::reformat(const char* data) const
{
TString& str = _ctl_data._park;
if (!real::is_null(data))
{
const int d = decimals();
word s = size();
if (d == 0 && s <= 6)
{
str.format("%ld", atol(data)); // Gestione "veloce" degli interi
}
else
{
const real r(data); // Gestione standard dei reali
str = r.string(0, decimals());
}
if (_flags.zerofilled)
{
if (roman())
{
s = d;
if (s <= 0) s = 4;
}
str.right_just(s, '0');
}
}
else
str.cut(0);
return str;
}
bool TReal_field::on_key(KEY key)
{
if (to_check(key))
{
const TString& n = get_window_data();
if (roman())
{
const int r = atoi(n);
if (r < 0) return error_box("Numero romano errato");
}
else
{
if (!real::is_real(n))
return error_box("Valore numerico non valido");
if (_flags.uppercase && real(n).sign() < 0)
return error_box("Il numero deve essere positivo");
if (key == K_TAB && _flags.firm)
{
const long f = atol(n);
if (f > 0 && prefix().exist(f))
prefix().set_codditta(f);
}
}
set_window_data(raw2win(n));
}
else
{
if (_ctl->is_edit_key(key))
{
bool ok = TRUE;
switch (key)
{
case '.':
ok = !(_flags.zerofilled || _flags.roman || size() < 4);
break;
case ',':
ok = _decimals > 0;
break;
case '-':
ok = !_flags.uppercase;
break;
default :
if (_flags.roman)
ok = strchr("0123456789IVXLCDMivxlcdm", key) != NULL;
else
ok = strchr("0123456789", key) != NULL;
break;
}
if (!ok)
beep();
return ok;
}
else
if (key == K_F12)
{
if (has_virtual_keyboard())
{
TVirtual_numpad numpad(*this);
get_window_data();
numpad.run();
}
return true;
}
}
return TEdit_field::on_key(key);
}
void TReal_field::parse_head(TScanner& scanner)
{
_ctl_data._size = scanner.integer();
#ifdef DBG
if (_ctl_data._size <= 0)
{
_ctl_data._size = 9;
yesnofatal_box("Il campo %d ha dimensione nulla (uso %d)", _ctl_data._dlg, _ctl_data._size);
}
#endif
_ctl_data._width = _ctl_data._size;
_decimals = scanner.integer();
}
const char* TReal_field::raw2win(const char* data) const
{
TString& s = _ctl_data._park;
if (data == NULL) data = "";
if (roman())
{
s = itor(atoi(data));
}
else
{
if (!real::is_null(data))
{
real n(data);
if (_picture.empty())
{
if (_flags.zerofilled)
s = n.stringa(_size, _decimals, '0');
else
s = n.stringa(0, _decimals);
}
else
{
s = n.string(_picture);
}
const int extra = s.len() - _size;
if (extra > 0)
s.ltrim(extra);
}
else
s.cut(0);
}
return s;
}
const char* TReal_field::win2raw(const char* data) const
{
TString& str = _ctl_data._park;
if (roman())
{
int r = atoi(data);
if (r == 0) // Se non e' scritto in arabo converti da romano
r = rtoi(data);
if (r > 0)
{
int d = decimals();
if (d < 1) d = 4;
if (_flags.zerofilled)
str.format("%0*d", d, r);
else
str.format("%*d", d, r);
}
else
str.cut(0);
}
else
{
real n(real::ita2eng(data));
if (n.is_zero())
str.cut(0);
else
{
if (_flags.zerofilled)
str = n.string(_size, _decimals, '0');
else
str = n.string();
}
}
return str;
}
void TReal_field::set_decimals(int d)
{
_decimals = d;
if (_picture[0] == '.')
{
if (d > 0) _picture.format(".%d", d);
else _picture = ".";
}
else
{
if (_picture.not_empty())
{
const int pdot = _picture.find(',');
if (pdot >= 0)
_picture.cut(pdot);
if (d > 0)
{
_picture << ',';
while (d-- > 0)
_picture << '@';
}
}
}
}
///////////////////////////////////////////////////////////
// Currency_field
///////////////////////////////////////////////////////////
#include <currency.h>
// Certified 100%
word TCurrency_field::class_id() const
{ return CLASS_CURRENCY_FIELD; }
// Certified 100%
bool TCurrency_field::is_kind_of(word cid) const
{ return cid == CLASS_CURRENCY_FIELD || TEdit_field::is_kind_of(cid); }
TCurrency& TCurrency_field::get_currency(TCurrency& cur) const
{
const real num(get());
const char* value = NULL;
real exchange;
exchange_type et = _exchange_undefined;
const TMask_field* d0 = driver(0);
if (d0)
{
value = d0->get();
const TMask_field* d1 = driver(1);
if (d1)
{
exchange = real(d1->get());
const TMask_field* d2 = driver(2);
if (d2)
et = d2->get().blank() ? _exchange_base : _exchange_contro;
}
}
cur.set_num(num);
cur.force_value(value, exchange, et);
cur.set_price(_flags.uppercase != 0);
return cur;
}
void TCurrency_field::set(const TCurrency& cur, bool hit)
{
TMask_field* d0 = (TMask_field*)driver(0);
if (d0) d0->set(cur.get_value());
const real& num = cur.get_num();
if (num.is_zero())
TEdit_field::set("");
else
TEdit_field::set(num.string());
if (hit)
on_hit();
}
const char* TCurrency_field::reformat(const char* data) const
{
return real::is_null(data) ? "" : data;
}
const char* TCurrency_field::raw2win(const char* data) const
{
const real num = data;
if (num == ZERO)
return "";
const TMask_field* d0 = driver(0);
const char* value = d0 ? (const char*)d0->get() : NULL;
const bool price = _flags.uppercase != 0;
TCurrency cur(num, value, ZERO, _exchange_undefined, price);
TString& s = _ctl_data._park;
s = cur.string(TRUE);
const int extra = s.len() - size();
if (extra > 0) s.ltrim(extra);
return s;
}
const char* TCurrency_field::win2raw(const char* data) const
{
TString& str = _ctl_data._park;
str = data;
str.strip("."); str.replace(',', '.');
bool is_formula = FALSE;
for (int i = 0; str[i]; i++)
{
if (strchr("0123456789.", str[i]) == NULL)
{
is_formula = TRUE;
break;
}
}
real num;
if (is_formula)
{
TExpression e(str, _numexpr, TRUE);
for (int i = e.numvar()-1; i >= 0; i--)
{
TMask_field* f = mask().find_by_fieldname(e.varname(i));
if (f)
e.setvar(i, f->get());
}
num = e.as_real();
}
else
num = real(str);
if (num.is_zero())
str.cut(0);
else
{
const TMask_field* d0 = driver(0);
const char* value = d0 ? (const char*)d0->get() : NULL;
const bool price = _flags.uppercase != 0;
TCurrency cur(num, value, ZERO, _exchange_undefined, price);
str = cur.get_num().string();
}
return str;
}
bool TCurrency_field::on_key(KEY key)
{
if (key == K_TAB && focusdirty())
{
const TString& raw = get_window_data();
set_window_data(raw2win(raw));
}
else
{
if (_ctl->is_edit_key(key))
{
bool ok = TRUE;
switch (key)
{
case '-':
ok = !_flags.uppercase;
break;
case K_F12 :
if (has_virtual_keyboard())
{
TVirtual_numpad numpad(*this, true);
get_window_data();
numpad.run();
}
return true;
break;
default :
ok = strchr("0123456789.,+*-/()", key) != NULL;
break;
}
if (!ok)
beep();
return ok;
}
}
return TEdit_field::on_key(key);
}
bool TCurrency_field::autosave(TRelation& r)
{
return TEditable_field::autosave(r);
}
bool TCurrency_field::autoload(const TRelation& r)
{
return TEditable_field::autoload(r);
}
void TCurrency_field::parse_head(TScanner& scanner)
{
int size = scanner.integer();
if (size <= 0)
size = 18;
_ctl_data._size = _ctl_data._width = size;
}
void TCurrency_field::create(WINDOW w)
{
_ctl_data._flags.strip("AMZ");
_ctl_data._flags << 'R';
TEdit_field::create(w);
}
TCurrency_field::TCurrency_field(TMask* m) : TEdit_field(m)
{ }
///////////////////////////////////////////////////////////
// List_field
///////////////////////////////////////////////////////////
TList_field::TList_field(TMask* m)
: TEditable_field(m), _size(0)
{ }
word TList_field::class_id() const
{ return CLASS_LIST_FIELD; }
void TList_field::read_item(TScanner& scanner)
{
TToken_string ts(scanner.string());
_codes.add(ts.get());
const char* v = dictionary_translate_prompt(ts.get(), _ctl_data._width);
_values.add(v);
CHECKS(v == NULL || strlen(v) <= (word)_ctl_data._width, "List item is too long:", v);
ts.cut(0);
while (scanner.popkey() == "ME")
ts.add(scanner.line().strip_spaces());
scanner.push();
*message(-1, TRUE) = ts;
}
void TList_field::parse_head(TScanner& scanner)
{
_ctl_data._size = scanner.integer();
_ctl_data._width = scanner.integer();
if (_ctl_data._width == 0)
_ctl_data._width = _ctl_data._size;
}
bool TList_field::parse_item(TScanner& scanner)
{
if (scanner.key() == "IT") // ITEM
{
read_item(scanner);
return true;
}
return TEditable_field::parse_item(scanner);
}
int TList_field::items() const
{
return _codes.items();
}
// @doc EXTERNAL
// @mfunc Aggiunge delle voci al list sheet
void TList_field::add_item(
const char* s) // @parm Voci da aggiungere
// @comm Se il parametro <p s> e' passato con il formato di una <c TToken_string>
// composta da codice|descrizione
{
TToken_string t(s);
TString item(t.get());
const int pos = _codes.get_pos(item);
if (pos < 0)
{
_codes.add(item);
item = t.get();
_values.add(item);
((TListbox_control*)_ctl)->set_values(_codes, _values);
}
}
void TList_field::delete_item(const char* s)
{
const TString t(s);
const int pos = _codes.get_pos(t);
if (pos >= 0 )
{
_codes.destroy(pos);
_values.destroy(pos);
((TListbox_control*)_ctl)->set_values(_codes, _values);
if (pos == current())
{
current(0);
if (active() || ghost())
on_hit();
}
}
}
void TList_field::add_list()
{
if (roman() && _codes.items() < 12)
{
TString csafe, vsafe;
if (atoi(_codes) > 0)
{
csafe = _codes; _codes = "";
vsafe = _values; _values = "";
}
for (int i = 1; i <= 12; i++)
{
char num[4]; sprintf(num, "%02d", i);
_codes.add(num);
_values.add(itom(i));
}
if (atoi(csafe) > 0)
{
_codes.add(csafe);
_values.add(vsafe);
if (message(0))
{
*message(_codes.items()-1, TRUE) = *message(0);
message(0)->cut(0);
}
}
}
((TListbox_control*)_ctl)->set_values(_codes, _values);
if (roman() && automagic())
{
const char* init = format("%02d", TDate(TODAY).month());
set(init);
}
else
current(0);
}
const char* TList_field::win2raw(const char* data) const
{
// fool the compiler to keep const
TToken_string& codes = ((TList_field*)this)->_codes;
TToken_string& value = ((TList_field*)this)->_values;
TString80 str = data; // data puo' venire da una TToken_string::get
int pos = value.get_pos(str);
if (pos < 0) // Ci riprovo coi codici
pos = codes.get_pos(str);
if (pos < 0 && (str.blank() || str == "0"))
{
str = codes.get(0); // Uso codes come riferimento per blank
if (str.blank() || str == "0")
pos = 0;
}
CHECKS(pos >= 0, "Unknown listbox value:", data);
return codes.get(pos);
}
const char* TList_field::raw2win(const char* data) const
{
// fool the compiler to keep const
TToken_string& codes = ((TList_field*)this)->_codes;
TToken_string& value = ((TList_field*)this)->_values;
TString256 str = data; // data puo' venire da una TToken_string::get
int pos = codes.get_pos(str);
if (pos < 0 && (str.blank() || str == "0"))
{
codes.get(0, str);
if (str.blank() || str == "0")
pos = 0;
}
CHECKS(pos >= 0, "Unknown listbox code:", data);
return value.get(pos);
}
bool TList_field::select_by_ofs(int n)
{
const bool changed = ((TListbox_control*)_ctl)->select_by_ofs(n);
if (changed)
_str = _codes.get(current());
return changed;
}
bool TList_field::select_by_initial(char c)
{
const bool changed = ((TListbox_control*)_ctl)->select_by_initial(c);
if (changed)
_str = _codes.get(current());
return changed;
}
// @doc EXTERNAL
// @mfunc Sostituisce alle voci correnti quelle passate come parametri
void TList_field::replace_items(
const char* codes, // @parm Codici da sostituire ai correnti
const char* values) // @parm Voci da sostituire a quelle correnti
// @comm I parametri <p codes> e <p values> devono essere TToken_string se lo voci da sostiutire
// sono piu' di una
{
_codes = codes;
_values = values;
if (_ctl)
add_list();
}
void TList_field::create(WINDOW parent)
{
const int len = create_prompt(parent, 0, 0);
_ctl_data._x += len;
_size = _ctl_data._width;
_ctl = new TListbox_control(parent, _ctl_data._dlg,
_ctl_data._x, _ctl_data._y,
_ctl_data._width,
_ctl_data._flags, _ctl_data._prompt,
_codes, _values);
add_list();
}
int TList_field::str2curr(const char* data)
{
TString str(data);
if (roman() && str.len() < 2)
str.insert("0",0);
if (_flags.uppercase)
str.upper();
int i = str.blank() ? 0 : _codes.get_pos(str);
if (i < 0) // Se non trova il codice ritenta dopo trim
{
for (i = 0; str[i] == '0' || str[i] == ' '; i++);
if (i > 0)
{
str.ltrim(i);
i = _codes.get_pos(str);
}
}
if (i < 0)
{
if (shown() || ghost())
{
if (items() && str.not_empty())
NFCHECK("'%s' non e' un valore valido per il campo %s: %d",
data, prompt(), dlg());
}
i = 0;
}
return i;
}
void TList_field::reset()
{
if (!_flags.persistent)
current(0);
}
void TList_field::set(const char* data)
{
const int i = str2curr(data);
current(i);
set_dirty();
}
void TList_field::set_window_data(const char* data)
{
NFCHECK(0,"So' passato da 'sta stronza!!!");
const int i = str2curr(win2raw(data));
current(i);
}
void TList_field::current(int n)
{
if (_ctl)
((TListbox_control*)_ctl)->select(n);
_str = _codes.get(n);
_str.trim();
}
int TList_field::current() const
{
int c;
if (_ctl)
c = ((TListbox_control*)_ctl)->selected();
else
c = ((TList_field*)this)->_codes.get_pos(_str); // Fool the compiler for const sake
return c;
}
TString& TList_field::get_window_data()
{
const int c = current();
_str = ((TList_field*)this)->_codes.get(c);
_str.trim();
return _str;
}
bool TList_field::on_hit()
{
const bool ok = handler(K_SPACE);
if (ok)
{
const int n = current();
do_message(n);
}
return ok;
}
bool TList_field::on_key(KEY key)
{
switch(key)
{
case K_CTRL+K_TAB:
set_focusdirty(FALSE);
break;
case K_SPACE:
get_window_data();
set_dirty();
return on_hit();
case K_F2:
if (!read_only())
current(0);
break;
default:
if (to_check(key, TRUE) || key == K_ENTER)
{
bool ok = TRUE;
if (validate_func() >= 0)
{
ok = validate(key);
if (!ok)
{
if (has_warning())
return error_box(get_warning());
}
}
}
break;
}
return TEditable_field::on_key(key);
}
// Certified 100%
bool TList_field::is_kind_of(word cid) const
{ return cid == CLASS_LIST_FIELD || TEditable_field::is_kind_of(cid); }
///////////////////////////////////////////////////////////
// TRadio_field
///////////////////////////////////////////////////////////
TRadio_field::TRadio_field(TMask* mask)
: TList_field(mask)
{ }
// Annulla _ctl altrimenti verrebbe cancellato due volte essendo anche nell'array
TRadio_field::~TRadio_field()
{ }
word TRadio_field::class_id() const
{
return CLASS_RADIO_FIELD;
}
void TRadio_field::create(WINDOW parent)
{
const int items = _codes.items();
if (_ctl_data._prompt.full())
{
const word dy = _flags.zerofilled ? 3 : items+2;
create_prompt(parent, _ctl_data._width, dy);
}
_ctl = new TRadiobutton_control(parent, _ctl_data._dlg,
_ctl_data._x + 1, _ctl_data._y + 1,
_ctl_data._width - 2, _flags.zerofilled ? 1 : items,
_ctl_data._flags, _values);
current(0);
}
int TRadio_field::current() const
{
int c;
if (_ctl)
c = ((TRadiobutton_control*)_ctl)->get_checked();
else
c = TList_field::current();
return c;
}
void TRadio_field::current(int n)
{
if (_ctl)
((TRadiobutton_control*)_ctl)->check_button(n);
_str = _codes.get(n);
_str.trim();
}
bool TRadio_field::select_by_initial(char c)
{
for (int i = _values.items()-1; i >= 0; i--)
{
const char* tok = _values.get(i);
if (toupper(*tok) == toupper(c) && _str != _codes.get(i))
{
current(i);
return true;
}
}
return false;
}
///////////////////////////////////////////////////////////
// TMemo_field
///////////////////////////////////////////////////////////
TMemo_field::TMemo_field(TMask* mask) : TEdit_field(mask)
{
}
TMemo_field::~TMemo_field()
{
}
void TMemo_field::parse_head(TScanner& scanner)
{
_ctl_data._width = scanner.integer();
_ctl_data._height = scanner.integer();
}
void TMemo_field::create(WINDOW parent)
{
create_prompt(parent, 0, 1);
if (_ctl_data._height > 1)
_ctl_data._height--;
_size = 8192;
_ctl = new TMultiline_control(parent, _ctl_data._dlg,
_ctl_data._x, _ctl_data._y+1,
_ctl_data._width, _ctl_data._height, _size,
_ctl_data._flags, "");
}
// Certified 100%
// Aggiusta un valore letto da file in formato RAW
const char* TMemo_field::reformat(const char* data) const
{
return data;
}
const char* TMemo_field::raw2win(const char* data) const
{
//#ifdef XI_R4
if (strchr(data, '\r') == NULL)
return data;
TString& s = _ctl_data._park;
s = data;
s.replace('\r', '\n');
/* #else
if (strchr(data, '\n') == NULL)
return data;
TString& s = _ctl_data._park;
s = data;
for (int i = 0; s[i]; i++)
if (s[i] == '\n') s[i] = '\r';
#endif */
return s;
}
const char* TMemo_field::win2raw(const char* data) const
{
//#ifdef XI_R4
return data;
/*
#else
if (strchr(data, '\r') == NULL)
return data;
_ctl_data._park = data;
for (char* s = (char*)(const char*)_ctl_data._park; *s; s++)
if (*s == '\r') *s = '\n';
return _ctl_data._park;
#endif
*/
}
bool TMemo_field::on_key(KEY k)
{
if (k == K_ENTER || k == K_TAB && focusdirty())
get_window_data();
return TEdit_field::on_key(k);
}
///////////////////////////////////////////////////////////
// Zoom_field
///////////////////////////////////////////////////////////
TZoom_field::TZoom_field(TMask* mask)
: TEdit_field(mask)
{
}
TZoom_field::~TZoom_field( )
{
}
void TZoom_field::create(WINDOW parent)
{
_ctl_data._flags << 'B';
TEdit_field::create(parent);
}
class TZoom_mask : public TAutomask
{
protected:
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
public:
TZoom_mask(const char * prompt);
virtual ~TZoom_mask() {}
};
bool TZoom_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
return true;
}
TZoom_mask::TZoom_mask(const char * prompt) : TAutomask("Zoom", 1, 72, 18)
{
const bool select = AUTOSELECT;
AUTOSELECT = false;
AUTOEND = true;
add_memo(101, 0, prompt, 1, 0, -1, -3);
add_button(DLG_OK, 0, "", -12, -1, 10, 2);
add_button(DLG_CANCEL, 0, "", -22, -1, 10, 2);
AUTOEND = false;
AUTOSELECT = select;
set_handlers();
}
bool TZoom_field::on_key( KEY key )
{
static KEY __k = '\0';
switch (key)
{
case K_TAB:
if (focusdirty())
get_window_data();
break;
case K_F9:
if (browse() != NULL)
break;
case K_F8:
{
get_window_data();
TZoom_mask m(prompt());
if (__k)
{
_str << (const char) __k;
__k = '\0';
}
m.set(101, _str);
if (m.run() == K_ENTER && !read_only())
{
_str = m.get(101);
set_window_data(raw2win(_str));
}
return TRUE;
}
break;
default:
if (AUTOZOOM && xvt_chr_is_alnum(key))
{
get_window_data();
if (_str.len() >= size())
{
__k = key;
if (mask().is_running())
on_key(K_F8);
else
{
TSheet_field * s = mask().get_sheet();
if (s != NULL)
dispatch_e_char(s->mask().win(), K_F8);
}
}
}
break;
}
return TEdit_field::on_key(key);
}
// Certified 100%
// Aggiusta un valore letto da file in formato RAW
const char* TZoom_field::reformat(const char* data) const
{
return data;
}
const char* TZoom_field::raw2win(const char* data) const
{
TFixed_string str(data);
int a_capo = str.find('\n');
if (a_capo < 0 || a_capo > (int)size())
a_capo = min((int)size(), str.len());
const char c = str[a_capo];
str[a_capo] = '\0';
_ctl_data._park = str;
str[a_capo] = c;
return _ctl_data._park;
}
const char* TZoom_field::win2raw(const char* data) const
{
TString& str = _ctl_data._park;
str = data;
// Elimino improbabili righe successive da data
int a_capo = str.find('\r');
if (a_capo >= 0) str.cut(a_capo);
// Aggiungo le righe del memo a partire dalla seconda
a_capo = _str.find('\n');
if (a_capo < 0 || a_capo > (int)size())
a_capo = min((int) size(), _str.len());
const char* d = _str;
str << (d+a_capo);
return str;
}
const char* TZoom_field::get_first_line() const
{ return raw2win(_str); }