campo-sirio/include/maskfld.cpp
guy e9a34d143f Migliorata gestione sheet ricerca
git-svn-id: svn://10.65.10.50/branches/R_10_00@23179 c028cbd2-c16b-5b4b-a496-9718f37d4682
2016-02-25 11:34:01 +00:00

4261 lines
96 KiB
C++
Executable File
Raw Blame History

// Disble annoying vsprintf warnings
#define _CRT_SECURE_NO_WARNINGS
#include <about.h>
#include <automask.h>
#include <colors.h>
#include <controls.h>
#include <dongle.h>
#include <execp.h>
#include <expr.h>
#include <modaut.h>
#include <msksheet.h>
#include <recarray.h>
#include <relapp.h>
#include <tabutil.h>
#include <text.h>
#include <toolfld.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;
}
*/
if (mode & 2) s.rtrim();
if (mode & 1) s.ltrim();
}
///////////////////////////////////////////////////////////
// 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 = 0x3;
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;
}
///////////////////////////////////////////////////////////
// TField_property_sheet
///////////////////////////////////////////////////////////
class TField_property_sheet : public TProperty_sheet
{
public:
TField_property_sheet(const TOperable_field& f);
};
TField_property_sheet::TField_property_sheet(const TOperable_field& f)
: TProperty_sheet(f.prompt(), 60, 10)
{
add_cat(TR("Sorgente"));
TFilename fn = f.mask().source_file(); fn.lower();
add_prop(TR("Maschera"), fn);
add_prop(TR("Personalizzata"), fn.find("custom") > 0 ? "Si" : "No");
if (f.mask().get_sheet() != NULL)
add_prop(TR("Spreadsheet"), f.mask().get_sheet()->dlg());
add_cat(TR("Informazioni"));
TString16 id; id << f.dlg();
// p.add_prop(TR("Tipo"), class_name()); // Per ora ritorna sempre "Field"!
add_prop(TR("Identificatore"), id);
add_prop(TR("Lunghezza"), long(f.size()));
if (f.help().full())
add_prop(TR("Help"), f.help());
add_prop(TR("Obbligatorio"), f.required() ? TR("Si") : TR("No"));
add_cat(TR("Database"));
id.cut(0);
if (f.field() != NULL)
{
const TIsam_handle f0 = atoi(f.field()->id());
if (f0 <= 0)
{
if (main_app().class_id() == CLASS_RELATION_APPLICATION)
{
TRelation_application& ra = (TRelation_application&)main_app();
id = ra.get_relation()->file(0).name();
}
}
else
id << f0;
TString80 str; str << *f.field();
add_prop(TR("Campo"), str);
}
else
{
// add_prop(TR("Campo"), TR("Nessuno")); ???
if (class_id() == CLASS_EDIT_FIELD || is_kind_of(CLASS_EDIT_FIELD))
{
const TEdit_field& ef = (TEdit_field&)f;
const TBrowse* b = ef.browse();
if (b != NULL && b->cursor() != NULL)
id = b->cursor()->file(0).name();
}
}
if (id.full())
{
add_prop(TR("Tabella"), id);
add_prop(TR("Descrizione"), prefix().description(id));
}
}
///////////////////////////////////////////////////////////
// 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), _modules(NULL), _ctl(NULL)
{ }
// Certified 100%
TMask_field::~TMask_field()
{
if (_ctl) delete _ctl;
if (_groups) delete _groups;
if (_modules) delete _modules;
}
// 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:
case CLASS_HTML_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
const TMask& m = mask();
if (scanner.key() != "BE")
{
NFCHECK("Testata errata o BEGIN mancante nel campo %d della maschera",
_ctl_data._dlg, (const char*)m.source_file());
scanner.push();
}
if (_ctl_data._dlg > DLG_NULL)
{
FOR_EACH_MASK_FIELD(m, i, mf)
{
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);
if (is_edit())
{
TBrowse* b = ((TEdit_field*)this)->browse();
if (b != NULL)
b->custom_display();
}
// Controllo se il campo (anche non operable) e' visibile solo con certi moduli
if (in_module(0) && _ctl_data._flags.find('H') < 0)
{
long mod = _modules->last_one();
for (; mod > BAAUT; mod--)
{
const word m = (word)mod;
if (in_module(m) && main_app().has_module(m))
break;
}
if (mod <= 0)
_ctl_data._flags << 'H';
}
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);
}
void TMask_field::set_module(word m)
{
if (m > BAAUT && m < ENDAUT)
{
if (_modules == NULL)
_modules = new TBit_array;
_modules->set(long(m));
}
}
bool TMask_field::in_module(word m) const
{
if (_modules != NULL)
{
if (m == BAAUT || m >= ENDAUT)
return _modules->first_one() > BAAUT;
else
return (*_modules)[m];
}
return false;
}
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") // GROUPS
{
if (_groups == NULL)
_groups = new TBit_array;
_groups->set(scanner.line());
return true;
}
if (scanner.key() == "MO") // MODULES
{
TToken_string m(scanner.line(), ',');
FOR_EACH_TOKEN(m, mod)
{
const word cod = dongle().module_name2code(mod);
set_module(cod);
}
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);
}
void TMask_field::set_rect(short cx, short cy, short cwidth, short cheight, short clen)
{
if (_ctl) _ctl->set_rect(cx, cy, cwidth, cheight, clen);
}
// 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)
{
if (on && !_flags.show_default && in_module(0))
on = false; // Nego la visibilt<6C> in assenza del modulo opportuno
_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;
}
_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_field* fld = mask().find_by_id(id); // Handles negatives id too
if (fld)
return fld->get();
return EMPTY_STRING;
}
const TString & TMask_field::evaluate_field(const char* s) const
{
if (s && *s)
{
if (s[0] == '#')
s++;
if (isdigit(*s) || *s=='-')
{
const short id = atoi(s);
return evaluate_field(id);
} else
if (*s>='A' && *s<='Z')
{
const TMask_field* fld = mask().find_by_fieldname(s);
if (fld)
return fld->get();
}
}
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), _help(NULL)
{ }
TOperable_field::~TOperable_field()
{
if (_help)
delete _help;
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
{
_help = new TString(scanner.string());
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());
if (_ctl != NULL)
_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))
{
TProperty_sheet p(prompt(), 60, 10);
p.add_cat(TR("Sorgente"));
TFilename fn = mask().source_file(); fn.lower();
p.add_prop(TR("Maschera"), fn);
p.add_prop(TR("Personalizzata"), fn.find("custom") > 0 ? "Si" : "No");
if (mask().get_sheet() != NULL)
p.add_prop(TR("Spreadsheet"), mask().get_sheet()->dlg());
p.add_cat(TR("Informazioni"));
TString16 id; id << dlg();
// p.add_prop(TR("Tipo"), class_name()); // Per ora ritorna sempre "Field"!
p.add_prop(TR("Identificatore"), id);
p.add_prop(TR("Lunghezza"), long(size()));
if (_help != NULL)
p.add_prop(TR("Help"), *_help);
p.add_prop(TR("Obbligatorio"), required() ? TR("Si") : TR("No"));
p.add_cat(TR("Database"));
id.cut(0);
if (field() != NULL)
{
const TIsam_handle f0 = atoi(field()->id());
if (f0 <= 0)
{
if (main_app().class_id() == CLASS_RELATION_APPLICATION)
{
TRelation_application& ra = (TRelation_application&)main_app();
id = ra.get_relation()->file(0).name();
}
}
else
id << f0;
TString80 str; str << *field();
p.add_prop(TR("Campo"), str);
}
else
{
// p.add_prop(TR("Campo"), TR("Nessuno")); ???
if (class_id() == CLASS_EDIT_FIELD || is_kind_of(CLASS_EDIT_FIELD))
{
const TEdit_field& ef = (TEdit_field&)*this;
const TBrowse* b = ef.browse();
if (b != NULL && b->cursor() != NULL)
id = b->cursor()->file(0).name();
}
}
if (id.full())
{
p.add_prop(TR("Tabella"), id);
p.add_prop(TR("Descrizione"), prefix().description(id));
}
p.run();
}
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;
const TMask_field& ff = mask.focus_field();
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 == '#')
{
a << ff.evaluate_field(f);
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
{
const int pos = mask().id2pos(fld);
if (pos >= 0)
{
TMask_field& f = mask().fld(pos);
const char* prev = f.get();
if (value != prev)
{
f.set(value);
if (f.shown() || f.ghost())
f.on_hit();
}
}
#ifdef DBG
// else error?
#endif
}
}
}
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())
{
TString4 flags;
if (hidden() || _ctl_data._flags.find('H') >= 0)
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)
{
// Cerco di mostrare un campo di un modulo proibito?
if (on && !_flags.show_default && in_module(0))
on = false; // Ho detto di Nooo!
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.full())
_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)
{ }
///////////////////////////////////////////////////////////
// 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)
{
CHECKD(w > 0 && w <= 50, "Invalid field length ", w);
_size = 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;
short id = scanner.integer();
if (id != 0)
{
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)
{
const TMask_field& f = m->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, altkey = 0;
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")
{
const TString& k = scanner.pop();
key = atoi(k);
const int maxkey = r ? r->curr().rec_des().NKeys : MAX_KEYS;
if (key <= 0 || key > maxkey)
{
#ifdef DBG
yesnofatal_box("Chiave %d non valida nella USE del campo %d", key, dlg());
#endif
key = 1;
}
if (key > 1 && !is_kind_of(CLASS_REAL_FIELD))
{
const int par = k.find('(');
if (par > 0)
altkey = atoi(k.mid(par+1));
if (altkey <= 2 || altkey > maxkey)
{
switch (logicnum)
{
case LF_CLIFO: altkey = 6; break;
default : altkey = 0; break;
}
if (altkey == key)
altkey = 0;
}
}
}
else scanner.push();
TString filter;
if (scanner.popkey() == "SE")
filter = (const char*)scanner.line();
else
scanner.push();
TToken_string orderby;
if (scanner.popkey() == "BY")
{
const char sep = orderby.separator();
orderby.separator(' ');
orderby = scanner.line();
orderby.strip_double_spaces();
orderby.replace(' ', sep);
orderby.separator(sep);
// Trasforma i nomi dei files in numeri se necessario
if (orderby.find('.') > 0)
{
TToken_string fld(16, '.');
TString16 name;
for (int i = 0; orderby.get(i, fld); i++)
{
if (!isdigit(fld[0]) && fld.find('.') > 0)
{
fld.get(0, name);
const int num = ::table2logic(name);
if (num != 0)
{
fld.add(num, 0);
orderby.add(fld, i);
}
}
}
}
}
else
scanner.push();
if (r != NULL)
{
_browse = new TBrowse(this, r, key, filter, orderby); // create browse
// ... 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);
}
if (altkey > 2)
((TBrowse*)_browse)->set_alt_browse(altkey);
_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 (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 && active())
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())
{
const 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 <= 20) ? 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_date_sel(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() != NULL)
{
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() && size() == 4 && decimals() == 0)
{
const TDate oggi(TODAY);
int anno = oggi.year(); // Anno solare o ...
if (has_query_button() && browse() != NULL && browse()->cursor() != NULL)
{
TCursor& cur = *browse()->cursor();
const TRecnotype ne = cur.items();
if (ne > 0 && xvt_str_same(cur.file(0).name(), "ESC")) // ... codice esercizio?
{
const TRectype& esc = cur.curr();
for (cur = ne-1; cur.pos() > 0; --cur)
{
const TDate dataini = esc.get("D0");
const TDate datafin = esc.get("D1");
if (oggi >= dataini && oggi <= datafin)
{
anno = esc.get_int("CODTAB");
break;
}
}
}
}
TMask_field::set(anno);
}
}
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 || roman()) && s <= 6)
{
str.format("%ld", atol(data)); // Gestione "veloce" degli interi
}
else
{
const real r(data); // Gestione standard dei reali
str = r.string(0, d);
}
if (_flags.zerofilled)
{
if (roman())
{
s = d;
if (s <= 0) s = 4;
const real r(data);
str = r.string(s, 0, '0');
}
else
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
{
const 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 << '@';
}
}
}
}
bool TReal_field::autosave(TRelation& r)
{
// Qundo salvo un intero in un sottocampo (ad esempio CODTAB[2,7]) lo allineo a destra
if (field() != NULL && field()->to() > 1 && decimals() == 0 &&
size() > 1 && !empty() && field()->name() == "CODTAB")
{
const int len = field()->len(r.curr(field()->file()));
if (size() == len && get().len() < len)
{
TString16 val = get();
val.right_just(len);
field()->write(val, r);
return true;
}
}
return TEditable_field::autosave(r);
}
///////////////////////////////////////////////////////////
// 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;
const TMask_field* d0 = driver(0);
if (d0)
{
value = d0->get();
const TMask_field* d1 = driver(1);
if (d1)
exchange = real(d1->get());
}
cur.set_num(num);
cur.force_value(value, exchange);
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, 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, 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++)
{
_codes.add(format("%02d", i));
_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
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, int width = 70);
};
bool TZoom_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
switch (o.dlg())
{
case DLG_DELREC:
if (e == fe_button)
{
reset(DLG_USER);
return false;
}
break;
default:
break;
}
return true;
}
TZoom_mask::TZoom_mask(const char* prompt, int width) : TAutomask(prompt, 1, width+2, 18)
{
const bool select = AUTOSELECT;
const bool autoend = AUTOEND;
AUTOSELECT = false;
AUTOEND = true;
add_button_tool(DLG_OK, "", TOOL_OK);
add_button_tool(DLG_DELREC, "Azzera", TOOL_DELREC);
add_button_tool(DLG_CANCEL, "", TOOL_CANCEL);
add_memo(DLG_USER, 0, "", 1, 0, width, -2);
set_handlers();
AUTOSELECT = select;
AUTOEND = autoend;
}
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(), size());
if (xvt_chr_is_alnum(__k))
{
_str << char(__k);
__k = char(0);
}
m.set(DLG_USER, _str.rtrim());
if (m.run() == K_ENTER && !read_only())
{
_str = m.get(DLG_USER);
set_window_data(raw2win(_str.rtrim()));
}
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); }