f9b938f706
controls.cpp Abbassati legermente i checkbox mask.cpp Corretto controllo sulle maschere multipagina non a tutto schermo maskfld.cpp Corretto passaggio al campo successivo doppo un tasto F9 msksheet.cpp Corretta gestione del messaggio di inizializzazione in modo da cercare di andare sempre sulla prima riga progind.cpp Corretto calcolo della percentuale (arrotondato e non troncato) relapp.h Reso pubblico il metoto TRelation_application::lnflag() const git-svn-id: svn://10.65.10.50/trunk@3573 c028cbd2-c16b-5b4b-a496-9718f37d4682
2154 lines
58 KiB
C++
Executable File
2154 lines
58 KiB
C++
Executable File
#define XI_INTERNAL
|
||
#include <xi.h>
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
#include <xiutils.h>
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#include <colors.h>
|
||
#include <controls.h>
|
||
#include <keys.h>
|
||
#include <msksheet.h>
|
||
#include <urldefid.h>
|
||
#include <utility.h>
|
||
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// TSpreadsheet
|
||
///////////////////////////////////////////////////////////
|
||
|
||
// @doc INTERNAL
|
||
|
||
// @class TSpreadsheet | Classe per la creazione di uno spreadsheet all'interno
|
||
// di una maschera
|
||
//
|
||
// @base public | TWindow
|
||
class TSpreadsheet : public TControl
|
||
{
|
||
// @author:(INTERNAL) Guido
|
||
|
||
// @cfriend TSheet_field
|
||
friend class TSheet_field;
|
||
|
||
// @access:(INTERNAL) Private Member
|
||
|
||
// @cmember:(INTERNAL) Array di TToken_strings contenenti le righe
|
||
TString_array _str;
|
||
// @cmember:(INTERNAL) Array delle colonne disattivate (solo visualizzazione)
|
||
TBit_array _column_disabled;
|
||
// @cmember:(INTERNAL) Array dell celle disattivate (solo visualizzazione)
|
||
TArray _disabled;
|
||
|
||
// @cmember:(INTERNAL) Maschera in cui e' contenuto lo spreadsheet
|
||
TMask _mask;
|
||
// @cmember:(INTERNAL) Numero di colonne presenti nello spreadsheet
|
||
int _columns;
|
||
// @cmember:(INTERNAL) Indica se e' attivo lo spreadsheet
|
||
bool _active;
|
||
|
||
// @cmember:(INTERNAL) Funzione per la gestione di una riga dello sheet (vedi <t SPREADSHEET_NOTIFY>)
|
||
SPREADSHEET_NOTIFY _notify;
|
||
|
||
// @cmember:(INTERNAL) Campo corrente che si sta editando
|
||
TOperable_field* _edit_field;
|
||
// @cmember:(INTERNAL) Coordinata della riga della cella corrente
|
||
int _cur_row;
|
||
// @cmember:(INTERNAL) Numero del record sul file al quale fa riferimento la cella corrente
|
||
int _cur_rec;
|
||
// @cmember:(INTERNAL) Coordinata della colonna della cella corrente
|
||
int _cur_col;
|
||
// @cmember:(INTERNAL) Indica se la riga corrente e' stata modificata
|
||
bool _row_dirty;
|
||
// @cmember:(INTERNAL) Indica se la cella corrente e' stata modificata
|
||
bool _cell_dirty;
|
||
// @cmember:(INTERNAL) Permette di gestire i check OFF_ROW e OFF_CELL
|
||
bool _check_enabled;
|
||
// @cmember:(INTERNAL) Numero della riga che necessita aggiornamento (vengono aggiornate
|
||
// nella <mf TSpreadsheet::on_idle>)
|
||
int _needs_update;
|
||
// @cmember:(INTERNAL) Numero della riga a cui saltare appena possibile
|
||
int _selection_posted;
|
||
|
||
// @cmember:(INTERNAL) Inizializza lo spreadsheet
|
||
void init();
|
||
// @cmember:(INTERNAL) Funzione che intercetta gli eventi dello spreadsheet
|
||
friend void XVT_CALLCONV1 xiev_handler(XI_OBJ *itf, XI_EVENT *xiev);
|
||
|
||
// @access Protected Member
|
||
protected:
|
||
//@cmember Gestisce gli eventi delle celle (chiamata dal <mf TSpreadsheet::xiev_handler>)
|
||
virtual bool event_handler(XI_OBJ* itf, XI_EVENT* xiev);
|
||
|
||
//@cmember Copia una cella nel corrispondente campo della maschera e ne ritorna il contenuto
|
||
const char* copy_cell2field(XI_OBJ* cell = NULL);
|
||
|
||
//@cmember Gestisce l'uscita delle celle (chiamata dal <mf TSpreadsheet::list_handler>)
|
||
bool off_cell_handler(XI_OBJ* cell = NULL);
|
||
|
||
// @cmember Ritorna il campo della maschera corrispondente alla cella dello
|
||
// spreadsheet indicata da <p pos>
|
||
TOperable_field* col2field(int pos) const;
|
||
// @cmember Ritorna il campo della maschera corrispondente alla cella dello
|
||
// spreadsheet indicata da <p cell> (chiama <mf TMask::col2field>)
|
||
TOperable_field* cell2field(const XI_OBJ* cell) const;
|
||
// @cmember Ritorna la posizione della colonna con identificatore <p cid>
|
||
int cid2col(short cid) const;
|
||
// @cmember Ritorna la colonna corrispondente al campo <p f> della maschera
|
||
int field2col(const TOperable_field* f) const;
|
||
|
||
// @cmember Aggiorna il record sullo spreadsheet
|
||
void update_rec(int rec);
|
||
TOperable_field* field(short id) const;
|
||
|
||
// @cmember Converte il numero del record nel corrispondente numero della riga
|
||
int rec2row(int rec);
|
||
// @cmember Converte il numero della riga nel corrispondente
|
||
// numero del record
|
||
int row2rec(int& row);
|
||
// @cmember Setta la posizione (riga e colonna) del focus sullo spreadsheet.
|
||
// Ritorna il numero del record corrente
|
||
int set_pos(int row, int col)
|
||
{ _cur_col = col; _cur_row = row; return _cur_rec = row2rec(_cur_row); }
|
||
|
||
// @cmember Chiama la funzione specificata con la <mf TSpreadsheet::set_notify>
|
||
bool notify(int row, KEY k);
|
||
// @cmember Chiama la funzione specificata con la <mf TSpreadsheet::set_notify>
|
||
// ogni volta che c'e' una modifica nello spreadsheet
|
||
void notify_change();
|
||
// @cmember Permette di fare tutti gli aggiornamenti necessari (indicati in
|
||
// <p _needs_update>)
|
||
void on_idle();
|
||
|
||
// @cmember Cerca la colonna col
|
||
XI_OBJ* find_column(int col) const;
|
||
|
||
TSheet_field& owner() const { return (TSheet_field&)*_fld; }
|
||
|
||
// @access Public Member
|
||
public:
|
||
// @cmember Modifica a video la riga
|
||
void update(int row);
|
||
// @cmember Ritorna la disabilitazione della colonna <p col>
|
||
bool column_disabled(int col) const { return _column_disabled[col]; }
|
||
|
||
// @cmember Ritorna il contenuto della riga <p n>-esima
|
||
TToken_string& row(int n)
|
||
{ return _str.row(n); }
|
||
// @cmember Aggiunge una riga allo spreadsheet passata come puntatore
|
||
// (vedi <mf TArray::add>)
|
||
int add(const TToken_string& s)
|
||
{ return _str.add(s); }
|
||
// @cmember Aggiunge una riga allo spreadsheet (vedi <mf TArray::add>)
|
||
int add(TToken_string* s)
|
||
{ return _str.add(s); }
|
||
// @cmember Inserisce un record in una posizione stabilita
|
||
int insert(int rec);
|
||
// @cmember Elimina il record <p rec>
|
||
bool destroy(int rec = -1, bool update_sheet = TRUE);
|
||
// @cmember Ritorna l'array di tutte le stringhe delle righe
|
||
TString_array& rows_array()
|
||
{ return _str; }
|
||
|
||
// @cmember Trova una colonna abilitata a partire da colonna
|
||
int find_enabled_column(int rec, int colonna, int direction) const;
|
||
// @cmember Trova un record abilitato a partire da rec
|
||
int find_enabled_record(int rec, int direction) const;
|
||
// @cmember Permette di mettere il focus su una cella
|
||
void set_focus_cell(int riga, int colonna);
|
||
// @cmember Abilita/disabilita tutto lo spreadsheet (vedi <mf TMask::activate>)
|
||
void activate(bool on);
|
||
// @cmember Permette di abilitare/disabilitare una colonna
|
||
void enable_column(int col, bool on = TRUE);
|
||
// @cmember Permette di eliminare una colonna dallo spreadsheet
|
||
void delete_column(const int col) const;
|
||
// @cmember Sposta la colonna dalla posizione <p fromindex> alla posizione
|
||
// <p toindex>
|
||
void move_column(const int fromindex, const int toindex) const;
|
||
// @cmember Permette di invertire la posizione di due colonne
|
||
void swap_columns(const int fromid, const int toid) const;
|
||
// @cmember Permette di invertire la posizione di due righe
|
||
void swap_rows(const int fromindex, const int toindex);
|
||
|
||
// @cmember Setta la larghezza della colonna
|
||
void set_column_width(const int col, const int width) const;
|
||
// @cmember Setta il titolo della colonna
|
||
void set_column_header(const int col, const TString& header) const;
|
||
// @cmember Setta l'allineamento di una colonna
|
||
void set_column_justify(int col, bool right);
|
||
// @cmember Permette di abilitare/disabilitare una singola cella
|
||
void enable_cell(int row, int column, bool on = TRUE);
|
||
// @cmember Controlla se una cella e' disabilitata
|
||
bool cell_disabled(int row, int column) const;
|
||
|
||
// @cmember Ritorna la maschera che appartiene allo spreadsheet
|
||
TMask& sheet_mask() const;
|
||
|
||
// @cmember Ritorna la maschera cui appartiene lo spreadsheet
|
||
TMask& mask() const;
|
||
|
||
// @cmember Ricopia i campi della maschera nel record <p n>-esimo ed
|
||
// aggiorna il display
|
||
void mask2str(int n);
|
||
// @cmember Ricopia i campi del record <p n>-esimo nella maschera ed
|
||
// aggiorna il display
|
||
void str2mask(int n);
|
||
// @cmember Apre la maschera della riga <p n>-esima editando la riga
|
||
KEY edit(int n);
|
||
|
||
// @cmember Ritorna il numero di righe dello sheet
|
||
int items() const
|
||
{ return _str.items(); }
|
||
// @cmember Ritorna il record corrente
|
||
int selected() const
|
||
{ return _cur_rec; }
|
||
// @cmember Seleziona una riga dandogli il focus
|
||
void select(int r, bool scrollto);
|
||
// @cmember Ritorna il numero di colonne presenti nello spreadsheet
|
||
int columns() const
|
||
{ return _columns; }
|
||
|
||
// @cmember Seleziona una riga appena possibile
|
||
void post_select(int r);
|
||
|
||
// @cmember Controlla se e' stato modificato una cella dello spreadsheet
|
||
bool dirty() const
|
||
{ return owner().dirty(); }
|
||
// @cmember Permette di indicare se e' stata modificata una cella dello spreadsheet
|
||
void set_dirty(bool spork = TRUE)
|
||
{ owner().set_dirty(spork); }
|
||
|
||
// @cmember Ritorna il valore della variabile active
|
||
bool active() const
|
||
{ return _active; }
|
||
|
||
// @cmember Ritorna se e' possibile lasciare il focus dallo spreadsheet (TRUE se e' possibile)
|
||
bool test_focus_change();
|
||
|
||
// @cmember Setta il membro <p _notify> al valore <p n>
|
||
void set_notify(SPREADSHEET_NOTIFY n)
|
||
{ _notify = n; }
|
||
|
||
// @cmember Costruttore
|
||
TSpreadsheet(WINDOW parent, short dlg, short x, short y, short dx, short dy, const char* maskname, int maskno, const char* head, TSheet_field* owner);
|
||
// @cmember Distruttore
|
||
virtual ~TSpreadsheet();
|
||
};
|
||
|
||
// @doc INTERNAL
|
||
|
||
// @mfunc Costruttore
|
||
TSpreadsheet::TSpreadsheet(
|
||
WINDOW parent, // @parm Finestra alla quale appartiene lo spreadsheet
|
||
short dlg, // @parm Identificatore del campo
|
||
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* maskname, // @parm Nome del file della maschera
|
||
int maskno, // @parm Numero identificativo della maschera nel file
|
||
const char* head, // @parm Titolo delle colonne
|
||
TSheet_field* o) // @parm Indica il campo della maschera che contiene lo spreadsheet
|
||
:
|
||
_mask(maskname, maskno), _notify(NULL),
|
||
_cur_row(0), _cur_col(1), _cur_rec(0), _edit_field(NULL), _active(TRUE),
|
||
_row_dirty(FALSE), _cell_dirty(FALSE), _check_enabled(TRUE),
|
||
_needs_update(-1), _selection_posted(-1)
|
||
{
|
||
const int NUMBER_WIDTH = 3;
|
||
const int MAX_COL = 32;
|
||
int m_width[MAX_COL], v_width[MAX_COL];
|
||
int fixed_columns = 1; // Number of fixed columns
|
||
|
||
TControl::_fld = o;
|
||
sheet_mask().set_sheet(o);
|
||
|
||
// Calcolo larghezza massima tabella
|
||
|
||
TToken_string header(head);
|
||
TToken_string new_header(256);
|
||
int i = 0, tot_width = NUMBER_WIDTH+1;
|
||
int f_width = tot_width<<1; // 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);
|
||
|
||
const int cid = FIRST_FIELD+i; // Column & Field ID
|
||
const TOperable_field* f = field(cid); // Field on mask
|
||
CHECKD(f, "The spreadsheet mask needs ALSO field ", cid);
|
||
|
||
TString testa(h);
|
||
const int at = testa.find('@');
|
||
const int m = f->size(); // Memory width
|
||
int v = m; // 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;
|
||
}
|
||
testa.cut(at);
|
||
v = max(at, v+(f->has_query_button() ? 1 : 0));
|
||
}
|
||
else
|
||
{
|
||
v = max(testa.len(), m+(f->has_query_button() ? 1 : 0));
|
||
}
|
||
if (v > 69)
|
||
v = 69;
|
||
|
||
m_width[i] = m+1; // m = number of allowed chars
|
||
v_width[i] = v+1; // v = width of column
|
||
if (v >= max_width) max_width = v+1;
|
||
|
||
tot_width += v_width[i];
|
||
|
||
new_header.add(testa);
|
||
}
|
||
_columns = i;
|
||
|
||
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, dlg,
|
||
rct.top, rct.left, rct.bottom-rct.top,
|
||
XI_ATR_ENABLED | XI_ATR_VISIBLE,
|
||
NORMAL_COLOR, NORMAL_BACK_COLOR, // normal
|
||
NORMAL_COLOR, DISABLED_BACK_COLOR, // disabled
|
||
FOCUS_COLOR, // active
|
||
0);
|
||
|
||
CHECK(listdef, "Can't create spreadsheet definition");
|
||
listdef->app_data = (long)this;
|
||
XI_LIST_DEF* l = listdef->v.list;
|
||
l->width = rct.right - rct.left;
|
||
l->min_heading_height = xi_button_calc_height_font_id(xvt_default_font());
|
||
l->sizable_columns = TRUE;
|
||
l->movable_columns = TRUE;
|
||
l->scroll_bar = TRUE;
|
||
l->scroll_bar_button = TRUE;
|
||
l->fixed_columns = fixed_columns;
|
||
l->active_back_color = FOCUS_BACK_COLOR;
|
||
l->white_space_color = MASK_DARK_COLOR;
|
||
l->rule_color = MASK_DARK_COLOR;
|
||
|
||
// Definizione della prima colonna (numero di riga)
|
||
word attr = XI_ATR_RJUST;
|
||
if (sheet_mask().id2pos(FIRST_FIELD -1) != -1)
|
||
attr |= XI_ATR_SELECTABLE;
|
||
|
||
XI_OBJ_DEF* coldef = xi_add_column_def(listdef, 0, attr, 0,
|
||
NUMBER_WIDTH * XI_FU_MULTIPLE, NUMBER_WIDTH+1,
|
||
attr & XI_ATR_SELECTABLE ? "X" : "");
|
||
|
||
coldef->app_data = (long)this;
|
||
coldef->v.column->heading_platform = TRUE;
|
||
coldef->v.column->column_platform = TRUE;
|
||
|
||
if (attr & XI_ATR_SELECTABLE)
|
||
{
|
||
coldef->v.column->icon_rid = ICO_SEARCH;
|
||
coldef->v.column->icon_x = 2;
|
||
if (listdef->v.list->min_heading_height < 20)
|
||
listdef->v.list->min_heading_height = 20;
|
||
}
|
||
else
|
||
coldef->v.column->center_heading = TRUE;
|
||
|
||
|
||
for (h = new_header.get(0), i = 0; h; h = new_header.get(), i++)
|
||
{
|
||
const TString testo(h);
|
||
const int cid = FIRST_FIELD+i; // Column & Field ID
|
||
const TOperable_field* f = field(cid); // Field on mask
|
||
const int acqua = f->class_id();
|
||
|
||
long flags = XI_ATR_EDITMENU | XI_ATR_AUTOSCROLL | XI_ATR_FOCUSBORDER;
|
||
|
||
if (AUTOSELECT)
|
||
flags |= XI_ATR_AUTOSELECT;
|
||
|
||
switch (acqua)
|
||
{
|
||
case CLASS_EDIT_FIELD:
|
||
if (f->right_justified())
|
||
flags |= XI_ATR_RJUST;
|
||
break;
|
||
case CLASS_REAL_FIELD:
|
||
flags |= XI_ATR_RJUST;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
if (f->active()) flags |= XI_ATR_ENABLED;
|
||
else _column_disabled.set(i);
|
||
|
||
coldef = xi_add_column_def(listdef, cid, flags, cid,
|
||
v_width[i] * XI_FU_MULTIPLE, m_width[i],
|
||
(char*)(const char*)testo);
|
||
|
||
coldef->app_data = (long)this;
|
||
coldef->v.column->heading_platform = TRUE;
|
||
coldef->v.column->center_heading = TRUE;
|
||
}
|
||
|
||
// Create the whole thing!
|
||
_obj = xi_create(itf, listdef);
|
||
xi_dequeue(); // Flush events in XOL
|
||
xi_tree_free(listdef); // Free definitions
|
||
|
||
CHECKD(_obj, "Can't create spreadsheet ", owner().dlg());
|
||
|
||
update_tab_cid();
|
||
}
|
||
|
||
TSpreadsheet::~TSpreadsheet()
|
||
{
|
||
}
|
||
|
||
TMask& TSpreadsheet::sheet_mask() const
|
||
{
|
||
return ((TSpreadsheet*)this)->_mask;
|
||
}
|
||
|
||
|
||
// Converts a row number in the correspondig record number
|
||
int TSpreadsheet::row2rec(int& row)
|
||
{
|
||
int rows;
|
||
const long* handle = xi_get_list_info(_obj, &rows);
|
||
|
||
if (row < 0)
|
||
row = 0;
|
||
else
|
||
{
|
||
if (row >= rows)
|
||
row = rows-1;
|
||
}
|
||
const int r = (int)handle[row];
|
||
|
||
CHECKD(r >= 0 && r < items(), "Sheet line out of range: ", row);
|
||
|
||
return r;
|
||
}
|
||
|
||
|
||
// Converts a row number in the correspondig record number
|
||
int TSpreadsheet::rec2row(int record)
|
||
{
|
||
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;
|
||
}
|
||
|
||
|
||
// Retrieves the corresponding field of the mask from a spredsheet cell
|
||
TOperable_field* TSpreadsheet::col2field(int pos) const
|
||
{
|
||
int num;
|
||
XI_OBJ** column = xi_get_member_list(_obj, &num);
|
||
CHECKD(pos >= 0 && pos < num, "Bad column number", pos);
|
||
|
||
TOperable_field* good = NULL;
|
||
for (short id = column[pos]->cid; ; id += 100)
|
||
{
|
||
TOperable_field* f = field(id);
|
||
if (f == NULL) break; // Search failed
|
||
good = f; // We've found a field with the proper ID ...
|
||
if (f->active()) break; // ... and it's active: end of search
|
||
}
|
||
|
||
CHECKD(good, "Can't find field corresponding to column ", pos);
|
||
return good;
|
||
}
|
||
|
||
|
||
// Retrieves the corresponding field of the mask from a spredsheet cell
|
||
TOperable_field* TSpreadsheet::cell2field(const XI_OBJ* cell) const
|
||
{
|
||
XI_OBJ cella;
|
||
if (cell == NULL)
|
||
{
|
||
XI_MAKE_CELL(&cella, _obj, _cur_row, _cur_col);
|
||
cell = &cella;
|
||
}
|
||
return col2field(cell->v.cell.column);
|
||
}
|
||
|
||
int TSpreadsheet::cid2col(short cid) const
|
||
{
|
||
CHECKD(cid >= FIRST_FIELD, "Bad column id ", cid);
|
||
int num;
|
||
XI_OBJ** column = xi_get_member_list(_obj, &num);
|
||
for (int c = num-1; c > 1; c--)
|
||
{
|
||
if (column[c]->cid == cid)
|
||
return c;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
int TSpreadsheet::field2col(const TOperable_field* f) const
|
||
{
|
||
const short cid = FIRST_FIELD + (f->dlg() % 100) - 1;
|
||
return cid2col(cid);
|
||
}
|
||
|
||
void TSpreadsheet::update_rec(int rec)
|
||
{
|
||
const int riga = rec2row(rec);
|
||
if (riga >= 0)
|
||
{
|
||
const bool has_focus = rec == selected() && mask().focus_field().dlg() == owner().dlg();
|
||
|
||
// if (has_focus) xi_set_focus(get_interface());
|
||
|
||
XI_OBJ row;
|
||
XI_MAKE_ROW(&row, _obj, riga);
|
||
xi_cell_request(&row); // Update internal values
|
||
|
||
if (has_focus)
|
||
{
|
||
str2mask(_cur_rec);
|
||
set_focus_cell(riga, _cur_col);
|
||
}
|
||
}
|
||
|
||
if (_needs_update == rec)
|
||
_needs_update = -1;
|
||
}
|
||
|
||
// Cerca una colonna abilitata a partire da colonna
|
||
// La prima cella utilizzabile ha indice 1
|
||
// rec e' un numero di record assoluto
|
||
// colonna e' un numero di colonna a video: puo' succedere che la 3 corrisponda al campo 107
|
||
int TSpreadsheet::find_enabled_column(int rec, int colonna, int direction) const
|
||
{
|
||
CHECKD(direction == +1 || direction == -1, "Bad column search direction", direction);
|
||
|
||
int num;
|
||
XI_OBJ** column = xi_get_member_list(_obj, &num);
|
||
if (colonna <= 0 || colonna >= num)
|
||
colonna = 1;
|
||
|
||
int c = colonna;
|
||
do
|
||
{
|
||
const short n = column[c]->cid - FIRST_FIELD;
|
||
if (!cell_disabled(rec, n))
|
||
return c;
|
||
|
||
c += direction;
|
||
if (c >= num)
|
||
c = 1;
|
||
else
|
||
if (c <= 0)
|
||
c = num-1;
|
||
}
|
||
while (c != colonna);
|
||
|
||
return 0;
|
||
}
|
||
|
||
int TSpreadsheet::find_enabled_record(int rec, int direction) const
|
||
{
|
||
for (int r = rec+direction; r >= 0 && r < items(); r += direction)
|
||
{
|
||
if (find_enabled_column(r, 1, +1) > 0)
|
||
return r;
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
// riga (da 0), colonna (0 = numero, 1 = prima cella, ...)
|
||
void TSpreadsheet::set_focus_cell(int riga, int colonna)
|
||
{
|
||
// xi_set_focus(get_interface());
|
||
|
||
const int rec = row2rec(riga);
|
||
colonna = find_enabled_column(rec, colonna, +1);
|
||
|
||
if (colonna > 0)
|
||
{
|
||
WINDOW win = xvt_scr_get_focus_vobj(); // Puo' essere NULL per cui poi non funziona ...
|
||
WINDOW par = parent(); // ... la xi_set_focus(&cell)
|
||
if (win != par)
|
||
{
|
||
xvt_scr_set_focus_vobj(par);
|
||
xvt_vobj_raise(par);
|
||
}
|
||
|
||
XI_OBJ cell;
|
||
XI_MAKE_CELL(&cell, _obj, riga, colonna);
|
||
|
||
xi_set_focus(&cell);
|
||
|
||
_edit_field = col2field(_cur_col = colonna);
|
||
if (rec != _cur_rec)
|
||
{
|
||
_cur_rec = rec;
|
||
_cur_row = riga;
|
||
/* Guy! str2mask(_cur_rec); */
|
||
_row_dirty = FALSE;
|
||
}
|
||
}
|
||
}
|
||
|
||
// @doc INTERNAL
|
||
|
||
// @mfunc Inserisce un record in una posizione stabilita
|
||
//
|
||
// @rdesc Ritorna la posizione nella quale e' stato inserito il record. Se non riesce ad inserirlo
|
||
// ritorna -1.
|
||
int TSpreadsheet::insert(
|
||
int rec) // @parm Numero del record da inserire nello spreadsheet
|
||
|
||
// @comm Non e' possibile inserire un nuovo record nel caso nello spreadsheet vi siano
|
||
// almeno 999 righe oppure se lo spreadsheet non e' attivo.
|
||
{
|
||
static bool ininsert = FALSE;
|
||
|
||
if (ininsert || items() >= 999)
|
||
return -1;
|
||
|
||
if (rec < 0 && items() > 0 && !owner().append() )
|
||
rec = _cur_rec + 1;
|
||
|
||
ininsert = TRUE;
|
||
int r = _str.insert(new TToken_string(80), rec);
|
||
|
||
const bool ok = notify(r, K_INS);
|
||
if (ok)
|
||
{
|
||
_disabled.insert(NULL, r);
|
||
xi_insert_row(_obj, INT_MAX);
|
||
xi_cell_request(_obj);
|
||
|
||
// Notifica che l'inserimento <20> terminato
|
||
notify(r, K_CTRL + K_INS);
|
||
}
|
||
else
|
||
{
|
||
_str.destroy(r);
|
||
r = -1;
|
||
}
|
||
|
||
ininsert = FALSE;
|
||
return r;
|
||
}
|
||
|
||
// @doc INTERNAL
|
||
|
||
// @mfunc Elimina una riga
|
||
//
|
||
// @rdesc Ritorna il risultato dell'operazione:
|
||
//
|
||
// @flag TRUE | Se la riga esisteve e quindi e' stata eliminata
|
||
// @flag FALSE | Se la riga non esisteve
|
||
bool TSpreadsheet::destroy(
|
||
int rec, // @parm Numero della riga da eliminare
|
||
bool update_sheet) // @parm Aggiornamento visuale dell sheet
|
||
|
||
// @comm Se il parametro <p rec> assume valore -1 vengono eliminate tutte le righe presenti
|
||
// nello spreadsheet
|
||
{
|
||
static bool indestroy = FALSE;
|
||
|
||
if ( indestroy )
|
||
return FALSE;
|
||
|
||
indestroy = TRUE;
|
||
bool ok = TRUE;
|
||
|
||
if (rec < 0)
|
||
{
|
||
_disabled.destroy();
|
||
_str.destroy();
|
||
set_dirty(_row_dirty = FALSE);
|
||
}
|
||
else
|
||
{
|
||
_disabled.destroy(rec, TRUE); // Destroy enable info
|
||
ok = _str.destroy(rec, TRUE); // Destroy line
|
||
}
|
||
|
||
if (ok && mask().is_running() && update_sheet)
|
||
update(-1);
|
||
|
||
indestroy = FALSE;
|
||
return ok;
|
||
}
|
||
|
||
// @doc INTERNAL
|
||
|
||
// @mfunc Modifica a video la riga
|
||
void TSpreadsheet::update(
|
||
int rec) // @parm Numero della riga da modificare
|
||
|
||
// @comm Se il valore di <p row> e' minore di 0 viene aggiornato l'intero spreadsheet
|
||
{
|
||
if (rec < 0)
|
||
{
|
||
// xi_cell_request(_obj); // Update cell values
|
||
|
||
int num = 0;
|
||
const long* handle = xi_get_list_info(_obj, &num);
|
||
|
||
int first = 0, last = 0;
|
||
bool scroll = items() == 0; // || !owner().mask().is_running();
|
||
if (!scroll)
|
||
{
|
||
xi_get_visible_rows(_obj, &first, &last);
|
||
scroll = items() <= handle[first];
|
||
}
|
||
|
||
if (scroll)
|
||
xi_scroll(_obj, XI_SCROLL_FIRST);
|
||
else
|
||
{
|
||
const long as = AUTOSELECT ? XI_ATR_AUTOSELECT : 0;
|
||
xi_scroll_rec(_obj, handle[first], NORMAL_COLOR, XI_ATR_ENABLED | as, 0);
|
||
}
|
||
|
||
_needs_update = -1; // Clear pending row update
|
||
}
|
||
else
|
||
update_rec(rec);
|
||
}
|
||
|
||
|
||
void TSpreadsheet::notify_change()
|
||
{
|
||
if (!_row_dirty)
|
||
{
|
||
str2mask(_cur_rec);
|
||
_edit_field = cell2field(NULL); // Ricalcola correttamente il campo corrente
|
||
|
||
notify(_cur_rec, K_SPACE);
|
||
_row_dirty = _cell_dirty = TRUE;
|
||
set_dirty();
|
||
}
|
||
}
|
||
|
||
const char* TSpreadsheet::copy_cell2field(XI_OBJ* cell)
|
||
{
|
||
const char* txt;
|
||
|
||
if (cell == NULL)
|
||
{
|
||
XI_OBJ cella;
|
||
XI_MAKE_CELL(&cella, _obj, _cur_row, _cur_col);
|
||
txt = xi_get_text(&cella, NULL, -1);
|
||
}
|
||
else
|
||
txt = xi_get_text(cell, NULL, -1);
|
||
if (_edit_field->is_editable())
|
||
{
|
||
const char* val = _edit_field->is_kind_of(CLASS_LIST_FIELD) ? txt :
|
||
(const char*)((TEditable_field*)_edit_field)->win2raw(txt);
|
||
_edit_field->set(val);
|
||
_edit_field->set_dirty(); // Get it dirty!
|
||
}
|
||
return _edit_field->get();
|
||
}
|
||
|
||
bool TSpreadsheet::off_cell_handler(XI_OBJ *cell)
|
||
{
|
||
bool ok = TRUE;
|
||
if (_edit_field != NULL)
|
||
{
|
||
const char* nuo = copy_cell2field(cell);
|
||
if (_edit_field->on_key(_edit_field->is_edit() ? K_TAB : K_SPACE) == FALSE) // Test it
|
||
ok = *nuo == '\0'; // Se e' vuoto lascia stare
|
||
else
|
||
_cell_dirty = FALSE;
|
||
if (_row_dirty)
|
||
mask2str(_cur_rec); // Update sheet row
|
||
}
|
||
return ok;
|
||
}
|
||
|
||
bool TSpreadsheet::test_focus_change()
|
||
{
|
||
bool ok = xi_move_focus(get_interface()) ? TRUE : FALSE;
|
||
return ok;
|
||
}
|
||
|
||
// Certified 75%
|
||
bool TSpreadsheet::event_handler(XI_OBJ* itf, XI_EVENT *xiev)
|
||
{
|
||
static KEY _lastab = K_TAB;
|
||
|
||
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 int rec = (int)xiev->v.cell_request.rec;
|
||
const int maxlen = xiev->v.cell_request.len;
|
||
|
||
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;
|
||
const TOperable_field* f = field(cid);
|
||
if (f->is_editable())
|
||
{
|
||
const TEditable_field* e = (const TEditable_field*)f;
|
||
src = row(rec).get(col); // Set value for cell
|
||
if (src && *src)
|
||
{
|
||
if (e->is_kind_of(CLASS_LIST_FIELD))
|
||
/* src = src */; // Leave code as is
|
||
else
|
||
src = e->raw2win(src); // Get formatted string
|
||
}
|
||
|
||
if (cell_disabled(rec, col))
|
||
{
|
||
xiev->v.cell_request.back_color = DISABLED_BACK_COLOR;
|
||
xiev->v.cell_request.attrib &= ~XI_ATR_ENABLED;
|
||
}
|
||
|
||
if (e->has_query_button())
|
||
{
|
||
xiev->v.cell_request.button = TRUE;
|
||
xiev->v.cell_request.button_on_focus = TRUE;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
src = format("%d", rec+1);
|
||
}
|
||
|
||
char* dst = xiev->v.cell_request.s;
|
||
if (src && *src)
|
||
{
|
||
strncpy(dst, src, maxlen);
|
||
dst[maxlen-1] = '\0';
|
||
}
|
||
else
|
||
*dst = '\0';
|
||
}
|
||
break;
|
||
case XIE_CHG_CELL:
|
||
if (_edit_field && !_cell_dirty)
|
||
{
|
||
notify_change();
|
||
_cell_dirty = TRUE;
|
||
_edit_field->set_dirty();
|
||
}
|
||
break;
|
||
case XIE_BUTTON:
|
||
if (_check_enabled)
|
||
{
|
||
on_idle(); // Termina tutti gli eventuali update in corso
|
||
|
||
if (xiev->v.xi_obj->type == XIT_CELL)
|
||
{
|
||
XI_CELL_DATA& cell = xiev->v.xi_obj->v.cell;
|
||
int num;
|
||
XI_OBJ** column = xi_get_member_list(_obj, &num);
|
||
CHECK(cell.column < num, "Bad column");
|
||
int rec = cell.row;
|
||
rec = row2rec(rec);
|
||
const int col = column[cell.column]->cid - FIRST_FIELD;
|
||
if (!cell_disabled(rec, col))
|
||
{
|
||
if (xi_move_focus(xiev->v.xi_obj))
|
||
dispatch_e_char(parent(), K_F9);
|
||
}
|
||
}
|
||
else
|
||
if (xiev->v.xi_obj->type == XIT_LIST)
|
||
{
|
||
owner().mask().notify_focus_field(owner().dlg());
|
||
insert(-1);
|
||
}
|
||
}
|
||
break;
|
||
case XIE_SELECT:
|
||
if (xiev->v.xi_obj->type == XIT_ROW)
|
||
{
|
||
_check_enabled = FALSE;
|
||
if (_cell_dirty)
|
||
off_cell_handler();
|
||
|
||
const int oldrec = _cur_rec;
|
||
set_pos(xiev->v.select.xi_obj->v.row, 1);
|
||
if (oldrec != _cur_rec)
|
||
{
|
||
_row_dirty = FALSE;
|
||
on_idle(); // Forces update delayed by str2mask
|
||
}
|
||
|
||
const int button_pos = sheet_mask().id2pos(FIRST_FIELD-1);
|
||
if (button_pos >= 0)
|
||
{
|
||
TMask_field& button = sheet_mask().fld(button_pos);
|
||
if (button.active())
|
||
{
|
||
str2mask(_cur_rec);
|
||
button.on_hit();
|
||
if (sheet_mask().dirty())
|
||
{
|
||
notify_change();
|
||
mask2str(_cur_rec);
|
||
}
|
||
}
|
||
}
|
||
_check_enabled = TRUE;
|
||
owner().highlight();
|
||
}
|
||
refused = TRUE;
|
||
break;
|
||
case XIE_DBL_CELL:
|
||
{
|
||
_check_enabled = FALSE;
|
||
|
||
const int oldrec = _cur_rec;
|
||
if ( xiev->v.xi_obj != NULL )
|
||
{
|
||
set_pos(xiev->v.xi_obj->v.cell.row, xiev->v.xi_obj->v.cell.column);
|
||
}
|
||
|
||
if (oldrec != _cur_rec || !_row_dirty)
|
||
{
|
||
_row_dirty = FALSE;
|
||
notify_change();
|
||
}
|
||
const KEY k = edit(_cur_rec);
|
||
if (k == K_ENTER)
|
||
{
|
||
// update_rec(_cur_rec);
|
||
_row_dirty = TRUE;
|
||
} else
|
||
if (k == K_DEL)
|
||
{
|
||
_row_dirty = _cell_dirty = FALSE;
|
||
|
||
if (_cur_rec >= items())
|
||
{
|
||
_row_dirty = _cell_dirty = FALSE;
|
||
_cur_rec = items()-1;
|
||
_cur_row = 0; _cur_col = 1;
|
||
}
|
||
if (_cur_rec >= 0 && _cur_rec < items())
|
||
set_focus_cell(_cur_row, _cur_col);
|
||
}
|
||
|
||
_check_enabled = TRUE;
|
||
}
|
||
break;
|
||
case XIE_ON_LIST:
|
||
owner().mask().notify_focus_field(owner().dlg());
|
||
break;
|
||
case XIE_OFF_LIST:
|
||
on_idle();
|
||
break;
|
||
case XIE_ON_ROW:
|
||
if (_check_enabled)
|
||
{
|
||
const int row = xiev->v.xi_obj->v.row; // Riga in cui si sta entrando
|
||
int rows; // Numero totale di righe attive
|
||
const long* handle = xi_get_list_info(_obj, &rows);
|
||
|
||
// Calcola il numero del record corrispondente alla riga
|
||
const bool exist = row >= 0 && row < rows;
|
||
int next_rec = exist ? (int)handle[row] : items()-1;
|
||
|
||
// Se la riga non esiste o non ha nessuna cella valida abilitata ...
|
||
// ... cerca la prossima riga valida e rifiuta l'ingresso in questa
|
||
if (!exist || find_enabled_column(next_rec, 1, +1) <= 0)
|
||
{
|
||
next_rec = find_enabled_record(next_rec, next_rec >= _cur_rec ? +1 : -1);
|
||
post_select(next_rec);
|
||
refused = TRUE;
|
||
break;
|
||
}
|
||
|
||
// Setta _cur_rec in base a alla riga e cella correnti
|
||
set_pos(xiev->v.xi_obj->v.row, _cur_col);
|
||
if (_cur_rec < items() && notify(_cur_rec, K_TAB))
|
||
{
|
||
/* Guy! str2mask(_cur_rec); */
|
||
_row_dirty = FALSE;
|
||
}
|
||
else
|
||
{
|
||
_cur_row = _cur_rec = 0;
|
||
refused = TRUE;
|
||
}
|
||
}
|
||
break;
|
||
case XIE_OFF_ROW:
|
||
if (_check_enabled)
|
||
{
|
||
_check_enabled = FALSE; // Avoid recursion!
|
||
if (_row_dirty && active())
|
||
{
|
||
bool ok = sheet_mask().check_fields();
|
||
if (ok)
|
||
{
|
||
mask2str(_cur_rec); // Update sheet with mask contents
|
||
ok = notify(_cur_rec, K_ENTER); // Notify edit
|
||
_row_dirty = FALSE; // Avoid double notifications!
|
||
}
|
||
if (ok)
|
||
{
|
||
xvt_statbar_refresh();
|
||
}
|
||
else
|
||
{
|
||
refused = TRUE;
|
||
}
|
||
}
|
||
if (!refused) // Notifica l'abbandono della riga
|
||
refused = !notify(_cur_rec, K_CTRL+K_TAB);
|
||
|
||
_check_enabled = TRUE;
|
||
}
|
||
break;
|
||
case XIE_ON_CELL:
|
||
if (_check_enabled)
|
||
{
|
||
TOperable_field* f = cell2field(xiev->v.xi_obj);
|
||
const int logical_column = (f->dlg()-FIRST_FIELD) % 100;
|
||
const int physical_column = xiev->v.xi_obj->v.cell.column;
|
||
if (cell_disabled(_cur_rec, logical_column)) // If the cell is disabled ...
|
||
{
|
||
const int dir = _lastab == K_TAB ? +1 : -1;
|
||
const int nex = find_enabled_column(_cur_rec, physical_column, dir);
|
||
if (nex > 0) // If at least one enabled cell exists
|
||
{
|
||
set_focus_cell(_cur_row, nex);
|
||
}
|
||
else
|
||
refused = TRUE;
|
||
}
|
||
else
|
||
{
|
||
_edit_field = f;
|
||
_cur_col = physical_column;
|
||
_edit_field->set_focusdirty(_cell_dirty = FALSE);
|
||
|
||
// Azzera il flag di update_pending
|
||
EVENT e; e.type = E_UPDATE;
|
||
xi_eh(_obj->itf->v.itf->xvt_win, &e);
|
||
}
|
||
}
|
||
break;
|
||
case XIE_OFF_CELL:
|
||
if (_edit_field && _check_enabled && _cell_dirty)
|
||
{
|
||
_check_enabled = FALSE;
|
||
XI_OBJ* cell = xiev->v.xi_obj;
|
||
refused = !off_cell_handler(cell);
|
||
_check_enabled = TRUE;
|
||
}
|
||
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_CLEANUP:
|
||
break;
|
||
case XIE_CHAR_CELL:
|
||
if (_edit_field)
|
||
{
|
||
const KEY k = xiev_to_key(xiev);
|
||
switch(k)
|
||
{
|
||
case K_F8:
|
||
case K_F9:
|
||
if (_edit_field != NULL)
|
||
{
|
||
notify_change();
|
||
copy_cell2field();
|
||
}
|
||
case K_F2:
|
||
case K_F11:
|
||
if (_check_enabled && active())
|
||
{
|
||
_check_enabled = FALSE; // Disable checks
|
||
notify_change();
|
||
bool ok = TRUE;
|
||
|
||
if (k == K_F9 && _edit_field->is_kind_of(CLASS_LIST_FIELD)) // list
|
||
{
|
||
XI_OBJ cell; XI_MAKE_CELL(&cell, _obj, _cur_row, _cur_col);
|
||
// droppa giu'
|
||
TList_field& lst = (TList_field&)(*_edit_field);
|
||
TDropDownList ddl(&cell, lst.get_codes(), lst.get_values());
|
||
ddl.open();
|
||
while (ddl.is_open())
|
||
do_events();
|
||
// sdroppa su
|
||
copy_cell2field();
|
||
}
|
||
else // edit_field
|
||
{
|
||
// Notifica il corretto campo col focus sulla maschera
|
||
sheet_mask().notify_focus_field(_edit_field->dlg());
|
||
|
||
ok = _edit_field->on_key(k);
|
||
|
||
if (!ok && k == K_F9) // Ricerca non completata?
|
||
{
|
||
_edit_field = &sheet_mask().focus_field();
|
||
const int col = field2col(_edit_field);
|
||
|
||
if (col != _cur_col) // Ricerca alternativa
|
||
{
|
||
_cur_col = col;
|
||
dispatch_e_char(parent(), K_F9);
|
||
}
|
||
}
|
||
}
|
||
if (ok)
|
||
{
|
||
mask2str(_cur_rec);
|
||
on_idle(); // Update immediately!
|
||
}
|
||
else
|
||
set_focus_cell(_cur_row, _cur_col);
|
||
|
||
_check_enabled = TRUE; // Re-enable checks
|
||
}
|
||
break;
|
||
case K_CTRL + '-':
|
||
{
|
||
if (owner().mask().id2pos(DLG_DELREC) && notify(_cur_rec, K_DEL))
|
||
{
|
||
int rec = _cur_rec;
|
||
destroy(rec);
|
||
if (rec < items())
|
||
str2mask(rec);
|
||
notify(rec, K_CTRL+K_DEL); // Notifica l'avvenuta cancellazione
|
||
if (rec >= items())
|
||
rec = items() - 1;
|
||
if (rec >= 0)
|
||
select(rec, FALSE);
|
||
}
|
||
refused = TRUE;
|
||
}
|
||
break;
|
||
case K_CTRL + '+':
|
||
owner().mask().notify_focus_field(owner().dlg());
|
||
insert(-1);
|
||
refused = TRUE;
|
||
break;
|
||
case K_CTRL+K_PREV:
|
||
xi_scroll(_obj, XI_SCROLL_PGUP);
|
||
break;
|
||
case K_CTRL+K_NEXT:
|
||
xi_scroll(_obj, XI_SCROLL_PGDOWN);
|
||
break;
|
||
case K_CTRL+K_HOME:
|
||
xi_scroll(_obj, XI_SCROLL_FIRST);
|
||
break;
|
||
case K_CTRL+K_END:
|
||
xi_scroll(_obj, XI_SCROLL_LAST);
|
||
break;
|
||
default:
|
||
if (k > K_CTRL)
|
||
{
|
||
refused = TRUE;
|
||
} else
|
||
if (is_edit_key(k) && !_edit_field->on_key(k))
|
||
{
|
||
refused = TRUE;
|
||
beep();
|
||
} else
|
||
if (_edit_field->is_kind_of(CLASS_LIST_FIELD))
|
||
{
|
||
notify_change(); // Aggiorna valore corrente listbox
|
||
|
||
TList_field& lst = ((TList_field&)*_edit_field);
|
||
bool changed = FALSE;
|
||
switch (k)
|
||
{
|
||
case K_RIGHT:
|
||
changed = lst.select_next();
|
||
break;
|
||
case K_LEFT:
|
||
changed = lst.select_prev();
|
||
break;
|
||
default:
|
||
if (k >= ' ' && k <= 'z')
|
||
changed = lst.select_by_initial(k);
|
||
break;
|
||
}
|
||
if (changed)
|
||
{
|
||
XI_OBJ cell; XI_MAKE_CELL(&cell, _obj, _cur_row, _cur_col);
|
||
xi_set_text(&cell, (char*)(const char*)lst.get());
|
||
_cell_dirty = TRUE;
|
||
}
|
||
refused = TRUE;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
case XIE_XVT_EVENT:
|
||
if (xiev->v.xvte.type == E_CHAR)
|
||
{
|
||
const KEY k = e_char_to_key(&xiev->v.xvte);
|
||
switch (k)
|
||
{
|
||
case K_ROWEDIT:
|
||
xiev->type = XIE_DBL_CELL;
|
||
xiev->v.xi_obj = NULL;
|
||
event_handler(itf, xiev);
|
||
break;
|
||
case K_TAB:
|
||
case K_BTAB:
|
||
_lastab = k;
|
||
break;
|
||
case K_UP:
|
||
case K_DOWN:
|
||
_lastab = (_cur_col == 2) ? K_BTAB : K_TAB;
|
||
break;
|
||
case K_ENTER:
|
||
case K_SHIFT+K_ENTER:
|
||
{
|
||
const int next_rec = find_enabled_record(_cur_rec, k == K_ENTER ? +1 : -1);
|
||
if (next_rec >= 0)
|
||
{
|
||
dispatch_e_char(parent(), k == K_ENTER ? K_DOWN : K_UP);
|
||
}
|
||
else
|
||
{
|
||
// if (xi_move_focus(get_interface())) // Test di uscita dalla cella corrente
|
||
// {
|
||
// xi_set_focus(_obj); // Riporta il focus sullo sheet
|
||
dispatch_e_char(parent(), k == K_ENTER ? K_F3 : K_F4);
|
||
// }
|
||
refused = TRUE;
|
||
}
|
||
}
|
||
break;
|
||
case K_ESC:
|
||
if (xi_move_focus(get_interface()))
|
||
{
|
||
owner().mask().on_key(k);
|
||
refused = TRUE;
|
||
}
|
||
break;
|
||
case K_CTRL + '-':
|
||
case K_CTRL + '+':
|
||
case K_CTRL+K_PREV:
|
||
case K_CTRL+K_NEXT:
|
||
case K_CTRL+K_HOME:
|
||
case K_CTRL+K_END:
|
||
break;
|
||
default:
|
||
if (k > K_CTRL)
|
||
{
|
||
if (xi_move_focus(get_interface()))
|
||
owner().mask().on_key(k);
|
||
refused = TRUE;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return !refused;
|
||
}
|
||
|
||
void TSpreadsheet::activate(bool on)
|
||
{
|
||
_active = on;
|
||
|
||
const dword old = xi_get_attrib(_obj);
|
||
dword att = on ? (old & ~XI_ATR_NAVIGATE) : (old | XI_ATR_NAVIGATE);
|
||
if (old != att)
|
||
{
|
||
int num;
|
||
XI_OBJ** columns = xi_get_member_list(_obj, &num);
|
||
|
||
xi_move_focus(get_interface()); // Set focus to interface
|
||
if (on)
|
||
att |= XI_ATR_TABWRAP;
|
||
else
|
||
att &= ~XI_ATR_TABWRAP;
|
||
|
||
xi_set_attrib(_obj, att);
|
||
|
||
for (int col = 1; col < num; col++)
|
||
{
|
||
XI_OBJ* column = columns[col];
|
||
att = xi_get_attrib(column);
|
||
if (on)
|
||
{
|
||
att &= ~XI_ATR_READONLY;
|
||
if (AUTOSELECT)
|
||
att |= XI_ATR_AUTOSELECT;
|
||
}
|
||
else
|
||
{
|
||
att |= XI_ATR_READONLY;
|
||
att &= ~XI_ATR_AUTOSELECT;
|
||
}
|
||
xi_set_attrib(column, att); // Set new attributes
|
||
}
|
||
}
|
||
}
|
||
|
||
void TSpreadsheet::select(int rec, bool scrollto)
|
||
{
|
||
if (!scrollto)
|
||
{
|
||
int rows;
|
||
const long* handle = xi_get_list_info(_obj, &rows);
|
||
|
||
int first = 0, last = 0;
|
||
xi_get_visible_rows(_obj, &first, &last);
|
||
|
||
scrollto = rec < handle[first] || rec > handle[last];
|
||
}
|
||
|
||
if (scrollto)
|
||
{
|
||
const long as = AUTOSELECT ? XI_ATR_AUTOSELECT : 0;
|
||
xi_scroll_rec(_obj, rec, NORMAL_COLOR, XI_ATR_ENABLED | as, 0);
|
||
}
|
||
|
||
const int row = rec2row(rec);
|
||
const bool has_focus = mask().focus_field().dlg() == owner().dlg();
|
||
if (has_focus)
|
||
{
|
||
_cur_rec = -1;
|
||
set_focus_cell(row, 1);
|
||
}
|
||
else
|
||
{
|
||
_edit_field = col2field(_cur_col = 1);
|
||
_cur_rec = rec;
|
||
_cur_row = row;
|
||
str2mask(_cur_rec);
|
||
_row_dirty = FALSE;
|
||
}
|
||
notify(rec, K_TAB);
|
||
}
|
||
|
||
void TSpreadsheet::post_select(int rec)
|
||
{
|
||
_selection_posted = rec;
|
||
}
|
||
|
||
void TSpreadsheet::on_idle()
|
||
{
|
||
if (_needs_update >= 0)
|
||
{
|
||
if (_needs_update < items())
|
||
update_rec(_needs_update);
|
||
_needs_update = -1;
|
||
}
|
||
|
||
if (_selection_posted >= 0)
|
||
{
|
||
const int next_row = _selection_posted;
|
||
_selection_posted = -1;
|
||
if (next_row < items())
|
||
select(next_row, FALSE);
|
||
}
|
||
}
|
||
|
||
// @doc INTERNAL
|
||
|
||
// @mfunc Cerca la colonna col
|
||
XI_OBJ* TSpreadsheet::find_column(
|
||
int col) const // @parm Indice o identificatore colonna
|
||
{
|
||
CHECKD(col >= 0, "Bad column ", col);
|
||
if (col < FIRST_FIELD) // Se e' un indice trasformalo in identificatore
|
||
col += FIRST_FIELD;
|
||
else
|
||
if (col >= FIRST_FIELD+100) // Riportalo nel range 101 - 199
|
||
col = FIRST_FIELD + (col % 100) -1;
|
||
|
||
int num;
|
||
XI_OBJ** columns = xi_get_member_list(_obj, &num);
|
||
for (int c = num-1; c > 0; c--)
|
||
{
|
||
if (columns[c]->cid == col)
|
||
break;
|
||
}
|
||
|
||
if (c <= 0)
|
||
{
|
||
yesnofatal_box("Can't find column with id=%d", col);
|
||
c = 1;
|
||
}
|
||
|
||
return columns[c];
|
||
}
|
||
|
||
|
||
TMask& TSpreadsheet::mask() const
|
||
{
|
||
TMask* m = (TMask*)xvt_vobj_get_data(parent());
|
||
return *m;
|
||
}
|
||
|
||
|
||
// Ritorna il campo con l'identificatore dato della maschera dello sheet
|
||
TOperable_field* TSpreadsheet::field(short id) const
|
||
{
|
||
const int pos = sheet_mask().id2pos(id);
|
||
return pos < 0 ? NULL : (TOperable_field*)&sheet_mask().fld(pos);
|
||
}
|
||
|
||
|
||
// Ricopia i campi della maschera nel record dato ed aggiorna il display
|
||
void TSpreadsheet::mask2str(int rec)
|
||
{
|
||
TToken_string& r = row(rec);
|
||
|
||
owner().mask2row(rec, r);
|
||
|
||
if (_needs_update != rec)
|
||
{
|
||
if (_needs_update >= 0)
|
||
update_rec(_needs_update); // Double update!
|
||
_needs_update = rec;
|
||
}
|
||
}
|
||
|
||
|
||
// Certified 50%
|
||
// @doc INTERNAL
|
||
|
||
// @mfunc Permette di abilitare/disabilitare una singola cella
|
||
void TSpreadsheet::enable_cell(
|
||
int row, // @parm Riga della cella da abilitare/disabilitare
|
||
int column, // @parm Colonna della cella da abilitare/disabilitare
|
||
bool on) // @parm Indica l'operazione da effettuare sulla cella:
|
||
//
|
||
// @flag TRUE | La cella viene abilitata (default)
|
||
// @flag FALSE| La cella viene disabilitata
|
||
{
|
||
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.add(ba, row);
|
||
}
|
||
|
||
if (column >= 0)
|
||
{
|
||
ba->set(column, !on);
|
||
}
|
||
else
|
||
{
|
||
if (on)
|
||
_disabled.destroy(row, FALSE); // Let's save some memory!
|
||
else
|
||
{
|
||
ba->set(_columns); // Force right array size
|
||
ba->set(); // Set all bits
|
||
}
|
||
}
|
||
}
|
||
|
||
// @doc INTERNAL
|
||
|
||
// @mfunc Permette di abilitare/disabiltare una colonna
|
||
void TSpreadsheet::enable_column(
|
||
int col, // @parm Numero della colonna da abilitare/disabilitare
|
||
bool on) // @parm Indica l'operazione da effettuare sulla colonna:
|
||
//
|
||
// @flag TRUE | Abilita la colonna (default)
|
||
// @flag FALSE| Disabilita la colonna
|
||
{
|
||
if (col >= FIRST_FIELD)
|
||
col = cid2col(col);
|
||
const bool change = _column_disabled[col] == on;
|
||
_column_disabled.set(col, !on);
|
||
|
||
if (change)
|
||
{
|
||
XI_OBJ* column = find_column(col);
|
||
dword attr = xi_get_attrib(column);
|
||
if (on) attr |= XI_ATR_ENABLED;
|
||
else attr &= ~XI_ATR_ENABLED;
|
||
|
||
xi_set_attrib(column, attr); // Set new attributes
|
||
// update(-1); // Guy: Meno andi e rivieni
|
||
}
|
||
}
|
||
|
||
void TSpreadsheet::delete_column( const int col ) const
|
||
{
|
||
XI_OBJ* column = find_column(col);
|
||
xi_delete( column );
|
||
}
|
||
|
||
|
||
void TSpreadsheet::move_column( const int fromindex, const int toindex) const
|
||
{
|
||
int num;
|
||
XI_OBJ** columns = xi_get_member_list(_obj, &num);
|
||
CHECKD(fromindex+1 < num, "Can't move column ", fromindex);
|
||
XI_OBJ* column = columns[fromindex+1];
|
||
|
||
xi_move_column( column, toindex );
|
||
}
|
||
|
||
void TSpreadsheet::swap_columns(const int fromid, const int toid) const
|
||
{
|
||
int num;
|
||
XI_OBJ** columns = xi_get_member_list(_obj, &num);
|
||
|
||
XI_OBJ* from_column = XI_NULL_OBJ;
|
||
XI_OBJ* to_column = XI_NULL_OBJ;
|
||
int from_pos = 0;
|
||
int to_pos = 0;
|
||
|
||
for (int c = num-1; c > 0; c--)
|
||
{
|
||
XI_OBJ* column = columns[c];
|
||
if (column->cid == fromid)
|
||
{
|
||
from_column = column;
|
||
from_pos = c;
|
||
}
|
||
if (column->cid == toid)
|
||
{
|
||
to_column = column;
|
||
to_pos = c;
|
||
};
|
||
}
|
||
CHECKD(from_pos, "Can't swap column ", fromid);
|
||
CHECKD(to_pos, "Can't swap column ", toid);
|
||
xi_move_column(from_column, to_pos);
|
||
xi_move_column(to_column, from_pos);
|
||
}
|
||
|
||
void TSpreadsheet::swap_rows( const int fromindex, const int toindex)
|
||
{
|
||
_str.swap(fromindex, toindex);
|
||
_disabled.swap(fromindex, toindex);
|
||
}
|
||
|
||
void TSpreadsheet::set_column_width(const int col, const int width) const
|
||
{
|
||
XI_OBJ* column = find_column(col);
|
||
xi_set_column_width(column, width); // Force redraw
|
||
}
|
||
|
||
void TSpreadsheet::set_column_header(const int col, const TString& header) const
|
||
{
|
||
XI_OBJ* column = find_column(col);
|
||
xi_set_text(column, (char *)(const char *)header );
|
||
RCT r; xi_get_rect(column, &r);
|
||
xi_set_column_width(column, (r.right-r.left+1) / CHARX); // Force redraw
|
||
}
|
||
|
||
void TSpreadsheet::set_column_justify(int col, bool right)
|
||
{
|
||
XI_OBJ* column = find_column(col);
|
||
dword attr = xi_get_attrib(column);
|
||
if (right)
|
||
attr |= XI_ATR_RJUST;
|
||
else
|
||
attr &= ~XI_ATR_RJUST;
|
||
xi_set_attrib(column, attr); // Set new attribute
|
||
update(-1);
|
||
}
|
||
|
||
// Certified 99%
|
||
// @doc INTERNAL
|
||
|
||
// @mfunc Controlla se una cella o un'intera riga e' disabilitata
|
||
//
|
||
// @rdesc Se column e' minore di zero si considera l'intera riga
|
||
// @rdesc Ritorna lo stato della cella indicata:
|
||
//
|
||
// @flag TRUE | Se la cella e' disabilitata
|
||
// @flag FALSE| Se la cella e' abilitata
|
||
bool TSpreadsheet::cell_disabled(int row, int column) const
|
||
{
|
||
TBit_array* ba = (TBit_array*)_disabled.objptr(row);
|
||
bool d;
|
||
if (column < 0)
|
||
d = (ba == NULL) ? FALSE : (ba->ones() >= columns()-1);
|
||
else
|
||
{
|
||
d = _column_disabled[column]; // Controlla la colonna
|
||
if (d == FALSE && ba != NULL) // Se la colonna e' disabilitata e' inutile proseguire
|
||
d = (*ba)[column]; // Controlla la cella
|
||
}
|
||
return d;
|
||
}
|
||
|
||
|
||
// Certified 75%
|
||
void TSpreadsheet::str2mask(int riga)
|
||
{
|
||
if (riga == items())
|
||
{
|
||
sheet_mask().reset();
|
||
mask2str(riga);
|
||
return;
|
||
}
|
||
|
||
TToken_string& r = row(riga);
|
||
|
||
owner().row2mask(riga, r);
|
||
}
|
||
|
||
|
||
// Certified 100%
|
||
bool TSpreadsheet::notify(int rec, KEY k)
|
||
{
|
||
const bool ok = _notify ? _notify(owner(), rec, k) : TRUE;
|
||
if (k == K_ENTER)
|
||
set_dirty(ok ? TRUE : 3);
|
||
return ok;
|
||
}
|
||
|
||
// Certified 99%
|
||
KEY TSpreadsheet::edit(int n)
|
||
{
|
||
str2mask(n);
|
||
KEY k = owner().run_editmask(n);
|
||
|
||
if (active())
|
||
{
|
||
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);
|
||
if (n < items())
|
||
str2mask(n);
|
||
notify(n, K_CTRL+K_DEL); // Notifica l'avvenuta cancellazione
|
||
}
|
||
}
|
||
else
|
||
if (k == K_ESC)
|
||
{
|
||
str2mask(n); // Ripristina valori precedenti
|
||
}
|
||
}
|
||
}
|
||
|
||
return k;
|
||
}
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// TSheet_field
|
||
///////////////////////////////////////////////////////////
|
||
|
||
// Certified 100%
|
||
TSheet_field::TSheet_field(TMask* m)
|
||
: TOperable_field(m), _append(TRUE)
|
||
{ }
|
||
|
||
// Certified 100%
|
||
word TSheet_field::class_id() const
|
||
{
|
||
return CLASS_SHEET_FIELD;
|
||
}
|
||
|
||
bool TSheet_field::is_kind_of(word cid) const
|
||
{ return cid == CLASS_SHEET_FIELD || TOperable_field::is_kind_of(cid); }
|
||
|
||
// Certified 100%
|
||
TSheet_field::~TSheet_field()
|
||
{
|
||
}
|
||
|
||
// Certified 100%
|
||
void TSheet_field::reset()
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->destroy();
|
||
s->sheet_mask().reset();
|
||
set_dirty(); // Reset any error (dirty = 3)
|
||
set_dirty(mask().is_running()); // Set dirty state based on mask status
|
||
force_update();
|
||
}
|
||
|
||
// Certified 100%
|
||
void TSheet_field::destroy(int r, bool update_sheet)
|
||
{
|
||
((TSpreadsheet*)_ctl)->destroy(r, update_sheet);
|
||
}
|
||
|
||
void TSheet_field::parse_head(TScanner& scanner)
|
||
{
|
||
_ctl_data._width = scanner.integer();
|
||
_ctl_data._height = scanner.integer();
|
||
if (_ctl_data._height == 0)
|
||
_ctl_data._height = -1;
|
||
}
|
||
|
||
|
||
// Certified 100%
|
||
bool TSheet_field::parse_item(TScanner& scanner)
|
||
{
|
||
if (scanner.key() == "IT")
|
||
{
|
||
_ctl_data._park.add(scanner.string());
|
||
return TRUE;
|
||
}
|
||
return TMask_field::parse_item(scanner);
|
||
}
|
||
|
||
// Certified 100%
|
||
void TSheet_field::create(WINDOW parent)
|
||
{
|
||
const TMask& m = mask();
|
||
const TString head(_ctl_data._park);
|
||
_ctl = new TSpreadsheet(parent, dlg(), _ctl_data._x, _ctl_data._y, _ctl_data._width, _ctl_data._height,
|
||
m.source_file(), m.sheets(), head, this);
|
||
|
||
_ctl->show(shown());
|
||
if (!_flags.enable_default)
|
||
{
|
||
_flags.enabled = TRUE; // Lo sheet e' sempre operabile anche se non editabile
|
||
disable();
|
||
}
|
||
}
|
||
|
||
|
||
// Certified 100%
|
||
TString_array& TSheet_field::rows_array() const
|
||
{
|
||
return ((TSpreadsheet*)_ctl)->rows_array();
|
||
}
|
||
|
||
|
||
// Certified 100%
|
||
// Ritorna l'indice della prima riga vuota dello sheet
|
||
int TSheet_field::first_empty() const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
const int max = (int)s->items();
|
||
for (int n = 0; n < max; n++)
|
||
if (s->row(n).empty_items())
|
||
break;
|
||
return n;
|
||
}
|
||
|
||
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Ritorna nuova riga dello spreadshhet
|
||
//
|
||
// @rdesc Ritorna la stringa letta
|
||
TToken_string& TSheet_field::row(
|
||
int n) // @parm Numero della riga da leggere/creare
|
||
|
||
// @comm Se il parametro <p n> e maggiore del numero massimo di righe presenti
|
||
// o minore di 0 viene aggiunta una riga vuota in fondo allo spreadsheet
|
||
// (viene chiamata la <mf TSpreadsheet::add>)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
const int max = (int)s->items();
|
||
if (n < 0 || n >= max)
|
||
{
|
||
if (n < 0) n = first_empty();
|
||
if (n >= max)
|
||
n = (int)s->add(new TToken_string(80));
|
||
}
|
||
return s->row(n);
|
||
}
|
||
|
||
// @doc EXTERNAL
|
||
|
||
// @mfunc Forza l'aggiornamento dei dati della riga sullo schermo
|
||
void TSheet_field::force_update(
|
||
int r) // @parm Numero della riga da aggiornare
|
||
|
||
// @comm Se il parametro <p r> assume valore -1 vengono aggiornate tutte le righe presenti
|
||
// nello spreadsheet
|
||
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->update(r);
|
||
}
|
||
|
||
int TSheet_field::items() const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
return (int)s->items();
|
||
}
|
||
|
||
int TSheet_field::selected() const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
return (int)s->selected();
|
||
}
|
||
|
||
void TSheet_field::set_notify(SPREADSHEET_NOTIFY n)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->set_notify(n);
|
||
}
|
||
|
||
// Certified 50%
|
||
void TSheet_field::highlight() const
|
||
{
|
||
// TEditable_field::highlight();
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
if (s->_check_enabled)
|
||
{
|
||
int rows; xi_get_list_info(s->_obj, &rows);
|
||
if (rows > 0)
|
||
{
|
||
if (s->notify(s->_cur_rec, K_TAB))
|
||
{
|
||
s->set_focus_cell(s->_cur_row, s->_cur_col);
|
||
s->str2mask(selected());
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void TSheet_field::enable(bool on)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->activate(on);
|
||
}
|
||
|
||
bool TSheet_field::enabled() const
|
||
{
|
||
return items() > 0;
|
||
}
|
||
|
||
void TSheet_field::enable_column(int column, bool on)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->enable_column(column, on);
|
||
}
|
||
|
||
|
||
void TSheet_field::enable_cell(int row, int column, bool on)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->enable_cell(row, column, on);
|
||
}
|
||
|
||
bool TSheet_field::cell_disabled(int row, int column) const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
return s->cell_disabled(row, column);
|
||
}
|
||
|
||
// Matteo
|
||
void TSheet_field::delete_column( const int col ) const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->delete_column( col );
|
||
}
|
||
|
||
void TSheet_field::move_column( const int fromindex, const int toindex ) const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->move_column(fromindex, toindex);
|
||
}
|
||
|
||
void TSheet_field::swap_columns(const int fromid, const int toid) const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->swap_columns(fromid, toid);
|
||
}
|
||
|
||
void TSheet_field::swap_rows( const int fromindex, const int toindex)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->swap_rows(fromindex, toindex);
|
||
}
|
||
|
||
void TSheet_field::set_column_width( const int col, const int width ) const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->set_column_width(col, width);
|
||
}
|
||
|
||
void TSheet_field::set_column_header( const int col, const TString& header ) const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->set_column_header(col, header);
|
||
}
|
||
|
||
void TSheet_field::set_column_justify(int col, bool right)
|
||
{
|
||
if (col < FIRST_FIELD)
|
||
col += FIRST_FIELD;
|
||
sheet_mask().field(col).set_justify(right);
|
||
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->set_column_justify(col, right);
|
||
}
|
||
|
||
TMask& TSheet_field::sheet_mask() const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
return s->sheet_mask();
|
||
}
|
||
|
||
bool TSheet_field::on_hit()
|
||
{
|
||
if (!mask().is_running()) // Inizializzazione maschera
|
||
{
|
||
force_update();
|
||
|
||
mask().notify_focus_field(dlg()); // Fa' credere alla maschera che ha il focus ...
|
||
select(0); // ... cosi' la set_focus_cell funziona bene
|
||
|
||
set_dirty(FALSE);
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
void TSheet_field::select(int r, bool scrollto)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->select(r, scrollto);
|
||
}
|
||
|
||
bool TSheet_field::on_key(KEY k)
|
||
{
|
||
if (k == K_TAB && items() > 0)
|
||
{
|
||
if (focusdirty())
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
if (!s->test_focus_change())
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
if (k == K_ROWEDIT && items() > 0)
|
||
{
|
||
select(items()-1);
|
||
XI_EVENT xie;
|
||
xie.type = XIE_DBL_CELL;
|
||
xie.v.xi_obj = NULL;
|
||
_ctl->event_handler(NULL, &xie);
|
||
return TRUE;
|
||
}
|
||
|
||
return TOperable_field::on_key(k);
|
||
}
|
||
|
||
void TSheet_field::on_idle()
|
||
{
|
||
((TSpreadsheet*)_ctl)->on_idle();
|
||
}
|
||
|
||
void TSheet_field::exchange(bool show_value, const real& nuo)
|
||
{
|
||
TMask& m = sheet_mask();
|
||
|
||
const real& vec = mask().exchange();
|
||
|
||
if (vec != nuo)
|
||
{
|
||
TBit_array valuta(32);
|
||
int i = 0;
|
||
for (int f = FIRST_FIELD; ;f++, i++)
|
||
{
|
||
const int pos = m.id2pos(f);
|
||
if (pos < 0) break;
|
||
if (m.fld(pos).class_id() == CLASS_REAL_FIELD)
|
||
{
|
||
if (m.fld(pos).exchangeable())
|
||
valuta.set(i);
|
||
}
|
||
}
|
||
|
||
for (int riga = 0; riga < items(); riga++)
|
||
{
|
||
TToken_string& r = row(riga);
|
||
for (const char* s = r.get(i = 0); s; s = r.get(++i))
|
||
if (*s > ' ' && valuta[i])
|
||
{
|
||
real v(s);
|
||
v *= nuo;
|
||
v /= vec;
|
||
v.round();
|
||
r.add(v.string(), i);
|
||
}
|
||
}
|
||
}
|
||
|
||
m.set_exchange(show_value, nuo);
|
||
|
||
if (mask().is_running())
|
||
force_update();
|
||
}
|
||
|
||
// Ricopia i campi della maschera nel record dato
|
||
void TSheet_field::mask2row(int n, TToken_string & rec)
|
||
{
|
||
const TMask& m = TSheet_field::sheet_mask();
|
||
|
||
rec.cut(0);
|
||
const TSpreadsheet& s = (const TSpreadsheet&)*_ctl;
|
||
|
||
for (short id = FIRST_FIELD; ; id++)
|
||
{
|
||
int pos = m.id2pos(id);
|
||
if (pos < 0) break;
|
||
|
||
for(int dlg = id; pos >= 0; pos = m.id2pos(dlg += 100))
|
||
{
|
||
const TMask_field& f = m.fld(pos);
|
||
if (f.shown() || f.ghost())
|
||
{
|
||
rec.add(f.get());
|
||
if (s.active())
|
||
{
|
||
const int col = id-FIRST_FIELD;
|
||
|
||
if (!s.column_disabled(col))
|
||
{
|
||
const bool on = f.enabled();
|
||
enable_cell(n, col, on);
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
if (pos < 0)
|
||
{
|
||
#ifdef DBG
|
||
if (s.cid2col(id) > 0)
|
||
yesnofatal_box("Mask2str: Non e' visibile il campo %d", dlg);
|
||
#endif
|
||
rec.add(" ");
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// Ricopia i campi del record dato nella maschera
|
||
void TSheet_field::row2mask(int n, TToken_string & r)
|
||
{
|
||
TString val(80);
|
||
|
||
TMask& m = TSheet_field::sheet_mask();
|
||
const int campi = m.fields();
|
||
const TSpreadsheet& s = (const TSpreadsheet&)*_ctl;
|
||
|
||
for (int i = 0; i < campi; i++)
|
||
{
|
||
TMask_field& f = m.fld(i);
|
||
const short id = f.dlg();
|
||
if (id >= FIRST_FIELD)
|
||
{
|
||
const int index = (id % 100)-1;
|
||
val = r.get(index);
|
||
f.set(val);
|
||
const bool on = s.active() && !cell_disabled(n, index);
|
||
if (f.enabled() != on)
|
||
f.enable(on);
|
||
}
|
||
}
|
||
|
||
for (i = 0; i < campi; i++)
|
||
{
|
||
TMask_field& f = m.fld(i);
|
||
const short id = f.dlg();
|
||
if (id >= FIRST_FIELD &&
|
||
!f.is_kind_of(CLASS_BUTTON_FIELD) &&
|
||
(f.active() || f.ghost()))
|
||
{
|
||
if (f.has_check())
|
||
f.check(STARTING_CHECK);
|
||
f.set_dirty(FALSE);
|
||
f.on_hit();
|
||
}
|
||
}
|
||
|
||
for (i = 0; i < campi; i++)
|
||
{
|
||
TMask_field& f = m.fld(i);
|
||
const short id = f.dlg();
|
||
if (id > FIRST_FIELD)
|
||
{
|
||
if (f.dirty() == TRUE)
|
||
f.set_dirty(FALSE);
|
||
}
|
||
}
|
||
|
||
val.format("Riga %d", n+1);
|
||
m.set_caption(val);
|
||
}
|
||
|