golem.cpp Migliorata gestione degli hook agli handler di finestra msksheet.cpp Eliminati molti sfarfallamenti duante cambio focus relapp.cpp Corretta gestione messaggio ED sheet.cpp Corretto posizionamento iniziale su righe disabilitate xvtility.cpp Migliorata gestione dell'event hook. git-svn-id: svn://10.65.10.50/trunk@3328 c028cbd2-c16b-5b4b-a496-9718f37d4682
1239 lines
32 KiB
C++
Executable File
1239 lines
32 KiB
C++
Executable File
#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, 0,
|
|
/* NUMBER_WIDTH*/ 2 * 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++)
|
|
{
|
|
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, FIRST_FIELD+i+1000, attr, i+1,
|
|
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);
|
|
src = "";
|
|
}
|
|
|
|
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 - 1000;
|
|
if (cid >= FIRST_FIELD)
|
|
{
|
|
if (check_enabled())
|
|
toggle(rec);
|
|
}
|
|
else
|
|
{
|
|
if (_cur_rec == rec)
|
|
_sheet->on_key(K_CTRL+'G');
|
|
}
|
|
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_SPACE:
|
|
check(selected(), !checked(selected()));
|
|
break;
|
|
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(30883, 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, "~Gestione", K_CTRL+'G');
|
|
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();
|
|
|
|
if (on)
|
|
{
|
|
long i = selected();
|
|
if (i < 0 || i >= items())
|
|
i = 0;
|
|
if (row_disabled(i))
|
|
for (i = 0; row_disabled(i); i++);
|
|
post_select(i);
|
|
}
|
|
}
|
|
|
|
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+'G':
|
|
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
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
HIDDEN bool _can_post = FALSE;
|
|
|
|
KEY TCursor_sheet::run()
|
|
{
|
|
_records = _cursor->items();
|
|
_cursor->freeze(TRUE);
|
|
|
|
select(_cursor->pos());
|
|
// post_select(_cursor->pos());
|
|
_can_post = TRUE;
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
RCT r; f.get_rect(r);
|
|
xvt_dwin_invalidate_rect(f.parent(), &r);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
bool TBrowse_sheet::last_browse_field_handler(TMask_field& f, KEY k)
|
|
{
|
|
const bool ok = browse_field_handler(f, k);
|
|
if (ok)
|
|
{
|
|
if (k == K_TAB && _can_post)
|
|
{
|
|
_cur_browse->post_select(_cur_browse->selected());
|
|
_can_post = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (k == K_CTRL+K_TAB)
|
|
{
|
|
RCT r; f.get_rect(r);
|
|
xvt_dwin_invalidate_rect(f.parent(), &r);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
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, c.size() > 50 ? 50 : c.size() );
|
|
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->dlg() == f->dlg())
|
|
first_focus(e->dlg());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|