3a6fa88f87
git-svn-id: svn://10.65.10.50/trunk@20 c028cbd2-c16b-5b4b-a496-9718f37d4682
1074 lines
23 KiB
C++
Executable File
1074 lines
23 KiB
C++
Executable File
#include <msksheet.h>
|
|
#include <real.h>
|
|
#include <urldefid.h>
|
|
#include <utility.h>
|
|
|
|
const short FIRST_FIELD = 101;
|
|
|
|
#if XVT_OS == XVT_OS_WIN
|
|
|
|
#include <xil.h>
|
|
#include <colors.h>
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TSpreadsheet
|
|
// /////////////////////////////////////////////////////////
|
|
|
|
#define K_PLUS '+'
|
|
|
|
class TSpreadsheet:public TWindow
|
|
{
|
|
enum
|
|
{
|
|
ITF_CID = 0, LIST_CID = 1
|
|
};
|
|
|
|
TArray _str; // Array di TToken_strings
|
|
|
|
TBit_array _column_disabled;
|
|
TArray _disabled; // Array di TBit_array
|
|
|
|
TMask _mask;
|
|
int _columns;
|
|
bool _dirty;
|
|
|
|
XI_OBJ *_list;
|
|
|
|
SPREADSHEET_NOTIFY _notify;
|
|
|
|
static void xiev_handler (XI_OBJ * itf, XI_EVENT * xiev);
|
|
void init ();
|
|
|
|
protected:
|
|
void list_handler (XI_EVENT * xiev);
|
|
|
|
TMask_field *cell2field (const XI_OBJ * cell) const;
|
|
void update_rec (int rec);
|
|
void set_focus_cell (int riga, int colonna);
|
|
|
|
void mask2str (int n);
|
|
void str2mask (int n);
|
|
KEY edit (int n);
|
|
|
|
TMask_field *field (short id) const;
|
|
|
|
int rec2row (int rec);
|
|
int row2rec (int row);
|
|
|
|
bool notify (int r, KEY k);
|
|
|
|
public:
|
|
void update (int row);
|
|
|
|
TToken_string & row (int n);
|
|
TArray & rows_array () const
|
|
{
|
|
return (TArray &) _str;
|
|
}
|
|
int add (TToken_string &);
|
|
int insert (int rec);
|
|
bool destroy (int rec = -1);
|
|
|
|
void enable_column (int col, bool on = TRUE);
|
|
void enable_cell (int row, int column, bool on = TRUE);
|
|
bool cell_disabled (int row, int column) const;
|
|
|
|
TMask & mask ()
|
|
{
|
|
return _mask;
|
|
}
|
|
|
|
int items () const
|
|
{
|
|
return _str.items ();
|
|
}
|
|
|
|
int columns () const
|
|
{
|
|
return _columns;
|
|
}
|
|
|
|
bool dirty () const
|
|
{
|
|
return _dirty;
|
|
}
|
|
|
|
void set_notify (SPREADSHEET_NOTIFY n)
|
|
{
|
|
_notify = n;
|
|
}
|
|
|
|
void set_dirty (bool spork = TRUE)
|
|
{
|
|
_dirty = spork;
|
|
}
|
|
|
|
TSpreadsheet (short x, short y, short dx, short dy, const char *maskname, int maskno,
|
|
const char *head, WINDOW parent);
|
|
};
|
|
|
|
// Certified 99%
|
|
void TSpreadsheet ::init ()
|
|
{
|
|
static bool first = TRUE;
|
|
|
|
if (!first) return;
|
|
|
|
xvt_set_font (TASK_WIN, FF_FIXED, 0);
|
|
DRAW_CTOOLS ct;
|
|
win_get_draw_ctools (TASK_WIN, &ct);
|
|
xi_set_font (&ct.font);
|
|
|
|
xi_init ();
|
|
xi_set_pref (XI_PREF_3D_LOOK, TRUE);
|
|
// xi_set_pref(XI_PREF_COLOR_LIGHT, COLOR_CYAN);
|
|
// xi_set_pref(XI_PREF_COLOR_CTRL, MASK_BACK_COLOR);
|
|
// xi_set_pref(XI_PREF_COLOR_DARK, COLOR_GRAY);
|
|
|
|
first = FALSE;
|
|
}
|
|
|
|
TSpreadsheet ::TSpreadsheet (short x, short y, short dx, short dy,
|
|
const char *maskname, int maskno,
|
|
const char *head, WINDOW parent)
|
|
: _mask (maskname, NO_MODE, maskno), _notify (NULL)
|
|
|
|
{
|
|
const int NUMBER_WIDTH = 3;
|
|
const int MAX_COL = 32;
|
|
int width[MAX_COL];
|
|
|
|
init ();
|
|
|
|
// Calcolo larghezza massima tabella
|
|
|
|
TToken_string header (head);
|
|
TToken_string new_header (256);
|
|
int i = 0, tot_width = NUMBER_WIDTH + 1;
|
|
for (const char *h = header.get (); h; h = header.get (), i++)
|
|
{
|
|
CHECKD (i < MAX_COL, "Tu meni calumns in scit: ", i);
|
|
int w;
|
|
char *at = strchr (h, '@');
|
|
if (at)
|
|
{
|
|
w = atoi (at + 1);
|
|
*at = '\0';
|
|
}
|
|
else
|
|
w = strlen (h);
|
|
|
|
width[i] = w + 1;
|
|
|
|
const int cid = FIRST_FIELD + i; // Column & Field ID
|
|
const TMask_field * f = field (cid); // Field on mask
|
|
CHECKD (f, "The spreadsheet mask needs ALSO field ", cid);
|
|
if (f->has_query ())w += 2;
|
|
|
|
tot_width += w;
|
|
new_header.add (h);
|
|
}
|
|
_columns = i;
|
|
|
|
if (x < 0) x = 0;
|
|
if (y < 0) y = 0;
|
|
if (dx == 0)
|
|
{
|
|
dx = tot_width;
|
|
if (dx > 76) dx = -x;
|
|
}
|
|
|
|
RCT rct = resize_rect (x, y, dx, dy, WO_TE, parent);
|
|
rct.right -= 20;
|
|
rct.bottom -= 8;
|
|
|
|
XI_OBJ_DEF * itfdef = xi_create_itf_def (ITF_CID,
|
|
(XI_EVENT_HANDLER) xiev_handler, &rct, (char *) maskname,
|
|
PTR_LONG (this));
|
|
itfdef->v.itf->automatic_back_color = FALSE;
|
|
itfdef->v.itf->back_color = MASK_BACK_COLOR;
|
|
|
|
XI_OBJ_DEF * listdef = xi_add_list_def (itfdef, LIST_CID,
|
|
0, 0, rct.bottom - rct.top,
|
|
XI_ATR_ENABLED | XI_ATR_VISIBLE,
|
|
NORMAL_COLOR, NORMAL_BACK_COLOR,
|
|
NORMAL_COLOR, DISABLED_BACK_COLOR, NORMAL_COLOR,
|
|
LIST_CID);
|
|
listdef->v.list->scroll_bar = TRUE;
|
|
listdef->v.list->sizable_columns = TRUE;
|
|
listdef->v.list->movable_columns = TRUE;
|
|
listdef->v.list->scroll_bar_button = TRUE;
|
|
listdef->v.list->fixed_columns = 1;
|
|
listdef->v.list->width = rct.right - rct.left;
|
|
listdef->v.list->min_cell_height = CHARY;
|
|
listdef->v.list->min_heading_height = CHARY;
|
|
listdef->v.list->white_space_color = COLOR_GRAY;
|
|
|
|
XI_OBJ_DEF * coldef = xi_add_column_def (listdef, 0,
|
|
XI_ATR_RJUST, 0, NUMBER_WIDTH, NUMBER_WIDTH, "");
|
|
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
|
|
const TMask_field * f = field (cid); // Field on mask
|
|
const int w = width[i] + (f->has_query ()? 2 : 0); // Column
|
|
// width
|
|
|
|
long flags = XI_ATR_EDITMENU | XI_ATR_AUTOSCROLL;
|
|
if (f->class_id () == CLASS_REAL_FIELD) flags |= XI_ATR_RJUST;
|
|
if (f->active ())flags |= XI_ATR_ENABLED;
|
|
else
|
|
_column_disabled.set (i);
|
|
|
|
coldef = xi_add_column_def (listdef, cid,
|
|
flags, cid, w, width[i], (char *) h);
|
|
coldef->v.column->heading_platform = TRUE;
|
|
coldef->v.column->center_heading = TRUE;
|
|
}
|
|
|
|
RCT itfrct;
|
|
xi_get_def_rect (itfdef, &itfrct);
|
|
offset_rect (&itfrct, rct.left, rct.top);
|
|
itfrct.bottom++;
|
|
|
|
WINDOW win = create_window (W_NO_BORDER, &itfrct, "", 0, parent,
|
|
0, EM_ALL, (EVENT_HANDLER) xi_event, 0L);
|
|
CHECK (win, "Can't create a window for the spreadsheet");
|
|
|
|
set_win (win); // Set TWindow::_win
|
|
itfdef->v.itf->win = win;
|
|
|
|
xi_create (NULL, itfdef);
|
|
xi_tree_free (itfdef);
|
|
|
|
XI_OBJ * itf = xi_get_itf (win);
|
|
_list = xi_get_obj (itf, LIST_CID);
|
|
}
|
|
|
|
// Converts a row number in the correspondig record number
|
|
int TSpreadsheet ::row2rec (int row)
|
|
{
|
|
int rows;
|
|
const long *rec = xi_get_list_info (_list, &rows);
|
|
|
|
#ifdef DBG
|
|
if (row < 0 || row >= rows)
|
|
{
|
|
error_box ("Line %d is not visible", row);
|
|
return 0L;
|
|
}
|
|
#endif
|
|
|
|
return (int) rec[row];
|
|
}
|
|
|
|
// Converts a row number in the correspondig record number
|
|
int TSpreadsheet ::rec2row (int record)
|
|
{
|
|
int rows;
|
|
const long *rec = xi_get_list_info (_list, &rows);
|
|
int r = int (record - rec[0]);
|
|
if (r < 0 || r >= rows)
|
|
r = -1;
|
|
|
|
return r;
|
|
}
|
|
|
|
// Retrieves the corresponding field of the mask from a spredsheet cell
|
|
TMask_field * TSpreadsheet ::cell2field (const XI_OBJ * cell) const
|
|
{
|
|
const int pos = cell->v.cell.column;
|
|
|
|
int num;
|
|
XI_OBJ ** column = xi_get_member_list (_list, &num);
|
|
|
|
TMask_field * good = NULL;
|
|
for (short id = column[pos]->cid;; id += 100)
|
|
{
|
|
TMask_field * f = field (id);
|
|
if (f == NULL) break;
|
|
good = f;
|
|
if (f->active ())break;
|
|
}
|
|
|
|
return good;
|
|
}
|
|
|
|
void TSpreadsheet ::update_rec (int rec)
|
|
{
|
|
const int riga = rec2row (rec);
|
|
if (riga >= 0)
|
|
{
|
|
XI_OBJ row;
|
|
XI_MAKE_ROW (&row, _list, riga);
|
|
xi_cell_request (&row); // Update internal values
|
|
xi_set_row_height (&row, CHARY + 1); // Force row updating
|
|
}
|
|
}
|
|
|
|
void TSpreadsheet ::set_focus_cell (int riga, int colonna)
|
|
{
|
|
set_front_window (win ());
|
|
XI_OBJ cell;
|
|
XI_MAKE_CELL (&cell, _list, rec2row (riga), colonna);
|
|
xi_set_focus (&cell);
|
|
}
|
|
|
|
int TSpreadsheet ::insert (int rec)
|
|
{
|
|
const bool ok = notify (rec, K_INS);
|
|
if (!ok) return -1;
|
|
|
|
TToken_string s; // Empty row
|
|
const int r = _str.insert (s, rec);
|
|
_disabled.insert (NULL, rec);
|
|
|
|
xi_insert_row (_list, INT_MAX);
|
|
xi_cell_request (_list);
|
|
|
|
return r;
|
|
}
|
|
|
|
bool TSpreadsheet ::destroy (int rec)
|
|
{
|
|
bool ok = TRUE;
|
|
|
|
if (rec < 0)
|
|
{
|
|
_disabled.destroy ();
|
|
_str.destroy ();
|
|
}
|
|
else
|
|
{
|
|
_disabled.destroy (rec, TRUE); // Destroy enable info
|
|
ok = _str.destroy (rec, TRUE); // Destroy line
|
|
enable_cell (_str.items (), -1); // Enable last line
|
|
}
|
|
|
|
if (ok) xi_cell_request (_list);
|
|
|
|
return ok;
|
|
}
|
|
|
|
void TSpreadsheet ::update (int row)
|
|
{
|
|
if (row < 0)
|
|
{
|
|
xi_cell_request (_list);
|
|
xi_scroll (_list, XI_SCROLL_FIRST);
|
|
set_front_window (win ());
|
|
}
|
|
else
|
|
update_rec (row);
|
|
}
|
|
|
|
void TSpreadsheet ::xiev_handler (XI_OBJ * itf, XI_EVENT * xiev)
|
|
{
|
|
TSpreadsheet * es = (TSpreadsheet *) xi_get_app_data (itf);
|
|
CHECK (es, "NULL Edit sheet in xi event");
|
|
es->list_handler (xiev);
|
|
}
|
|
|
|
// Certified 75%
|
|
void TSpreadsheet ::list_handler (XI_EVENT * xiev)
|
|
{
|
|
static TMask_field * edit_field = NULL; // Current edit field
|
|
static int cur_row = 0, cur_col = 0; // Current cell
|
|
static bool row_dirty = FALSE; // Current row changed
|
|
static bool check_enabled = TRUE; // Perform OFF_ROW checks
|
|
|
|
switch (xiev->type)
|
|
{
|
|
case XIE_GET_FIRST:
|
|
{
|
|
const long max = items ();
|
|
if (max <= 0L)
|
|
{
|
|
xiev->refused = TRUE;
|
|
break;
|
|
}
|
|
long n = max * (long)xiev->v.rec_request.percent / 100L;
|
|
if (n < 0L) n = 0L;
|
|
xiev->v.rec_request.data_rec = n;
|
|
}
|
|
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 ())
|
|
xiev->refused = TRUE;
|
|
else
|
|
xiev->v.rec_request.data_rec = n;
|
|
}
|
|
break;
|
|
case XIE_CELL_REQUEST:
|
|
{
|
|
const int rec = (int)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;
|
|
|
|
if (cid >= FIRST_FIELD)
|
|
{
|
|
if (rec < items ())
|
|
{
|
|
const int col = cid - FIRST_FIELD;
|
|
TMask_field * f = field (cid);
|
|
src = row (rec).get (col); // Set value for cell
|
|
if (src && *src && f->class_id () == CLASS_REAL_FIELD)
|
|
{
|
|
src = f->picture_data (src, FALSE); // Get formatted string
|
|
}
|
|
if (field (cid)->has_query ())
|
|
{
|
|
xiev->v.cell_request.button =
|
|
xiev->v.cell_request.button_on_focus = TRUE;
|
|
}
|
|
if (cell_disabled (rec, col))
|
|
xiev->v.cell_request.back_color = MASK_BACK_COLOR;
|
|
}
|
|
}
|
|
else
|
|
src = format ("%d", rec + 1);
|
|
|
|
const int len = xiev->v.cell_request.len;
|
|
char *dst = xiev->v.cell_request.s;
|
|
if (src)
|
|
{
|
|
strncpy (dst, src, len);
|
|
if (isspace (*dst))
|
|
{
|
|
TFixed_string d (dst);
|
|
d.ltrim ();
|
|
}
|
|
}
|
|
else
|
|
*dst = '\0';
|
|
}
|
|
break;
|
|
case XIE_BUTTON:
|
|
if (xiev->v.xi_obj->type == XIT_CELL)
|
|
{
|
|
if (edit_field)
|
|
{
|
|
const char *val = xi_get_text (xiev->v.xi_obj, NULL, -1);
|
|
edit_field->set (val); // Update current cell
|
|
check_enabled = FALSE; // Disable checks
|
|
if (!row_dirty) notify (cur_row, K_SPACE);
|
|
if (edit_field->on_key (K_F9)) // Show search sheet
|
|
{
|
|
mask2str (cur_row); // Update row
|
|
row_dirty = TRUE;
|
|
}
|
|
check_enabled = TRUE; // Enable checks
|
|
xi_set_focus (xiev->v.xi_obj); // Restore focus to cell
|
|
}
|
|
}
|
|
else
|
|
if (xiev->v.xi_obj->type == XIT_LIST)
|
|
insert (-1);
|
|
break;
|
|
case XIE_DBL_CELL:
|
|
{
|
|
check_enabled = FALSE;
|
|
cur_row = row2rec (xiev->v.xi_obj->v.cell.row);
|
|
cur_col = xiev->v.xi_obj->v.cell.column;
|
|
const KEY k = edit (cur_row);
|
|
if (k == K_ENTER)
|
|
{
|
|
update_rec (cur_row);
|
|
row_dirty = TRUE;
|
|
}
|
|
xi_set_focus (xiev->v.xi_obj);
|
|
check_enabled = TRUE;
|
|
}
|
|
break;
|
|
case XIE_ON_ROW:
|
|
{
|
|
const int rec = row2rec (xiev->v.xi_obj->v.row);
|
|
if (rec < items ())
|
|
{
|
|
cur_row = rec;
|
|
str2mask (rec);
|
|
row_dirty = FALSE;
|
|
}
|
|
else
|
|
xiev->refused = TRUE;
|
|
}
|
|
break;
|
|
case XIE_OFF_ROW:
|
|
if (row_dirty && check_enabled)
|
|
{
|
|
check_enabled = FALSE; // Avoid recursion!
|
|
set_dirty ();
|
|
str2mask (cur_row); // It shouldn't have to be necessary
|
|
bool ok = _mask.check_fields ();
|
|
if (ok)
|
|
{
|
|
mask2str (cur_row);
|
|
ok = notify (cur_row, K_ENTER); // Notify edit
|
|
}
|
|
else
|
|
{
|
|
xiev->refused = TRUE;
|
|
set_dirty (2); // Set error status
|
|
set_focus_cell (cur_row, cur_col);
|
|
}
|
|
check_enabled = TRUE;
|
|
}
|
|
break;
|
|
case XIE_ON_CELL:
|
|
{
|
|
TMask_field * f = cell2field (xiev->v.xi_obj);
|
|
const int col = (f->dlg () - FIRST_FIELD) % 100;
|
|
if (!cell_disabled (cur_row, col))
|
|
{
|
|
edit_field = f;
|
|
cur_col = xiev->v.xi_obj->v.cell.column;
|
|
xi_set_color (xiev->v.xi_obj, XIC_BACK, FOCUS_BACK_COLOR);
|
|
}
|
|
else
|
|
{
|
|
xiev->refused = TRUE; // Refuse focus on disabled cells
|
|
}
|
|
}
|
|
break;
|
|
case XIE_OFF_CELL:
|
|
if (edit_field && check_enabled)
|
|
{
|
|
TMask_field * c = edit_field; // Save field, it could turn out to
|
|
// be NULL on error
|
|
const TString80 old (c->get ()); // Save old value on mask
|
|
const TString80 nuo (c->picture_data (xi_get_text (xiev->v.xi_obj, NULL, -1), TRUE));
|
|
if (old != nuo)
|
|
{
|
|
check_enabled = FALSE;
|
|
if (!row_dirty)
|
|
{
|
|
notify (cur_row, K_SPACE);
|
|
row_dirty = TRUE;
|
|
}
|
|
c->set (nuo); // Set new mask value
|
|
c->set_dirty (); // Get it dirty!
|
|
if (c->on_key (K_TAB) == FALSE) // Test it
|
|
{
|
|
c->set (old);
|
|
xi_set_focus (xiev->v.xi_obj);
|
|
}
|
|
else
|
|
{
|
|
mask2str (cur_row); // Update sheet row
|
|
edit_field = NULL; // Reset current field
|
|
}
|
|
check_enabled = TRUE;
|
|
}
|
|
xi_set_color (xiev->v.xi_obj, XIC_BACK, NORMAL_BACK_COLOR);
|
|
}
|
|
break;
|
|
case XIE_GET_PERCENT:
|
|
{
|
|
const long rec = xiev->v.get_percent.record;
|
|
long n = items (); if (n < 1) n = 1;
|
|
xiev->v.get_percent.percent = int (rec * 100L / n);
|
|
}
|
|
break;
|
|
case XIE_CLEANUP:
|
|
set_win (NULL_WIN);
|
|
break;
|
|
case XIE_XVT_EVENT:
|
|
{
|
|
EVENT * ep = &xiev->v.xvte;
|
|
switch (ep->type)
|
|
{
|
|
case E_FOCUS:
|
|
if (ep->v.active == FALSE)
|
|
{
|
|
XI_OBJ * itf = xi_get_itf (win ());
|
|
const bool ok = (bool) xi_move_focus (itf);
|
|
if (!ok)
|
|
xiev->refused = TRUE;
|
|
}
|
|
break;
|
|
case E_CHAR:
|
|
if (edit_field)
|
|
{
|
|
const KEY k = e_char_to_key (ep);
|
|
switch (k)
|
|
{
|
|
case K_F1:
|
|
check_enabled = FALSE; // Disable checks
|
|
edit_field->on_key (K_F1);
|
|
set_focus_cell (cur_row, cur_col);
|
|
check_enabled = TRUE; // Enable checks
|
|
// xiev->refused = TRUE;
|
|
break;
|
|
case K_F2:
|
|
case K_F3:
|
|
case K_F8:
|
|
case K_F9:
|
|
{
|
|
check_enabled = FALSE; // Disable checks
|
|
if (!row_dirty) notify (cur_row, K_SPACE);
|
|
if (edit_field->on_key (k))
|
|
{
|
|
mask2str (cur_row);
|
|
row_dirty = TRUE;
|
|
}
|
|
set_focus_cell (cur_row, cur_col);
|
|
check_enabled = TRUE; // Enable checks
|
|
}
|
|
break;
|
|
case K_PLUS:
|
|
insert (cur_row);
|
|
xiev->refused = TRUE;
|
|
break;
|
|
case K_PREV:
|
|
xi_scroll (_list, XI_SCROLL_PGUP);
|
|
// xiev->refused = TRUE;
|
|
break;
|
|
case K_NEXT:
|
|
xi_scroll (_list, XI_SCROLL_PGDOWN);
|
|
// xiev->refused = TRUE;
|
|
break;
|
|
case K_HOME:
|
|
xi_scroll (_list, XI_SCROLL_FIRST);
|
|
// xiev->refused = TRUE;
|
|
break;
|
|
case K_END:
|
|
xi_scroll (_list, XI_SCROLL_LAST);
|
|
// xiev->refused = TRUE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
int TSpreadsheet ::add (TToken_string & t)
|
|
{
|
|
return _str.add (t);
|
|
}
|
|
|
|
TToken_string & TSpreadsheet ::row (int n)
|
|
{
|
|
return (TToken_string &) _str[n];
|
|
}
|
|
|
|
#else
|
|
|
|
#include <sheet.h>
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TSpreadsheet
|
|
// /////////////////////////////////////////////////////////
|
|
|
|
class TSpreadsheet:public TArray_sheet
|
|
{
|
|
TMask _mask;
|
|
SPREADSHEET_NOTIFY _notify;
|
|
bool _dirty;
|
|
|
|
TBit_array _column_disabled;
|
|
TArray _disabled; // Array di TBit_array
|
|
|
|
protected:
|
|
virtual bool on_key (KEY key);
|
|
KEY edit (int n);
|
|
bool notify (int r, KEY k);
|
|
|
|
TMask_field *field (short id) const;
|
|
|
|
void mask2str (int riga);
|
|
void str2mask (int riga);
|
|
|
|
public:
|
|
TSpreadsheet (short x, short y, short dx, short dy, const char *maskname, int maskno,
|
|
const char *head, WINDOW parent);
|
|
|
|
TArray & rows_array () const
|
|
{
|
|
return data ();
|
|
}
|
|
|
|
TMask & mask ()
|
|
{
|
|
return _mask;
|
|
}
|
|
void set_notify (SPREADSHEET_NOTIFY n)
|
|
{
|
|
_notify = n;
|
|
}
|
|
void set_dirty (bool spork = TRUE)
|
|
{_dirty = spork;
|
|
}
|
|
bool dirty ()const
|
|
{
|
|
return _dirty;
|
|
}
|
|
|
|
void enable_column (int col, bool on);
|
|
void enable_cell (int row, int column, bool on = TRUE);
|
|
bool cell_disabled (int row, int column) const;
|
|
};
|
|
|
|
TSpreadsheet ::TSpreadsheet (short x, short y, short dx, short dy,
|
|
const char *maskname, int maskno,
|
|
const char *head, WINDOW parent)
|
|
:TArray_sheet (x, y, dx, dy, maskname, head, 0, parent),
|
|
_mask (maskname, NO_MODE, maskno), _notify (NULL)
|
|
{
|
|
}
|
|
|
|
bool TSpreadsheet ::on_key (KEY k)
|
|
{
|
|
switch (k)
|
|
{
|
|
case K_SHIFT_ENTER:
|
|
case K_ESC:
|
|
mask ().send_key (k, 0);
|
|
return TRUE;
|
|
case K_ENTER: // Selezione riga per editing
|
|
|
|
if (items () < 1) k = K_INS; // Se vuoto crea riga da editare
|
|
case K_INS:
|
|
case 'A': // Aggiunge dopo
|
|
|
|
case 'I': // Aggiunge prima
|
|
|
|
{
|
|
int n = (int)selected ();
|
|
if (k != K_ENTER)
|
|
{
|
|
if (k == K_INS) n = items ();
|
|
else // Aggiunge alla fine
|
|
|
|
if (k == 'A') n++;
|
|
|
|
if (n < 0) n = 0;
|
|
else
|
|
if (n > items ())n = items (); // Controlla range n
|
|
|
|
if (notify (n, K_INS) == FALSE) // Chiede l'ok alla applicazione
|
|
return FALSE;
|
|
|
|
insert (TToken_string (80), n); // Aggiunge una riga vuota
|
|
k = K_INS; // Inserimento in corso
|
|
}
|
|
|
|
edit (n); // Edita riga selezionata o creata
|
|
|
|
set_front_window (win ()); // Aggiorna sheet a video
|
|
open ();
|
|
}
|
|
break;
|
|
case K_TAB:
|
|
case K_BTAB:
|
|
case K_SHIFT_TAB:
|
|
dispatch_e_char (get_parent (win ()), k);
|
|
return TRUE;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return TArray_sheet ::on_key (k);
|
|
}
|
|
|
|
#endif
|
|
|
|
TMask_field * TSpreadsheet ::field (short id) const
|
|
{
|
|
const int pos = _mask.id2pos (id);
|
|
if (pos < 0) return NULL;
|
|
return &_mask.fld (pos);
|
|
}
|
|
|
|
void TSpreadsheet ::mask2str (int riga)
|
|
{
|
|
TToken_string & r = row (riga);
|
|
r.cut (0);
|
|
for (short id = FIRST_FIELD;; id++)
|
|
{
|
|
const int pos = _mask.id2pos (id);
|
|
if (pos < 0) break;
|
|
r.add (_mask.fld (pos).get ());
|
|
}
|
|
#if XVT_OS == XVT_OS_WIN
|
|
update_rec (riga);
|
|
#endif
|
|
}
|
|
|
|
// Certified 50%
|
|
void TSpreadsheet ::enable_cell (int row, int column, bool on)
|
|
{
|
|
TBit_array * ba = (TBit_array *) _disabled.objptr (row);
|
|
if (ba == NULL)
|
|
{
|
|
if (on) return; // Don't waste time and memory
|
|
ba = new TBit_array (_column_disabled);
|
|
_disabled.add (ba, row);
|
|
}
|
|
|
|
if (column >= 0)
|
|
ba->set (column, !on);
|
|
else
|
|
{
|
|
if (on)
|
|
_disabled.destroy (row, FALSE); // Let's save some memory!
|
|
else
|
|
{
|
|
#if XVT_OS == XVT_OS_WIN
|
|
ba->set (_columns); // Force right array size
|
|
#else
|
|
ba->set (32); // Force array size
|
|
#endif
|
|
ba->set (); // Set all bits
|
|
}
|
|
}
|
|
}
|
|
|
|
void TSpreadsheet ::enable_column (int col, bool on)
|
|
{
|
|
_column_disabled.set (col, !on);
|
|
}
|
|
|
|
// Certified 99%
|
|
bool TSpreadsheet ::cell_disabled (int row, int column) const
|
|
{
|
|
TBit_array * ba = (TBit_array *) _disabled.objptr (row);
|
|
if (ba == NULL) return _column_disabled[column]; // Use default
|
|
return (*ba)[column];
|
|
}
|
|
|
|
// Certified 75%
|
|
void TSpreadsheet ::str2mask (int riga)
|
|
{
|
|
if (riga == items ())
|
|
{
|
|
_mask.reset ();
|
|
mask2str (riga);
|
|
return;
|
|
}
|
|
TToken_string & r = row (riga);
|
|
r.restart ();
|
|
|
|
TString80 val;
|
|
for (short id = FIRST_FIELD;; id++)
|
|
{
|
|
int pos = _mask.id2pos (id);
|
|
if (pos < 0) break;
|
|
|
|
val = r.get (); // Value to set
|
|
|
|
int rid = id;
|
|
while (pos >= 0)
|
|
{
|
|
TMask_field & f = _mask.fld (pos);
|
|
f.set (val);
|
|
f.enable (!cell_disabled (riga, id - FIRST_FIELD));
|
|
if (f.active () || f.ghost ())
|
|
{
|
|
if (f.has_check ())f.check (STARTING_CHECK);
|
|
f.on_hit ();
|
|
}
|
|
f.set_dirty (FALSE);
|
|
|
|
rid += 100;
|
|
pos = _mask.id2pos (rid);
|
|
}
|
|
}
|
|
|
|
_mask.set_caption (format ("Riga %d", riga + 1));
|
|
}
|
|
|
|
// Certified 100%
|
|
bool TSpreadsheet ::notify (int n, KEY k)
|
|
{
|
|
return _notify ? _notify (n, k) : TRUE;
|
|
}
|
|
|
|
// Certified 99%
|
|
KEY TSpreadsheet ::edit (int n)
|
|
{
|
|
str2mask (n);
|
|
notify (n, K_SPACE); // Notifica intenzione di modificare
|
|
const KEY k = _mask.run ();
|
|
if (k == K_ENTER)
|
|
{
|
|
mask2str (n);
|
|
}
|
|
else
|
|
if (k == K_DEL)
|
|
{
|
|
const bool ok = notify (n, K_DEL); // Notifica intenzione di cancellare
|
|
if (ok)
|
|
{
|
|
destroy (n);
|
|
str2mask (n);
|
|
}
|
|
}
|
|
return k;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TSheet_field
|
|
// /////////////////////////////////////////////////////////
|
|
|
|
// Certified 100%
|
|
TSheet_field ::TSheet_field (TMask * m)
|
|
: TMask_field (m), _sheet (NULL)
|
|
{
|
|
}
|
|
|
|
// Certified 100%
|
|
word TSheet_field ::class_id ()const
|
|
{
|
|
return CLASS_SHEET_FIELD;
|
|
}
|
|
|
|
// Certified 100%
|
|
TSheet_field ::~TSheet_field ()
|
|
{
|
|
CHECK (_sheet, "Can't delete NULL sheet");
|
|
delete _sheet;
|
|
}
|
|
|
|
// Certified 100%
|
|
void TSheet_field ::reset ()
|
|
{
|
|
_sheet->destroy ();
|
|
}
|
|
|
|
void TSheet_field ::parse_head (TScanner & scanner)
|
|
{
|
|
_width = scanner.integer ();
|
|
_size = scanner.integer ();
|
|
if (_size == 0) _size = -1;
|
|
}
|
|
|
|
// Certified 100%
|
|
bool TSheet_field ::parse_item (TScanner & scanner)
|
|
{
|
|
if (scanner.key () == "IT")
|
|
{
|
|
_head.add (scanner.string ());
|
|
return TRUE;
|
|
}
|
|
return TMask_field ::parse_item (scanner);
|
|
}
|
|
|
|
// Certified 100%
|
|
void TSheet_field ::create (WINDOW parent)
|
|
{
|
|
const TMask & m = mask ();
|
|
_sheet = new TSpreadsheet (_x, _y, _width, _size, m.source_file (), m.sheets (),
|
|
_head, parent);
|
|
|
|
_win = _sheet->win ();
|
|
enable_window (_win, enabled ());
|
|
show_window (_win, showed ());
|
|
}
|
|
|
|
// Certified 100%
|
|
TArray & TSheet_field ::rows_array ()const
|
|
{
|
|
return _sheet->rows_array ();
|
|
}
|
|
|
|
// Certified 100%
|
|
// Ritorna l'indice della prima riga vuota dello sheet
|
|
int TSheet_field ::first_empty ()const
|
|
{
|
|
const int max = _sheet->items ();
|
|
for (int n = 0; n < max; n++)
|
|
if (_sheet->row (n).empty_items ())
|
|
break;
|
|
return n;
|
|
}
|
|
|
|
TToken_string & TSheet_field ::row (int n)
|
|
{
|
|
const int max = _sheet->items ();
|
|
if (n < 0 || n >= max)
|
|
{
|
|
if (n < 0) n = first_empty ();
|
|
if (n >= max) n = _sheet->add (TToken_string (80));
|
|
}
|
|
return _sheet->row (n);
|
|
}
|
|
|
|
void TSheet_field ::force_update (int r)
|
|
{
|
|
#if XVTWS == WMWS
|
|
_sheet->open ();
|
|
#else
|
|
_sheet->update (r);
|
|
#endif
|
|
}
|
|
|
|
void TSheet_field ::set_window_data (const char *)
|
|
{
|
|
_sheet->set_dirty (FALSE);
|
|
set_dirty (FALSE);
|
|
}
|
|
|
|
void TSheet_field ::set_field_data (const char *)
|
|
{
|
|
set_dirty (_sheet->dirty ());
|
|
}
|
|
|
|
int TSheet_field ::items ()const
|
|
{
|
|
return (int)_sheet->items ();
|
|
}
|
|
|
|
void TSheet_field ::set_notify (SPREADSHEET_NOTIFY n)
|
|
{
|
|
_sheet->set_notify (n);
|
|
}
|
|
|
|
void TSheet_field ::enable_column (int column, bool on)
|
|
{
|
|
_sheet->enable_column (column, on);
|
|
}
|
|
|
|
void TSheet_field ::enable_cell (int row, int column, bool on)
|
|
{
|
|
_sheet->enable_cell (row, column, on);
|
|
}
|
|
|
|
TMask & TSheet_field ::sheet_mask ()const
|
|
{
|
|
return _sheet->mask ();
|
|
}
|
|
|
|
bool TSheet_field ::on_key (KEY k)
|
|
{
|
|
if (k == K_TAB)
|
|
{
|
|
const bool spork = _sheet->dirty ();
|
|
if (spork < FALSE || spork > TRUE)
|
|
return error_box ("Tabella inconsistente: correggere i valori errati prima di uscirne");
|
|
set_dirty (spork);
|
|
}
|
|
return TMask_field ::on_key (k);
|
|
}
|