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