campo-sirio/include/sheet.cpp

1206 lines
32 KiB
C++
Raw Normal View History

#include <colors.h>
#include <controls.h>
#include <maskfld.h>
#include <relation.h>
#include <sheet.h>
#include <urldefid.h>
#include <utility.h>
#include <xvtility.h>
///////////////////////////////////////////////////////////
// TSheet_control
///////////////////////////////////////////////////////////
class TSheet_control : public TControl
{
enum { FIRST_FIELD = 101, MAX_COL = 128 };
TSheet* _sheet;
long _cur_rec;
// @cmember:(INTERNAL) Tipo di ogni colonna
byte _type[MAX_COL];
// @cmember:(INTERNAL) Indica se e attivata la gestione dei check delle righe
bool _check_enabled;
// @cmember:(INTERNAL) Array di righe attivate
TBit_array _checked;
// @cmember:(INTERNAL) Array di righe disabilitate
TBit_array _disabled;
protected: // TControl
//@cmember Gestisce gli eventi delle celle
virtual bool event_handler(XI_OBJ* itf, XI_EVENT* xiev);
protected:
long items() const { return _sheet->items(); }
TToken_string& row(long n) const { return _sheet->row(n); }
int rec2row(long rec) const;
long row2rec(int row) const;
void make_current(long rec);
public: // TControl
virtual void set_rect(const RCT& r);
public:
long selected() const { return _cur_rec; }
void select(long n);
void set_focus_rec(long rec);
void enable_check(bool on) { _check_enabled = on && _type[0] == 'C'; }
bool check_enabled() const { return _check_enabled; }
void check(long n, bool on);
void toggle(long n);
bool checked(long n) const { return _checked[n]; }
long checked() const { return _checked.ones(); }
bool one_checked() const;
int visible_rows() const;
void enable_row(long r, bool on);
void disable_row(long r);
bool row_enabled(long n) const { return _disabled[n] == FALSE; }
bool one_enabled() const { return _disabled.ones() < _sheet->items(); }
byte& column_type(int c) { CHECKD(c >= 0 && c < MAX_COL, "Bad column ", c); return _type[c]; }
void update(long n = -1);
TSheet_control(WINDOW sheet, short cid,
short x, short y, short dx, short dy,
const char* flags, const char* head);
virtual ~TSheet_control() {}
};
TSheet_control::TSheet_control(
WINDOW parent, // @parm Finestra alla quale appartiene lo spreadsheet
short cid, // @parm Identificatore
short x, // @parm Coordinata x (in caratteri) nel quale posizionare lo spreadsheet
short y, // @parm Coordinata y (in caratteri) nel quale posizionare lo spreadsheet
short dx, // @parm Larghezza (in caratteri) dello spreasheet
short dy, // @parm Lunghezza (in caratteri) dello spreasheet
const char* flags, // @parm Flags di abilitazione
const char* head) // @parm Titolo delle colonne
: _sheet(NULL), _cur_rec(0), _check_enabled(FALSE)
{
const int NUMBER_WIDTH = 7;
short v_width[MAX_COL];
short m_width[MAX_COL];
int fixed_columns = 1; // Number of fixed columns
_sheet = (TSheet*)xvt_vobj_get_data(parent);
// Calcolo larghezza massima tabella
TToken_string header(head);
TToken_string new_header(256);
int i = 0;
int f_width = NUMBER_WIDTH; // Stima larghezza colonne fisse
int max_width = f_width; // Stima larghezza della colonna piu' grande
for (const char* h = header.get(); h; h = header.get(), i++)
{
CHECKD(i < MAX_COL, "Tu meni calumns in scit: ", i);
_type[i] = ' ';
TString testa(h);
const int at = testa.find('@');
int v = testa.len(); // Video width
if (at >= 0)
{
const TString& wi = testa.mid(at+1);
v = atoi(wi);
if (wi.find('F') >= 0)
{
fixed_columns++;
f_width += v+1;
}
if (wi.find('R') >= 0)
_type[i] = 'R'; else
if (wi.find('M') >= 0)
_type[i] = 'M'; else
if (wi.find('C') >= 0)
_type[i] = 'C';
if (i == 0 && v <= 1)
{
_type[i] = 'C';
_check_enabled = TRUE;
fixed_columns++;
f_width += v+1;
}
testa.cut(at);
v = max(at, v);
}
v++;
m_width[i] = v; // v = memory width of column
if (v > 64) v = 64;
v_width[i] = v;
if (v_width[i] > max_width) max_width = v_width[i];
new_header.add(testa);
}
const int _columns = i;
// Calcola rettangolo massimo per lo sheet
XI_RCT rct; coord2rct(parent, x, y, dx, dy, rct);
rct.right -= 2*XI_FU_MULTIPLE; // toglie scroll-bar
// Controlla se ci sono troppe colonne fisse
if ((f_width+max_width)*XI_FU_MULTIPLE > rct.right)
fixed_columns = 1;
XI_OBJ* itf = get_interface(parent);
XI_OBJ_DEF* listdef = xi_add_list_def(NULL, cid,
rct.top, rct.left, rct.bottom-rct.top,
XI_ATR_ENABLED | XI_ATR_VISIBLE,
NORMAL_COLOR, NORMAL_BACK_COLOR, // normal
DISABLED_COLOR, DISABLED_BACK_COLOR, // disabled
FOCUS_COLOR, // active
0);
listdef->app_data = (long)this;
XI_LIST_DEF* l = listdef->v.list;
l->min_heading_height = xi_button_calc_height_font_id(xvt_default_font());
l->sizable_columns = TRUE;
l->movable_columns = TRUE;
l->fixed_columns = fixed_columns;
l->scroll_bar = TRUE;
l->scroll_bar_button = TRUE;
l->white_space_color = MASK_DARK_COLOR;
l->rule_color = MASK_DARK_COLOR;
// Definizione della prima colonna (numero di riga)
const long attr = XI_ATR_VISIBLE | XI_ATR_RJUST | XI_ATR_SELECTABLE;
XI_OBJ_DEF* coldef = xi_add_column_def(listdef, FIRST_FIELD+1000-1, attr, FIRST_FIELD+1000,
NUMBER_WIDTH * XI_FU_MULTIPLE, NUMBER_WIDTH, "");
coldef->app_data = (long)this;
coldef->v.column->heading_platform = TRUE;
coldef->v.column->column_platform = TRUE;
coldef->v.column->center_heading = TRUE;
for (h = new_header.get(0), i = 0; h; h = new_header.get(), i++)
{
const int cid = FIRST_FIELD+i; // Column & Field ID
long attr = XI_ATR_VISIBLE | XI_ATR_ENABLED | XI_ATR_AUTOSCROLL | XI_ATR_READONLY;
if (_type[i] == 'C')
attr |= XI_ATR_SELECTABLE;
if (_type[i] == 'R')
attr |= XI_ATR_RJUST;
coldef = xi_add_column_def(listdef, cid+1000, attr, cid+1001,
v_width[i] * XI_FU_MULTIPLE, m_width[i], (char*)h);
coldef->app_data = (long)this;
coldef->v.column->heading_platform = TRUE;
coldef->v.column->center_heading = TRUE;
if (i == 0 && _type[i] == 'C')
{
coldef->v.column->icon_rid = ICO_CHECK_ON;
if (l->min_heading_height < 20)
l->min_heading_height = 20;
}
}
RCT rd; xi_get_def_rect(listdef, &rd);
if ((rd.right - rd.left) > (rct.right - rct.left))
l->width = rct.right - rct.left;
_obj = xi_create(itf, listdef); // Create the whole thing!
xi_dequeue(); // Flush events in XOL
xi_tree_free(listdef); // Free definitions
CHECKD(_obj, "Can't create spreadsheet ", cid);
update_tab_cid();
// Se la finestra e' troppo grande riducila
RCT cli; xvt_vobj_get_client_rect(parent, &cli);
XI_RCT xc = cli; xi_pu_to_fu(itf, (PNT*)&xc, 2);
if (xc.right > 45 * XI_FU_MULTIPLE) // Deve contenere almeno 4 bottoni
{
xi_get_rect(_obj, &rct);
const int width = rct.right + 2*XI_FU_MULTIPLE;
if (width < cli.right)
{
cli.left += (cli.right - width) / 2;
cli.right = cli.left + width;
xvt_vobj_translate_points(parent, xvt_vobj_get_parent(parent), (PNT*)&cli, 2);
xvt_vobj_move(parent, &cli);
}
}
}
void TSheet_control::set_rect(const RCT& r)
{
const int width = r.right - r.left - 2*XI_FU_MULTIPLE;
const int height = r.bottom - r.top;
xi_set_list_size(_obj, height, width);
}
// Converts a row number in the correspondig record number
int TSheet_control::rec2row(long record) const
{
int rows;
const long* rec = xi_get_list_info(_obj, &rows);
int r = int(record - rec[0]);
if (r < 0 || r >= rows)
r = -1;
return r;
}
// Converts a row number in the correspondig record number
long TSheet_control::row2rec(int row) const
{
int rows;
const long* handle = xi_get_list_info(_obj, &rows);
if (row < 0)
row = 0;
else
{
if (row >= rows)
row = rows-1;
}
const long r = handle[row];
CHECKD(r >= 0 && r < items(), "Sheet line out of range: ", row);
return r;
}
int TSheet_control::visible_rows() const
{
return xi_get_visible_rows(_obj, NULL, NULL);
}
void TSheet_control::update(long n)
{
if (n >= 0)
{
const int riga = rec2row(n);
if (riga >= 0)
{
XI_OBJ row;
XI_MAKE_ROW(&row, _obj, riga);
xi_cell_request(&row);
}
}
else
{
// xi_cell_request(_obj);
int num = 0;
const long* handle = xi_get_list_info(_obj, &num);
bool scroll_first = items() == 0; // || !owner().mask().is_running();
if (!scroll_first)
{
int first = 0, last = 0;
xi_get_visible_rows(_obj, &first, &last);
n = handle[first];
scroll_first = n > items();
}
if (scroll_first)
xi_scroll(_obj, XI_SCROLL_FIRST);
else
xi_scroll_rec(_obj, n, NORMAL_COLOR, XI_ATR_ENABLED, 0);
}
}
void TSheet_control::make_current(long rec)
{
const long old = _cur_rec;
_cur_rec = rec;
XI_OBJ o;
const int oldrow = rec2row(old);
if (oldrow >= 0)
{
XI_MAKE_ROW(&o, _obj, oldrow);
xi_cell_request(&o);
}
const int newrow = rec2row(rec);
if (newrow >= 0 && newrow != oldrow)
{
XI_MAKE_ROW(&o, _obj, newrow);
xi_cell_request(&o);
}
}
void TSheet_control::select(long rec)
{
if (rec >= 0 && rec < items())
{
int rows;
const long* handle = xi_get_list_info(_obj, &rows);
int first = 0, last = 0;
xi_get_visible_rows(_obj, &first, &last);
if (rec < handle[first] || rec > handle[last])
xi_scroll_rec(_obj, rec, NORMAL_COLOR, XI_ATR_ENABLED, 0);
}
make_current(rec);
}
void TSheet_control::set_focus_rec(long rec)
{
if (rec < 0)
rec = selected();
int r = rec2row(rec);
if (r < 0)
{
select(rec);
r = rec2row(rec);
}
const int c = _type[0] == 'C' ? 2 : 1;
XI_OBJ cell; XI_MAKE_CELL(&cell, _obj, r, c);
xi_set_focus(&cell);
}
bool TSheet_control::one_checked() const
{
bool yes = FALSE;
if (check_enabled())
{
const long first = _checked.first_one();
yes = first >= 0;
}
return yes;
}
// @mfunc Permette di attivare/disattivare una riga
void TSheet_control::check(
long n, // @parm Numero della riga da attivare/disattivare
bool on) // @parm Operazione da effettuare sulla riga:
//
// @flag TRUE | Attiva la riga <p n>.esima (default)
// @flag FALSE | Disattiva la riga <p n>.esima
{
if (n < 0)
{
if (on)
{
const long tot = items()-1;
_checked.set(tot); // Forza le dimensioni del bit array
_checked.set(); // Setta tutti i bit
// Elimina i bit in eccesso alla fine dell'array
for (long i = _checked.items()-1; i > tot; i--)
_checked.reset(i);
// Elimina i bit corrispondenti a righe disabilitate
if (_disabled.first_one() >= 0)
{
for (long i = tot; i >= 0; i--)
if (_disabled[i]) _checked.reset(i);
}
}
else
_checked.reset();
// Aggiorna tutta la prima colonna
XI_OBJ* column = xi_get_obj(_obj, FIRST_FIELD+1000);
xi_cell_request(column);
}
else
{
if (!_disabled[n])
_checked.set(n, on);
// Aggiorna la riga
XI_OBJ cell; XI_MAKE_CELL(&cell, _obj, rec2row(n), 1);
xi_cell_request(&cell);
}
}
void TSheet_control::toggle(long n)
{
check(n, !checked(n));
}
// @doc INTERNAL
// @mfunc Abilita/disabilita una riga
void TSheet_control::enable_row(
long n, // @parm Numero della riga da abilitare/diabilitare (default -1)
bool on) // @parm Operazione da svolgere sulla riga
//
// @flag TRUE | Abilita la riga <p n>-esima (default)
// @flag FALSE | Disabilita la riga <p n>-esima
// @comm Se <p n> e' minore di 0 allora vengono abilitate/disabilitate tutte le righe
{
if (n >= 0)
{
_disabled.set(n, !on);
}
else
{
if (on)
_disabled.reset();
else
{
const long tot = items()-1;
_disabled.set(tot); // Forza le dimensioni del bit-array
_disabled.set(); // Disabilita tutte le righe
// Resetta i bit in ecesso alla fine del bit-array
for (long i = _disabled.items()-1; i > tot; i--)
_disabled.reset(i);
}
}
update(n);
}
// Certified 75%
bool TSheet_control::event_handler(XI_OBJ* itf, XI_EVENT *xiev)
{
BOOLEAN& refused = xiev->refused;
switch (xiev->type)
{
case XIE_GET_FIRST:
if (items() > 0L)
{
long n = items() * (long)xiev->v.rec_request.percent / 100L;
if (n < 0L) n = 0L;
xiev->v.rec_request.data_rec = n;
}
else
refused = TRUE;
break;
case XIE_GET_LAST:
xiev->v.rec_request.data_rec = items()-1;
break;
case XIE_GET_PREV:
case XIE_GET_NEXT:
{
const long n = xiev->v.rec_request.spec_rec + (xiev->type == XIE_GET_NEXT ? +1 : -1) ;
if (n < 0 || n >= items())
refused = TRUE;
else
xiev->v.rec_request.data_rec = n;
}
break;
case XIE_CELL_REQUEST:
{
const long rec = xiev->v.cell_request.rec;
const char* src = NULL;
int nm;
XI_OBJ** obj = xi_get_member_list(xiev->v.cell_request.list, &nm);
const int num = xiev->v.cell_request.col_nbr;
const int cid = obj[num]->cid - 1000;
if (cid >= FIRST_FIELD)
{
if (rec < items())
{
const int col = cid - FIRST_FIELD;
switch (_type[col])
{
case 'C': // Set value for "checkable" cell
{
const bool on = checked(rec);
xiev->v.cell_request.icon_rid = on ? ICO_CHECK_ON : ICO_CHECK_OFF;
// if (on) src = "X"; // A volte visualizza la X!
}
break;
case 'M': // Set value for "roman" cell
src = itor(atoi(row(rec).get(col)));
break;
default: // Set value for "normal" cell
src = row(rec).get(col);
break;
}
if (_disabled[rec])
{
xiev->v.cell_request.color = DISABLED_COLOR;
xiev->v.cell_request.back_color = DISABLED_BACK_COLOR;
}
else
if (rec == _cur_rec)
{
xiev->v.cell_request.color = FOCUS_COLOR;
xiev->v.cell_request.back_color = FOCUS_BACK_COLOR;
}
}
}
else
{
xiev->v.cell_request.color = NORMAL_COLOR;
src = format("%ld", rec+1);
}
char* dst = xiev->v.cell_request.s;
if (src && *src)
{
const int len = xiev->v.cell_request.len;
strncpy(dst, src, len);
dst[len-1] = '\0';
}
else
*dst = '\0';
}
break;
case XIE_DBL_CELL:
{
const long rec = row2rec(xiev->v.xi_obj->v.cell.row);
if (!_disabled[rec])
{
make_current(rec);
_sheet->stop_run(K_ENTER);
}
else
refused = TRUE;
}
break;
case XIE_ON_ROW:
{
const long rec = row2rec(xiev->v.xi_obj->v.row);
if (_disabled[rec])
{
refused = TRUE;
// Cerca la prossima riga abilitata e valida
const int dir = rec > selected() ? +1: -1;
const long max = items();
for (long r = rec+dir; r >= 0 && r < max; r += dir) if (!_disabled[r])
{
_sheet->post_select(r);
break;
}
}
else
if (_sheet->_select_row < 0)
make_current(rec);
}
break;
case XIE_GET_PERCENT:
{
const long rec = xiev->v.get_percent.record;
long n = items(); if (n <= 0) n = 1;
xiev->v.get_percent.percent = int(rec * 100L / n);
}
break;
case XIE_SELECT:
if (xiev->v.xi_obj->type == XIT_ROW)
{
int num;
XI_OBJ** column = xi_get_member_list(_obj, &num);
const int col = xiev->v.select.column;
const int row = xiev->v.select.xi_obj->v.row;
const long rec = row2rec(row);
const short cid = column[col]->cid;
if (cid >= FIRST_FIELD)
{
if (check_enabled())
toggle(rec);
}
else
{
if (_cur_rec == rec)
_sheet->on_key(K_CTRL+'C');
}
const int c = _type[0] == 'C' ? 2 : 1;
XI_OBJ cell; XI_MAKE_CELL(&cell, _obj, row, c);
xi_set_focus(&cell);
make_current(rec);
}
refused = TRUE;
break;
case XIE_BUTTON:
if (xiev->v.xi_obj->type == XIT_LIST)
_sheet->on_key(K_CTRL+'N');
break;
case XIE_XVT_EVENT:
if (xiev->v.xvte.type == E_CHAR)
{
const KEY k = e_char_to_key(&xiev->v.xvte);
long rec = -1;
switch (k)
{
case K_ENTER:
if (_disabled[_cur_rec])
break;
case K_ESC:
_sheet->stop_run(k);
break;
case K_LHOME:
rec = 0;
break;
case K_PREV:
rec = _cur_rec - visible_rows();
if (rec < 0) rec = 0;
break;
case K_NEXT:
rec = _cur_rec + visible_rows();
if (rec >= items())
rec = items()-1;
break;
case K_LEND:
rec = items()-1;
break;
default:
break;
}
if (rec >= 0)
{
_sheet->post_select(rec);
refused = TRUE;
}
}
break;
default:
break;
}
return !refused;
}
///////////////////////////////////////////////////////////
// TQuery_field
///////////////////////////////////////////////////////////
class TQuery_field : public TOperable_field
{
protected:
virtual void create(WINDOW parent);
public:
TSheet_control* sheet() const { return (TSheet_control*)_ctl; }
TQuery_field(TMask* m) : TOperable_field(m) { }
virtual ~TQuery_field() { }
};
void TQuery_field::create(WINDOW parent)
{
_ctl = new TSheet_control(parent, dlg(),
_ctl_data._x, _ctl_data._y,
_ctl_data._width, _ctl_data._size,
_ctl_data._flags, _ctl_data._prompt);
}
///////////////////////////////////////////////////////////
// TSheet
///////////////////////////////////////////////////////////
TSheet::TSheet(short x, short y, short dx, short dy,
const char* title, const char* head,
byte buttons, short sht_y)
: TMask(title, sht_y == 0 ? 1 : 2, dx, dy, x, y),
_parked(-1), _sheet(NULL), _select_row(-1)
{
TQuery_field* qf = new TQuery_field(this);
qf->construct(883, head, 1, sht_y, -3, win(), "", -1);
fields_array().add(qf);
_sheet = qf->sheet();
if (!(buttons & 0x10)) add_button(DLG_SELECT, "Selezione", K_ENTER);
if (check_enabled())
{
add_button(DLG_USER, "Tutti", 0);
set_handler(DLG_USER, tutti_handler);
}
if (buttons & 0x1) add_button(DLG_LINK, "~Collega", K_CTRL+'C', BMP_LINK);
if (buttons & 0x2) add_button(DLG_NEWREC, "~Nuovo", K_INS, BMP_NEWREC, BMP_NEWRECDN);
if (buttons & 0x4) add_button(DLG_DELREC, "Elimina", K_DEL, BMP_DELREC, BMP_DELRECDN);
if (buttons & 0x8) add_button(DLG_QUIT, "Fine", K_ESC);
else add_button(DLG_CANCEL, "Annulla", K_ESC);
}
TSheet::~TSheet()
{
delete _sheet;
}
TSheet_control& TSheet::sheet()
{ return *_sheet; }
// @doc INTERNAL
// @mfunc Aggiunge un bottone nella finestra
void TSheet::add_button(
short id, // @parm Identificatore del bottone da aggiungere
const char* caption, // @parm Testo del bottone da aggiungere
KEY key, // @parm Combinazione di tasti corrispondente
short bmp_up, // @parm Bitmap normale
short bmp_dn) // @parm Bitmap premuta
{
TButton_field& butt = TMask::add_button(id, 0, caption, 0, -1, 11, 2,
"", bmp_up, bmp_dn);
butt.set_hot_key(key);
}
void TSheet::repos_buttons() const
{
if (_sheet == NULL)
return; // Sono ancora in fase di creazione: aspetta!
RCT br;
int buttons = 0;
for (int f = fields()-1; f >= 0; f--)
{
TMask_field& c = fld(f);
if (c.is_kind_of(CLASS_BUTTON_FIELD))
{
if (buttons == 0)
c.get_rect(br);
buttons++;
}
}
RCT wr; xvt_vobj_get_client_rect(win(), &wr);
const short width = br.right - br.left;
const short height = br.bottom - br.top;
int space = (wr.right - buttons * width) / (buttons+1);
if (space < 0) space = 0;
int x = space;
const int y = wr.bottom - height - XI_FU_MULTIPLE;
for (f = 0; buttons > 0; f++)
{
TMask_field& c = fld(f);
if (c.is_kind_of(CLASS_BUTTON_FIELD))
{
buttons--;
const PNT p = { y, x };
xvt_rect_set_pos(&br, p);
c.set_rect(br);
x += space+width;
}
}
}
void TSheet::start_run()
{
const bool on = items() > 0 && _sheet->one_enabled();
// Abilita selezione se c'e' almeno un elemento
int pos = id2pos(DLG_SELECT);
if (pos >= 0)
fld(pos).enable(on);
pos = id2pos(DLG_LINK);
if (pos >= 0)
fld(pos).enable(on);
_parked = -1;
repos_buttons();
_sheet->update();
}
long TSheet::selected() const
{ return _sheet->selected(); }
bool TSheet::check_enabled() const
{ return _sheet->check_enabled(); }
void TSheet::enable_check(bool on)
{ _sheet->enable_check(on); }
void TSheet::check(long n, bool on)
{ _sheet->check(n, on); }
bool TSheet::checked(long n) const
{ return _sheet->checked(n); }
long TSheet::checked() const
{ return _sheet->checked(); }
bool TSheet::one_checked() const
{ return _sheet->one_checked(); }
void TSheet::enable_row(long r, bool on)
{ _sheet->enable_row(r, on); }
bool TSheet::row_enabled(long r) const
{ return _sheet->row_enabled(r); }
bool TSheet::on_key(KEY key)
{
switch(key)
{
case K_ESC:
stop_run(key);
break;
case K_DEL:
if (items() && id2pos(DLG_DELREC) >= 0)
stop_run(key);
break;
case K_CTRL+'N':
if (id2pos(DLG_NEWREC) >= 0)
stop_run(K_INS);
break;
case K_CTRL+'C':
if (id2pos(DLG_LINK) >= 0)
stop_run(key);
break;
default:
break;
}
if (check_enabled() && items() > 0)
{
switch(key)
{
case K_SPACE:
check(selected(), !checked(selected()));
break;
case K_F7:
uncheck(-1);
break;
case K_F8:
check(-1);
break;
default:
break;
}
}
return TRUE;
}
// @doc INTERNAL
// @mfunc Seleziona una riga facendola diventare corrente
void TSheet::select(
long n) // @parm Riga da selezionare
{
_sheet->select(n);
}
void TSheet::post_select(long rec)
{
_select_row = rec;
}
void TSheet::on_idle()
{
if (_select_row >= 0)
{
const short focus_id = get_focus_id(win());
_sheet->select(_select_row);
if (focus_id == _sheet->id())
_sheet->set_focus_rec(-1);
_select_row = -1;
}
}
// @doc INTERNAL
// @mfunc Ritorna il contenuto di una riga
//
// @rdesc Ritorna la <c TToken_string> con tutti gli elemnti della riga
TToken_string& TSheet::row(
long n) // @parm Riga di cui ritorna il contenuto (default -1)
// @comm Se viene passato un numero di riga minore di 1 viene ritornato il contenuto della riga
// selezionata.
{
if (n < 0) n = selected();
if (n != _parked)
get_row(_parked = n, _park);
return _park;
}
bool TSheet::tutti_handler(TMask_field& f, KEY k)
{
if (k == K_SPACE)
{
TSheet& s = (TSheet&)f.mask();
if (s.check_enabled())
s.check(-1, !s.one_checked());
}
return TRUE;
}
///////////////////////////////////////////////////////////
// TArray_sheet
///////////////////////////////////////////////////////////
TArray_sheet::TArray_sheet(short x, short y, short dx, short dy,
const char* caption, const char* head, byte buttons)
: TSheet(x, y, dx, dy, caption, head, buttons)
{
}
// Certified 90%
bool TArray_sheet::destroy(int i)
{
uncheck(-1);
enable(-1);
return _data.destroy(i, TRUE);
}
// @doc EXTERNAL
// @mfunc Aggiunge un elemento allo sheet
//
// @rdesc Ritorna il numero di elemnti presenti nello sheet
long TArray_sheet::add(
const TToken_string& s) // @parm Oggetto da aggiungere
// @parm const TToken_string | *s | Oggetto da aggiungere passato per indirizzo
// @syntax add(const TToken_string& s)
// @syntax add(const TToken_string* s)
{
const long n = _data.add(s);
return n;
}
long TArray_sheet::add(TToken_string* s)
{
const long n = _data.add(s);
return n;
}
long TArray_sheet::insert(const TToken_string& s, long n)
{
_data.insert(s, (int)n);
return n;
}
///////////////////////////////////////////////////////////
// TCursor_sheet
///////////////////////////////////////////////////////////
TCursor_sheet::TCursor_sheet(TCursor* cursor, const char* fields,
const char* title, const char* head,
byte buttons, short sht_y)
: TSheet(sht_y ? 3 : 0, sht_y ? 3 : 0, sht_y ? -3 : 0, sht_y ? -3 : 0,
title, head, buttons, sht_y),
_cursor(cursor), _records(cursor->items())
{
TToken_string fldlst(fields);
int campo = 0;
for (const char* t = fldlst.get(0); t; t = fldlst.get(), campo++)
{
if (*t > ' ' && *t != '"')
{
const TFieldref fr(t, 0);
TRecfield* rf = new TRecfield(_cursor->curr(fr.file()),
fr.name(), fr.from(), fr.to() - 1);
_fields.add(rf, campo);
const TFieldtypes tipo = rf->type();
if (tipo == _intfld || tipo == _longfld || tipo == _realfld)
{
byte& c = sheet().column_type(campo);
if (c == '\0') c = 'R'; // Allinea a destra tutti i campi numerici
}
}
}
}
KEY TCursor_sheet::run()
{
_records = _cursor->items();
_cursor->freeze(TRUE);
select(_cursor->pos());
post_select(_cursor->pos());
const KEY k = TSheet::run();
_cursor->freeze(FALSE);
return k;
}
void TCursor_sheet::get_row(long row, TToken_string& l)
{
*_cursor = (TRecnotype)row;
l.cut(0);
const int last = _fields.last();
for (int i = 0; i <= last; i++)
{
const TRecfield* rf = (TRecfield*)_fields.objptr(i);
const char* s = rf ? (const char*)*rf : "";
l.add(s);
}
}
///////////////////////////////////////////////////////////
// TBrowse_sheet
///////////////////////////////////////////////////////////
HIDDEN TBrowse_sheet* _cur_browse = NULL;
HIDDEN bool _can_post = FALSE;
bool TBrowse_sheet::browse_field_handler(TMask_field& f, KEY k)
{
long rec = -1;
if (k == K_SPACE)
{
TEdit_field& e = _cur_browse->field(); // Campo padre dello sheet
TMask& m = e.mask(); // Maschera che contiene lo sheet
TMask_field& c = m.field(f.dlg()); // Campo corrispondente sulla maschera
// Ricopia su campo maschera
if (f.is_edit())
{
TEdit_field& ef = (TEdit_field&)f;
const TString& wd = ef.get_window_data();
c.set(wd);
}
else
c.set(f.get());
TBrowse* b = e.browse();
b->do_input(FALSE);
rec = b->cursor()->read(_isgteq);
} else
if (k == K_F2)
rec = 0;
if (rec >= 0 && rec != _cur_browse->selected())
{
_cur_browse->select(rec); // Non mettere post_select
_can_post = TRUE;
}
return TRUE;
}
bool TBrowse_sheet::last_browse_field_handler(TMask_field& f, KEY k)
{
const bool ok = browse_field_handler(f, k);
if (ok && k == K_TAB && _can_post)
{
_cur_browse->post_select(_cur_browse->selected());
_can_post = FALSE;
}
return ok;
}
TBrowse_sheet::TBrowse_sheet(TCursor* cursor, const char* fields,
const char* title, const char* head, byte buttons,
TEdit_field* f, TToken_string& sibling)
: TCursor_sheet(cursor, fields, title, head, buttons, f->browse()->input_fields()),
_field(f), _sel(0)
{
TToken_string ca; // Tag buttons
int n = 0;
for (const char* s = sibling.get(0); s && *s; s = sibling.get(), n++)
{
const short id = f->atodlg(s);
const char* pr = sibling.get();
if (id == f->dlg())
{
_sel = n;
}
ca.add(pr);
}
if (n > 0)
add_tag_button(0, ca, _sel);
TToken_string tids = head;
TToken_string tfns = fields;
TToken_string ids = f->browse()->get_input_fields();
TToken_string fns = f->browse()->get_input_field_names();
TEditable_field* e = NULL;
short y = 0;
for (const char* i = ids.get(0); i; i = ids.get())
{
if (*i != '"' && strchr(i, '@') == NULL)
{
const TMask_field& c = f->mask().field(f->atodlg(i));
if (c.is_editable() && c.active())
{
int pos = ids.get_pos(c.dlg());
CHECK(pos >= 0, "Invalid input field");
TString80 p = fns.get(pos);
pos = tfns.get_pos(p);
if (pos >= 0)
{
p = tids.get(pos);
pos = p.find('@');
if (pos >= 0)
p.cut(pos);
}
else
p.cut(0);
if (p.empty())
{
p = c.prompt();
// Toglie spazi e simboli iniziali dal prompt
for (int a = 0; p[a] && !isalnum(p[a]); a++);
p.ltrim(a);
}
p.left_just(16);
TString16 flags;
if (c.roman()) flags << 'M';
if (c.right_justified()) flags << 'R';
if (c.uppercase()) flags << 'U';
if (c.zerofilled()) flags << 'Z';
switch (c.class_id())
{
case CLASS_EDIT_FIELD:
e = &add_string(c.dlg(), 0, p, 1, y++, c.size(), flags);
break;
case CLASS_REAL_FIELD:
e = &add_number(c.dlg(), 0, p, 1, y++, c.size(), flags);
break;
case CLASS_DATE_FIELD:
e = &add_date (c.dlg(), 0, p, 1, y++, flags);
break;
default:
e = NULL;
break;
}
if (e)
{
e->set_handler(browse_field_handler);
e->set(c.get());
}
}
}
}
if (e != NULL)
e->set_handler(last_browse_field_handler);
}
bool TBrowse_sheet::on_key(KEY k)
{
if (k >= K_CTRL+K_F1 && k < K_CTRL+K_F10)
{
const int what = k - K_CTRL - K_F1;
if (what >= 0 && what != _sel)
TWindow::stop_run(k);
return TRUE;
}
return TSheet::on_key(k);
}
KEY TBrowse_sheet::run()
{
_cur_browse = this;
const KEY key = TCursor_sheet::run();
_cur_browse = NULL;
return key;
}