campo-sirio/include/maskfld.cpp
pirro 65f26fccde Corretto autocambiamento della ditta
git-svn-id: svn://10.65.10.50/trunk@1111 c028cbd2-c16b-5b4b-a496-9718f37d4682
1995-03-13 11:48:49 +00:00

3179 lines
65 KiB
C++
Executable File

// $Id: maskfld.cpp,v 1.83 1995-03-13 11:48:49 pirro Exp $
#include <xvt.h>
#include <applicat.h>
#include <defmask.h>
#include <execp.h>
#include <mailbox.h>
#include <mask.h>
#include <prefix.h>
#include <relation.h>
#include <sheet.h>
#include <tabutil.h>
#include <urldefid.h>
#include <utility.h>
#include <validate.h>
#include <xvtility.h>
#if XVT_OS == XVT_OS_WIN
#include <windows.h>
#endif
HIDDEN TString256 fpark;
///////////////////////////////////////////////////////////
// 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 = FALSE;
dirty = focusdirty = FALSE;
roman = exchange = FALSE;
firm = ghost = FALSE;
password = FALSE;
trim = TRUE;
}
// Certified 100%
char TMask_field::TField_Flags::update(const char* f)
{
for (const char* s = f; *s; s++)
switch(toupper(*s))
{
case ' ':
case '_':
trim = FALSE; break;
case '*':
password = TRUE; break;
case 'A':
automagic = persistent = TRUE; break;
case 'D':
enable_default = enabled = FALSE; break;
case 'F':
firm = persistent = TRUE; break;
case 'G':
ghost = TRUE; break;
case 'H':
show_default = shown = FALSE; break;
case 'M':
roman = TRUE; break;
case 'P':
persistent = TRUE; break;
case 'R':
rightjust = TRUE; break;
case 'U':
uppercase = TRUE; break;
case 'V':
exchange = TRUE; break;
case 'Z':
zerofilled = TRUE; break;
default :
CHECKS(0, "FLAG sconosciuto in ", f);
break;
}
return *s;
}
///////////////////////////////////////////////////////////
// TMask_field
///////////////////////////////////////////////////////////
int TMask_field::_x; // Position of the field
int TMask_field::_y;
int TMask_field::_width;
TString80 TMask_field::_prompt;
TMask_field::TMask_field(TMask* m)
: _mask(m), _win(NULL_WIN), _promptwin(NULL_WIN), _dlg(0),
_keys(0), _groups(0), _help(0), _handler(NULL),
_validate_func(-1), _validate_parms(1), _field(NULL)
{}
// Certified 100%
TMask_field::~TMask_field()
{
if (_field) delete _field;
}
// Certified 100%
bool TMask_field::is_edit() const
{
const word c = class_id();
return c == CLASS_EDIT_FIELD || c == CLASS_REAL_FIELD || c == CLASS_DATE_FIELD;
}
// 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::ok() const
{ return win() != NULL_WIN && dlg() >= -1; }
// Certified 100%
void TMask_field::parse_head(TScanner&)
{}
// Certified 100%
short TMask_field::atodlg(const char* s) const
{
short d = s ? atoi(s) : 0;
#ifdef DBG
if (d == 0 || d < -1 || d > 1000)
{
yesnofatal_box("Identificatore non valido nel campo %d: '%s'", dlg(), s);
d = -1;
}
#endif
return d;
}
void TMask_field::construct(short id, const char* prompt, int x, int y,
int len, WINDOW parent, const char* flags, int width)
{
_x = x; _y = y;
_prompt = prompt;
_size = len;
if (class_id() == CLASS_REAL_FIELD)
{
((TReal_field*)this)->set_decimals(width);
_width = _size;
}
else _width = width < 1 ? _size : width;
_dlg = id;
_flags.update(flags);
create(parent);
}
void TMask_field::construct(TScanner& scanner, WINDOW parent)
{
_dlg = atodlg(scanner.pop());
parse_head(scanner);
_prompt.cut(0);
scanner.popkey(); // BEGIN
#ifdef DBG
if (scanner.key() != "BE")
{
yesnofatal_box("Testata errata o BEGIN mancante nel campo %d", _dlg);
scanner.push();
}
#endif
while(scanner.popkey() != "EN") // END of control
parse_item(scanner);
create(parent);
}
bool TMask_field::parse_item(TScanner& scanner)
{
if (scanner.key() == "PR") // PROMPT
{
_x = scanner.integer();
_y = scanner.integer();
_prompt = scanner.string();
return TRUE;
}
if (scanner.key() == "FL") // FLAG
{
const char* f = scanner.string();
return _flags.update(f) == '\0';
}
if (scanner.key() == "FI") // FIELD
{
CHECKD(_field == NULL, "Only one FIELD, please: ", dlg());
_field = new TFieldref(scanner.line(), 0);
return TRUE;
}
if (scanner.key() == "HE") // HELP
{
_help = scanner.string();
return TRUE;
}
if (scanner.key() == "KE") // KEY
{
_keys.set(scanner.line());
_keys.set(0L);
return TRUE;
}
if ( scanner.key() == "CU") // CUSTOM DATA
{
_userdata.add(scanner.string());
return TRUE;
}
if (scanner.key() == "ME")
{
if (_message.objptr(0) == 0)
_message.add(new TToken_string(64), 0);
TToken_string& ts = (TToken_string&)_message[0];
ts.add(scanner.line().strip_spaces());
return TRUE;
}
if (scanner.key() == "GR")
{
_groups.set(scanner.line());
return TRUE;
}
return FALSE;
}
long TMask_field::default_flags() const
{
long f = CTL_FLAG_NATIVE_JUST;
if (_flags.show_default == FALSE) f |= CTL_FLAG_INVISIBLE;
if (_flags.enable_default == FALSE) f |= CTL_FLAG_DISABLED;
return f;
}
// Certified 100%
WINDOW TMask_field::wincreate(WIN_TYPE ct, short dx, short dy,
const char* title, WINDOW parent,
long flags)
{
_win = xvt_create_control(ct,
_x, _y, dx, dy,
(char*)title,
parent,
flags | default_flags(),
PTR_LONG(this),
_dlg);
return _win;
}
// Certified 100%
WINDOW TMask_field::parent() const
{ return get_parent(win()); }
// Certified 90%
int TMask_field::create_prompt(WINDOW parent, int width, int heigth)
{
const WIN_TYPE wt = (heigth < 3) ? WC_TEXT : WC_GROUPBOX;
if (width < 1) width = _prompt.len();
_prompt.rtrim(); // Could save some bytes
if (width)
{
const long flags = default_flags() & (~CTL_FLAG_DISABLED); // Static controls shouldn't be grayed
#if XVT_OS == XVT_OS_WIN
const int k = _prompt.find('~');
if (k >= 0) _prompt[k] = '&';
#endif
_promptwin = xvt_create_control
(
wt,
_x, _y, width, heigth,
_prompt,
parent,
flags,
0L,
-1
);
}
return width;
}
// Certified 100%
void TMask_field::destroy()
{
if (_win)
{ close_window(_win); _win = NULL_WIN; }
if (_promptwin)
{ close_window(_promptwin); _promptwin = NULL_WIN; }
}
// Certified 100%
void TMask_field::create(WINDOW parent)
{
_width = _prompt.len();
if (_width)
wincreate(WC_TEXT, _width, 1, _prompt, parent, CTL_FLAG_LEFT_JUST);
}
// Certified 100%
void TMask_field::enable(bool on)
{
const word c = class_id();
if (c != CLASS_FIELD)
{
enable_window(_win, on);
_flags.enabled = on;
}
}
// Certified 100%
void TMask_field::enable_default()
{
const bool ed = _flags.enable_default;
enable(ed);
}
// Certified 100%
void TMask_field::show(bool on)
{
show_window(_win, on);
if (_promptwin != NULL_WIN)
show_window(_promptwin, 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 enabled() && shown() && class_id() != CLASS_FIELD;
};
// Certified 90%
word TMask_field::last_key() const
{
long u = _keys.last_one();
if (u < 0) u = 0;
return (word)u;
}
void TMask_field::set_dirty(bool d)
{
if (_flags.dirty == 3 && d == FALSE)
return;
_flags.dirty = d;
set_focusdirty(d);
}
// Certified 99%
const char* TMask_field::get_window_data() const
{
return get_title(win(), (char*)(const char*)fpark, fpark.size());
}
// Certified 99%
void TMask_field::set_window_data(const char* data)
{
if (data != NULL)
set_title(win(), (char*)data);
}
// Certified 100%
void TMask_field::set_field_data(const char*)
{}
// Certified 100%
const char* TMask_field::get_field_data() const
{ return NULL; }
const char* TMask_field::picture_data(const char* data, bool video)
{
fpark = data;
if (video)
{
fpark.trim();
if (_flags.uppercase) fpark.upper();
}
return fpark;
}
// Certified 90%
const char* TMask_field::prompt() const
{
if (_promptwin != NULL_WIN)
_prompt = xvt_get_title(_promptwin);
else
_prompt = "";
return _prompt;
}
// Certified 100%
void TMask_field::reset()
{
if (!_flags.persistent && class_id() != CLASS_FIELD)
set("");
}
// Certified 100%
void TMask_field::set_prompt(const char* p)
{
if (_promptwin != NULL_WIN)
set_title(_promptwin, (char*) p);
}
void TMask_field::set(const char* s)
{
if (_dlg == 108)
_dlg = 108;
if (mask().is_running())
{
set_window_data(s);
set_dirty();
}
else
set_field_data(s);
}
TString& TMask_field::get() const
{
static TString256 gpark;
if (mask().is_running())
gpark = get_window_data();
else
gpark = get_field_data();
if (_flags.trim) gpark.trim();
return gpark;
}
void TMask_field::undo()
{
set_window_data(get_field_data());
}
bool TMask_field::autoload(const TRelation* r)
{
if (_field)
{
set(_field->read(r));
return TRUE;
}
return FALSE;
}
bool TMask_field::autosave(TRelation* r) const
{
if (_field)
{
_field->write(get(), r);
return TRUE;
}
return FALSE;
}
// 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(const TMask& mask, TToken_string& msg)
{
TFilename a(msg.get(1));
for (const char* m = msg.get(); m; m = msg.get())
{
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();
}
void TMask_field::send_key(KEY k, short to)
{
mask().send_key(k, to, this);
}
// Certified 90%
bool TMask_field::do_message(int num)
{
const int MAX_CMD = 17;
static const char* commands[MAX_CMD] =
{
"ADD", // 0
"CLEAR", // 1
"CO", // 2
"DEL", // 3
"DIRTY", // 4
"DISABLE", // 5
"ENABLE", // 6
"ENABLEDEF", // 7
"EXIT", // 8
"HIDE", // 9
"NORMAL", // 10
"PUSH", // 11
"REQUIRED", // 12
"RESET", // 13
"RU", // 14
"SHOW", // 15
"UNDO" // 16
};
TToken_string* message = (TToken_string*)_message.objptr(num);
if (message == NULL || message->empty()) return FALSE;
TToken_string msg(16, ',');
TString256 value;
for (const char* m = message->get(0); m && *m; m = message->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 == 8)
{
mask().stop_run(atoi(dlg));
continue;
} else
if (cmd == 14)
{
run_app(mask(), msg);
continue;
}
short fld = (dlg && dlg[0] > ' ') ? atodlg(dlg) : 0;
bool broadcast = dlg && strchr(dlg, '@');
if (value[0] == '"') value = value.strip("\"'");
else switch (cmd)
{
case 0:
modify_list(TRUE, mask().field(fld), msg); continue;
case 1:
key = 11000+'c'; break;
case 2:
value = copy_value(msg, get()); break;
case 3:
modify_list(FALSE, mask().field(fld), msg); continue;
case 4:
mask().field(fld).set_dirty(); continue;
case 5:
key = 11000+'d'; break;
case 6:
key = 11000+'e'; break;
case 7:
key = 11000+'E'; break;
case 9:
key = 11000+'h'; break;
case 10:
mask().efield(fld).check_type(CHECK_NORMAL); continue;
case 11:
key = K_SPACE; break;
case 12:
mask().efield(fld).check_type(CHECK_REQUIRED); continue;
case 13:
key = K_F2; break;
case 15:
key = 11000+'s'; break;
case 16:
key = K_F3; break;
default:
key = atoi(value);
break;
}
if (key)
{
if (key > 0)
{
if (broadcast) fld = -fld;
send_key(key, fld);
}
}
else
{
// Setta a value il campo fld solo se ha un valore diverso da value
if (broadcast)
{
for (int i = 0; i < mask().fields(); i++)
{
TMask_field& f = mask().fld(i);
if (f.in_group((int)fld))
{
const char* 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;
}
bool TMask_field::test_focus_change()
{
bool ok = TRUE;
if (focusdirty()) on_key(K_TAB); // Comportamento normale
else if (is_edit() && in_key(1)) on_hit(); // Serve per eseguire gli handler autoprementi
return ok;
}
// Certified 90%
bool TMask_field::on_hit()
{
if (_handler)
{
bool ok = _handler(*this, is_edit() ? K_TAB : K_SPACE);
if (!ok) return FALSE;
}
do_message(0);
return TRUE;
}
bool TMask_field::to_check(KEY k, bool checkrun) const
{
bool yes = (k == K_TAB && focusdirty()) || (k == K_ENTER && dirty());
if (!yes && checkrun)
yes = k == K_TAB && !mask().is_running();
return yes;
}
// Certified 90%
bool TMask_field::on_key(KEY key)
{
if (key > 11000)
{
switch(key-11000)
{
case 'E':
enable_default(); break;
case 'c':
reset(); on_hit();
case 'd':
disable(); break;
case 'e':
enable(); break;
case 'h':
hide(); break;
case 's':
show(); break;
#ifdef DBG
default :
return yesnofatal_box("Invalid key sent to field %d: %d", dlg(), key);
#endif
}
return TRUE;
}
switch(key)
{
case K_SPACE:
set_dirty();
break;
case K_PREV:
case K_NEXT:
send_key(key, 0);
break;
case K_F1:
#if XVT_OS == XVT_OS_WIN
if (fexist("prassi.hlp"))
{
struct MULTIGUY
{
UINT mkSize;
BYTE mkKeylist;
char mkKeyphrase[16];
} mk;
TFilename topic(mask().source_file()); topic.ext("");
mk.mkSize = sizeof(MULTIGUY);
mk.mkKeylist = 'M';
strcpy(mk.mkKeyphrase, topic);
TFilename hlp("prassi.hlp");
const TString16 mod(topic.left(2));
if (mod != "ba") hlp.insert(mod, 0);
HWND hwnd = (HWND)get_value(TASK_WIN, ATTR_NATIVE_WINDOW);
WinHelp(hwnd, hlp, HELP_MULTIKEY, (DWORD)&mk);
break;
}
#endif
case K_SHIFT+K_F1:
if (_help.not_empty())
message_box(_help);
else
beep();
set_focus();
break;
case K_F11:
{
const char* c = "";
if (field())
c = field()->name();
message_box("State utilizzando il campo %d della maschera '%s'\n"
"corrispondente al campo su file '%s'",
dlg(), (const char*)mask().source_file(), c);
set_focus();
}
break;
case K_F2:
if (is_edit()) set("");
else reset();
set_dirty();
break;
case K_F3:
undo();
set_dirty();
break;
default:
break;
}
if (_handler)
return _handler(*this, key);
return TRUE;
}
void TMask_field::highlight() const
{
set_front_window(win());
}
void TMask_field::set_focus() const
{
const bool force = mask().is_running();
mask().set_focus_win(win(), force);
}
HIDDEN char* const _msg = &__tmp_string[512];
#define build_msg() va_list argptr;va_start(argptr,fmt);vsprintf(_msg,fmt,argptr);va_end(argptr)
bool TMask_field::error_box(const char* fmt, ...) const
{
build_msg();
if (mask().is_sheetmask() && !mask().is_running())
{
xvt_statbar_set(_msg);
beep();
}
else
{
set_focus();
::error_box("%s", _msg);
set_focus();
}
return FALSE;
}
bool TMask_field::message_box(const char* fmt, ...) const
{
set_focus();
build_msg();
::message_box("%s", _msg);
set_focus();
return FALSE;
}
bool TMask_field::warning_box(const char* fmt, ...) const
{
build_msg();
if (mask().is_sheetmask() && !mask().is_running())
{
xvt_statbar_set(_msg);
beep();
}
else
{
set_focus();
::warning_box("%s", _msg);
set_focus();
}
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;
}
///////////////////////////////////////////////////////////
// TList_sheet
///////////////////////////////////////////////////////////
// Certified 100%
TList_sheet::TList_sheet(TEdit_field* f, const char* caption, const char* head)
: _fld(f), _row(-1)
{
_sheet = new TArray_sheet(-1, -1, 0, 0, caption, head);
}
// Certified 100%
TList_sheet::~TList_sheet()
{
delete _sheet;
}
// Certified 100%
TMask_field& TList_sheet::field(short id) const
{ return field().mask().field(id); }
// Certified 100%
void TList_sheet::read_item(TScanner& scanner)
{
TToken_string ts(scanner.string());
_sheet->add(ts);
}
// Certified 100%
void TList_sheet::parse_input(TScanner& scanner)
{
_inp_id.add(scanner.pop());
}
// 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()) 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 = _fld->atodlg(fld);
if (id > 0) rowsel.add(field().mask().get(id));
else rowsel.add("");
}
}
TString80 fd, it;
for (int i = 0 ; i < _sheet->items(); i++)
{
TToken_string& ts =_sheet->row(i);
ts.restart();
for ( const char* item = rowsel.get(0); item ; item = rowsel.get())
{
it = item; it.trim();
fd = ts.get(); fd.trim();
if (fd != it) break;
}
if (!item) return i;
}
return -1; // Value not found!
}
// Certified 50%
void TList_sheet::do_output(CheckTime t)
{
if (_row < 0 || t == FINAL_CHECK)
return;
_out_id.restart();
TToken_string& rowsel = _sheet->row(_row);
rowsel.restart();
for (const char* fld = _out_id.get(); fld; fld = _out_id.get())
{
const short id = _fld->atodlg(fld);
if (t != STARTING_CHECK || field().field() == NULL)
{
TMask_field& f = field(id);
f.set(rowsel.get());
if (field().dlg() != id)
f.on_hit();
}
}
}
// Certified 100%
KEY TList_sheet::run()
{
_row = do_input();
_sheet->select(_row);
const KEY k = _sheet->run();
switch (k)
{
case K_ENTER:
_row = (int)_sheet->selected();
do_output();
break;
default:
break;
}
return k;
}
// Certified 100%
bool TList_sheet::check(CheckTime t)
{
const bool passed = (_row = do_input()) != -1;
if (passed) do_output(t);
return passed;
}
///////////////////////////////////////////////////////////
// TBrowse
///////////////////////////////////////////////////////////
// Certified 100%
TBrowse::TBrowse(TEdit_field* f, TRelation* r, int key, const char* filter)
: _relation(r), _cursor(new TCursor (r, filter, key)),
_fld(f), _filter(filter), _secondary(FALSE), _checked(FALSE)
{}
// Certified 100%
TBrowse::TBrowse(TEdit_field* f, TCursor* c)
: _relation(NULL), _cursor(c), _fld(f), _secondary(FALSE), _checked(FALSE)
{}
// Certified 100%
TBrowse::~TBrowse()
{
if (_relation)
{
delete _relation;
delete _cursor;
}
}
// Certified 100%
void TBrowse::parse_display(TScanner& scanner)
{
const char* s;
s = scanner.string();
_head.add(s);
s = scanner.line();
_items.add(s);
}
void TBrowse::parse_input(TScanner& scanner)
{
const char* s = scanner.pop();
_inp_fn.add(s);
s = scanner.pop();
if (*s == '"') // Constant string
{
scanner.push();
_inp_id.add(scanner.line());
}
else // Field on the mask
{
TString80 str(s);
if (scanner.popkey() == "SE") str << '@'; // Special FILTERing field
else scanner.push();
_inp_id.add(str);
}
}
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);
}
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()._warning.empty())
field()._warning = b.field()._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 = TRUE;
}
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();
byte 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 TString16 key(scanner.popkey());
if (key == "NO") _insert = "";
else
{
if (key == "RU")
{
_insert = "R";
_insert << scanner.line();
}
else
{
_insert = "M";
_insert << scanner.line();
}
_insert.trim();
}
}
// Certified 100%
TMask_field& TBrowse::field(short n) const
{ return _fld->mask().field(n); }
// Ritorna il numero di inputs senza contare quelli che funzionano solo da filtro
int TBrowse::inputs()
{
int inp = 0;
for (const char* fld = _inp_id.get(0); fld; fld = _inp_id.get())
{
if (*fld != '"' && strchr(fld, '@') == NULL && field(atoi(fld)).is_edit())
inp++;
}
return inp;
}
// Ritorna il numero di campi non vuoti e non filtrati
int TBrowse::do_input(bool filter)
{
int ne = 0;
if (_inp_id.empty()) return ne;
TRectype& cur = _cursor->curr();
cur.zero();
TRectype filtrec(cur);
_inp_id.restart();
_inp_fn.restart();
TString256 val; // Value to output
bool tofilter;
for (const char* fld = _inp_id.get(); fld; fld = _inp_id.get())
{
if (*fld == '"')
{
val = (fld+1);
if (val.not_empty()) val.rtrim(1);
tofilter = filter;
}
else
{
const short id = _fld->atodlg(fld);
const bool filter_flag = strchr(fld, '@') != NULL;
tofilter = filter && filter_flag;
val = field(id).get();
if (field(id).is_edit() && val.not_empty() && !filter_flag)
ne++; // Increment not empty fields count
}
TFieldref fldref(_inp_fn.get(), 0); // Output field
fldref.write(val, _cursor->relation());
if (tofilter)
{
if (val.empty()) val.fill('~', fldref.len(cur));
fldref.write(val, filtrec);
}
}
if (!filter) return ne;
TString work(_filter.size());
for (int i = 0; _filter[i]; i++)
{
if (_filter[i] == '"')
{
do
{
work << _filter[i++];
} while (_filter[i] && _filter[i] != '"');
work << '"';
if (!_filter[i]) break;
}
else
if (_filter[i] == '#')
{
work << '"' << field(atoi(&_filter[++i])).get() << '"';
while (isspace(_filter[i])) i++;
while (isdigit(_filter[i])) i++;
i--;
}
else work << _filter[i];
}
_cursor->setfilter(work);
_cursor->setregion(filtrec, filtrec);
return ne;
}
void TBrowse::do_output(CheckTime t)
{
if (t == FINAL_CHECK)
return;
TString256 sum;
TToken_string flds(24, '+');
_out_fn.restart();
for (const char* fld = _out_id.get(0); fld && *fld; fld = _out_id.get())
{
const short id = field().atodlg(fld);
TMask_field& f = field(id);
flds = _out_fn.get();
if (t != STARTING_CHECK || f.field() == NULL || f.mask().mode() == MODE_INS)
{
sum.cut(0);
for(const char* fr = flds.get(0); fr; fr = flds.get())
{
const char* val;
if (*fr == '"')
{
const TString80 v(fr);
val = v.mid(1, v.len()-2);
}
else
{
const TFieldref fld(fr, 0);
val = fld.read(_cursor->relation());
}
sum << val;
}
f.set(sum);
if (field().dlg() != id)
f.on_hit();
}
}
}
void TBrowse::do_clear()
{
for (TString16 fld = _out_id.get(0); fld.not_empty(); fld = _out_id.get())
{
TMask_field& f = field(atoi(fld));
if (f.field() == NULL && _inp_id.get_pos(fld) < 0)
f.reset();
}
}
bool TBrowse::do_insert()
{
bool ok = FALSE;
TString80 app;
if (_insert[0] == 'M')
{
TString80 nm(_insert.mid(1));
if (strncmp(nm, "BATB", 4) == 0) // Programma gestione tabelle
app = format("ba3 -0 %s", (const char*)nm.mid(4));
// Obbligatorio usare la format globale
else // Programma generico di browse/edit
app = format("ba3 -3 %s %d", (const char*)nm, _cursor->file().num());
// Obbligatorio usare la format globale
}
else
{
app = _insert.mid(1);
}
#if XVT_OS == XVT_OS_WIN
if (strnicmp(app, main_app().name(), 3) == 0)
app.insert("a", 3);
#endif
TMailbox mail;
TMessage msg(app, MSG_AI, "");
mail.send(msg);
TExternal_app a(app);
a.run();
if (mail.check())
{
TMessage* rcv = mail.next_s(MSG_AI);
if (rcv != NULL) _rec = atoi(rcv->body());
if (_rec > 0)
{
_cursor->file().readat(_rec);
ok = _cursor->ok();
if (ok) do_output();
#ifdef DBG
else yesnofatal_box("Selezione da programma esterno errata");
#endif
}
}
return ok;
}
TToken_string& TBrowse::create_siblings(TToken_string& siblings)
{
const TMask& mask = field().mask();
siblings = ""; // Azzera la lista dei campi associati
// if (!mask.is_running()) return siblings;
TBit_array key(4); // Elenco delle chiavi gia' utilizzate
key.set(_cursor->key());
// 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 = _fld->atodlg(i);
const TMask_field& f = mask.field(id);
if (!f.shown() || !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 == _fld->dlg()))
{
TString16 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()
{
do_input(TRUE);
_cursor->read(_isgteq);
const TLocalisamfile& f = _cursor->file();
TString80 caption(prefhndl->description(f.name()));
if (!isalnum(caption[0]))
caption = "Selezione";
KEY k = K_ESC;
long selected = 0;
TToken_string siblings;
create_siblings(siblings);
{
TToken_string* sib = siblings.empty() ? NULL : &siblings;
byte buttons = 0;
if (_insert.not_empty())
{
TFilename path;
if (_insert[0] == 'M')
path = "ba3 -0";
else
path = _insert.mid(1);
if (main_app().name() != cmd2name(path)) // Se non lancerei me stesso
buttons = 1;
}
TBrowse_sheet s(_cursor, _items, caption, _head, buttons, _fld, sib);
k = s.run();
selected = s.selected();
}
switch (k)
{
case K_INS:
k = do_insert() ? K_ENTER : K_ESC;
break;
case K_ENTER:
*_cursor = selected;
do_output();
break;
default:
if (k >= K_CTRL)
{
const TMask& m = _fld->mask();
const short id = siblings.get_int((k - K_CTRL) << 1);
TEdit_field& ef = m.efield(id);
ef.set_focus();
k = K_F9;
if (m.is_running())
ef.send_key(k, 0);
}
break;
}
return k;
}
bool TBrowse::check(CheckTime t)
{
bool passed = TRUE;
if (_secondary == TRUE && t != RUNNING_CHECK)
return TRUE;
if (_fld->check_type() != CHECK_NONE)
{
const TMaskmode mode = (TMaskmode)field().mask().mode();
CheckType chk = _fld->check_type();
const int ne = do_input(TRUE);
if (t == STARTING_CHECK || mode == MODE_QUERY) chk = CHECK_NORMAL;
if (ne || chk == CHECK_REQUIRED)
{
_cursor->setkey();
_cursor->file().read(_isequal);
passed = _cursor->ok();
if (t != FINAL_CHECK)
{
if (passed)
{
_cursor->repos();
do_output(t);
}
else
{
do_clear();
if (!_fld->mask().query_mode() && _fld->check_enabled())
_fld->set_dirty(3);
}
}
}
else
if (t != FINAL_CHECK) do_clear();
}
return passed;
}
bool TBrowse::empty_check()
{
if ( field().mask().query_mode() || _fld->check_type() == CHECK_NONE ||
_fld->check_type() == CHECK_NORMAL)
return TRUE;
else
return do_input() > 0;
}
///////////////////////////////////////////////////////////
// TEdit_field
///////////////////////////////////////////////////////////
TEdit_field::TEdit_field(TMask* mask)
: TMask_field(mask), _browse(NULL), _sheet(NULL),
_buttonwin(NULL_WIN), _check(CHECK_NONE), _check_enabled(TRUE),
_forced(FALSE)
{}
TEdit_field::~TEdit_field()
{
if (_browse) delete _browse; else
if (_sheet) delete _sheet;
}
word TEdit_field::class_id() const
{ return CLASS_EDIT_FIELD; }
void TEdit_field::enable(bool on)
{
TMask_field::enable(on);
if (_buttonwin != NULL_WIN)
show_window(_buttonwin, on && check_enabled() && shown());
}
void TEdit_field::show(bool on)
{
TMask_field::show(on);
if (_buttonwin != NULL_WIN)
show_window(_buttonwin, on && check_enabled() && enabled());
}
void TEdit_field::parse_head(TScanner& scanner)
{
_size = scanner.integer();
#ifdef DBG
if (_size < 1)
{
_size = 8;
yesnofatal_box("Il campo %d ha dimensione nulla (uso %d)", dlg(), _size);
}
#endif
_width = scanner.integer();
if (_width == 0) _width = _size;
}
const TBrowse* TEdit_field::get_browse(TScanner& scanner) const
{
const int id = scanner.integer();
const TEdit_field& f = mask().efield(id);
const TBrowse* b = (const TBrowse*)f.browse();
#ifdef DBG
if (b == NULL)
yesnofatal_box("La USE del campo %d e' nulla e non puo' essere copiata nel campo %d", id, dlg());
#endif
return b;
}
bool TEdit_field::parse_item(TScanner& scanner)
{
if (scanner.key() == "PI") // PICTURE
{
_picture = scanner.string();
#ifdef DBG
if (_picture == "." && _size > 9 && _size != 15)
::warning_box("Guy propone una dimensione di 15 per il campo %d: %s\nMa probabilmente ha toppato ...",
dlg(), (const char*)_prompt);
#endif
return TRUE;
}
if (scanner.key() == "CH")
{
scanner.pop();
if (scanner.key() == "NO") _check = CHECK_NORMAL;
else if (scanner.key() == "RE") _check = CHECK_REQUIRED;
else if (scanner.key() == "FO") {_check = CHECK_REQUIRED; _forced = TRUE;}
else _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;
const int logicnum = scanner.integer();
TString16 tabmaskname;
if (logicnum > 0)
r = new TRelation(logicnum);
else
{
tabmaskname = scanner.pop();
#ifdef DBG
if (tabmaskname.len() > 4)
return yesnofatal_box("'%s' non e' una tabella valida: %d",
(const char*)tabmaskname, dlg());
#endif
r = new TRelation(tabmaskname);
}
if (scanner.popkey() == "KE")
{
key = scanner.integer();
#ifdef DBG
if (key < 1)
{
yesnofatal_box("Chiave %d non valida nella USE del campo %d", key, dlg());
key = 1;
}
#endif
}
else scanner.push();
const char* filter = "";
if (scanner.popkey() == "SE")
filter = (const char*)scanner.line();
else
scanner.push();
_browse = new TBrowse(this, r, key, filter);
if (tabmaskname.not_empty())
{
if (strncmp(main_app().name(), "ba3", 3) != 0)
{
tabmaskname.insert("MBATB", 0);
_browse->set_insert(tabmaskname);
}
}
return TRUE;
}
if (scanner.key() == "CO") // Copyuse
{
const TString16 what(scanner.popkey());
const TBrowse* b = get_browse(scanner);
if (b == NULL) return FALSE;
if (what == "US" || what == "AL")
_browse = new TBrowse(this, b->cursor());
if (_browse)
return _browse->parse_copy(what, *b);
#ifdef DBG
return yesnofatal_box("Impossibile COPY senza USE nel campo %d", dlg());
#endif
}
if (scanner.key() == "JO")
{
#ifdef DBG
if(!_browse) return yesnofatal_box("JOIN senza USE nel campo %d", dlg());
#endif
_browse->parse_join(scanner);
return TRUE;
}
if (scanner.key() == "SH") // SHEET
{
#ifdef DBG
if (_sheet) return yesnofatal_box("SHEET duplicato nel campo %d", dlg());
#endif
_sheet = new TList_sheet(this, _prompt, scanner.string());
return TRUE;
}
if (scanner.key() == "IT") // ITEM
{
#ifdef DBG
if (_sheet == NULL) return yesnofatal_box("ITEM senza SHEET nel campo %d", dlg());
#endif
_sheet->read_item(scanner);
return TRUE;
}
if (scanner.key() == "IN")
{
if (_browse) _browse->parse_input(scanner); else
if (_sheet) _sheet->parse_input(scanner);
#ifdef DBG
else yesnofatal_box("INPUT senza USE o SHEET nel campo %d", dlg());
#endif
return TRUE;
}
if (scanner.key() == "DI")
{
#ifdef DBG
if(!_browse) return yesnofatal_box("DISPLAY senza USE nel campo %d", dlg());
#endif
_browse->parse_display(scanner);
return TRUE;
}
if (scanner.key() == "OU")
{
if (_browse) _browse->parse_output(scanner);
else if (_sheet) _sheet->parse_output(scanner);
#ifdef DBG
else return yesnofatal_box("OUTPUT senza USE nel campo %d", dlg());
#endif
return TRUE;
}
if (scanner.key() == "AD")
{
#ifdef DBG
if(!_browse) return yesnofatal_box("ADD senza USE nel campo %d", dlg());
#endif
_browse->parse_insert(scanner);
return TRUE;
}
if (scanner.key() == "VA")
{
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, 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", dlg(), _nparms);
#endif
for(int i = 0; i < _nparms; i++)
_validate_parms.add(scanner.operand());
return TRUE;
}
if (scanner.key() == "WA")
{
_warning = scanner.string();
return TRUE;
}
if (scanner.key() == "ME")
{
TFixed_string l(scanner.line().strip_spaces());
int m = 0;
if (l[0] == '0')
{
l.ltrim(1);
l.ltrim();
m = 1;
}
if (_message.objptr(m) == 0)
_message.add(new TToken_string(64), m);
TToken_string& ts = (TToken_string&)_message[m];
ts.add(l);
return TRUE;
}
return TMask_field::parse_item(scanner);
}
void TEdit_field::create(WINDOW parent)
{
const int len = create_prompt(parent);
long bandiere = _flags.rightjust ? CTL_FLAG_RIGHT_JUST : CTL_FLAG_LEFT_JUST;
if (_flags.uppercase) bandiere |= CTL_FLAG_MAC_GENEVA9;
if (_flags.password) bandiere |= CTL_FLAG_MAC_MONACO9;
_x += len;
#if XVTWS == WMWS
const int delta = 2;
#else
const int delta = 1;
#endif
wincreate(WC_EDIT, _width+delta, 1, _str, parent, bandiere);
#if XVT_OS == XVT_OS_WIN
HWND hwnd = (HWND)get_value(win(), ATTR_NATIVE_WINDOW);
SendMessage(hwnd, EM_LIMITTEXT, _size, 0L); // Limita il testo
#endif
if (_browse || _sheet)
{
long flags = default_flags();
if (flags & CTL_FLAG_DISABLED)
{
flags &= ~CTL_FLAG_DISABLED;
flags |= CTL_FLAG_INVISIBLE;
}
_buttonwin = xvt_create_control(WC_PUSHBUTTON, _x+_width+delta, _y,
2, 1, "*", parent, flags, PTR_LONG(this), DLG_F9);
}
}
void TEdit_field::destroy()
{
if (_buttonwin)
{ close_window(_buttonwin); _buttonwin = NULL_WIN; }
TMask_field::destroy();
}
void TEdit_field::set_window_data(const char* data)
{
TMask_field::set_window_data(format(data));
}
void TEdit_field::set_field_data(const char* data)
{ _str = data; }
const char* TEdit_field::get_field_data() const
{ return _str; }
const char* TEdit_field::format(const char* d)
{
fpark = d;
if (_flags.trim) fpark.trim();
if (fpark.not_empty())
{
int len = fpark.len();
if (len > _size)
{
#ifdef DBG
yesnofatal_box("Campo %d troppo lungo: %d > %d", dlg(), fpark.len(), _size);
#endif
fpark.cut(len = _size);
}
if (len < _size)
{
if (_flags.zerofilled)
{
if (isdigit(fpark[0]) && real::is_real(fpark))
fpark.right_just(_size, '0');
}
else
if (_flags.rightjust)
fpark.right_just(_size);
}
if (_flags.uppercase)
fpark.upper();
}
return fpark;
}
const char* TEdit_field::picture_data(const char* data, bool video)
{
if (video)
{
data = format(data);
set_title(win(), (char*)data);
return get_window_data();
}
set_window_data(data);
TMask_field::get_window_data();
if (_flags.trim) fpark.trim();
return fpark;
}
bool TEdit_field::validate(KEY k)
{
return ::validate(_validate_func, *this, k, _validate_parms);
}
// Certified 90%
bool TEdit_field::on_hit()
{
if (_handler)
{
bool ok = _handler(*this, is_edit() ? K_TAB : K_SPACE);
if (!ok) return FALSE;
}
if (_message.objptr(1) && get() == "") do_message(1);
else do_message(0);
return TRUE;
}
bool TEdit_field::default_error_box() const
{
if (_warning.empty())
{
const TString& p = prompt();
if (isalnum(p[0]))
error_box("Valore non valido per %s: '%s'", (const char*)p, (const char*)get());
else
error_box("Valore non valido: '%s'", (const char*)get());
}
else
error_box(_warning);
return FALSE;
}
bool TEdit_field::on_key(KEY key)
{
switch(key)
{
case K_TAB:
if (_validate_func == AUTOEXIT_FUNC ||
_validate_func == NUMCALC_FUNC ||
_validate_func == STRCALC_FUNC)
set_focusdirty(); // Forza validate
if (to_check(K_TAB, TRUE))
{
set(get());
bool ok = validate(key); // Check validation expression
if (!ok)
{
if (_warning.not_empty())
error_box(_warning);
return FALSE;
}
TMask& m = mask();
const bool query = m.query_mode();
if (_sheet) ok = query || _sheet->check(); // Check consistency
else
if (_browse && check_enabled() && (!query || forced()) && _validate_func != 21)
ok = _browse->check();
if (!ok) return default_error_box();
ok = on_hit();
if (!ok) return FALSE;
if (query && required() && in_key(0))
{
const byte keys = m.num_keys();
for (int i = 1; i <= keys; i++)
if (in_key(i) && m.key_valid(i))
{
for (int fld = m.get_key_field(i, TRUE); fld != -1; fld = m.get_key_field(i, FALSE))
m.field(fld).set_dirty(FALSE);
mask().stop_run(K_AUTO_ENTER);
break;
}
}
return TRUE;
}
break;
case K_ENTER:
if (field() != NULL || mask().mode() == NO_MODE)
{
if (focusdirty()) set(get());
bool ok = validate(K_ENTER); // Check validation expression
if (!ok)
{
if (_warning.not_empty())
error_box(_warning);
return FALSE;
}
const bool query = mask().query_mode();
// check consistency
if (_sheet) ok = query || _sheet->check(FINAL_CHECK);
else
if (_browse &&
check_enabled() &&
_validate_func != 21 && // 21 = NOT_EMPTY_CHECK_FIELD
(!query || forced()))
{
if (dirty()) ok = _browse->check(FINAL_CHECK); // Check consistency
else ok = _browse->empty_check();
}
else
ok = query || !(check_type() == CHECK_REQUIRED && get().empty());
if (!ok)
return default_error_box();
}
break;
case K_F9:
if (check_enabled())
{
enable_check(FALSE);
if (dirty()) set(get());
KEY k = K_ESC;
if (_browse) k = _browse->run();
else
if (_sheet) k = _sheet->run();
else beep();
if (k != K_F9) set_focus();
enable_check(TRUE);
if (k == K_ENTER)
{
set_dirty();
if (mask().is_running())
send_key(K_TAB, 0);
else
on_hit();
return TRUE;
}
else
return FALSE;
}
break;
default:
break;
}
return TMask_field::on_key(key);
}
bool TEdit_field::has_check() const
{
if (_browse) return check_type() != CHECK_NONE;
return _sheet != NULL;
}
bool TEdit_field::check(CheckTime t)
{
bool ok = TRUE;
if (check_enabled() || (t == STARTING_CHECK && shown()))
{
if (_browse) ok = (_validate_func == 21) || _browse->check(t);
else if (_sheet) ok = _sheet->check(t);
}
return ok;
}
void TEdit_field::enable_check(bool on)
{
_check_enabled = on;
if (_buttonwin != NULL_WIN)
show_window(_buttonwin, on);
}
///////////////////////////////////////////////////////////
// Boolean_field
///////////////////////////////////////////////////////////
TBoolean_field::TBoolean_field(TMask* m)
: TMask_field(m), _on(FALSE)
{}
word TBoolean_field::class_id() const
{ return CLASS_BOOLEAN_FIELD; }
void TBoolean_field::create(WINDOW parent)
{
wincreate(WC_CHECKBOX, _prompt.len()+4, 1, _prompt, parent, 0);
}
const char* TBoolean_field::get_window_data() const
{
CHECK(win(), "Control window not initialized");
fpark[0] = xvt_get_checked_state(win()) ? 'X' : ' ';
fpark[1] = '\0';
return fpark;
}
void TBoolean_field::set_window_data(const char* data)
{
CHECK(win(), "Control window not initialized");
if (data == NULL) data = "";
const bool b = toupper(*data) == 'X';
xvt_check_box(win(), b);
}
void TBoolean_field::set_field_data(const char* data)
{
if (data == NULL) data = "";
_on = toupper(*data) == 'X';
}
const char* TBoolean_field::get_field_data() const
{
return _on ? "X" : " ";
}
bool TBoolean_field::parse_item(TScanner& scanner)
{
if (scanner.key() == "ME")
{
const bool tf = scanner.integer() ? TRUE : FALSE; // Message TRUE or FALSE
if (_message.items() == 0)
{
_message.add(new TToken_string(16));
_message.add(new TToken_string(16));
}
TToken_string& ts = (TToken_string&)_message[tf];
ts.add(scanner.line().strip_spaces());
return TRUE;
}
return TMask_field::parse_item(scanner);
}
void TBoolean_field::enable(bool on)
{
_flags.enabled = on;
xvt_enable_control(_win, on);
}
bool TBoolean_field::on_hit()
{
if (_handler)
{
bool ok = _handler(*this, K_SPACE);
if (!ok) return FALSE;
}
const int n = mask().is_running() ? xvt_get_checked_state(win()) : _on;
do_message(n);
return TRUE;
}
bool TBoolean_field::on_key(KEY key)
{
if (key == K_SPACE)
{
on_hit();
set_dirty();
return TRUE;
}
return TMask_field::on_key(key);
}
///////////////////////////////////////////////////////////
// Button_field
///////////////////////////////////////////////////////////
TButton_field::TButton_field(TMask* m)
: TMask_field(m)
{
_flags.persistent = TRUE;
}
word TButton_field::class_id() const
{ return CLASS_BUTTON_FIELD; }
void TButton_field::parse_head(TScanner& scanner)
{
_width = scanner.integer();
if (_width < 1) _width = 9;
_size = scanner.integer(); // Height
if (_size < 1) _size = 1;
}
bool TButton_field::parse_item(TScanner& scanner)
{
if (scanner.key() == "PI")
{
const int bmp = scanner.integer();
_prompt << '#' << bmp;
return bmp > 0;
}
return TMask_field::parse_item(scanner);
}
void TButton_field::create(WINDOW parent)
{
long flags = CTL_FLAG_CENTER_JUST;
switch (dlg())
{
case DLG_OK:
if (_prompt.empty())
_prompt = "Conferma";
_virtual_key = _exit_key = K_ENTER;
flags |= CTL_FLAG_DEFAULT;
break;
case DLG_CANCEL:
if (_prompt.empty())
_prompt = "Annulla";
_virtual_key = _exit_key = K_ESC;
break;
case DLG_DELREC:
if (_prompt.empty())
_prompt = "Elimina";
_virtual_key = 'E';
_exit_key = K_DEL;
break;
case DLG_PRINT:
if (_prompt.empty())
_prompt = "Stampa";
_virtual_key = 'S';
_exit_key = K_ENTER;
break;
case DLG_QUIT:
if (_prompt.empty())
_prompt = "Fine";
_virtual_key = K_F4;
_exit_key = K_QUIT;
break;
default:
{
_exit_key = 0;
TToken_string* message = (TToken_string*)_message.objptr(0);
if (message != NULL)
{
TToken_string msg(message->get(0), ',');
const TFixed_string m(msg.get(0));
if (m == "EXIT")
_exit_key = msg.get_int();
else
if (msg.get_int() == 0) _exit_key = atoi(m);
}
const int n = _prompt.find('~');
_virtual_key = (n >= 0) ? toupper(_prompt[n+1]) : _exit_key;
}
break;
}
#if XWTWS == WMWS
const int diesis = _prompt.find('#');
if (diesis > 0) _prompt.cut(diesis);
_prompt.center_just(_width);
#endif
wincreate(WC_PUSHBUTTON, _width + 2, _size, _prompt, parent, flags);
}
void TButton_field::enable(bool on)
{
_flags.enabled = on;
xvt_enable_control(_win, on);
}
void TButton_field::show(bool on)
{
TMask_field::show(on);
}
bool TButton_field::on_key(KEY key)
{
if (key == K_SPACE)
{
on_hit();
return TRUE;
}
return TMask_field::on_key(key);
}
///////////////////////////////////////////////////////////
// Date_field
///////////////////////////////////////////////////////////
word TDate_field::class_id() const
{ return CLASS_DATE_FIELD; }
void TDate_field::create(WINDOW w)
{
TEdit_field::create(w);
if (automagic())
{
TDate d(TODAY);
set(d.string());
}
}
void TDate_field::parse_head(TScanner&) {}
TDate_field::TDate_field(TMask* m) : TEdit_field(m)
{
_size = _width = 10;
}
bool TDate_field::on_key(KEY key)
{
if (to_check(key))
{
TFixed_string data(get_window_data(), 15);
data.trim();
if (data.not_empty())
{
bool changed = FALSE;
if (isdigit(data[0]))
{
if (data.len() == 6) // Fix century (for this millenium only)
{
data.insert("19", 4);
changed = TRUE;
}
for (int meno = 2; meno <= 5; meno += 3)
if (data[meno] != '-')
{
data.insert("-", meno);
changed = TRUE;
}
if (data.len() == 8) // Fix century (for this millenium only)
{
data.insert("19", 6);
changed = TRUE;
}
}
else
{
TDate g(TODAY);
data.upper();
if (data == "IERI")
{
--g;
changed = TRUE;
}
else
if (data == "DOMANI")
{
++g;
changed = TRUE;
}
TString16 gstring(g.string());
if (data == "PRIMO")
{
gstring.overwrite("01-01", 0);
changed = TRUE;
}
else
if (data == "NATALE")
{
gstring.overwrite("25-12", 0);
changed = TRUE;
}
else
if (data == "ULTIMO")
{
gstring.overwrite("31-12", 0);
changed = TRUE;
}
else
if (data == "OGGI") changed = TRUE;
if (changed) data = gstring;
}
TDate d(data);
if (!d.ok())
{
error_box("Data errata o formato non valido");
return FALSE;
}
else
if (changed)
TMask_field::set_window_data(d.string());
}
}
return TEdit_field::on_key(key);
}
const char * TDate_field::get_window_data() const
{
const char * data = TEdit_field::get_window_data();
if (roman())
{
const TDate d(data);
data = d.string(ANSI);
}
return data;
}
void TDate_field::set_window_data(const char * data)
{
if (roman())
{
const TDate d(data);
data = d.string();
}
TEdit_field::set_window_data(data);
}
///////////////////////////////////////////////////////////
// Real_field
///////////////////////////////////////////////////////////
TReal_field::TReal_field(TMask* m) : TEdit_field(m)
{}
word TReal_field::class_id() const
{ return CLASS_REAL_FIELD; }
void TReal_field::create(WINDOW w)
{
TEdit_field::create(w);
if (_flags.firm)
set(::format("%ld", main_app().get_firm()));
else
if (automagic())
{
TDate d(TODAY);
set(::format("%d", d.year()));
}
}
bool TReal_field::autoload(const TRelation* r)
{
const bool ok = TMask_field::autoload(r);
if (ok && _flags.zerofilled && _str.not_empty())
{
int s = size();
if (roman())
{
s = decimals();
if (s < 1) s = 4;
}
_str.right_just(s, '0');
}
return ok;
}
bool TReal_field::on_key(KEY key)
{
if (to_check(key))
{
if (roman())
{
const int r = atoi(get_window_data());
if (r < 0) return error_box("Numero romano errato");
}
else
{
const char* n = get();
if (*n && !real::is_real(n))
return error_box("Valore numerico non valido");
if (_flags.uppercase && *n == '-')
return error_box("Il numero deve essere positivo");
if (_flags.firm)
{
const long f = atol(n);
if (f > 0 && prefhndl->exist(f))
main_app().set_firm(f);
}
}
}
return TEdit_field::on_key(key);
}
void TReal_field::parse_head(TScanner& scanner)
{
_size = scanner.integer();
#ifdef DBG
if (_size < 1)
{
_size = 9;
yesnofatal_box("Il campo %d ha dimensione nulla (uso %d)", dlg(), _size);
}
#endif
_width = _size;
_decimals = scanner.integer();
}
void TReal_field::set_window_data(const char* data)
{
if (data == NULL) data = "";
if (roman())
{
data = itor(atoi(data));
TMask_field::set_window_data(data);
}
else
{
real n(data);
if (!n.is_zero())
{
if (exchangeable() && decimals())
{
const real& e = mask().exchange();
n /= e;
}
if (_picture.empty())
data = n.stringa(_size, _decimals);
else
data = n.string(_picture);
}
else data = "";
TEdit_field::set_window_data(data);
}
}
const char* TReal_field::get_window_data() const
{
TEdit_field::get_window_data();
if (roman())
{
int r = atoi(fpark);
if (r == 0) r = rtoi(fpark);
if (r > 0)
{
int s = decimals();
if (s < 1) s = 4;
if (_flags.zerofilled)
fpark.format("%0*d", s, r);
else
fpark.format("%*d", s, r);
}
else fpark.cut(0);
}
else
{
fpark = real::ita2eng(fpark);
if (exchangeable() && decimals())
{
real n(fpark);
const real& e = mask().exchange();
n *= e;
if (n.is_zero()) fpark.cut(0);
else fpark = n.string();
}
}
return fpark;
}
void TReal_field::set_decimals(int d)
{
_decimals = d;
if (_picture[0] == '.')
{
if (d > 0) _picture.format(".%d", d);
else _picture = ".";
}
}
void TReal_field::exchange(bool show_value, const real& nuo)
{
const int dec = show_value ? 2 : 0; // Quanti decimali voglio
const bool value = decimals() != 0; // Sono attualmente in valuta ?
if (show_value == value && show_value) return; // Se cambio da valuta a valuta esco subito!
if (mask().is_running())
{
const char* n = get_window_data();
if (*n)
{
const real& vec = mask().exchange();
real r(n);
if (!show_value)
r *= nuo;
r /= vec;
r.round(dec);
set_decimals(dec);
TEdit_field::set_window_data(r.string(_picture));
}
}
if (decimals() != dec)
set_decimals(dec);
}
///////////////////////////////////////////////////////////
// List_field
///////////////////////////////////////////////////////////
TList_field::TList_field(TMask* m) : TMask_field(m)
{}
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());
_values.add(ts.get());
ts = "";
while (scanner.popkey() == "ME")
ts.add(scanner.line().strip_spaces());
scanner.push();
_message.add(ts);
}
void TList_field::parse_head(TScanner& scanner)
{
_size = scanner.integer();
_width = scanner.integer();
if (_width < 1) _width = _size+3;
}
bool TList_field::parse_item(TScanner& scanner)
{
if (scanner.key() == "IT") // ITEM
{
read_item(scanner);
return TRUE;
}
if (scanner.key() == "LI") // LISTITEM
{
TScanner sc(scanner.pop());
while (sc.popkey() == "IT") // ITEM
read_item(sc);
return TRUE;
}
return TMask_field::parse_item(scanner);
}
int TList_field::items() const
{
return _codes.items();
}
void TList_field::add_item(const char* s)
{
TToken_string t(s);
const TString16 item(t.get());
const int pos = _codes.get_pos(item);
if (pos < 0 )
{
_codes.add(item);
win_list_add(win(), -1, (char*)t.get());
}
}
void TList_field::delete_item(const char* s)
{
TString16 t(s);
const int pos = _codes.get_pos(t);
if (pos >= 0 )
{
_codes.destroy(pos);
win_list_delete(win(), pos);
if (mask().is_running())
{
win_list_set_sel(win(), 0, TRUE);
if (shown()) on_hit();
}
}
}
void TList_field::add_list()
{
if (roman() && _codes.items() < 12)
{
TString csafe, vsafe;
if (atoi(_codes) > 0)
{
csafe = _codes; _codes = "";
vsafe = _values; _values = "";
}
_codes.add("01|02|03|04|05|06|07|08|09|10|11|12");
_values.add("Gennaio|Febbraio|Marzo|Aprile|Maggio|Giugno");
_values.add("Luglio|Agosto|Settembre|Ottobre|Novembre|Dicembre");
if (atoi(csafe) > 0)
{
_codes.add(csafe);
_values.add(vsafe);
if (_message.objptr(0))
{
_message.add(_message[0], _codes.items()-1);
_message.add(NULL, 0);
}
}
}
SLIST lst = slist_new();
for (const char* item = _values.get(0); item; item = _values.get())
slist_add(lst, (SLIST_ELT)NULL, (char*)item, 0L);
win_list_add(win(), -1, (char*)lst);
slist_dispose(lst);
const char* init = "";
if (roman() && automagic())
init = format("%02d", TDate(TODAY).month());
set_field_data(init);
}
void TList_field::replace_items(const char* codes, const char* values)
{
_codes = codes;
_values = values;
if (win() != NULL_WIN)
{
win_list_clear(win());
add_list();
current(0);
}
}
void TList_field::create(WINDOW parent)
{
const int len = create_prompt(parent);
_x += len;
wincreate(WC_LISTBUTTON, _width, 5, "", parent,0);
add_list();
}
int TList_field::str2curr(const char* data)
{
TString16 str(data);
if (roman() && str.len() < 2)
str.insert("0",0);
if (_flags.uppercase)
str.upper();
int i = str.not_empty() ? _codes.get_pos(str) : 0;
if (i < 0) // Se non trova il codice ritenta dopo trim
{
for (i = 0; str[i] == '0' || str[i] == ' '; i++);
if (i > 0)
{
str.ltrim(i);
i = _codes.get_pos(str);
}
}
if (i < 0)
{
if (items() && str.not_empty())
yesnofatal_box("'%s' non e' un valore valido per il campo %s: %d",
data, prompt(), dlg());
i = 0;
}
return i;
}
void TList_field::set_window_data(const char* data)
{
CHECKD(win(), "Control window not initialized ", dlg());
const int i = str2curr(data);
current(i);
}
void TList_field::current(int n)
{
win_list_set_sel(win(), n, TRUE);
}
int TList_field::current() const
{
const int sel = win_list_get_sel_index(win());
#ifdef DBG
if (sel < 0 && items() > 0)
error_box("Lista senza selezione nel campo %d", dlg());
#endif
return sel;
}
const char* TList_field::get_window_data() const
{
const int c = current();
const char* v = ((TList_field*)this)->_codes.get(c);
return v;
}
void TList_field::set_field_data(const char* data)
{
const int i = str2curr(data);
_str = _codes.get(i);
}
bool TList_field::on_hit()
{
if (_handler)
{
bool ok = _handler(*this, K_SPACE);
if (!ok) return FALSE;
}
const int n = mask().is_running() ? current() : str2curr(_str);
do_message(n);
return TRUE;
}
const char* TList_field::get_field_data() const
{
return _str;
}
bool TList_field::on_key(KEY key)
{
if (key >= '0' && key <= 'z')
{
const int index = win_list_get_sel_index(win());
CHECK(index >= 0, "List with no selection!");
int newindex = -1;
#if XVTWS == WMWS
if (key >= 'A' && key <= 'z')
{
for (int i = index+1; i != index; i++)
{
char item[16];
bool flag;
do
{
flag = win_list_get_elt(win(), i, item, 16);
if (!flag)
{
CHECK(i, "La lista e' vuota!");
i = -1;
break;
}
} while (!flag);
if (flag && toupper(*item) == toupper(key))
{
newindex = i;
break;
}
} // for
} // alphabetic
#endif
if (key >= '0' && key <= '9')
{
newindex = (key == '0') ? 10 : key - '1';
if (newindex > items())
{
newindex = -1;
beep();
}
}
if (newindex >= 0)
{
win_list_suspend(win());
win_list_set_sel(win(), index, FALSE);
win_list_set_sel(win(), newindex, TRUE);
win_list_resume(win());
}
} // alphanumeric
#if XVTWS == VMWS
if (key == K_TAB && class_id() == CLASS_LIST_FIELD)
dispacth_e_char(win(), K_F9);
#endif
if (key == K_SPACE) on_hit();
return TMask_field::on_key(key);
}
///////////////////////////////////////////////////////////
// TRadio_field
///////////////////////////////////////////////////////////
TRadio_field::TRadio_field(TMask* mask)
: TList_field(mask), _nitems(0), _active_item(0)
{}
word TRadio_field::class_id() const
{
return CLASS_RADIO_FIELD;
}
void TRadio_field::create(WINDOW parent)
{
const short id = dlg(); // Salva il control id
const int items = _codes.items();
if (_prompt.not_empty())
{
const int dy = _flags.zerofilled ? 3 : items+2;
create_prompt(parent, _width, dy);
}
_x++; _y++;
_values.restart();
const char* s;
const int width = _flags.zerofilled ? (_width-2)/items-1 : _width-2;
for(_nitems = 0; (s = _values.get()) != NULL; _nitems++)
{
CHECKD(_nitems < MAX_RADIO, "Too many items in radio button ", id);
wincreate(WC_RADIOBUTTON, width, 1, s, parent,0);
_radio_ctl_win[_nitems] = _win;
_dlg += 1000;
if (_flags.zerofilled)
_x += width+1;
else
_y++;
}
_radio_ctl_win[_nitems] = NULL_WIN; // Comodo per debug
_dlg = id; // Ripristina control id
set_field_data("");
}
void TRadio_field::destroy()
{
if (_promptwin)
{ close_window(_promptwin); _promptwin = NULL_WIN; }
for(int i = 0; i < _nitems; i++)
{
close_window(_radio_ctl_win[i]);
_radio_ctl_win[i] = NULL_WIN;
}
}
int TRadio_field::current() const
{
const int c = xvt_get_checked_radio(_radio_ctl_win, _nitems);
return c;
}
void TRadio_field::current(int n)
{
_active_item = n;
xvt_check_radio_button(win(), _radio_ctl_win, _nitems);
}
void TRadio_field::check_radiobutton(WINDOW checked)
{
for(int i = 0; i < _nitems && checked != _radio_ctl_win[i]; i++);
CHECK(i < _nitems, "Trying to check an invalid radio button");
current(i);
}
void TRadio_field::enable(bool on)
{
_flags.enabled = on;
for(int i = 0; i < _nitems; i++)
xvt_enable_control(_radio_ctl_win[i], on);
}
void TRadio_field::show(bool on)
{
if (_promptwin)
show_window(_promptwin, on);
for(int i = 0; i < _nitems; i++)
show_window(_radio_ctl_win[i], on);
_flags.shown = on;
}
// Return TRUE if focus has left the radio
bool TRadio_field::move_focus(int d)
{
const int act = _active_item + d;
if (act >= _nitems || act < 0)
{
_active_item = current();
return TRUE;
}
xvt_set_front_control(_radio_ctl_win[_active_item = act]);
return FALSE;
}
///////////////////////////////////////////////////////////
// TGroup_field
///////////////////////////////////////////////////////////
TGroup_field::TGroup_field(TMask* mask) : TMask_field(mask)
{
_flags.persistent = TRUE;
}
// _size means _heigth
void TGroup_field::parse_head(TScanner& scanner)
{
_width = scanner.integer();
_size = scanner.integer();
}
void TGroup_field::create(WINDOW parent)
{
const long f = _flags.rightjust ? CTL_FLAG_MULTIPLE : 0;
wincreate(WC_GROUPBOX, _width, _size, _prompt, parent, f);
}
void TGroup_field::set_window_data(const char* data)
{ xvt_set_title(win(), data); }
void TGroup_field::set_field_data(const char* data)
{ xvt_set_title(win(), data); }