spreadsheets contenuti in una maschera che richiedeva di essere aggiornato da tutte le maschere derivate mask.cpp Modificato metodo sheets() che conta gli sheet presenti semplificando la vita alle maschere derivate Gestione menu di modifica msksheet.cpp Adeguato uso del metodo TMask::sheets() varmask.h Modificata indentazione varmask.cpp Adeguato uso del metodo TMask::sheets() Tolta stringa statica var_mask_str maskfld.* Tolti metodi obsoleti on_clipboard git-svn-id: svn://10.65.10.50/trunk@6042 c028cbd2-c16b-5b4b-a496-9718f37d4682
4221 lines
94 KiB
C++
Executable File
4221 lines
94 KiB
C++
Executable File
#define STRICT
|
|
#define XVT_INCL_NATIVE
|
|
#include <xvt.h>
|
|
|
|
#include <applicat.h>
|
|
#include <colors.h>
|
|
#include <controls.h>
|
|
#include <defmask.h>
|
|
#include <execp.h>
|
|
#include <mailbox.h>
|
|
#include <mask.h>
|
|
#include <prefix.h>
|
|
#include <relation.h>
|
|
#include <sheet.h>
|
|
#include <tabutil.h>
|
|
#include <urldefid.h>
|
|
#include <utility.h>
|
|
#include <validate.h>
|
|
#include <xvtility.h>
|
|
#include <text.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 = exchange = FALSE;
|
|
firm = ghost = FALSE;
|
|
password = FALSE;
|
|
trim = 3;
|
|
pipeallowed = FALSE;
|
|
}
|
|
|
|
// Certified 100%
|
|
char TMask_field::TField_Flags::update(const char* f)
|
|
{
|
|
for (const char* s = f; *s; s++)
|
|
switch(*s)
|
|
{
|
|
case '#':
|
|
trim = 2; break;
|
|
case '@':
|
|
trim = 1; break;
|
|
case ' ':
|
|
case '_':
|
|
trim = 0; break;
|
|
case '*':
|
|
password = TRUE; break;
|
|
case 'A':
|
|
automagic = persistent = TRUE; break;
|
|
case 'B':
|
|
button = TRUE; break;
|
|
case 'D':
|
|
enable_default = enabled = FALSE; break;
|
|
case 'F':
|
|
firm = persistent = TRUE; break;
|
|
case 'G':
|
|
ghost = TRUE; break;
|
|
case 'H':
|
|
show_default = shown = FALSE; break;
|
|
case 'I':
|
|
break; // reserved for sheetfield insert
|
|
case 'M':
|
|
roman = TRUE; break;
|
|
case 'P':
|
|
persistent = TRUE; break;
|
|
case 'R':
|
|
rightjust = TRUE; break;
|
|
case 'U':
|
|
uppercase = TRUE; break;
|
|
case 'V':
|
|
exchange = TRUE; break;
|
|
case 'Z':
|
|
zerofilled = TRUE; 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);
|
|
}
|
|
|
|
|
|
TMask_field::TMask_field(TMask* m)
|
|
: _mask(m), _ctl(NULL), _groups(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
|
|
}
|
|
|
|
|
|
|
|
// @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 ? 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 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
|
|
// @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:
|
|
_ctl_data._height = len;
|
|
_ctl_data._width = width <= 0 ? 12 : width;
|
|
break;
|
|
case CLASS_MEMO_FIELD:
|
|
_ctl_data._height = len;
|
|
_ctl_data._width = width;
|
|
_ctl_data._size = len * width;
|
|
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::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 = scanner.string();
|
|
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();
|
|
}
|
|
|
|
|
|
void TMask_field::set_dirty(bool 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);
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
|
|
void TMask_field::set(const char*)
|
|
{
|
|
}
|
|
|
|
void TMask_field::set(long n)
|
|
{
|
|
char s[16]; sprintf(s, "%ld", n);
|
|
set(s);
|
|
}
|
|
|
|
const TString& TMask_field::get() const
|
|
{
|
|
return _ctl_data._park.cut(0);
|
|
}
|
|
|
|
// @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 = (char*)(const char*)_ctl_data._park;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();
|
|
if (mask().is_sheetmask() && !mask().is_running())
|
|
{
|
|
xvt_statbar_set(_msg);
|
|
beep();
|
|
}
|
|
else
|
|
{
|
|
mask().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_statbar_set(_msg);
|
|
beep();
|
|
}
|
|
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
|
|
///////////////////////////////////////////////////////////
|
|
|
|
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), _handler(NULL), _message(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().strip_spaces();
|
|
message(0, TRUE)->add(m);
|
|
return TRUE;
|
|
}
|
|
|
|
return TMask_field::parse_item(scanner);
|
|
}
|
|
|
|
void TOperable_field::set_focus() const
|
|
{
|
|
mask().set_focus_field(dlg());
|
|
}
|
|
|
|
// 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:
|
|
{
|
|
TString msg(80);
|
|
msg << "Identificatore: " << dlg() << '\n'
|
|
<< "Maschera: " << mask().source_file() << '\n';
|
|
if (field() != NULL)
|
|
msg << "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)
|
|
{
|
|
mask().stop_run(atoi(dlg));
|
|
continue;
|
|
} else
|
|
if (cmd == 15)
|
|
{
|
|
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;
|
|
if (_handler)
|
|
ok = _handler(*this, k);
|
|
else
|
|
ok = TRUE;
|
|
return ok;
|
|
}
|
|
|
|
// Certified 90%
|
|
bool TOperable_field::on_hit()
|
|
{
|
|
const bool ok = handler(K_SPACE);
|
|
if (ok && has_message())
|
|
do_message(0);
|
|
return ok;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// 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)
|
|
{
|
|
_exit_key = 0;
|
|
_virtual_key = 0;
|
|
switch (dlg())
|
|
{
|
|
case DLG_OK:
|
|
if (_ctl_data._prompt.empty() || _ctl_data._prompt == "Conferma")
|
|
_ctl_data._prompt = "~Conferma";
|
|
_virtual_key = 'C';
|
|
_exit_key = K_ENTER;
|
|
if (_ctl_data._bmp_up == 0 && _ctl_data._prompt == "~Conferma")
|
|
_ctl_data._bmp_up = BMP_OK;
|
|
break;
|
|
case DLG_CANCEL:
|
|
if (_ctl_data._prompt.empty())
|
|
_ctl_data._prompt = "Annulla";
|
|
_virtual_key = _exit_key = K_ESC;
|
|
if (_ctl_data._bmp_up == 0 && _ctl_data._prompt == "Annulla")
|
|
_ctl_data._bmp_up = BMP_CANCEL;
|
|
break;
|
|
case DLG_DELREC:
|
|
if (_ctl_data._prompt.empty() || _ctl_data._prompt == "Elimina")
|
|
_ctl_data._prompt = "~Elimina";
|
|
_virtual_key = 'E';
|
|
_exit_key = K_DEL;
|
|
if (_ctl_data._bmp_up == 0 && _ctl_data._prompt == "~Elimina")
|
|
{
|
|
_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 = "~Stampa";
|
|
_virtual_key = 'S';
|
|
_exit_key = K_ENTER;
|
|
if (_ctl_data._bmp_up <= 0 && _ctl_data._prompt == "~Stampa")
|
|
_ctl_data._bmp_up = BMP_PRINT;
|
|
break;
|
|
case DLG_QUIT:
|
|
if (_ctl_data._prompt.empty())
|
|
_ctl_data._prompt = "Fine";
|
|
_virtual_key = K_F4;
|
|
_exit_key = K_QUIT;
|
|
if (_ctl_data._bmp_up <= 0 && _ctl_data._prompt == "Fine")
|
|
{
|
|
_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;
|
|
}
|
|
|
|
TToken_string* mess = message(0);
|
|
if (mess)
|
|
{
|
|
TToken_string msg(mess->get(0), ',');
|
|
const TString m(msg.get(0));
|
|
if (m == "EXIT")
|
|
_exit_key = msg.get_int();
|
|
else
|
|
if (msg.get_int() == 0) _exit_key = atoi(m);
|
|
}
|
|
if (_virtual_key == 0)
|
|
{
|
|
const int n = _ctl_data._prompt.find('~');
|
|
_virtual_key = (n >= 0) ? toupper(_ctl_data._prompt[n+1]) : _exit_key;
|
|
}
|
|
|
|
_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);
|
|
}
|
|
|
|
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)
|
|
{
|
|
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_icon(word icon)
|
|
{
|
|
((TPushbutton_control*)_ctl)->set_icon(icon);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TEditable_field
|
|
///////////////////////////////////////////////////////////
|
|
|
|
TEditable_field::TEditable_field(TMask* m)
|
|
: TLoadable_field(m), _prompt(NULL), _field(NULL), _keys(NULL),
|
|
_validate(NULL), _warning(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;
|
|
}
|
|
|
|
|
|
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() : "";
|
|
}
|
|
|
|
|
|
// 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 == "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++)
|
|
_validate->_parms.add(scanner.operand());
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
if (scanner.key() == "WA")
|
|
{
|
|
set_warning(scanner.string());
|
|
return TRUE;
|
|
}
|
|
|
|
return TOperable_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 70%
|
|
word TEditable_field::first_key() const
|
|
{
|
|
if (_keys == NULL)
|
|
return 0;
|
|
const int last = last_key();
|
|
for (int i = 1; i <= last; i++)
|
|
if (in_key(i) == TRUE)
|
|
break;
|
|
return (word)i;
|
|
}
|
|
|
|
// Certified 70%
|
|
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)
|
|
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();
|
|
for (word 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)
|
|
{
|
|
CHECKD(_prompt, "Can't set prompt to control", dlg());
|
|
_prompt->set_caption(p);
|
|
}
|
|
|
|
// Certified 90%
|
|
void TEditable_field::set_field(const TString& fr)
|
|
{
|
|
if (_field != NULL)
|
|
{
|
|
if (fr.empty())
|
|
{
|
|
delete _field;
|
|
_field = NULL;
|
|
}
|
|
else
|
|
*_field = fr;
|
|
}
|
|
else
|
|
_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 TString& 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; }
|
|
|
|
|
|
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 ? ((TCheckbox_control*)_ctl)->checked() : FALSE;
|
|
_str = on ? "X" : "";
|
|
return _str;
|
|
}
|
|
|
|
bool TBoolean_field::parse_item(TScanner& scanner)
|
|
{
|
|
if (scanner.key() == "ME")
|
|
{
|
|
const bool tf = scanner.integer() ? TRUE : FALSE; // 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;
|
|
break;
|
|
case K_F2:
|
|
set("");
|
|
set_dirty();
|
|
return TRUE;
|
|
break;
|
|
default:
|
|
return TEditable_field::on_key(key);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// 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();
|
|
for ( const char* 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 (field().dlg() != id && hit)
|
|
{
|
|
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();
|
|
const bool passed = _row != -1;
|
|
if (passed) do_output(t);
|
|
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;
|
|
s = scanner.string();
|
|
_head.add(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(f.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;
|
|
}
|
|
|
|
|
|
// @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();
|
|
|
|
cur.zero();
|
|
TRectype filtrec(cur);
|
|
|
|
_inp_id.restart();
|
|
_inp_fn.restart();
|
|
|
|
TString256 val; // Value to output
|
|
bool tofilter;
|
|
|
|
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 short id = field().atodlg(fld);
|
|
const bool filter_flag = strchr(fld, '@') != NULL;
|
|
tofilter = filter && filter_flag;
|
|
val = field(id).get();
|
|
|
|
const TMask_field& f = field(id);
|
|
if (f.class_id() == CLASS_DATE_FIELD && f.right_justified())
|
|
{
|
|
const TDate d(val);
|
|
val = d.string(ANSI);
|
|
}
|
|
|
|
if (f.is_edit() && val.not_empty() && !filter_flag)
|
|
ne++; // Increment not empty fields count
|
|
}
|
|
|
|
TFieldref fldref(_inp_fn.get(), 0); // Output field
|
|
fldref.write(val, *_cursor->relation());
|
|
if (tofilter)
|
|
{
|
|
if (val.empty()) val.fill('~', fldref.len(cur));
|
|
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] == '#')
|
|
{
|
|
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();
|
|
if (t != STARTING_CHECK || f.field() == NULL || f.mask().mode() == MODE_INS)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
/*
|
|
if (hit)
|
|
{
|
|
f.check();
|
|
f.on_hit();
|
|
}
|
|
*/
|
|
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("batb", 4, TRUE) == 0) // Programma gestione tabelle
|
|
if (nm.compare("tb", 2, TRUE) == 0) // Programma gestione tabelle
|
|
{
|
|
// app = format("ba3 -0 %s", (const char*)nm.mid(4));
|
|
const char* module = ((TTable&)_cursor->file()).module();
|
|
TString prg("ba3 -0");
|
|
if (strcmp(module,"ba")!=0)
|
|
{
|
|
TConfig c(CONFIG_STUDIO);
|
|
prg = c.get("TabPrg",module);
|
|
if (prg.empty())
|
|
prg = "ba3 -0";
|
|
}
|
|
app = format("%s %s", (const char*)prg,(const char*)nm.mid(2));
|
|
// Obbligatorio usare la format globale
|
|
}
|
|
else // Programma generico di browse/edit
|
|
app = format("ba3 -3 %s %d", (const char*)nm, _cursor->file().num());
|
|
// Obbligatorio usare la format globale
|
|
}
|
|
else
|
|
{
|
|
app = &_insert[1];
|
|
}
|
|
if (app.find('#') != -1)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
TMailbox mail;
|
|
if (insert)
|
|
{
|
|
TMessage msg(app, MSG_AI, "");
|
|
mail.send(msg);
|
|
}
|
|
else
|
|
{
|
|
TToken_string body;
|
|
|
|
body.add(_cursor->key());
|
|
_inp_fn.restart();
|
|
for (const char* i = _inp_id.get(0); i; i = _inp_id.get())
|
|
{
|
|
TString inp_id(i);
|
|
TString16 field_name(_inp_fn.get());
|
|
TString s(field_name);
|
|
const int pos = s.find(",");
|
|
|
|
if (pos >= 0)
|
|
s.cut(pos);
|
|
|
|
s << "=";
|
|
if (inp_id[0] == '"')
|
|
{
|
|
inp_id.ltrim(1);
|
|
inp_id.rtrim(1);
|
|
s << inp_id;
|
|
}
|
|
else
|
|
{
|
|
const short id = field().atodlg(inp_id);
|
|
const TEditable_field & f = field(id);
|
|
|
|
TFieldref fldref(field_name, 0);
|
|
s << fldref.read(*_cursor->relation());
|
|
}
|
|
body.add(s);
|
|
}
|
|
TMessage msg(app, MSG_ED, body);
|
|
mail.send(msg);
|
|
}
|
|
|
|
TExternal_app a(app);
|
|
a.run();
|
|
field().mask().set_focus();
|
|
|
|
if (mail.check())
|
|
{
|
|
TMessage* rcv = mail.next_s(insert ? MSG_AI : MSG_LN);
|
|
if (rcv != NULL)
|
|
_rec = atol(rcv->body());
|
|
if (_rec > 0)
|
|
{
|
|
_cursor->file().readat(_rec);
|
|
ok = _cursor->ok();
|
|
if (ok) do_output();
|
|
#ifdef DBG
|
|
else yesnofatal_box("Selezione da programma esterno errata");
|
|
#endif
|
|
}
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
|
|
TToken_string& TBrowse::create_siblings(TToken_string& siblings)
|
|
{
|
|
const TMask& mask = field().mask();
|
|
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);
|
|
|
|
//const TLocalisamfile& f = _cursor->file();
|
|
//TString caption(prefix().description(f.name()));
|
|
TString caption(_cursor->file().description());
|
|
if (!isalnum(caption[0]))
|
|
caption = "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 != '"' && 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_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)
|
|
{
|
|
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;
|
|
|
|
if (field().check_type() != CHECK_NONE)
|
|
{
|
|
const TMaskmode mode = (TMaskmode)field().mask().mode();
|
|
|
|
CheckType chk = field().check_type();
|
|
if (chk == CHECK_REQUIRED && (t == STARTING_CHECK || mode == MODE_QUERY))
|
|
chk = CHECK_NORMAL;
|
|
|
|
const int ne = do_input(TRUE);
|
|
if (ne || chk == CHECK_REQUIRED)
|
|
{
|
|
/* Guy: vecchio modo
|
|
_cursor->setkey();
|
|
_cursor->file().read(_isequal);
|
|
passed = _cursor->ok();
|
|
*/
|
|
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;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TEdit_field
|
|
///////////////////////////////////////////////////////////
|
|
|
|
TEdit_field::TEdit_field(TMask* mask)
|
|
: TEditable_field(mask), _browse(NULL),
|
|
_check(CHECK_NONE), _check_enabled(FALSE), _forced(FALSE)
|
|
{ }
|
|
|
|
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);
|
|
|
|
/* _ctl_data.reset();
|
|
_ctl_data._dlg = dlg();
|
|
_ctl_data._x = x;
|
|
_ctl_data._y = y;
|
|
_ctl_data._prompt = prompt();
|
|
|
|
_ctl_data._size = size();
|
|
|
|
_ctl_data._flags = flags;
|
|
_flags.update(flags);
|
|
|
|
_ctl_data._width = width;
|
|
create(parent()); */
|
|
|
|
}
|
|
|
|
|
|
void TEdit_field::parse_head(TScanner& scanner)
|
|
{
|
|
_ctl_data._size = scanner.integer();
|
|
#ifdef DBG
|
|
if (_ctl_data._size <= 0)
|
|
{
|
|
_ctl_data._size = 8;
|
|
yesnofatal_box("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 int id = scanner.integer();
|
|
const TEdit_field& f = mask().efield(id);
|
|
const TBrowse* b = f.browse();
|
|
return b;
|
|
}
|
|
|
|
bool TEdit_field::parse_item(TScanner& scanner)
|
|
{
|
|
if (scanner.key() == "PI") // PICTURE
|
|
{
|
|
_picture = scanner.string();
|
|
return TRUE;
|
|
}
|
|
|
|
if (scanner.key() == "CH")
|
|
{
|
|
scanner.pop();
|
|
if (scanner.key() == "NO") _check = CHECK_NORMAL; else
|
|
if (scanner.key() == "RE") _check = CHECK_REQUIRED; else
|
|
if (scanner.key() == "FO") { _check = CHECK_REQUIRED; _forced = TRUE; } else
|
|
if (scanner.key() == "SE") _check = CHECK_SEARCH;
|
|
else _check = CHECK_NONE;
|
|
if (sheet())
|
|
{
|
|
#ifdef DBG
|
|
NFCHECK("Checktype inutile sul campo %d", dlg());
|
|
#endif
|
|
_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;
|
|
|
|
const int logicnum = scanner.integer();
|
|
TString16 tabmaskname;
|
|
|
|
if (logicnum > 0)
|
|
{
|
|
TDir d; d.get(logicnum);
|
|
if (fexist(d.filename())) // Controlla l'esistenza del file
|
|
r = new TRelation(logicnum);
|
|
}
|
|
else
|
|
{
|
|
tabmaskname = scanner.pop();
|
|
#ifdef DBG
|
|
if (tabmaskname.len() > 4)
|
|
return yesnofatal_box("'%s' non e' una tabella valida: %d",
|
|
(const char*)tabmaskname, dlg());
|
|
#endif
|
|
TDir d; d.get(TTable::name2log(tabmaskname));
|
|
if (fexist(d.filename())) // Controlla l'esistenza del file
|
|
r = new TRelation(tabmaskname);
|
|
}
|
|
|
|
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 (tabmaskname.not_empty())
|
|
{
|
|
// tabmaskname.insert("MBATB", 0);
|
|
tabmaskname.insert("MTB", 0);
|
|
browse()->set_insert(tabmaskname);
|
|
}
|
|
_check_enabled = TRUE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
if (scanner.key() == "CO") // Copyuse
|
|
{
|
|
const TString16 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);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (scanner.key() == "SH") // SHEET
|
|
{
|
|
#ifdef DBG
|
|
if (_browse)
|
|
return yesnofatal_box("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() == "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::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';
|
|
|
|
_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);
|
|
}
|
|
|
|
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 < size())
|
|
{
|
|
if (isdigit(s[0]) && real::is_natural(s))
|
|
s.right_just(size(), '0');
|
|
}
|
|
for (const char * w = (const char *) s; *w == '0'; w++) ;
|
|
if (*w == '\0')
|
|
s.cut(0);
|
|
}
|
|
|
|
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("Valore non valido per %s: %s", (const char*)p, (const char*)val);
|
|
}
|
|
else
|
|
error_box("Valore non valido: %s", (const char*)get());
|
|
}
|
|
else
|
|
error_box(get_warning());
|
|
return FALSE;
|
|
}
|
|
|
|
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 (sheet())
|
|
{
|
|
ok = query || sheet()->check(); // Check consistency
|
|
}
|
|
else
|
|
{
|
|
// if (check_enabled() && (!query || forced()) && vf != 21)
|
|
if (check_enabled() && vf != 21)
|
|
{
|
|
if (!query || forced())
|
|
ok = browse()->check();
|
|
else
|
|
browse()->check();
|
|
}
|
|
}
|
|
}
|
|
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
|
|
return handler(K_TAB);
|
|
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 (sheet())
|
|
ok = sheet()->check(FINAL_CHECK);
|
|
else
|
|
{
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
if (!ok) return default_error_box();
|
|
}
|
|
}
|
|
break;
|
|
case K_F2:
|
|
set("");
|
|
break;
|
|
case K_F9:
|
|
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())
|
|
return handler(K_F9);
|
|
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);
|
|
if (_browse)
|
|
((TField_control*)_ctl)->show_button(on);
|
|
}
|
|
|
|
// @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);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// 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 ULTIMO | Ultimo giorno dell'anno (31-12-aa)
|
|
// @flag NATALE | Giorno di natale (25-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 == "IERI")
|
|
{
|
|
--g;
|
|
} else
|
|
if (s == "DOMANI")
|
|
{
|
|
++g;
|
|
} else
|
|
if (s == "POSDOMANI")
|
|
{
|
|
g += 2;
|
|
} else
|
|
if (s == "ALTROIERI")
|
|
{
|
|
g -= 2;
|
|
} else
|
|
if (s == "PRIMO")
|
|
{
|
|
g.set_month(1);
|
|
g.set_day(1);
|
|
} else
|
|
if (s == "NATALE")
|
|
{
|
|
g.set_month(12);
|
|
g.set_day(25);
|
|
} else
|
|
if (s == "ULTIMO")
|
|
{
|
|
g.set_month(12);
|
|
g.set_day(31);
|
|
} else
|
|
if (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
|
|
{
|
|
#ifdef _DEMO_
|
|
TDate d(data);
|
|
int y = d.year();
|
|
|
|
if (y & 0x0001) y--;
|
|
y >>= 3;
|
|
y++;
|
|
y /= 10;
|
|
if (y >= 25)
|
|
{
|
|
int m = d.month();
|
|
if (m > 3)
|
|
d.set_month(rand() % 3 + 1);
|
|
}
|
|
set_window_data(d.string());
|
|
#else
|
|
set_window_data(data);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_ctl->is_edit_key(key))
|
|
{
|
|
const bool ok = strchr("-0123456789ADEGILMNOPRSTUadegilmnoprstu", key) != NULL;
|
|
if (!ok) beep();
|
|
return ok;
|
|
}
|
|
}
|
|
|
|
return TEdit_field::on_key(key);
|
|
}
|
|
|
|
bool TDate_field::autosave(TRelation& r)
|
|
{
|
|
if (field())
|
|
{
|
|
const char* td = get();
|
|
#ifdef _DEMO_
|
|
{
|
|
TDate d(td);
|
|
int y = d.year();
|
|
|
|
y += 8;
|
|
y /= 25;
|
|
y >>= 3;
|
|
if (y >= 10)
|
|
{
|
|
int m = d.month() >> 2;
|
|
if (m > 0)
|
|
d.set_month(rand() % 3 + 1);
|
|
}
|
|
td = d.string();
|
|
}
|
|
#endif
|
|
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(main_app().get_firm());
|
|
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;
|
|
}
|
|
}
|
|
//#ifdef DBG
|
|
// const int preferred_size = 19;
|
|
// if (_ctl_data._size > 9 && _ctl_data._size != preferred_size)
|
|
// ::warning_box("Guy propone una dimensione di %d per il campo %d: %s\nMa probabilmente ha toppato ...",
|
|
// preferred_size, _ctl_data._dlg, (const char*)_ctl_data._prompt);
|
|
//#endif
|
|
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))
|
|
{
|
|
str = data;
|
|
if (_flags.zerofilled)
|
|
{
|
|
word s = size();
|
|
if (roman())
|
|
{
|
|
s = decimals();
|
|
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))
|
|
main_app().set_firm(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;
|
|
}
|
|
}
|
|
|
|
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 (exchangeable() && decimals())
|
|
{
|
|
const real& e = mask().exchange();
|
|
n /= e;
|
|
}
|
|
if (_picture.empty())
|
|
{
|
|
if (_flags.zerofilled)
|
|
s = n.stringa(_size, _decimals, '0');
|
|
else
|
|
s = n.stringa(0, _decimals);
|
|
}
|
|
else
|
|
{
|
|
s = n.string(_picture);
|
|
}
|
|
}
|
|
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 (exchangeable() && decimals())
|
|
{
|
|
const real& e = mask().exchange();
|
|
n *= e;
|
|
}
|
|
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 = ".";
|
|
}
|
|
}
|
|
|
|
|
|
void TReal_field::exchange(bool show_value, const real& nuo)
|
|
{
|
|
const int dec = show_value ? 2 : 0; // Quanti decimali voglio
|
|
const bool value = decimals() != 0; // Sono attualmente in valuta ?
|
|
|
|
if (show_value == value && show_value) return; // Se cambio da valuta a valuta esco subito!
|
|
|
|
if (mask().is_running())
|
|
{
|
|
const char* n = get_window_data();
|
|
if (*n)
|
|
{
|
|
const real& vec = mask().exchange();
|
|
real r(n);
|
|
if (!show_value)
|
|
r *= nuo;
|
|
r /= vec;
|
|
r.round(dec);
|
|
set_decimals(dec);
|
|
TEdit_field::set_window_data(r.string(_picture));
|
|
}
|
|
}
|
|
|
|
if (decimals() != dec)
|
|
set_decimals(dec);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// 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 = ts.get();
|
|
_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> vengono
|
|
// aggiunte tante voci quanti sono gli elementi.
|
|
{
|
|
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 = "";
|
|
}
|
|
_codes.add("01|02|03|04|05|06|07|08|09|10|11|12");
|
|
_values.add("Gennaio|Febbraio|Marzo|Aprile|Maggio|Giugno|"
|
|
"Luglio|Agosto|Settembre|Ottobre|Novembre|Dicembre");
|
|
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;
|
|
|
|
_ctl_data._park = data; // data puo' venire da una TToken_string::get
|
|
int pos = 0;
|
|
|
|
if (_ctl_data._park.len() > 2) // E' veramente una descrizione
|
|
pos = value.get_pos(_ctl_data._park);
|
|
else // Oppure e' un codice
|
|
pos = codes.get_pos(_ctl_data._park);
|
|
|
|
if (pos < 0 && _ctl_data._park.blank())
|
|
{
|
|
_ctl_data._park = codes.get(0); // Uso codes come riferimento per blank
|
|
if (_ctl_data._park.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;
|
|
|
|
_ctl_data._park = data; // data puo' venire da una TToken_string::get
|
|
int pos = codes.get_pos(_ctl_data._park);
|
|
if (pos < 0 && _ctl_data._park.blank())
|
|
{
|
|
_ctl_data._park = codes.get(0);
|
|
if (_ctl_data._park.blank())
|
|
pos = 0;
|
|
}
|
|
CHECKS(pos >= 0, "Unknown listbox code:", (const char*)_ctl_data._park);
|
|
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 (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);
|
|
// if (mask().is_running())
|
|
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:
|
|
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.not_empty())
|
|
{
|
|
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();
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// 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
|
|
{
|
|
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';
|
|
return s;
|
|
}
|
|
|
|
const char* TMemo_field::win2raw(const char* data) const
|
|
{
|
|
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;
|
|
}
|
|
|
|
bool TMemo_field::on_key(KEY k)
|
|
{
|
|
if (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);
|
|
}
|
|
|
|
bool TZoom_field::on_key( KEY key )
|
|
{
|
|
switch (key)
|
|
{
|
|
case K_TAB:
|
|
if (focusdirty())
|
|
get_window_data();
|
|
break;
|
|
case K_F9:
|
|
if (browse() != NULL)
|
|
break;
|
|
case K_F8:
|
|
{
|
|
get_window_data();
|
|
TMask m("Zoom", 1, 72, 18);
|
|
m.add_memo(101, 0, prompt(), 1, 0, -1, -3);
|
|
m.add_button(DLG_OK, 0, "Conferma", -12, -1, 9, 2);
|
|
m.add_button(DLG_CANCEL, 0, "Annulla", -22, -1, 9, 2);
|
|
m.set(101, _str);
|
|
if (m.run() != K_ESC)
|
|
{
|
|
_str = m.get(101);
|
|
set_window_data(raw2win(_str));
|
|
}
|
|
return TRUE;
|
|
}
|
|
break;
|
|
default:
|
|
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); }
|
|
|
|
|
|
|