Files correlati : ve0.exe ve0300a.ini ve0100a.msk ve0200g.msk ve1300.alx ve1.exe ve17001.rep ve17002.rep ve1700a.msk ve1700a.msk ve2.exe ve6.exe ve61000a.msk ve17001.rep ve17002.rep ve17002.rep ve17001.rep ve1700a.msk ve6b00a.msk MODIFICHE CRPA Se si mette il flag P sulla data documento della maschera di un tipo documento viene proposta l’ultima data inserita. Possibilità di impostare il numero di copie nell’inserimento/modifica di un documento. Righe documento massime 10000 Aggiunta ricerca per riferimento cliente (ricerca alternativa). Aggiunto indirizzo cliente/fornitore sulla ricerca documenti. Lista documenti avanzata (report). Aggiunte le regolarizzazioni nella contabilizzazione documenti Sistema abilitazione della data registrazione in contabilizzazione documenti Aggiunta la possibilità di usare campi del documento nella dicitura del riferimento. Gestiti i movimenti di sola iva in contabilizzazione. Riferimento per mese nelle partite. Ordinamento per documento nell’evasione ordini con un flag in configurazione Impostato il tipo CF in base al tipo documento Aggiunto il messaggio cliente alla stampa report delle vendite git-svn-id: svn://10.65.10.50/branches/R_10_00@24025 c028cbd2-c16b-5b4b-a496-9718f37d4682
4109 lines
112 KiB
C++
Executable File
4109 lines
112 KiB
C++
Executable File
#define XI_INTERNAL
|
||
#include <xinclude.h>
|
||
|
||
extern "C"
|
||
{
|
||
#include <xiutils.h>
|
||
}
|
||
|
||
#include <colors.h>
|
||
#include <config.h>
|
||
#include <controls.h>
|
||
#include <currency.h>
|
||
#include <diction.h>
|
||
#include <msksheet.h>
|
||
#include <recarray.h>
|
||
#include <recset.h>
|
||
#include <relation.h>
|
||
#include <urldefid.h>
|
||
#include <utility.h>
|
||
|
||
class TCell_property : public TObject
|
||
{
|
||
COLOR _back, _fore;
|
||
|
||
public:
|
||
void set(COLOR back, COLOR fore) { _back = back; _fore = fore; }
|
||
bool get(COLOR& back, COLOR& fore) const;
|
||
|
||
virtual TCell_property & copy(const TCell_property & p);
|
||
virtual TObject* dup() const { return new TCell_property(*this); }
|
||
|
||
TCell_property(const TCell_property & p);
|
||
TCell_property();
|
||
};
|
||
|
||
bool TCell_property::get(COLOR& back, COLOR& fore) const
|
||
{
|
||
if (_back != COLOR_INVALID && _fore != COLOR_INVALID)
|
||
{
|
||
back = _back;
|
||
fore = _fore;
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
TCell_property & TCell_property::copy(const TCell_property & p)
|
||
{
|
||
_back = p._back;
|
||
_fore = p._fore;
|
||
return *this;
|
||
}
|
||
|
||
TCell_property::TCell_property(const TCell_property & p)
|
||
{
|
||
copy
|
||
(p);
|
||
}
|
||
|
||
TCell_property::TCell_property() : _back(COLOR_INVALID), _fore(COLOR_INVALID)
|
||
{ }
|
||
|
||
class TRow_property : public TObject
|
||
{
|
||
TBit_array _disabled;
|
||
COLOR _back, _fore;
|
||
int _height;
|
||
TArray * _cell_prop;
|
||
|
||
public:
|
||
void set(int col, COLOR back, COLOR fore);
|
||
bool get(int col, COLOR & back, COLOR & fore) const;
|
||
|
||
void set_height(int h) { _height = h; }
|
||
int height() const { return _height; }
|
||
|
||
TBit_array & disabled() { return _disabled;}
|
||
const TBit_array & disabled() const { return _disabled;}
|
||
|
||
virtual TRow_property & copy(const TRow_property & r);
|
||
virtual TObject* dup() const { return new TRow_property(*this); }
|
||
|
||
TRow_property(const TRow_property & p);
|
||
TRow_property();
|
||
virtual ~TRow_property() { }
|
||
};
|
||
|
||
TRow_property & TRow_property::copy(const TRow_property & p)
|
||
{
|
||
_disabled = p._disabled;
|
||
_back = p._back;
|
||
_fore = p._fore;
|
||
_height = p._height;
|
||
if (p._cell_prop != NULL)
|
||
_cell_prop = new TArray(*p._cell_prop);
|
||
else
|
||
_cell_prop = NULL;
|
||
return *this;
|
||
}
|
||
|
||
TRow_property::TRow_property(const TRow_property & p)
|
||
{
|
||
copy(p);
|
||
}
|
||
|
||
TRow_property::TRow_property()
|
||
: _back(COLOR_INVALID), _fore(COLOR_INVALID), _height(-1), _cell_prop(NULL)
|
||
{ }
|
||
|
||
void TRow_property::set(int col, COLOR back, COLOR fore)
|
||
{
|
||
if (col < 0)
|
||
{
|
||
_back = back;
|
||
_fore = fore;
|
||
if (_cell_prop != NULL)
|
||
{
|
||
delete _cell_prop;
|
||
_cell_prop = NULL;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (_cell_prop == NULL)
|
||
_cell_prop = new TArray;
|
||
|
||
TCell_property* p = (TCell_property*)_cell_prop->objptr(col);
|
||
|
||
if (back == COLOR_INVALID || fore == COLOR_INVALID)
|
||
{
|
||
if (p != NULL)
|
||
_cell_prop->destroy(col);
|
||
}
|
||
else
|
||
{
|
||
if (p == NULL)
|
||
{
|
||
p = new TCell_property;
|
||
_cell_prop->add(p, col);
|
||
}
|
||
p->set(back, fore);
|
||
}
|
||
}
|
||
}
|
||
|
||
bool TRow_property::get(int col, COLOR & back, COLOR & fore) const
|
||
{
|
||
if (col >= 0) // Lascia stare la colonna del numero riga
|
||
{
|
||
if (_cell_prop != NULL)
|
||
{
|
||
const TCell_property* cp = (const TCell_property*)_cell_prop->objptr(col);
|
||
if (cp != NULL && cp->get(back, fore))
|
||
return true;
|
||
}
|
||
if (_back != COLOR_INVALID && _fore != COLOR_INVALID)
|
||
{
|
||
back = _back;
|
||
fore = _fore;
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// 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) costanti
|
||
enum { MAX_COL=96 };
|
||
static int ROW_NUMBER_WIDTH;
|
||
|
||
// @cmember:(INTERNAL) Array di TToken_strings contenenti le righe
|
||
TString_array _str;
|
||
// @cmember:(INTERNAL) Array di TToken_strings contenenti le righe copiate
|
||
TString_array _copied_rows;
|
||
// @cmember:(INTERNAL) Array delle colonne disattivate (solo visualizzazione)
|
||
TBit_array _column_disabled;
|
||
|
||
// @cmember:(INTERNAL) righe selezionate
|
||
int _from;
|
||
int _to;
|
||
|
||
// @cmember:(INTERNAL) Array delle proprieta' delle righe
|
||
TArray _properties;
|
||
TArray * _saved_properties;
|
||
|
||
// @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) Indica se e' attivo l'auto append
|
||
bool _auto_append;
|
||
// @cmember:(INTERNAL) Identificatore della prima colonna di navigazione
|
||
short _first_nav_column_id;
|
||
// @cmember:(INTERNAL) Identificatore dell' ultima colonna di navigazione
|
||
short _last_nav_column_id;
|
||
|
||
// @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;
|
||
clock_t _ignore_button;
|
||
|
||
// @cmember:(INTERNAL) Dimensioni delle colonne
|
||
int _default_width[MAX_COL];
|
||
// @cmember:(INTERNAL) Bisogna salvare l'ordine delle colonne
|
||
byte _save_columns_order;
|
||
|
||
// @cmember:(INTERNAL) Campo corrente che si sta editando
|
||
TOperable_field* _f9_target;
|
||
|
||
// @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);
|
||
|
||
virtual void set_read_only(bool ro) { activate(!ro); }
|
||
virtual bool read_only() const { return !_active; }
|
||
virtual void set_rect(const RCT& r) { xi_set_rect(_obj, (XI_RCT*)&r, true); }
|
||
KEY barcode_newline() const;
|
||
|
||
//@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 Controlla se esiste il campo della maschera corrispondente alla cella dello
|
||
// spreadsheet indicata da <p pos>
|
||
TOperable_field* test_field(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 logica con identificatore <p cid>
|
||
int cid2index(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 le proprieta' della riga r e volendo le crea pure
|
||
TRow_property* get_property(int r, bool create = false);
|
||
|
||
TSheet_field& owner() const { return (TSheet_field&)*_fld; }
|
||
// @cmember Cerca la colonna col
|
||
XI_OBJ* find_column(int col) const;
|
||
|
||
// @access Public Member
|
||
public:
|
||
// @cmember Restituisce il numero di colonna corrente
|
||
const int cur_column() const { return _cur_col; }
|
||
// @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 l' abilitazione della colonna <p col>
|
||
bool column_enabled(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
|
||
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, bool update_sheet, bool call_notify);
|
||
// @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
|
||
bool 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 visualizzare/nascondere una colonna
|
||
void show_column(int col, bool on = true);
|
||
// @cmember Permette di eliminare una colonna dallo spreadsheet
|
||
void delete_column(const int col) const;
|
||
// @cmember Permette di attivare/ disattivare l'auto append
|
||
void set_auto_append(bool on) { _auto_append = on;}
|
||
// @cmember Permette di attivare la navigazione tra due colonne con invio
|
||
void set_nav_column(short firstcol, short lastcol) { _first_nav_column_id = firstcol; _last_nav_column_id = lastcol; }
|
||
// @cmember Permette di testare l'auto append
|
||
bool auto_append() const { return _auto_append;}
|
||
bool exist_column(const int col) const { return find_column(col) != NULL; }
|
||
// @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 Sposta la riga fromindex alla posizione toindex
|
||
void move_row(const int fromindex, const int toindex);
|
||
|
||
|
||
// @cmember L'utente ha salvato la disposizione delle colonne?
|
||
bool user_saved_columns_order() const;
|
||
// @cmember Salva la disposizione delle colonne
|
||
void save_columns_order() const;
|
||
// @cmember Salva la disposizione delle colonne
|
||
void load_columns_order();
|
||
// @cmember Setta la disposizione delle colonne
|
||
void set_columns_order();
|
||
// @cmember Setta la disposizione delle colonne
|
||
void set_columns_order(TToken_string* order);
|
||
|
||
static int set_line_number_width(int digits);
|
||
// @cmember Setta la larghezza della colonna
|
||
void set_column_width(const int col, const int width) const;
|
||
// @cmember Aggiorna la larghezza di default della colonna
|
||
void update_column_default_width(const int col) const;
|
||
// @cmember Setta il titolo della colonna
|
||
void set_column_header(const int col, const TString& header) const;
|
||
// @cmember Getta il titolo della colonna
|
||
const char* get_column_header(const int col) const;
|
||
// @cmember Setta l'allineamento di una colonna
|
||
void set_column_justify(int col, bool right);
|
||
// @cmember Setta l'altezza della riga
|
||
void set_row_height(const int row, const int height);
|
||
// @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 Setta i colori di una riga
|
||
void set_back_and_fore_color(COLOR back, COLOR fore, int row, int col);
|
||
// @cmember Legge i colori di una riga
|
||
bool get_back_and_fore_color(COLOR& back, COLOR& fore, int row, int col);
|
||
|
||
// @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 row, bool scrollto) { select(row, -1, scrollto); }
|
||
// @cmember Seleziona una riga e una colonna dandogli il focus
|
||
void select(int row, int col, 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
|
||
byte dirty() const { return owner().dirty(); }
|
||
// @cmember Permette di indicare se e' stata modificata una cella dello spreadsheet
|
||
void set_dirty(byte spork = true) { owner().set_dirty(spork); _row_dirty = _cell_dirty = spork!=0; }
|
||
|
||
// @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 aggiunge una riga
|
||
bool add_row_auto();
|
||
bool error_box(const char* msg);
|
||
|
||
bool point2cell(const PNT& pnt, short& id, long& row) const;
|
||
|
||
bool get_range_selection(int & from, int & to) const ;
|
||
void clear_range_selection();
|
||
void select_range(int row);
|
||
void copy_rows();
|
||
void paste_rows();
|
||
|
||
// @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();
|
||
};
|
||
|
||
int TSpreadsheet::ROW_NUMBER_WIDTH = 3;
|
||
|
||
KEY TSpreadsheet::barcode_newline() const
|
||
{
|
||
static KEY _barcode_newline = ini_get_int(CONFIG_INSTALL, "Main", "BarcodeNewline");
|
||
return _barcode_newline;
|
||
}
|
||
|
||
// @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(), _active(true), _notify(NULL),
|
||
_edit_field(NULL), _cur_row(0), _cur_rec(0), _cur_col(1),
|
||
_row_dirty(false), _cell_dirty(false), _check_enabled(true),
|
||
_needs_update(-1), _selection_posted(-1), _ignore_button(0), _save_columns_order(false),
|
||
_f9_target(NULL), _auto_append(false), _first_nav_column_id(-1), _last_nav_column_id(-1),
|
||
_from(-1), _to(-1), _saved_properties(NULL)
|
||
{
|
||
int m_width[MAX_COL], v_width[MAX_COL];
|
||
int fixed_cols = 0; // Number of fixed columns
|
||
int lines_in_header = 1; // Number of header lines
|
||
|
||
TControl::_fld = o;
|
||
_mask.set_sheet(o); // Collega la maschera allo sheet
|
||
_mask.read_mask(maskname, maskno, 0); // Legge la maschera
|
||
|
||
// Calcolo larghezza massima tabella
|
||
TToken_string header(head);
|
||
TToken_string new_header(256);
|
||
int i = 0, tot_width = ROW_NUMBER_WIDTH+1;
|
||
int max_width = tot_width<<1; // Stima larghezza della colonna piu' grande
|
||
unsigned char f_width[MAX_COL]; // Larghezza colonne fisse
|
||
const char * h;
|
||
|
||
for (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 = (TOperable_field &) _mask.field(cid); // Field on mask
|
||
|
||
TString testa(h);
|
||
|
||
char* t = testa.get_buffer();
|
||
for (int c = 0; t[c]; c++)
|
||
{
|
||
if (t[c] == '\\' && (t[c+1] == 'n' || t[c+1] == 'r'))
|
||
{
|
||
t[c] = '\n';
|
||
strcpy(t+c+1, t+c+2);
|
||
lines_in_header = 2;
|
||
}
|
||
}
|
||
|
||
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 (v == 0)
|
||
v = m;
|
||
if (f.has_query_button())
|
||
v++;
|
||
if (wi.find('F') >= 0)
|
||
{
|
||
f_width[fixed_cols] = v+1;
|
||
fixed_cols++;
|
||
}
|
||
testa.cut(at);
|
||
}
|
||
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;
|
||
|
||
XI_OBJ* itf = get_interface(parent);
|
||
XI_RCT rct = coord2rct(itf, x, y, dx, dy);
|
||
|
||
if (x > 0 && dx < 0)
|
||
{
|
||
RCT max_rct; xvt_vobj_get_client_rect((WINDOW)xi_get_window(itf), &max_rct);
|
||
const short MAXX = max_rct.right;
|
||
|
||
if (MAXX > 80 * CHARX)
|
||
rct.left += (MAXX - 80 * CHARX) / 2;
|
||
}
|
||
rct.right -= 2*XI_FU_MULTIPLE; // toglie scroll-bar
|
||
|
||
// Controlla se posso bloccare anche questa colonna
|
||
int f_totwidth=4+3;
|
||
for (int fc = 0; fc < fixed_cols; fc ++)
|
||
{
|
||
f_totwidth += f_width[fc];
|
||
if ((f_totwidth+max_width)*XI_FU_MULTIPLE >= rct.right)
|
||
{
|
||
fixed_cols = fc;
|
||
break;
|
||
}
|
||
}
|
||
|
||
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(xi_get_system_font()) * lines_in_header;
|
||
l->sizable_columns = true;
|
||
l->movable_columns = true;
|
||
l->scroll_bar = true;
|
||
l->scroll_bar_button = true;
|
||
l->fixed_columns = fixed_cols+1;
|
||
l->active_back_color = FOCUS_BACK_COLOR;
|
||
l->white_space_color = MASK_DARK_COLOR;
|
||
l->rule_color = MASK_DARK_COLOR;
|
||
#ifdef LINUX
|
||
l->scroll_on_thumb_track = true;
|
||
#endif
|
||
|
||
// Definizione della prima colonna (numero di riga)
|
||
word attr = XI_ATR_RJUST;
|
||
if (sheet_mask().id2pos(FIRST_FIELD-1) >= 0)
|
||
attr |= XI_ATR_SELECTABLE;
|
||
|
||
XI_OBJ_DEF* coldef = xi_add_column_def(listdef, 0, attr, 0,
|
||
ROW_NUMBER_WIDTH * XI_FU_MULTIPLE, ROW_NUMBER_WIDTH+1,
|
||
(char *)((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 = -4; // l'icona e' 32x32 ma e' disegnata solo al centro
|
||
coldef->v.column->icon_y = -8;
|
||
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 = (const TOperable_field &)_mask.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:
|
||
case CLASS_CURRENCY_FIELD:
|
||
flags |= XI_ATR_RJUST;
|
||
break;
|
||
case CLASS_BOOLEAN_FIELD:
|
||
flags |= XI_ATR_SELECTABLE;
|
||
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;
|
||
if (flags & XI_ATR_SELECTABLE)
|
||
coldef->v.column->icon_mode = XIM_ICON_HAS_PRIORITY;
|
||
|
||
if (l->max_lines_in_cell > 1 && acqua == CLASS_EDIT_FIELD && v_width[i] > 20)
|
||
coldef->v.column->wrap_text = 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();
|
||
|
||
int num;
|
||
XI_OBJ** column = xi_get_member_list(_obj, &num);
|
||
memset(_default_width, 0, sizeof(_default_width));
|
||
for (i = 0; i < num; i++)
|
||
{
|
||
XI_RCT rct; xi_get_rect(column[i], &rct);
|
||
_default_width[i] = rct.right - rct.left;
|
||
}
|
||
}
|
||
|
||
TSpreadsheet::~TSpreadsheet()
|
||
{
|
||
if (_saved_properties != NULL)
|
||
delete _saved_properties;
|
||
}
|
||
|
||
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 (rows <= 0)
|
||
return -1; // Empty sheet
|
||
|
||
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::test_field(int pos) const
|
||
{
|
||
TOperable_field* good = NULL;
|
||
if (pos > 0)
|
||
{
|
||
int num;
|
||
XI_OBJ** column = xi_get_member_list(_obj, &num);
|
||
CHECKD(pos >= 0 && pos < num, "Bad column number", pos);
|
||
|
||
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
|
||
}
|
||
}
|
||
else
|
||
good = field(DLG_USER);
|
||
|
||
return good;
|
||
}
|
||
|
||
// Retrieves the corresponding field of the mask from a spredsheet cell
|
||
TOperable_field* TSpreadsheet::col2field(int pos) const
|
||
{
|
||
TOperable_field* good = test_field(pos);
|
||
|
||
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 > 0; c--)
|
||
{
|
||
if (column[c]->cid == cid)
|
||
return c;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
int TSpreadsheet::cid2index(short cid) const
|
||
{
|
||
CHECKD(cid >= FIRST_FIELD, "Bad column id ", cid);
|
||
return (cid % 100) - 1;
|
||
}
|
||
|
||
int TSpreadsheet::field2col(const TOperable_field* f) const
|
||
{
|
||
const short cid = FIRST_FIELD + cid2index(f->dlg());
|
||
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);
|
||
|
||
const TRow_property* prop = ((TSpreadsheet*)this)->get_property(rec);
|
||
if (prop != NULL && prop->height() == 0)
|
||
return 0;
|
||
|
||
int num = 0;
|
||
XI_OBJ** column = xi_get_member_list(_obj, &num);
|
||
|
||
if (num > 1)
|
||
{
|
||
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, ...)
|
||
bool TSpreadsheet::set_focus_cell(int riga, int colonna)
|
||
{
|
||
// xi_set_focus(get_interface());
|
||
|
||
const int rec = row2rec(riga);
|
||
if (rec < 0 || rec >= items())
|
||
return false;
|
||
|
||
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);
|
||
|
||
if (rec != _cur_rec)
|
||
{
|
||
_cur_rec = rec;
|
||
_cur_row = riga;
|
||
_row_dirty = false;
|
||
}
|
||
_edit_field = col2field(_cur_col = colonna); // qui
|
||
}
|
||
|
||
return colonna > 0;
|
||
}
|
||
|
||
// @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
|
||
bool update_sheet, // @parm Chiama cell request
|
||
bool call_notify) // @parm Chiama funzione di notify
|
||
|
||
// @comm Non e' possibile inserire un nuovo record nel caso nello spreadsheet vi siano
|
||
// almeno 9999 righe oppure se lo spreadsheet non e' attivo.
|
||
{
|
||
static bool ininsert = false;
|
||
|
||
// TMask & m = owner().mask(); verificare
|
||
if (ininsert || items() >= 9999)
|
||
return -1;
|
||
|
||
ininsert = true;
|
||
int r = rec < 0 ? items() : rec;
|
||
|
||
bool ok = call_notify ? notify(r, K_INS) : true;
|
||
|
||
if (ok)
|
||
{
|
||
TToken_string* toktok = new TToken_string(80, owner().separator());
|
||
r = _str.insert(toktok, rec);
|
||
|
||
_properties.insert(NULL, r, true); // Crea lo spazio necessario per le proprieta'
|
||
|
||
// Notifica che l'inserimento e' terminato
|
||
owner().post_insert(r);
|
||
|
||
xi_insert_row(_obj, INT_MAX);
|
||
|
||
if (call_notify)
|
||
notify(r, K_CTRL + K_INS);
|
||
|
||
if (update_sheet)
|
||
{
|
||
xi_cell_request(_obj);
|
||
if (_selection_posted < 0)
|
||
post_select(r);
|
||
}
|
||
}
|
||
else
|
||
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)
|
||
{
|
||
_str.destroy();
|
||
_properties.destroy();
|
||
set_dirty(_row_dirty = false);
|
||
}
|
||
else
|
||
{
|
||
_properties.destroy(rec, true); // Destroy line 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)
|
||
{
|
||
|
||
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 (_cur_rec >= 0)
|
||
{
|
||
if (!_row_dirty)
|
||
{
|
||
str2mask(_cur_rec);
|
||
_edit_field = cell2field(NULL); // Ricalcola correttamente il campo corrente
|
||
|
||
notify(_cur_rec, K_SPACE);
|
||
xvtil_statbar_refresh();
|
||
set_dirty();
|
||
}
|
||
_row_dirty = _cell_dirty = true; // Era tra le graffe
|
||
}
|
||
}
|
||
|
||
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())
|
||
{
|
||
if (_edit_field->class_id() == CLASS_ZOOM_FIELD)
|
||
_edit_field->set(row(_cur_rec).get(cid2index(_edit_field->dlg())));
|
||
const char* val = (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)
|
||
{
|
||
owner().mask().notify_focus_field(id()); // A volte si diverte a perdere il focus
|
||
mask2str(_cur_rec); // Update sheet row
|
||
}
|
||
}
|
||
return ok;
|
||
}
|
||
|
||
bool TSpreadsheet::test_focus_change()
|
||
{
|
||
bool ok = true;
|
||
if (_cell_dirty)
|
||
ok = off_cell_handler();
|
||
if (ok)
|
||
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; verificare
|
||
static clock_t digit_timer = 0;
|
||
|
||
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;
|
||
const TRow_property* prop = get_property(0);
|
||
if (prop != NULL && prop->height() >= 0)
|
||
xiev->v.rec_request.row_height = prop->height();
|
||
}
|
||
else
|
||
refused = true;
|
||
break;
|
||
case XIE_GET_LAST:
|
||
{
|
||
xiev->v.rec_request.data_rec = items()-1;
|
||
const TRow_property* prop = get_property(xiev->v.rec_request.data_rec);
|
||
if (prop != NULL && prop->height() >= 0)
|
||
xiev->v.rec_request.row_height = prop->height();
|
||
}
|
||
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;
|
||
const TRow_property* prop = get_property(n);
|
||
if (prop != NULL && prop->height() >= 0)
|
||
xiev->v.rec_request.row_height = prop->height();
|
||
}
|
||
}
|
||
break;
|
||
case XIE_CELL_REQUEST:
|
||
{
|
||
const long& rec = xiev->v.cell_request.rec;
|
||
const short& maxlen = xiev->v.cell_request.len;
|
||
if (rec < 0 || rec >= items() || maxlen <= 0) // Puo' succedere: strano ma vero!
|
||
{
|
||
refused = true;
|
||
return false;
|
||
}
|
||
|
||
const char* src = NULL;
|
||
int nm;
|
||
XI_OBJ** obj = xi_get_member_list(xiev->v.cell_request.list, &nm);
|
||
const short& 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 int curr = _cur_rec;
|
||
_cur_rec = rec; // Memorizzo il record corrente per calcolare il campo correttamente
|
||
const TOperable_field* f = field(cid);
|
||
_cur_rec = curr; // Lo ripristino dopo il calcolo
|
||
if (f != NULL && f->is_editable())
|
||
{
|
||
const TEditable_field* e = (const TEditable_field*)f;
|
||
TToken_string& rowrec = row(rec);
|
||
src = rowrec.get(col); // Set value for cell
|
||
if (src && *src)
|
||
{
|
||
switch (e->class_id())
|
||
{
|
||
case CLASS_LIST_FIELD:
|
||
{
|
||
const TList_field& lst = *(TList_field*)f;
|
||
TToken_string codes = lst.get_codes();
|
||
TToken_string values = lst.get_values();
|
||
src = xvtil_get_cell_selection(obj[num], codes.get_pos(src), codes, values);
|
||
}
|
||
break;
|
||
case CLASS_BOOLEAN_FIELD:
|
||
if (*src <= ' ')
|
||
xiev->v.cell_request.icon_rid = ICO_CHECK_OFF;
|
||
else
|
||
xiev->v.cell_request.icon_rid = ICO_CHECK_ON;
|
||
break;
|
||
case CLASS_CURRENCY_FIELD:
|
||
if (e->driver(0))
|
||
{
|
||
TOperable_field* driver = e->driver(0);
|
||
if (driver->parent() == e->parent())
|
||
{
|
||
const real r(src); // Memorizzo valore numerico
|
||
const int pos = driver->dlg() - FIRST_FIELD;
|
||
const TString4 codval = rowrec.get(pos); // Codice valuta
|
||
const TCurrency c(r, codval, ZERO, e->uppercase());
|
||
src = c.string(true);
|
||
break;
|
||
}
|
||
}
|
||
//Fall down as usual
|
||
default:
|
||
src = e->raw2win(src); // Get formatted string
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (e->class_id() == CLASS_BOOLEAN_FIELD)
|
||
xiev->v.cell_request.icon_rid = ICO_CHECK_OFF;
|
||
}
|
||
|
||
if (cell_disabled(rec, col))
|
||
{
|
||
xiev->v.cell_request.back_color = DISABLED_BACK_COLOR;
|
||
xiev->v.cell_request.color = DISABLED_COLOR;
|
||
xiev->v.cell_request.attrib &= ~XI_ATR_ENABLED;
|
||
}
|
||
else
|
||
{
|
||
// Non impostare il colore per la cella correntemente col focus
|
||
if (rec != _cur_rec || num != _cur_col)
|
||
{
|
||
if (f->required())
|
||
xiev->v.cell_request.back_color = REQUIRED_BACK_COLOR;
|
||
else
|
||
get_back_and_fore_color(xiev->v.cell_request.back_color,
|
||
xiev->v.cell_request.color, rec, col);
|
||
}
|
||
|
||
if (e->has_query_button()) // Metto il bottone sulle celle attive
|
||
{
|
||
xiev->v.cell_request.button = true;
|
||
xiev->v.cell_request.button_on_focus = true;
|
||
// Imposto l'icona della lente per ricerche normali/customizzate sui campi testo
|
||
if (e->is_edit())
|
||
xiev->v.cell_request.button_icon_rid = ICO_SEARCH;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
xiev->v.cell_request.back_color = DISABLED_BACK_COLOR;
|
||
xiev->v.cell_request.color = DISABLED_COLOR;
|
||
xiev->v.cell_request.attrib &= ~XI_ATR_ENABLED;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
xiev->v.cell_request.color = COLOR_BLACK; // Ignored :-(
|
||
src = format("%d", rec+1); // Numero riga
|
||
}
|
||
|
||
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)
|
||
{
|
||
if (active())
|
||
{
|
||
notify_change();
|
||
_cell_dirty = true;
|
||
_edit_field->set_dirty();
|
||
}
|
||
else
|
||
refused = true;
|
||
}
|
||
break;
|
||
case XIE_BUTTON:
|
||
if (_check_enabled)
|
||
{
|
||
if (xiev->v.xi_obj->type == XIT_CELL) // Bottone della cella
|
||
{
|
||
on_idle(); // Termina tutti gli eventuali update in corso
|
||
|
||
const 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 row = cell.row;
|
||
const int rec = row2rec(row);
|
||
const int col = column[cell.column]->cid - FIRST_FIELD;
|
||
if (!cell_disabled(rec, col))
|
||
{
|
||
if (xi_move_focus(xiev->v.xi_obj))
|
||
{
|
||
if (clock() > _ignore_button)
|
||
dispatch_e_char(parent(), K_F9);
|
||
_ignore_button = 0;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
add_row_auto();
|
||
}
|
||
break;
|
||
case XIE_SELECT:
|
||
if (xiev->v.xi_obj->type == XIT_ROW)
|
||
{
|
||
_check_enabled = false;
|
||
refused = true;
|
||
|
||
if (!test_focus_change())
|
||
break;
|
||
|
||
TOperable_field* f = test_field(xiev->v.select.column);
|
||
if (f == NULL)
|
||
break; //se clicco su una cella non associata ad un campo esce
|
||
|
||
const int oldrec = _cur_rec;
|
||
const int record = set_pos(xiev->v.select.xi_obj->v.row, _cur_col);
|
||
if (oldrec != _cur_rec)
|
||
{
|
||
_row_dirty = _cell_dirty = false;
|
||
|
||
on_idle(); // Forces update delayed by str2mask
|
||
_cur_rec = record; // Forces correct record (may be changed by on_idle!)
|
||
notify(_cur_rec, K_TAB);
|
||
const int riga = xiev->v.select.xi_obj->v.row;
|
||
const int colonna = find_enabled_column(_cur_rec, 1, +1);
|
||
//set_pos(riga, colonna);
|
||
set_focus_cell(riga, colonna);
|
||
}
|
||
|
||
if (xiev->v.select.column > 0)
|
||
{
|
||
if (!cell_disabled(record, cid2index(f->dlg())) && active())
|
||
{
|
||
notify_change();
|
||
if (f->get().blank())
|
||
f->set("X");
|
||
else
|
||
f->set("");
|
||
f->on_key(K_SPACE);
|
||
mask2str(_cur_rec);
|
||
on_idle();
|
||
_cell_dirty = false; // Non e' necessario lasciare dirty la cella in quanto mask2str e' gia' fatta
|
||
}
|
||
}
|
||
else
|
||
{
|
||
TMask& sm = owner().sheet_mask();
|
||
const int button_pos = sm.id2pos(FIRST_FIELD-1);
|
||
if (button_pos >= 0)
|
||
{
|
||
TMask_field& button = sm.fld(button_pos);
|
||
if (button.active())
|
||
{
|
||
button.disable(); // Impedisce che un doppio click indesiderato abbia effetto
|
||
if (!_row_dirty)
|
||
{
|
||
notify_change();
|
||
_row_dirty = _cell_dirty = false;
|
||
FOR_EACH_MASK_FIELD(sm, i, fld)
|
||
fld->set_dirty(false);
|
||
}
|
||
button.on_hit();
|
||
if (sm.dirty())
|
||
{
|
||
_row_dirty = true;
|
||
mask2str(_cur_rec);
|
||
}
|
||
button.enable();
|
||
}
|
||
owner().highlight();
|
||
}
|
||
}
|
||
_check_enabled = true;
|
||
}
|
||
break;
|
||
case XIE_DBL_CELL:
|
||
if (!_cell_dirty || off_cell_handler())
|
||
{
|
||
_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);
|
||
const XI_CELL_DATA& cell = xiev->v.xi_obj->v.cell;
|
||
const bool ok = set_focus_cell(cell.row, cell.column);
|
||
if (!ok)
|
||
{
|
||
_check_enabled = true;
|
||
refused = true;
|
||
return false;
|
||
}
|
||
}
|
||
|
||
if (oldrec != _cur_rec || !_row_dirty)
|
||
{
|
||
_row_dirty = false;
|
||
notify_change();
|
||
_cell_dirty = false;
|
||
}
|
||
const KEY k = edit(_cur_rec);
|
||
if (k == K_ENTER)
|
||
_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);
|
||
}
|
||
else
|
||
if (k == K_ESC)
|
||
{
|
||
XI_OBJ row;
|
||
XI_MAKE_ROW(&row, _obj, _cur_row);
|
||
xi_cell_request(&row);
|
||
}
|
||
_check_enabled = true;
|
||
}
|
||
break;
|
||
case XIE_ON_LIST:
|
||
owner().mask().notify_focus_field(id());
|
||
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;
|
||
}
|
||
|
||
if (ENTER_AS_TAB && _first_nav_column_id > 0)
|
||
{
|
||
const int fcol = cid2col(_first_nav_column_id);
|
||
const int lcol = cid2col(_last_nav_column_id);
|
||
const int mcol = min(fcol, lcol);
|
||
|
||
if (_cur_col != mcol)
|
||
{
|
||
_cur_col = mcol;
|
||
set_focus_cell(xiev->v.xi_obj->v.row, _cur_col);
|
||
}
|
||
}
|
||
|
||
// 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 = _cell_dirty = false;
|
||
_ignore_button = clock()+250; // Ignora i click sui bottoni (invisibili) per un quarto di secondo
|
||
}
|
||
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 = owner().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)
|
||
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)
|
||
{
|
||
const int physical_column = xiev->v.xi_obj->v.cell.column;
|
||
TOperable_field* f = test_field(physical_column);
|
||
bool disabled = true;
|
||
if (f)
|
||
{
|
||
const int logical_column = (f->dlg()-FIRST_FIELD) % 100;
|
||
disabled = cell_disabled(_cur_rec, logical_column); // If the cell is disabled ...
|
||
}
|
||
if (disabled)
|
||
{
|
||
const int dir = physical_column >= _cur_col ? +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);
|
||
refused = true;
|
||
}
|
||
else
|
||
{
|
||
_edit_field = f;
|
||
_cur_col = physical_column;
|
||
_edit_field->set_focusdirty(_cell_dirty = false);
|
||
|
||
// Azzera il flag di update_pending
|
||
//#ifdef XI_R4
|
||
XinEvent e; e.type = XinEventPaint;
|
||
xi_eh(_obj->itf->v.itf->xin_win, &e);
|
||
/*
|
||
#else
|
||
EVENT e; e.type = E_UPDATE;
|
||
xi_eh(_obj->itf->v.itf->xvt_win, &e);
|
||
#endif
|
||
*/
|
||
owner().mask().notify_focus_field(id()); // Non si ripete mai abbastanza!
|
||
}
|
||
XI_OBJ row;
|
||
|
||
XI_MAKE_ROW(&row, _obj, _cur_row);
|
||
xi_cell_request(&row); // Update internal values
|
||
}
|
||
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;
|
||
}
|
||
if (! refused)
|
||
{
|
||
const int col = _cur_col;
|
||
_cur_col = -1;
|
||
XI_OBJ row; XI_MAKE_ROW(&row, _obj, _cur_row);
|
||
xi_cell_request(&row); // Update internal values
|
||
_cur_col = col;
|
||
}
|
||
break;
|
||
case XIE_COL_MOVE:
|
||
if (xiev->v.column.in_fixed ||
|
||
xiev->v.column.col_nbr < xi_get_fixed_columns(xiev->v.column.list))
|
||
refused = true;
|
||
else
|
||
_save_columns_order = true;
|
||
break;
|
||
case XIE_COL_SIZE:
|
||
_save_columns_order = 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)
|
||
{
|
||
KEY k = xiev_to_key(xiev);
|
||
|
||
if (xvt_chr_is_alnum(k))
|
||
digit_timer = clock();
|
||
else
|
||
{
|
||
if (k == barcode_newline())
|
||
{
|
||
const clock_t delay = clock() - digit_timer;
|
||
if (delay <= 60)
|
||
k = K_CTRL + '+'; // impedisce ulteriori elaborazioni
|
||
}
|
||
}
|
||
|
||
switch(k)
|
||
{
|
||
case K_F2:
|
||
_cell_dirty = true;
|
||
case K_F8:
|
||
case K_F9:
|
||
if (_f9_target != NULL)
|
||
{
|
||
_edit_field = _f9_target;
|
||
_f9_target = NULL;
|
||
}
|
||
if (_edit_field != NULL)
|
||
{
|
||
const bool spork = _edit_field->dirty() != 0; // TBT
|
||
|
||
notify_change();
|
||
//gestione campi che non appaiono nello sheet ma che possono essere usati nelle ricerche
|
||
//es: per evitare di avere il valore della prima colonna in una descrizione che si puo' usere..
|
||
//..per le ricerche, ma che non appare nello sheet (es. ca2100a.uml)
|
||
if (cid2index(_edit_field->dlg()) == 0 || _cur_col > 0)
|
||
copy_cell2field();
|
||
|
||
_edit_field->set_dirty(_cell_dirty = spork); // TBT
|
||
}
|
||
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 or radio
|
||
{
|
||
XI_OBJ cell; XI_MAKE_CELL(&cell, _obj, _cur_row, _cur_col);
|
||
const TList_field& lst = (const TList_field&)(*_edit_field);
|
||
const int sel = xvtil_drop_down_list(&cell, lst.get_codes(), lst.get_values());
|
||
if (sel >= 0)
|
||
copy_cell2field(&cell);
|
||
_ignore_button = clock() + 250;
|
||
}
|
||
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);
|
||
_cell_dirty = _edit_field->dirty() != 0; // TBT
|
||
|
||
_f9_target = NULL;
|
||
if (!ok && k == K_F9) // Ricerca non completata?
|
||
{
|
||
TOperable_field* target = &owner().sheet_mask().focus_field();
|
||
if (_edit_field != target) // Ricerca alternativa
|
||
{
|
||
_f9_target = target;
|
||
_cur_col = field2col(_f9_target);
|
||
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 + '-': // ********* delete line
|
||
if (_check_enabled)
|
||
{
|
||
_check_enabled = false; // Disable checks
|
||
notify_change();
|
||
if (sheet_mask().id2pos(DLG_DELREC)>=0 &&
|
||
sheet_mask().field(DLG_DELREC).enabled() &&
|
||
notify(_cur_rec, K_DEL))
|
||
{
|
||
int rec = _cur_rec;
|
||
_row_dirty = _cell_dirty = false;
|
||
destroy(rec);
|
||
if (rec < items())
|
||
str2mask(rec);
|
||
notify(rec, K_CTRL+K_DEL); // Notifica l'avvenuta cancellazione
|
||
set_dirty(); // Setta il flag sheet modificato
|
||
_row_dirty = _cell_dirty = false; // Resetta i flag di modifica appena settati di riflesso
|
||
if (rec >= items())
|
||
rec = items() - 1;
|
||
if (rec >= 0)
|
||
select(rec, false);
|
||
}
|
||
refused = true;
|
||
_check_enabled = true; // Re-enable checks
|
||
}
|
||
break;
|
||
case K_CTRL + '+': // ********* insert line
|
||
add_row_auto();
|
||
refused = true;
|
||
break;
|
||
case K_CTRL + 'A':
|
||
{
|
||
_check_enabled = false;
|
||
if (_cell_dirty)
|
||
off_cell_handler();
|
||
notify_change(); // CM500244
|
||
const KEY k = edit(_cur_rec);
|
||
if (k == K_ENTER)
|
||
_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);
|
||
}
|
||
else
|
||
if (k == K_ESC)
|
||
{
|
||
XI_OBJ row;
|
||
XI_MAKE_ROW(&row, _obj, _cur_row);
|
||
xi_cell_request(&row);
|
||
}
|
||
_check_enabled = true;
|
||
refused = true;
|
||
}
|
||
break;
|
||
case K_CTRL + 'B':
|
||
{
|
||
_check_enabled = false;
|
||
if (_cell_dirty)
|
||
off_cell_handler();
|
||
|
||
const int button_pos = sheet_mask().id2pos(FIRST_FIELD-1);
|
||
if (button_pos >= 0)
|
||
{
|
||
TMask & sm = owner().sheet_mask();
|
||
TMask_field& button = sm.fld(button_pos);
|
||
if (button.active())
|
||
{
|
||
notify_change();
|
||
button.on_hit();
|
||
if (sm.dirty())
|
||
mask2str(_cur_rec);
|
||
}
|
||
}
|
||
_check_enabled = true;
|
||
owner().highlight();
|
||
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 (_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 : changed = (k >= ' ' && k <= 'z') && lst.select_by_initial(char(k)); break;
|
||
}
|
||
if (changed)
|
||
{
|
||
XI_OBJ cell; XI_MAKE_CELL(&cell, _obj, _cur_row, _cur_col);
|
||
xi_set_text(&cell, (char*)lst.raw2win(lst.get()));
|
||
_cell_dirty = true;
|
||
}
|
||
refused = true;
|
||
} else
|
||
if (is_edit_key(k))
|
||
{
|
||
if (AUTOZOOM)
|
||
{
|
||
if ((_edit_field->class_id() == CLASS_ZOOM_FIELD))
|
||
copy_cell2field();
|
||
}
|
||
|
||
if (!_edit_field->on_key(k))
|
||
{
|
||
refused = true;
|
||
beep();
|
||
}
|
||
}
|
||
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_DOWN:
|
||
if (_auto_append && _cur_rec == items() - 1)
|
||
add_row_auto();
|
||
else
|
||
{
|
||
// Azzero il flag di pending paint che impedisce la navigazione!
|
||
XinEvent e; e.type = XinEventPaint;
|
||
xi_eh(_obj->itf->v.itf->xin_win, &e);
|
||
}
|
||
break;
|
||
case K_ROWEDIT:
|
||
xiev->type = XIE_DBL_CELL;
|
||
xiev->v.xi_obj = NULL;
|
||
event_handler(itf, xiev);
|
||
break;
|
||
case K_ENTER:
|
||
case K_SHIFT+K_ENTER:
|
||
{
|
||
const int dir = k == K_ENTER ? +1 : -1;
|
||
|
||
if (ENTER_AS_TAB)
|
||
{
|
||
int next_col = find_enabled_column(_cur_rec, _cur_col+dir, dir);
|
||
|
||
while (next_col > 0 && col2field(next_col)->is_kind_of(CLASS_BOOLEAN_FIELD))
|
||
next_col = find_enabled_column(_cur_rec, next_col+dir, dir);
|
||
if (_first_nav_column_id > 0)
|
||
{
|
||
const int fcol = cid2col(_first_nav_column_id);
|
||
const int lcol = cid2col(_last_nav_column_id);
|
||
|
||
if (k == K_ENTER)
|
||
{
|
||
const int mcol = max(fcol, lcol);
|
||
|
||
if (next_col > mcol)
|
||
next_col = -1;
|
||
}
|
||
else
|
||
{
|
||
const int mcol = min(fcol, lcol);
|
||
|
||
if (next_col < mcol)
|
||
next_col = _cur_col + 1;
|
||
}
|
||
}
|
||
if (next_col != 0 && next_col != _cur_col && ((next_col>_cur_col)^(dir < 0)))
|
||
{
|
||
dispatch_e_char(parent(), k == K_ENTER ? K_TAB : K_BTAB);
|
||
refused = true;
|
||
}
|
||
}
|
||
if (!refused)
|
||
{
|
||
if (ENTER_AS_TAB && _first_nav_column_id > 0)
|
||
{
|
||
const int fcol = cid2col(_first_nav_column_id);
|
||
const int lcol = cid2col(_last_nav_column_id);
|
||
|
||
_cur_col = min(fcol, lcol);
|
||
}
|
||
if (_auto_append && k == K_ENTER && _cur_rec == items() - 1)
|
||
{
|
||
dispatch_e_char(parent(), K_DOWN);
|
||
refused = true;
|
||
}
|
||
else
|
||
{
|
||
const int next_rec = find_enabled_record(_cur_rec, dir);
|
||
|
||
if (next_rec >= 0)
|
||
{
|
||
dispatch_e_char(parent(), K_TAB);
|
||
dispatch_e_char(parent(), k == K_ENTER ? K_DOWN : K_UP);
|
||
refused = true;
|
||
}
|
||
else
|
||
{
|
||
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 + 'A':
|
||
case K_CTRL + 'B':
|
||
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, int col, bool scrollto)
|
||
{
|
||
if (col <= 0)
|
||
{
|
||
if (col < -1) //ciapino per far funzionare ve0
|
||
_cur_col = find_enabled_column(rec, 1, +1);
|
||
col = _cur_col;
|
||
}
|
||
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, col);
|
||
}
|
||
else
|
||
{
|
||
_cur_col = find_enabled_column(rec, 1, +1);
|
||
_cur_rec = rec;
|
||
_cur_row = row;
|
||
_edit_field = _cur_col > 0 ? test_field(_cur_col) : NULL;
|
||
|
||
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 == _cur_rec)
|
||
// return ;
|
||
if (next_row < items())
|
||
select(next_row, 1, 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 + cid2index(col);
|
||
|
||
int num;
|
||
XI_OBJ** columns = xi_get_member_list(_obj, &num);
|
||
int c;
|
||
for (c = num-1; c >= 0; c--)
|
||
{
|
||
if (columns[c]->cid == col)
|
||
break;
|
||
}
|
||
return c >= 0 ? columns[c] : NULL;
|
||
}
|
||
|
||
|
||
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 TMask & sm = owner().sheet_mask();
|
||
const int pos = sm.id2pos(id);
|
||
return pos < 0 ? NULL : (TOperable_field*)&sm.fld(pos);
|
||
}
|
||
|
||
|
||
// Ricopia i campi della maschera nel record dato ed aggiorna il display
|
||
void TSpreadsheet::mask2str(int rec)
|
||
{
|
||
if (rec >= 0 && rec < items())
|
||
{
|
||
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 (-1=tutta la riga)
|
||
bool on) // @parm Indica l'operazione da effettuare sulla cella:
|
||
//
|
||
// @flag true | La cella viene abilitata (default)
|
||
// @flag false| La cella viene disabilitata
|
||
{
|
||
if (column >= FIRST_FIELD)
|
||
column = cid2index(column);
|
||
|
||
TRow_property* prop = get_property(row);
|
||
if (prop == NULL)
|
||
{
|
||
if (on) return; // Don't waste time and memory
|
||
prop = get_property(row, true);
|
||
}
|
||
|
||
TBit_array& ba = prop->disabled();
|
||
if (column >= 0)
|
||
{
|
||
ba.set(column, !on);
|
||
}
|
||
else
|
||
{
|
||
if (on)
|
||
ba.reset();
|
||
else
|
||
{
|
||
ba.set(_columns); // Force right array size
|
||
ba.set(); // Set all bits
|
||
}
|
||
}
|
||
}
|
||
|
||
void TSpreadsheet::set_back_and_fore_color(COLOR back, COLOR fore, int row, int col)
|
||
{
|
||
if (col >= FIRST_FIELD)
|
||
col = cid2index(col);
|
||
|
||
int first, last;
|
||
if (row < 0)
|
||
{
|
||
first = 0;
|
||
last = items()-1;
|
||
}
|
||
else
|
||
first = last = row;
|
||
|
||
if (col < 0 && same_color(back, NORMAL_BACK_COLOR) && same_color(fore, NORMAL_COLOR))
|
||
back = fore = COLOR_INVALID;
|
||
|
||
const bool crea = back != COLOR_INVALID && fore != COLOR_INVALID;
|
||
CHECK(!((back==COLOR_INVALID)^(fore== COLOR_INVALID)), "Coppia di colori mal assortita");
|
||
for (int r = first; r <= last; r++)
|
||
{
|
||
TRow_property* prop = get_property(r, crea);
|
||
if (prop)
|
||
prop->set(col, back, fore);
|
||
}
|
||
if (row < 0)
|
||
{
|
||
TRow_property* prop = get_property(row, true);
|
||
prop->set(col, back, fore);
|
||
}
|
||
}
|
||
|
||
bool TSpreadsheet::get_back_and_fore_color(COLOR& back, COLOR& fore, int row, int col)
|
||
{
|
||
TRow_property* prop = get_property(row, false);
|
||
if (prop == NULL)
|
||
prop = get_property(-1, false);
|
||
if (prop != NULL)
|
||
return prop->get(col, back, fore);
|
||
return false;
|
||
}
|
||
|
||
// @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 = cid2index(col);
|
||
|
||
const bool change = _column_disabled[col] == on;
|
||
_column_disabled.set(col, !on);
|
||
|
||
if (change)
|
||
{
|
||
XI_OBJ* column = find_column(col);
|
||
if (column)
|
||
{
|
||
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
|
||
}
|
||
}
|
||
}
|
||
|
||
void TSpreadsheet::show_column(int col, bool on)
|
||
{
|
||
CHECK(0, "xi_set_attrib(column, XI_ATR_VISIBLE) doesn't work!");
|
||
XI_OBJ* column = find_column(col);
|
||
if (column)
|
||
{
|
||
dword attr = xi_get_attrib(column);
|
||
if (on) attr |= XI_ATR_VISIBLE;
|
||
else attr &= ~XI_ATR_VISIBLE;
|
||
xi_set_attrib(column, attr); // Set new attributes
|
||
}
|
||
}
|
||
|
||
void TSpreadsheet::delete_column( const int col ) const
|
||
{
|
||
XI_OBJ* column = find_column(col);
|
||
if (column)
|
||
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)
|
||
{
|
||
if (fromindex != toindex)
|
||
{
|
||
_str.swap(fromindex, toindex);
|
||
_properties.swap(fromindex, toindex);
|
||
}
|
||
}
|
||
|
||
void TSpreadsheet::move_row(const int fromindex, const int toindex)
|
||
{
|
||
if (fromindex != toindex)
|
||
{
|
||
TObject* r = _str.remove(fromindex);
|
||
_str.insert(r, toindex, true);
|
||
_str.pack();
|
||
|
||
TObject* p = _properties.remove(fromindex);
|
||
_properties.insert(p, toindex, true);
|
||
_properties.pack();
|
||
}
|
||
}
|
||
|
||
|
||
int TSpreadsheet::set_line_number_width(int digits)
|
||
{
|
||
const int old = ROW_NUMBER_WIDTH;
|
||
ROW_NUMBER_WIDTH = digits;
|
||
return old;
|
||
}
|
||
|
||
void TSpreadsheet::set_column_width(const int col, const int width) const
|
||
{
|
||
XI_OBJ* column = find_column(col);
|
||
if (column)
|
||
xi_set_column_width(column, width); // Force redraw
|
||
}
|
||
|
||
void TSpreadsheet::update_column_default_width(const int col) const
|
||
{
|
||
XI_OBJ* column = find_column(col);
|
||
if (column)
|
||
{
|
||
XI_RCT rct; xi_get_rect(column, &rct);
|
||
int cid = col;
|
||
if (cid >= FIRST_FIELD+100) // Riportalo nel range 101 - 199
|
||
cid = FIRST_FIELD + cid2index(cid);
|
||
int num;
|
||
XI_OBJ** column = xi_get_member_list(_obj, &num);
|
||
for (int c = num-1; c > 0; c--)
|
||
{
|
||
if (column[c]->cid == cid)
|
||
((TSpreadsheet *)this)->_default_width[c] = rct.right - rct.left;
|
||
}
|
||
}
|
||
}
|
||
|
||
void TSpreadsheet::set_column_header(const int col, const TString& header) const
|
||
{
|
||
XI_OBJ* column = find_column(col);
|
||
if (column)
|
||
xi_set_text(column, (char *)(const char *)header );
|
||
}
|
||
|
||
const char* TSpreadsheet::get_column_header(const int col) const
|
||
{
|
||
const char* txt = "";
|
||
XI_OBJ* column = find_column(col);
|
||
if (column)
|
||
txt = xi_get_text(column, NULL, -1);
|
||
return txt;
|
||
}
|
||
|
||
void TSpreadsheet::set_column_justify(int col, bool right)
|
||
{
|
||
XI_OBJ* column = find_column(col);
|
||
if (column)
|
||
{
|
||
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);
|
||
}
|
||
}
|
||
|
||
void TSpreadsheet::set_row_height(const int row, const int height)
|
||
{
|
||
TRow_property* prop = get_property(row, true);
|
||
prop->set_height(height);
|
||
}
|
||
|
||
TRow_property* TSpreadsheet::get_property(int row, bool create)
|
||
{
|
||
if (row < 0)
|
||
row = 0;
|
||
|
||
TRow_property* p = (TRow_property*)_properties.objptr(row);
|
||
|
||
if (p == NULL && create)
|
||
{
|
||
p = new TRow_property;
|
||
_properties.add(p, row);
|
||
}
|
||
return p;
|
||
}
|
||
|
||
// Costruisce l'identificatore del paragrafo contenente la disposizione
|
||
// delle colonne del campo f
|
||
HIDDEN TFilename& field2parag(const TMask_field& f, TFilename& name)
|
||
{
|
||
const TMask& m = f.mask();
|
||
name = m.source_file();
|
||
name.ext(""); // Nome della maschera senza estensione
|
||
if (m.number() > 0) // Aggiunge l'eventuale numero di sotto-maschera
|
||
name << '(' << m.number() << ')';
|
||
return name;
|
||
}
|
||
|
||
bool TSpreadsheet::user_saved_columns_order() const
|
||
{
|
||
TFilename parag; field2parag(owner(), parag);
|
||
TConfig config(CONFIG_USER, parag); // Apre il file di configurazione
|
||
const int index = owner().dlg();
|
||
TToken_string order(config.get("Browse", NULL, index));
|
||
return !order.empty_items();
|
||
}
|
||
|
||
void TSpreadsheet::save_columns_order() const
|
||
{
|
||
if (_save_columns_order)
|
||
{
|
||
TFilename parag; field2parag(owner(), parag);
|
||
TConfig config(CONFIG_USER, parag); // Apre il file di configurazione
|
||
|
||
if (_save_columns_order == 1) // Se vale 3 devo solo resettare
|
||
{
|
||
int num;
|
||
XI_OBJ** column = xi_get_member_list(_obj, &num);
|
||
TToken_string order(127); // Nuovo ordine delle colonne
|
||
for (int i = 0; i < num; i++) // Scorre le colonne
|
||
{
|
||
order.add(column[i]->cid);
|
||
RCT rct; xi_get_rect(column[i], (XinRect *) &rct);
|
||
order << ',' << rct.right - rct.left;
|
||
}
|
||
config.set("Browse", order, NULL, true, owner().dlg());
|
||
}
|
||
else
|
||
config.remove("Browse", owner().dlg());
|
||
}
|
||
}
|
||
|
||
void TSpreadsheet::load_columns_order()
|
||
{
|
||
TFilename parag; field2parag(owner(), parag);
|
||
TConfig config(CONFIG_USER, parag);
|
||
const int index = owner().dlg();
|
||
TToken_string order(config.get("Browse", NULL, index));
|
||
if (order.empty_items())
|
||
config.remove("Browse", index);
|
||
else
|
||
set_columns_order(&order);
|
||
}
|
||
|
||
void TSpreadsheet::set_columns_order()
|
||
{
|
||
TFilename parag; field2parag(owner(), parag);
|
||
TConfig config(CONFIG_USER, parag);
|
||
const int index = owner().dlg();
|
||
TToken_string order(config.get("Browse", NULL, index));
|
||
if (!order.empty_items())
|
||
set_columns_order(&order);
|
||
}
|
||
|
||
void TSpreadsheet::set_columns_order(TToken_string* order)
|
||
{
|
||
XI_OBJ* itf = get_interface();
|
||
XI_OBJ* focus = xi_get_focus(itf);
|
||
xi_set_focus(itf);
|
||
|
||
int num_cols;
|
||
XI_OBJ** column = xi_get_member_list(_obj, &num_cols);
|
||
|
||
// Costante da sottrarre nella xi_column_set_pixel_width altrimenti la somma due volte!
|
||
const int offset = 2 * (int)xi_get_pref(XI_PREF_COLUMN_OFFSET);
|
||
const int fixed = xi_get_fixed_columns(_obj);
|
||
if (fixed > 1)
|
||
xi_set_fixed_columns(_obj, 1);
|
||
|
||
if (order == NULL)
|
||
{
|
||
int next_pos = 0;
|
||
for (int index = 0; _default_width[index] > 0; index++)
|
||
{
|
||
const short cid = index ? FIRST_FIELD + index - 1 : 0;
|
||
XI_OBJ* col = cid ? find_column(cid) : column[0];
|
||
if (col)
|
||
{
|
||
if (index >= fixed)
|
||
{
|
||
const int cur_pos = xi_obj_to_idx(col);
|
||
if (cur_pos != next_pos)
|
||
xi_move_column(col, next_pos);
|
||
}
|
||
next_pos++;
|
||
|
||
RCT rct; xi_get_rect(col, (XinRect *) &rct);
|
||
if (_default_width[index] != rct.right - rct.left)
|
||
xi_column_set_pixel_width(col, _default_width[index]-offset);
|
||
}
|
||
}
|
||
_save_columns_order = byte(0x3);
|
||
}
|
||
else
|
||
{
|
||
TToken_string col(8, ',');
|
||
int pos = 0;
|
||
for (col = order->get(0); !col.blank(); col = order->get(), pos++)
|
||
{
|
||
const int cid = col.get_int(0);
|
||
const int width = col.get_int();
|
||
XI_OBJ* col = cid ? find_column(cid) : column[0];
|
||
if (col) // Controlla che esista ancora
|
||
{
|
||
//if (pos >= fixed && pos < num_cols) // Da' problemi in presenza di colonne nascoste (livelli giacenza)
|
||
if (pos >= 1 && pos < num_cols)
|
||
{
|
||
const int cur_pos = xi_obj_to_idx(col);
|
||
if (cur_pos != pos)
|
||
xi_move_column(col, pos); // Sposta la colonna
|
||
}
|
||
if (width > XI_FU_MULTIPLE) // Se ha una larghezza valida
|
||
xi_column_set_pixel_width(col, width - offset);
|
||
}
|
||
}
|
||
_save_columns_order = false;
|
||
}
|
||
|
||
if (fixed > 1)
|
||
xi_set_fixed_columns(_obj, fixed);
|
||
|
||
if (focus)
|
||
xi_set_focus(focus);
|
||
}
|
||
|
||
// 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
|
||
{
|
||
const TRow_property* prop = ((TSpreadsheet*)this)->get_property(row);
|
||
|
||
bool d = false;
|
||
if (column < 0)
|
||
d = (prop == NULL) ? false : (prop->disabled().ones() >= columns()-1);
|
||
else
|
||
{
|
||
d = _column_disabled[column]; // Controlla la colonna
|
||
if (d == false && prop != NULL) // Se la colonna e' disabilitata e' inutile proseguire
|
||
d = prop->disabled()[column]; // Controlla la cella
|
||
}
|
||
return d;
|
||
}
|
||
|
||
|
||
// Certified 75%
|
||
void TSpreadsheet::str2mask(int riga)
|
||
{
|
||
if (riga == items())
|
||
{
|
||
const int curr = _cur_rec;
|
||
_cur_rec = riga;
|
||
owner().sheet_mask().reset();
|
||
_cur_rec = curr;
|
||
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)
|
||
{
|
||
const bool cell_dirty = _cell_dirty; // preservato lo stato di cell_dirty
|
||
set_dirty(ok ? 1 : 3);
|
||
_cell_dirty = cell_dirty;
|
||
}
|
||
return ok;
|
||
}
|
||
|
||
// Certified 99%
|
||
KEY TSpreadsheet::edit(int n)
|
||
{
|
||
str2mask(n);
|
||
if (_needs_update == n) // Altrimenti grossi problemi chiamando edit() durante editing cella
|
||
_needs_update = -1;
|
||
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
|
||
set_dirty();
|
||
}
|
||
}
|
||
else
|
||
if (k == K_ESC)
|
||
{
|
||
str2mask(n); // Ripristina valori precedenti
|
||
}
|
||
}
|
||
}
|
||
else
|
||
k = K_ESC;
|
||
|
||
return k;
|
||
}
|
||
|
||
bool TSpreadsheet::add_row_auto()
|
||
{
|
||
bool ok = false;
|
||
|
||
if (_check_enabled)
|
||
{
|
||
on_idle(); // Termina tutti gli eventuali update in corso
|
||
|
||
if (owner().active() && xi_move_focus(get_interface()))
|
||
{
|
||
int rec = -1;
|
||
|
||
TMask& om = owner().mask();
|
||
const bool omrun = om.is_running();
|
||
if (items() > 0 && !owner().append())
|
||
{
|
||
if (om.focus_field().dlg() == id())
|
||
rec = _cur_rec + 1;
|
||
else
|
||
rec = 0;
|
||
}
|
||
ok = insert(rec, omrun, true) >= 0;
|
||
if (ok)
|
||
{
|
||
_cell_dirty = _row_dirty = false;
|
||
if (omrun)
|
||
om.notify_focus_field(id());
|
||
}
|
||
}
|
||
}
|
||
return ok;
|
||
}
|
||
|
||
bool TSpreadsheet::error_box(const char* msg)
|
||
{
|
||
_check_enabled = false;
|
||
const int r = _cur_row;
|
||
const int c = _cur_col;
|
||
|
||
if (is_batch())
|
||
{
|
||
errors().add(msg);
|
||
return false;
|
||
}
|
||
if (ADVANCED_GRAPHICS && ANIMATED_BOXES)
|
||
xvt_dm_popup_error(msg);
|
||
else
|
||
xvt_dm_post_error(msg);
|
||
|
||
TMask& m = owner().mask();
|
||
m.set_focus_field(owner().dlg());
|
||
set_focus_cell(min(r, items()-1), c);
|
||
xvt_win_set_caret_visible(parent(), true);
|
||
_check_enabled = true;
|
||
return false;
|
||
}
|
||
|
||
bool TSpreadsheet::point2cell(const PNT& pnt, short& id, long& row) const
|
||
{
|
||
RCT rct; xi_get_rect(_obj, (XI_RCT*)&rct);
|
||
bool inside = xvt_rect_has_point(&rct, pnt) != 0;
|
||
id = DLG_NULL;
|
||
row = -1;
|
||
if (inside)
|
||
{
|
||
int num_cols;
|
||
XI_OBJ** column = xi_get_member_list(_obj, &num_cols);
|
||
for (int c = 0; c < num_cols; c++)
|
||
{
|
||
xi_get_rect(column[c], (XI_RCT*)&rct);
|
||
if (xvt_rect_has_point(&rct, pnt))
|
||
{
|
||
id = column[c]->cid;
|
||
break;
|
||
}
|
||
}
|
||
|
||
int first_vis, last_vis;
|
||
int rows = xi_get_visible_rows(_obj, &first_vis, &last_vis);
|
||
if (rows > 0)
|
||
{
|
||
XI_OBJ row1; XI_MAKE_ROW(&row1, _obj, first_vis);
|
||
XI_OBJ row2; XI_MAKE_ROW(&row2, _obj, last_vis);
|
||
XI_RCT r1; xi_get_rect(&row1, &r1);
|
||
XI_RCT r2; xi_get_rect(&row2, &r2);
|
||
const int r = first_vis + (pnt.v - r1.top) / (r1.bottom-r1.top);
|
||
if (r >= first_vis && r <= last_vis)
|
||
{
|
||
const long* handle = xi_get_list_info(_obj, &rows);
|
||
row = handle[r - first_vis];
|
||
}
|
||
}
|
||
}
|
||
return inside;
|
||
}
|
||
|
||
bool TSpreadsheet::get_range_selection(int & from, int & to) const
|
||
{
|
||
from = _from;
|
||
to = _to;
|
||
return _from >= 0;
|
||
}
|
||
|
||
void TSpreadsheet::clear_range_selection()
|
||
{
|
||
_from = _to = -1;
|
||
if (_saved_properties)
|
||
{
|
||
const int it = items();
|
||
for (int r = 0; r < it; r++)
|
||
{
|
||
TRow_property* prop = (TRow_property*)_saved_properties->objptr(r);
|
||
COLOR back = NORMAL_BACK_COLOR;
|
||
COLOR fore = NORMAL_COLOR;
|
||
|
||
if (prop != NULL)
|
||
prop->get(-1, back, fore);
|
||
set_back_and_fore_color(back, fore, r, -1);
|
||
}
|
||
delete _saved_properties;
|
||
_saved_properties = NULL;
|
||
}
|
||
}
|
||
|
||
void TSpreadsheet::select_range(int row)
|
||
{
|
||
//int from = _from;
|
||
// int to = _to;
|
||
|
||
if (row < 0)
|
||
row = selected();
|
||
if (_saved_properties == NULL)
|
||
_saved_properties = new TArray(_properties);
|
||
|
||
if (_from < 0)
|
||
_from = _to = row;
|
||
else
|
||
{
|
||
if (_from > row)
|
||
_from = row;
|
||
if (_to < row)
|
||
_to = row;
|
||
}
|
||
for (int r = _from; r <= _to; r++)
|
||
{
|
||
TRow_property* prop = (TRow_property*)_saved_properties->objptr(r);
|
||
COLOR back = NORMAL_BACK_COLOR;
|
||
COLOR fore = NORMAL_COLOR;
|
||
|
||
if (prop != NULL)
|
||
prop->get(-1, back, fore);
|
||
// if (r >= _from && r <= _to)
|
||
// back = blend_colors(back, fore, 0.01);
|
||
fore = blend_colors(back, fore, 0.6);
|
||
set_back_and_fore_color(fore, back, r, -1);
|
||
}
|
||
}
|
||
|
||
void TSpreadsheet::copy_rows()
|
||
{
|
||
int from = _from > 0 ? _from : 0;
|
||
int to = _to < items() - 1 ? _to : items() - 1;
|
||
|
||
_copied_rows.destroy();
|
||
for (int i = from; i <= to; i++)
|
||
_copied_rows.add(_str.row(i));
|
||
}
|
||
|
||
void TSpreadsheet::paste_rows()
|
||
{
|
||
int row = selected();
|
||
int nrows = _copied_rows.items();
|
||
|
||
if (row > _str.items() - 1)
|
||
row = _str.items() - 1;
|
||
|
||
/* if (row > _str.items() - 1)
|
||
{
|
||
row = _str.items() - 1;
|
||
_str.add(_copied_rows.row(--nrows));
|
||
|
||
TRow_property* prop = (TRow_property*)_saved_properties->objptr(row);
|
||
COLOR back = NORMAL_BACK_COLOR;
|
||
COLOR fore = NORMAL_COLOR;
|
||
|
||
if (prop != NULL)
|
||
prop->get(-1, back, fore);
|
||
set_back_and_fore_color(back, fore, row, -1);
|
||
|
||
} */
|
||
|
||
for (int i = nrows; i > 0; i--)
|
||
{
|
||
_str.insert(_copied_rows.row(i - 1), row + 1);
|
||
|
||
TRow_property* prop = (TRow_property*)_saved_properties->objptr(row + 1);
|
||
COLOR back = NORMAL_BACK_COLOR;
|
||
COLOR fore = NORMAL_COLOR;
|
||
|
||
if (prop != NULL)
|
||
prop->get(-1, back, fore);
|
||
set_back_and_fore_color(back, fore, row + 1, -1);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// TSheet_field
|
||
///////////////////////////////////////////////////////////
|
||
|
||
// Certified 100%
|
||
TSheet_field::TSheet_field(TMask* m)
|
||
: TLoadable_field(m), _append(true),
|
||
_separator('|'), _enable_autoload(false), _sheetfile(NULL),
|
||
_linee_rec(NULL), _external_record(false), _userput(NULL),_userget(NULL)
|
||
{
|
||
}
|
||
|
||
// 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()
|
||
{
|
||
if (_sheetfile!=NULL)
|
||
delete _sheetfile;
|
||
if (_linee_rec!=NULL && !_external_record)
|
||
delete _linee_rec;
|
||
|
||
}
|
||
|
||
// Certified 100%
|
||
void TSheet_field::reset()
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
// if (s->items()) s->select(0, false); // Non si capisce a cosa servisse dal 1996
|
||
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);
|
||
}
|
||
|
||
// Certified 100%
|
||
int TSheet_field::insert(int r, bool update_sheet, bool call_notify)
|
||
{
|
||
return ((TSpreadsheet*)_ctl)->insert(r, update_sheet, call_notify);
|
||
}
|
||
|
||
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: ...under debug...
|
||
bool TSheet_field::parse_item(TScanner& scanner)
|
||
{
|
||
if (scanner.key() == "IT") // ITEM
|
||
{
|
||
const char* h = dictionary_translate_header(scanner.string());
|
||
_ctl_data._park.add(h);
|
||
return true;
|
||
}
|
||
if (scanner.key() == "FL") // FLAGS
|
||
{
|
||
const char* flags = scanner.string();
|
||
for (const char* f = flags; *f; f++)
|
||
{
|
||
switch(*f)
|
||
{
|
||
case 'A': _enable_autoload = true; break;
|
||
case 'I': _append = false; break;
|
||
case '|': _separator = SAFE_PIPE_CHR; break;
|
||
case 'L': _flags.read_only = true; break;
|
||
case 'D': _flags.enable_default = false; break;
|
||
default : break;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
if (scanner.key() == "US") // USE
|
||
{
|
||
const int logicnum = scanner.integer();
|
||
|
||
if (logicnum > 0)
|
||
{
|
||
TDir d; d.get(logicnum);
|
||
const TFilename fn(d.filename());
|
||
if (fn.exist()) // Controlla l'esistenza del file
|
||
{
|
||
_sheetfile = new TLocalisamfile(logicnum);
|
||
TString s = scanner.pop();
|
||
|
||
// cerca l'indicazione del campo di numerazione
|
||
if (s == "KE")
|
||
{
|
||
s = scanner.pop();
|
||
_linee_rec= new TRecord_array(logicnum, s);// alloca i record
|
||
}
|
||
else
|
||
{
|
||
NFCHECK("Manca la definizione del campo di autonumerazione nel campo %d",
|
||
(int)dlg());
|
||
}
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
if (scanner.key() == "IN") // input (definisce la chiave)
|
||
{
|
||
parse_input(scanner);
|
||
return true;
|
||
}
|
||
|
||
return TLoadable_field::parse_item(scanner);
|
||
}
|
||
|
||
void TSheet_field::parse_input(TScanner& scanner)
|
||
{
|
||
const char* s = scanner.pop();
|
||
_file_k_names.add(s);
|
||
|
||
s = scanner.pop();
|
||
if (*s == '"') // Constant string
|
||
{
|
||
scanner.push();
|
||
TString& str = scanner.line();
|
||
_file_k_ids.add(str);
|
||
}
|
||
else // Field on the mask
|
||
{
|
||
CHECKS(_file_k_ids.get_pos(s) < 0, "Duplicate input field ", s);
|
||
_file_k_ids.add(s);
|
||
if (scanner.popkey() == "SE") _file_k_ids << '@'; // Special FILTERing field
|
||
else scanner.push();
|
||
}
|
||
}
|
||
|
||
// 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()+1, head, this);
|
||
|
||
_ctl->show(shown());
|
||
if (!_flags.enable_default)
|
||
{
|
||
_flags.enabled = true; // Lo sheet e' sempre operabile anche se non editabile
|
||
disable();
|
||
((TSpreadsheet*)_ctl)->activate(false);
|
||
}
|
||
if (_flags.read_only)
|
||
{
|
||
((TSpreadsheet*)_ctl)->activate(false);
|
||
}
|
||
|
||
const TMask& s = sheet_mask();
|
||
for (short id = FIRST_FIELD; ; id++)
|
||
{
|
||
if (s.id2pos(id) < 0)
|
||
{
|
||
_last_column_id = id - 1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
((TSpreadsheet*)_ctl)->load_columns_order();
|
||
}
|
||
|
||
// Certified 100%
|
||
TString_array& TSheet_field::rows_array() const
|
||
{
|
||
return ((TSpreadsheet*)_ctl)->rows_array();
|
||
}
|
||
|
||
const char* TSheet_field::cell(int r, int c) const
|
||
{
|
||
if (c >= FIRST_FIELD)
|
||
c = cid2index(c);
|
||
if (c < 0 || r < 0 || r >= items())
|
||
return "";
|
||
TToken_string& riga = ((TSheet_field*)this)->row(r);
|
||
const char* v = riga.get(c);
|
||
return v ? v : " ";
|
||
}
|
||
|
||
|
||
// 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();
|
||
int n;
|
||
for (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, _separator));
|
||
}
|
||
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;
|
||
int sel = s != NULL ?(int)s->selected() : -1;
|
||
|
||
return sel;
|
||
}
|
||
|
||
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 && s->_cur_rec >= 0 && s->_cur_rec < rows)
|
||
{
|
||
if (s->notify(s->_cur_rec, K_TAB))
|
||
{
|
||
s->set_focus_cell(s->_cur_row, s->_cur_col);
|
||
const int curr = selected();
|
||
if (curr >= 0)
|
||
s->str2mask(curr);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void TSheet_field::enable(bool on)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->activate(on);
|
||
}
|
||
|
||
void TSheet_field::set_auto_append(bool on)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->set_auto_append(on);
|
||
}
|
||
|
||
void TSheet_field::set_nav_column(short firstcol, short lastcol)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->set_nav_column(firstcol, lastcol);
|
||
}
|
||
|
||
bool TSheet_field::enabled() const
|
||
{
|
||
// return items() > 0;
|
||
return TMask_field::enabled();
|
||
}
|
||
|
||
int TSheet_field::cid2index(short cid) const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
return s->cid2index(cid);
|
||
}
|
||
|
||
void TSheet_field::enable_row(int row, bool on)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->enable_cell(row, -1 , on);
|
||
}
|
||
|
||
bool TSheet_field::row_enabled(int row)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
return (s->find_enabled_column(row,1,1) != 0);
|
||
}
|
||
|
||
void TSheet_field::enable_cell(int row, int column, bool on)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->enable_cell(row, column, on);
|
||
}
|
||
|
||
void TSheet_field::enable_column(int column, bool on)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->enable_column(column, on);
|
||
}
|
||
|
||
bool TSheet_field::column_enabled(int column) const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
return s->column_enabled(column);
|
||
}
|
||
|
||
bool TSheet_field::column_disabled(int column) const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
return s->column_disabled(column);
|
||
}
|
||
|
||
bool TSheet_field::exist_column(const int column) const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
return s->exist_column(column);
|
||
}
|
||
|
||
bool TSheet_field::cell_disabled(int row, int column) const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
return s->cell_disabled(row, column);
|
||
}
|
||
|
||
bool TSheet_field::cell_enabled(int row, int column) const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
return !s->cell_disabled(row, column);
|
||
}
|
||
|
||
void TSheet_field::show_column(int col, bool on) const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->show_column(col, on);
|
||
}
|
||
|
||
// Matteo was here!
|
||
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;
|
||
if (fromindex >= FIRST_FIELD)
|
||
s->move_column(s->cid2col(fromindex), toindex);
|
||
else
|
||
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);
|
||
}
|
||
|
||
bool TSheet_field::user_saved_columns_order() const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
return s->user_saved_columns_order();
|
||
}
|
||
|
||
void TSheet_field::set_columns_order(TToken_string* order)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->set_columns_order(order);
|
||
}
|
||
|
||
void TSheet_field::set_columns_order()
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->set_columns_order(NULL);
|
||
s->set_columns_order();
|
||
}
|
||
|
||
const char* TSheet_field::get_column_header( const int col) const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
return s->get_column_header(col);
|
||
}
|
||
|
||
void TSheet_field::swap_rows( const int fromindex, const int toindex)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->swap_rows(fromindex, toindex);
|
||
}
|
||
|
||
void TSheet_field::move_row(const int fromindex, const int toindex) const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->move_row(fromindex, toindex);
|
||
}
|
||
|
||
static int default_rows_compare(TSheet_field &s, int i, int j)
|
||
{
|
||
TToken_string &s1 = s.row(i);
|
||
TToken_string &s2 = s.row(j);
|
||
if (s1 == s2)
|
||
return 0;
|
||
return s1.compare(s2);
|
||
}
|
||
|
||
void TSheet_field::sort(ROWS_COMPARE_FUNCTION compare)
|
||
{
|
||
if (compare == NULL)
|
||
compare = default_rows_compare;
|
||
|
||
const long last = items()-1;
|
||
for (int i = 0; i < last; i++)
|
||
{
|
||
for (int j = i+1; j <= last; j++)
|
||
{
|
||
const int cmp = compare(*this, i, j);
|
||
if (cmp > 0)
|
||
swap_rows( i,j);
|
||
}
|
||
}
|
||
}
|
||
|
||
int TSheet_field::set_line_number_width(int width )
|
||
{
|
||
return TSpreadsheet::set_line_number_width(width);
|
||
}
|
||
|
||
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::update_column_width( const int col) const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->update_column_default_width(col);
|
||
}
|
||
|
||
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);
|
||
}
|
||
|
||
void TSheet_field::set_row_height( const int row, const int height )
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->set_row_height(row, height);
|
||
}
|
||
|
||
TMask& TSheet_field::sheet_mask() const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
return s->sheet_mask();
|
||
}
|
||
|
||
TMask& TSheet_field::sheet_row_mask(int /* row */) const
|
||
{
|
||
return sheet_mask();
|
||
}
|
||
|
||
bool TSheet_field::on_hit()
|
||
{
|
||
TMask& m = mask();
|
||
if (!m.is_running()) // Inizializzazione maschera
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
|
||
if (s->auto_append() && items() == 0 && !m.query_mode())
|
||
{
|
||
s->add_row_auto(); // Inserisco automaticamente la prima riga vuota nello sheet
|
||
force_update();
|
||
}
|
||
else
|
||
{
|
||
force_update();
|
||
if (items() > 0)
|
||
{
|
||
m.notify_focus_field(dlg()); // Fa' credere alla maschera che ha il focus ...
|
||
select(0, -2, true); // ... cosi' la set_focus_cell funziona bene
|
||
}
|
||
}
|
||
|
||
set_dirty(false);
|
||
}
|
||
const bool ok = handler(K_SPACE);
|
||
return ok;
|
||
}
|
||
|
||
void TSheet_field::select(int r, bool scrollto)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->select(r, scrollto);
|
||
}
|
||
|
||
void TSheet_field::select(int r, int c , bool scrollto)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->select(r, c, scrollto);
|
||
}
|
||
|
||
void TSheet_field::post_select(int r)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->post_select(r);
|
||
}
|
||
|
||
bool TSheet_field::set_focus_cell(int riga, int colonna)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
return s->set_focus_cell(riga, colonna);
|
||
}
|
||
|
||
bool TSheet_field::set_focus_cell_id(long rec, short cid)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
|
||
const int col = s->cid2col(cid);
|
||
const int row = s->rec2row(rec);
|
||
|
||
// Controlla che la cella sia veramente visibile
|
||
int first_col, last_col, first_row, last_row;
|
||
xi_get_visible_columns(s->_obj, &first_col, &last_col);
|
||
xi_get_visible_rows(s->_obj, &first_row, &last_row);
|
||
|
||
bool ok = false;
|
||
if (col >= first_col && col <= last_col && row >= first_row && row <= last_row)
|
||
ok = s->set_focus_cell(row, col);
|
||
else
|
||
s->select(rec, col, true);
|
||
return ok;
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
if (k == K_CTRL+'+')
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
s->add_row_auto();
|
||
return true;
|
||
}
|
||
|
||
if (k == K_CTRL+'-')
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
XI_EVENT e; memset(&e, 0, sizeof(e));
|
||
e.type = XIE_CHAR_CELL;
|
||
e.v.chr.ch = '-';
|
||
e.v.chr.control = true;
|
||
return s->event_handler(NULL, &e);
|
||
}
|
||
|
||
return TOperable_field::on_key(k);
|
||
}
|
||
|
||
void TSheet_field::on_idle()
|
||
{
|
||
((TSpreadsheet*)_ctl)->on_idle();
|
||
}
|
||
|
||
// Ricopia i campi della maschera nel record dato
|
||
void TSheet_field::mask2row(int n, TToken_string & rec)
|
||
{
|
||
const TMask& m = sheet_row_mask(n);
|
||
const TSpreadsheet& s = (const TSpreadsheet&)*_ctl;
|
||
|
||
rec.cut(0);
|
||
for (short id = FIRST_FIELD; id <= _last_column_id ; id++)
|
||
{
|
||
int pos = m.id2pos(id);
|
||
const int firstpos = pos;
|
||
|
||
if (pos >= 0)
|
||
{
|
||
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 (active() && s.active())
|
||
{
|
||
const int col = cid2index(id);
|
||
if (!s.column_disabled(col))
|
||
{
|
||
const bool on = f.enabled();
|
||
enable_cell(n, col, on);
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
#ifdef DBG
|
||
if (pos < 0 && s.cid2col(id) > 0)
|
||
{
|
||
static short _last_cid = 0;
|
||
if (id != _last_cid)
|
||
{
|
||
_last_cid = id;
|
||
yesnofatal_box("Mask2row: Non e' visibile il campo %d", id);
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
else
|
||
{
|
||
const int col = cid2index(id);
|
||
if (!s.column_disabled(col))
|
||
enable_cell(n, col, false);
|
||
}
|
||
|
||
if (pos < 0)
|
||
rec.add(firstpos >= 0 ? m.fld(firstpos).get() : " ");
|
||
}
|
||
rec.pack();
|
||
}
|
||
|
||
|
||
// Ricopia i campi del record dato nella maschera
|
||
void TSheet_field::row2mask(int n, TToken_string& r, int mode)
|
||
{
|
||
TMask& m = sheet_row_mask(n);
|
||
m.reset(); // Azzera tutti i campi, soprattutto quelli con (id > _last_column_id)
|
||
|
||
//const int campi = m.fields();
|
||
const TSpreadsheet& s = (const TSpreadsheet&)*_ctl;
|
||
TString val;
|
||
for (short id = FIRST_FIELD; id <= _last_column_id; id++)
|
||
{
|
||
const int index = cid2index(id);
|
||
val = r.get(index);
|
||
int dlg = id;
|
||
for(int pos = m.id2pos(dlg); pos >= 0; pos = m.id2pos(dlg += 100))
|
||
{
|
||
TMask_field& f = m.fld(pos);
|
||
f.set(val);
|
||
const bool on = s.active() && !cell_disabled(n, index);
|
||
if (f.enabled() != on)
|
||
f.enable(on);
|
||
}
|
||
}
|
||
|
||
if (mode > 0)
|
||
{
|
||
WINDOW last_parent = NULL_WIN;
|
||
FOR_EACH_MASK_FIELD(m, i, f)
|
||
{
|
||
const short id = f->dlg();
|
||
|
||
if (id >= FIRST_FIELD && (f->active() || f->ghost()) &&
|
||
!f->is_kind_of(CLASS_BUTTON_FIELD) && !f->is_kind_of(CLASS_BUTTON_TOOL))
|
||
{
|
||
WINDOW current_parent = f->parent();
|
||
if (current_parent != last_parent)
|
||
{
|
||
// Assegna il focus all'interfaccia per evitare effetti indesiderati durante i messaggi
|
||
low_set_focus_id(f->parent(), -1);
|
||
}
|
||
|
||
if (f->has_check() && (mode & 0x1))
|
||
f->check(STARTING_CHECK);
|
||
f->set_dirty(false);
|
||
if (mode & 0x2)
|
||
f->on_hit();
|
||
}
|
||
}
|
||
}
|
||
|
||
FOR_EACH_MASK_FIELD(m, i, f)
|
||
{
|
||
if (f->dirty() == 1)
|
||
f->set_dirty(false);
|
||
}
|
||
|
||
// Imposta titolo se pagina singola
|
||
if (m.page_win(1) == NULL_WIN) // Non esiste pagina 2?
|
||
{
|
||
TString caption; m.get_caption(caption);
|
||
if (caption.full())
|
||
{
|
||
const int spc = caption.find(" [");
|
||
if (spc > 0)
|
||
caption.cut(spc);
|
||
}
|
||
else
|
||
caption = TR("Riga");
|
||
caption << " [" << (n+1) << ']';
|
||
m.set_caption(caption);
|
||
}
|
||
}
|
||
|
||
KEY TSheet_field::run_editmask(int n)
|
||
{
|
||
TMask& m = sheet_row_mask(n);
|
||
return m.run();
|
||
}
|
||
|
||
void TSheet_field::set_back_and_fore_color(COLOR back, COLOR fore, int row, int col)
|
||
{
|
||
TSpreadsheet& s = (TSpreadsheet&)*_ctl;
|
||
s.set_back_and_fore_color(back, fore, row, col);
|
||
}
|
||
|
||
void TSheet_field::reset_columns_order()
|
||
{
|
||
TSpreadsheet& s = (TSpreadsheet&)*_ctl;
|
||
s.set_columns_order(NULL);
|
||
}
|
||
|
||
void TSheet_field::save_columns_order()
|
||
{
|
||
const TSpreadsheet& s = (const TSpreadsheet&)*_ctl;
|
||
s.save_columns_order();
|
||
}
|
||
|
||
void TSheet_field::check_row(int n, int mode)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
const int current = s->_cur_rec;
|
||
|
||
s->_cur_rec = n;
|
||
|
||
TMask& m = sheet_row_mask(n);
|
||
CHECK(!m.is_running(), "Can't use check_row while sheet mask is running");
|
||
TToken_string & r = row(n);
|
||
const int max = m.fields();
|
||
TMaskmode mask_mode = (TMaskmode) m.mode();
|
||
|
||
m.set_mode(mask().mode());
|
||
for (int i = max - 1; i >= 0; i--)
|
||
{
|
||
TMask_field & f = m.fld(i);
|
||
|
||
if (f.has_check())
|
||
f.set_dirty();
|
||
}
|
||
row2mask(n, r, mode);
|
||
mask2row(n, r);
|
||
m.set_mode(mask_mode);
|
||
s->_cur_rec = current;
|
||
}
|
||
|
||
|
||
// Certified: ...under debug..
|
||
void TSheet_field::set_lines_record(TRecord_array & r_a)
|
||
{
|
||
if (_linee_rec && !_external_record)
|
||
delete _linee_rec;
|
||
_linee_rec= & r_a;
|
||
_external_record = true; // il record attuale <20> esterno...
|
||
}
|
||
|
||
// Certified: ...under debug..
|
||
TRectype* TSheet_field::putkey(const TRelation& r)
|
||
{
|
||
if (_sheetfile)
|
||
{
|
||
// costruisce la chiave per il record array
|
||
_sheetfile->zero();
|
||
_file_k_ids.restart();
|
||
for (TString16 dbfieldname = _file_k_names.get(0);
|
||
dbfieldname.full();
|
||
dbfieldname = _file_k_names.get())
|
||
{
|
||
TString80 id = _file_k_ids.get();
|
||
if (id[0] == '"')
|
||
{
|
||
id.strip("\"");
|
||
_sheetfile->curr().renum_key(dbfieldname, id);
|
||
}
|
||
else
|
||
{
|
||
TMask_field& f = mask().field(atoi(id));
|
||
if (mask().edit_mode())
|
||
((TLoadable_field&)f).autoload(r); // Molto probabilmente inutile!
|
||
_sheetfile->curr().renum_key(dbfieldname, f.get());
|
||
}
|
||
}
|
||
return &_sheetfile->curr();
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
// Certified: ...under debug..
|
||
bool TSheet_field::autoload_line(int i, const TRectype& rec)
|
||
{
|
||
TMask& m = sheet_row_mask(i-1);
|
||
TToken_string &row= this->row(i-1);
|
||
|
||
row.cut(0);
|
||
for (short id = FIRST_FIELD; id <= _last_column_id; id++)
|
||
{
|
||
const TFieldref* dbfield = m.field(id).field();
|
||
if (dbfield == NULL && m.id2pos(id+100) > 0) // Succede coi campi analitici
|
||
dbfield = m.field(id+100).field();
|
||
if (dbfield)
|
||
row.add(dbfield->read(rec),id - FIRST_FIELD);
|
||
}
|
||
// completa l'operazione con le funzioni definite dall'utente
|
||
if (_userget)
|
||
_userget(*this,i);
|
||
check_row(i-1);
|
||
return true;
|
||
}
|
||
|
||
// Certified: ...under debug..
|
||
bool TSheet_field::autosave_line(int i,TRectype & rec)
|
||
{
|
||
TMask& m = sheet_row_mask(i-1);
|
||
for (short id = FIRST_FIELD; id <= _last_column_id; id++)
|
||
{
|
||
const TFieldref* dbfield = m.field(id).field();
|
||
if (dbfield == NULL && m.id2pos(id+100) > 0) // Succede coi campi analitici
|
||
dbfield = m.field(id+100).field();
|
||
if (dbfield)
|
||
dbfield->write(cell(i - 1, id - FIRST_FIELD), rec);
|
||
}
|
||
// completa l'operazione con le funzioni definite dall'utente
|
||
if (_userput)
|
||
_userput(*this,i);
|
||
return false;
|
||
}
|
||
|
||
// Certified: ...under debug..
|
||
bool TSheet_field::autoload(const TRelation& rel)
|
||
{
|
||
if (_enable_autoload)
|
||
{
|
||
CHECK(_linee_rec !=NULL, "Iu ev forgotten tu declare de Record array for de scit");
|
||
// *******
|
||
// trasferisce le linee dal record array allo sheet
|
||
destroy(); // cancella lo sheet
|
||
const int last_line = _linee_rec->last_row();
|
||
for (int i = 1; i <= last_line; i++)
|
||
autoload_line(i,_linee_rec->row(i, true));
|
||
|
||
return(0);
|
||
}
|
||
return _enable_autoload;
|
||
}
|
||
|
||
void TSheet_field::restart_key()
|
||
{
|
||
_file_k_names.restart();
|
||
_file_k_ids.restart();
|
||
}
|
||
|
||
TMask_field *TSheet_field::get_key(TString & dbfieldname)
|
||
{
|
||
if ((dbfieldname = _file_k_names.get())!="")
|
||
return &mask().field(atoi(_file_k_ids.get()));
|
||
return NULL;
|
||
}
|
||
|
||
// Certified: ...under debug..
|
||
bool TSheet_field::autosave(TRelation& rel)
|
||
{
|
||
if (_enable_autoload)
|
||
{
|
||
CHECK(_linee_rec !=NULL, "Iu ev forgotten tu declare de Record array for de scit");
|
||
_linee_rec->destroy_rows();
|
||
if (_sheetfile)
|
||
{
|
||
// trasferisce dal file locale
|
||
if (mask().insert_mode())
|
||
{
|
||
// rinumera la chiave
|
||
_file_k_ids.restart();
|
||
for (TString16 dbfieldname = _file_k_names.get(0);
|
||
dbfieldname.full();
|
||
dbfieldname = _file_k_names.get())
|
||
{
|
||
TString80 id = _file_k_ids.get();
|
||
if (id[0] == '"')
|
||
{
|
||
id.strip("\"");
|
||
_linee_rec->renum_key(dbfieldname, id);
|
||
}
|
||
else
|
||
{
|
||
const TMask_field& f = mask().field(atoi(id));
|
||
_linee_rec->renum_key(dbfieldname, f.get());
|
||
}
|
||
}
|
||
}
|
||
}
|
||
// *******
|
||
// trasferisce le linee dallo sheet al record array (ignorando righe vuote alla fine)
|
||
int i = items();
|
||
while (i > 0 && row(i-1).empty_items())
|
||
i--;
|
||
for (; i > 0; i--)
|
||
{
|
||
TRectype &rec = _linee_rec->row(i, true);
|
||
autosave_line(i,rec); // autosave_line parte da 1 :-(
|
||
}
|
||
}
|
||
return _enable_autoload;
|
||
}
|
||
|
||
// Certified: ...under debug..
|
||
void TSheet_field::set_userget(SHEET_USERGETPUT handler)
|
||
{
|
||
_userget = handler;
|
||
}
|
||
|
||
// Certified: ...under debug..
|
||
void TSheet_field::set_userput(SHEET_USERGETPUT handler)
|
||
{
|
||
_userput = handler;
|
||
}
|
||
|
||
static TString& clean_white_space(TString& str)
|
||
{
|
||
str.trim();
|
||
char* buff = str.get_buffer();
|
||
for (char* b = buff; *b; b++)
|
||
{
|
||
if (*b > '\0' && *b < ' ')
|
||
*b = ' ';
|
||
}
|
||
str.strip_double_spaces();
|
||
return str;
|
||
}
|
||
|
||
bool TSheet_field::get_range_selection(int &from, int & to) const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
|
||
return s->get_range_selection(from, to);
|
||
}
|
||
|
||
void TSheet_field::clear_range_selection()
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
|
||
s->clear_range_selection();
|
||
force_update();
|
||
s->set_focus_cell(s->_cur_row, s->_cur_col);
|
||
}
|
||
|
||
void TSheet_field::select_range(int row)
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
|
||
s->select_range(row);
|
||
force_update();
|
||
s->set_focus_cell(s->_cur_row, s->_cur_col);
|
||
}
|
||
|
||
void TSheet_field::copy_rows()
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
|
||
s->copy_rows();
|
||
}
|
||
|
||
void TSheet_field::paste_rows()
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
|
||
s->paste_rows();
|
||
on_key(K_CTRL + 'V');
|
||
force_update();
|
||
s->set_focus_cell(s->_cur_row, s->_cur_col);
|
||
}
|
||
///////////////////////////////////////////////////////////
|
||
// TSheet_recordset
|
||
///////////////////////////////////////////////////////////
|
||
|
||
class TSheet_recordset : public TRecordset
|
||
{
|
||
const TSpreadsheet* _sheet;
|
||
int _cols;
|
||
TRecnotype _curr;
|
||
|
||
protected:
|
||
virtual bool get_attr(int column, TAttributes& attr, bool header) const;
|
||
|
||
public:
|
||
virtual unsigned int columns() const { return _cols; }
|
||
virtual const TRecordset_column_info& column_info(unsigned int i) const;
|
||
virtual TRecnotype items() const { return _sheet->items(); }
|
||
virtual bool move_to(TRecnotype pos);
|
||
virtual TRecnotype current_row() const { return _curr; }
|
||
virtual void requery() {}
|
||
virtual const TVariant& get(unsigned int column) const;
|
||
|
||
public:
|
||
virtual const TString& query_text() const { return EMPTY_STRING; }
|
||
TSheet_recordset(const TSpreadsheet* s) : _sheet(s), _curr(-1)
|
||
{ xi_get_member_list(((TSpreadsheet*)s)->xi_object(), &_cols); _cols--; }
|
||
};
|
||
|
||
bool TSheet_recordset::move_to(TRecnotype pos)
|
||
{
|
||
const bool ok = pos >= 0 && pos < items();
|
||
if (ok)
|
||
_curr = pos;
|
||
return ok;
|
||
}
|
||
|
||
const TRecordset_column_info& TSheet_recordset::column_info(unsigned int i) const
|
||
{
|
||
static TRecordset_column_info _info;
|
||
|
||
int num;
|
||
XI_OBJ** columns = xi_get_member_list(((TSpreadsheet*)_sheet)->xi_object(), &num);
|
||
XI_OBJ* column = int(i+1) < num ? columns[i+1] : NULL;
|
||
if (column)
|
||
{
|
||
_info._pos = (column->cid % 100) - 1;
|
||
|
||
xi_get_text(column, _info._name.get_buffer(), _info._name.size());
|
||
_info._name.trim();
|
||
|
||
const TMask_field& fld = _sheet->sheet_mask().field(column->cid);
|
||
switch (fld.class_id())
|
||
{
|
||
case CLASS_BOOLEAN_FIELD : _info._type = _boolfld; break;
|
||
case CLASS_DATE_FIELD : _info._type = _datefld; break;
|
||
case CLASS_CURRENCY_FIELD:
|
||
case CLASS_REAL_FIELD : _info._type = _realfld; break;
|
||
default : _info._type = _alfafld; break;
|
||
}
|
||
_info._width = fld.size();
|
||
}
|
||
else
|
||
{
|
||
_info._pos = -1;
|
||
_info._name.cut(0);
|
||
_info._type = _nullfld;
|
||
_info._width = 0;
|
||
}
|
||
|
||
return _info;
|
||
}
|
||
|
||
const TVariant& TSheet_recordset::get(unsigned int i) const
|
||
{
|
||
if (_curr >= 0 && _curr < items() && i < columns())
|
||
{
|
||
const TRecordset_column_info& ci = column_info(i);
|
||
if (ci._pos >= 0)
|
||
{
|
||
TToken_string& row = ((TSpreadsheet*)_sheet)->row(_curr);
|
||
TVariant& tmp = get_tmp_var();
|
||
tmp = row.get(ci._pos);
|
||
tmp.convert_to(ci._type);
|
||
return tmp;
|
||
}
|
||
}
|
||
return NULL_VARIANT;
|
||
}
|
||
|
||
bool TSheet_recordset::get_attr(int i, TAttributes& attr, bool header) const
|
||
{
|
||
const TRecordset_column_info& ci = column_info(i);
|
||
bool is_valid = false;
|
||
if (ci._pos >= 0)
|
||
{
|
||
COLOR back, fore;
|
||
if (header)
|
||
{
|
||
back = BTN_BACK_COLOR;
|
||
fore = PROMPT_COLOR;
|
||
// is_valid = true; // Per ora non funziona
|
||
}
|
||
else
|
||
{
|
||
is_valid = ((TSpreadsheet*)_sheet)->get_back_and_fore_color(back, fore, _curr, ci._pos);
|
||
}
|
||
}
|
||
return is_valid;
|
||
}
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// Esportazione
|
||
///////////////////////////////////////////////////////////
|
||
|
||
bool TSheet_field::esporta() const
|
||
{
|
||
TFilename name;
|
||
name.tempdir();
|
||
name.add(mask().source_file().name_only());
|
||
name.ext("xls");
|
||
|
||
TSheet_recordset sr((TSpreadsheet*)_ctl);
|
||
sr.save_as(name);
|
||
|
||
/*
|
||
ofstream xls(name);
|
||
const char sep = '\t';
|
||
TToken_string tab(128, sep);
|
||
TString str;
|
||
|
||
int columns = 0;
|
||
XI_OBJ** pcols = xi_get_member_list(_ctl->xi_object(), &columns);
|
||
|
||
for (int c = 1; c < columns; c++)
|
||
{
|
||
xi_get_text(pcols[c], str.get_buffer(), str.size());
|
||
tab.add(clean_white_space(str));
|
||
}
|
||
|
||
xls << tab << endl;
|
||
|
||
for (long n = 0; n < items(); n++)
|
||
{
|
||
const TToken_string& r = ((TSheet_field*)this)->row(n);
|
||
tab.cut(0);
|
||
for (int c = 1; c < columns; c++)
|
||
{
|
||
const int idx = cid2index(pcols[c]->cid);
|
||
r.get(idx, str);
|
||
clean_white_space(str);
|
||
if (real::is_real(str))
|
||
{
|
||
if (real::is_null(str))
|
||
str.cut(0);
|
||
else
|
||
{
|
||
if (real::is_natural(str))
|
||
str.trim();
|
||
else
|
||
xvt_str_number_format(str.get_buffer(), str.size());
|
||
}
|
||
}
|
||
if (str.not_empty())
|
||
tab.add(str, c-1);
|
||
}
|
||
xls << tab << endl;
|
||
}
|
||
xls.close();
|
||
*/
|
||
|
||
xvt_sys_goto_url(name, "open");
|
||
|
||
return true;
|
||
}
|
||
|
||
bool TSheet_field::error_box(const char* fmt, ...) const
|
||
{
|
||
char msg[256];
|
||
va_list argptr;
|
||
va_start(argptr,fmt);
|
||
_vsnprintf(msg,sizeof(msg),fmt,argptr);
|
||
va_end(argptr);
|
||
msg[255] = '\0';
|
||
return ((TSpreadsheet*)_ctl)->error_box(msg);
|
||
}
|
||
|
||
const int TSheet_field::current_column() const
|
||
{
|
||
TSpreadsheet* s = (TSpreadsheet*)_ctl;
|
||
int sel = s->_cur_col;
|
||
return sel;
|
||
}
|
||
|
||
bool TSheet_field::point2cell(const PNT& pnt, short& id, long& row) const
|
||
{
|
||
TSpreadsheet& s = (TSpreadsheet&)*_ctl;
|
||
return s.point2cell(pnt, id, row);
|
||
}
|