Files correlati : Ricompilazione Demo : [ ] Commento : aggiunte xvt_chr_is_digit, xvt_chr_is_alpha e xvt_chr_is_alnum git-svn-id: svn://10.65.10.50/trunk@14717 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			3294 lines
		
	
	
		
			90 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			3294 lines
		
	
	
		
			90 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 <relation.h>
 | ||
| #include <urldefid.h>
 | ||
| 
 | ||
| #include <limits.h>
 | ||
| 
 | ||
| class TCell_property : public TObject
 | ||
| {
 | ||
|   COLOR _back, _fore; 
 | ||
| 
 | ||
| public:
 | ||
|   void set(COLOR back, COLOR fore) { _back = back; _fore = fore;}
 | ||
|   void get(COLOR & back, COLOR & fore) const { back = _back; fore = _fore;}
 | ||
|   
 | ||
|   TCell_property();
 | ||
|   virtual ~TCell_property() { }
 | ||
| };
 | ||
|   
 | ||
| TCell_property::TCell_property()
 | ||
|               : _back(NORMAL_BACK_COLOR), _fore(NORMAL_COLOR)
 | ||
| {
 | ||
| }
 | ||
| 
 | ||
| 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);
 | ||
|   void 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;}
 | ||
|   TRow_property();
 | ||
|   virtual ~TRow_property() { }
 | ||
| };
 | ||
| 
 | ||
| TRow_property::TRow_property()
 | ||
|              : _back(0), _fore(0), _height(-1), _cell_prop(NULL)
 | ||
| {
 | ||
| }
 | ||
| 
 | ||
| void TRow_property::set(int col, COLOR back, COLOR fore)
 | ||
| {
 | ||
|   if (col < 0)
 | ||
|   {
 | ||
|     if (back != COLOR_INVALID)
 | ||
|       _back = back;
 | ||
|     if (fore != COLOR_INVALID)
 | ||
|       _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 (p == NULL)
 | ||
|     {
 | ||
|       p = new TCell_property;
 | ||
|       _cell_prop->add(p, col);
 | ||
|     }
 | ||
|       
 | ||
|     p->set(back, fore);
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| void TRow_property::get(int col, COLOR & back, COLOR & fore) const
 | ||
| {     
 | ||
|   if (col > 0)
 | ||
|   {
 | ||
|     if (_cell_prop == NULL)
 | ||
|     {              
 | ||
|       back = _back;
 | ||
|       fore = _fore;
 | ||
|     }
 | ||
|     else
 | ||
|     {
 | ||
|       const TCell_property* cp = (const TCell_property*)_cell_prop->objptr(col);
 | ||
|       if (cp != NULL)
 | ||
|         cp->get(back, fore);
 | ||
|     }
 | ||
|   }   
 | ||
| }
 | ||
| 
 | ||
| ///////////////////////////////////////////////////////////
 | ||
| // 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 delle colonne disattivate (solo visualizzazione)
 | ||
|   TBit_array _column_disabled;
 | ||
| 
 | ||
|   // @cmember:(INTERNAL) Array delle proprieta' delle righe
 | ||
|   TArray _property;
 | ||
| 
 | ||
|   // @cmember:(INTERNAL) Maschera in cui e' contenuto lo spreadsheet
 | ||
|   TMask _mask;
 | ||
|   // @cmember:(INTERNAL) Numero di colonne presenti nello spreadsheet
 | ||
|   int _columns;
 | ||
|   // @cmember:(INTERNAL) Indica se e' attivo lo spreadsheet
 | ||
|   bool _active;
 | ||
| 
 | ||
|   // @cmember:(INTERNAL) Funzione per la gestione di una riga dello sheet (vedi <t SPREADSHEET_NOTIFY>)
 | ||
|   SPREADSHEET_NOTIFY _notify;
 | ||
| 
 | ||
|   // @cmember:(INTERNAL) Campo corrente che si sta editando
 | ||
|   TOperable_field* _edit_field;
 | ||
|   // @cmember:(INTERNAL) Coordinata della riga della cella corrente
 | ||
|   int _cur_row;
 | ||
|   // @cmember:(INTERNAL) Numero del record sul file al quale fa riferimento la cella corrente
 | ||
|   int _cur_rec;
 | ||
|   // @cmember:(INTERNAL) Coordinata della colonna della cella corrente
 | ||
|   int _cur_col;
 | ||
|   // @cmember:(INTERNAL) Indica se la riga corrente e' stata modificata
 | ||
|   bool _row_dirty;
 | ||
|   // @cmember:(INTERNAL) Indica se la cella corrente e' stata modificata
 | ||
|   bool _cell_dirty;
 | ||
|   // @cmember:(INTERNAL) Permette di gestire i check OFF_ROW e OFF_CELL
 | ||
|   bool _check_enabled;
 | ||
|   // @cmember:(INTERNAL) Numero della riga che necessita aggiornamento (vengono aggiornate 
 | ||
|   //                                    nella <mf TSpreadsheet::on_idle>)
 | ||
|   int _needs_update;
 | ||
|   // @cmember:(INTERNAL) Numero della riga a cui saltare appena possibile
 | ||
|   int _selection_posted;
 | ||
|   // @cmember:(INTERNAL) Dimensioni delle colonne
 | ||
|   int _default_width[MAX_COL];   
 | ||
|   // @cmember:(INTERNAL) Bisogna salvare l'ordien 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; }
 | ||
|   
 | ||
|   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 la colonna col                    
 | ||
|   XI_OBJ* find_column(int col) const;
 | ||
|   
 | ||
|   // @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; }
 | ||
| 
 | ||
|   // @access Public Member
 | ||
| public:
 | ||
|   // @cmember Modifica a video la riga
 | ||
|   void update(int row); 
 | ||
|   // @cmember Ritorna la disabilitazione della colonna <p col>
 | ||
|   bool column_disabled(int col) const { return _column_disabled[col]; }
 | ||
|   // @cmember Ritorna 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
 | ||
|   void set_focus_cell(int riga, int colonna);
 | ||
|   // @cmember Abilita/disabilita tutto lo spreadsheet (vedi <mf TMask::activate>)
 | ||
|   void activate(bool on);
 | ||
|   // @cmember Permette di abilitare/disabilitare una colonna
 | ||
|   void enable_column(int col, bool on = TRUE);
 | ||
|   // @cmember Permette di 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;
 | ||
|   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 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(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 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
 | ||
|   void 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 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 = 0xFFFF;
 | ||
|   if (_barcode_newline == 0xFFFF)
 | ||
|   {
 | ||
|     TConfig ini(CONFIG_INSTALL, "Main");
 | ||
|     _barcode_newline = ini.get_int("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), _save_columns_order(FALSE),
 | ||
|   _f9_target(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;
 | ||
|   
 | ||
|   RCT rct; coord2rct(parent, x, y, dx, dy, rct);
 | ||
|   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* itf = get_interface(parent);     
 | ||
| 
 | ||
|   XI_OBJ_DEF* listdef = xi_add_list_def(NULL, dlg,
 | ||
|                                         rct.top, rct.left, rct.bottom-rct.top,
 | ||
|                                         XI_ATR_ENABLED | XI_ATR_VISIBLE,
 | ||
|                                         NORMAL_COLOR, NORMAL_BACK_COLOR,    // normal
 | ||
|                                         NORMAL_COLOR, DISABLED_BACK_COLOR,  // disabled
 | ||
|                                         FOCUS_COLOR,                        // active
 | ||
|                                         0);
 | ||
|   
 | ||
|   CHECK(listdef, "Can't create spreadsheet definition");
 | ||
|   listdef->app_data = (long)this;
 | ||
|   XI_LIST_DEF* l = listdef->v.list;
 | ||
|   l->width = rct.right - rct.left;                
 | ||
| #ifdef XI_R4
 | ||
|   l->min_heading_height = xi_button_calc_height_font(xi_get_system_font()) * lines_in_header;
 | ||
| #else
 | ||
|   l->min_heading_height = xi_button_calc_height_font_id(xvt_default_font()) * lines_in_header;
 | ||
| #endif
 | ||
|   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 = 2;          
 | ||
|     if (listdef->v.list->min_heading_height < 20)
 | ||
|       listdef->v.list->min_heading_height = 20;
 | ||
|   }  
 | ||
|   else
 | ||
|     coldef->v.column->center_heading = TRUE; 
 | ||
| 
 | ||
| 
 | ||
|   for (h = new_header.get(0), i = 0; h; h = new_header.get(), i++)
 | ||
|   {                  
 | ||
|     const TString testo(h);
 | ||
|     const int cid = FIRST_FIELD+i;                     // Column & Field ID
 | ||
|     const TOperable_field & f = (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;
 | ||
|   }
 | ||
| 
 | ||
|   // 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() 
 | ||
| {                    
 | ||
| }             
 | ||
| 
 | ||
| TMask& TSpreadsheet::sheet_mask() const
 | ||
| { 
 | ||
|   return ((TSpreadsheet*)this)->_mask;  
 | ||
| }                                  
 | ||
|  
 | ||
| // Converts a row number in the correspondig record number
 | ||
| int TSpreadsheet::row2rec(int& row)
 | ||
| {
 | ||
|   int rows;
 | ||
|   const long* handle = xi_get_list_info(_obj, &rows);
 | ||
|   
 | ||
|   if (row < 0) 
 | ||
|     row = 0;
 | ||
|   else 
 | ||
|   {
 | ||
|     if (row >= rows) 
 | ||
|       row = rows-1;
 | ||
|   }    
 | ||
|   const int r = (int)handle[row];
 | ||
|   CHECKD(r >= 0 && r < items(), "Sheet line out of range: ", row);
 | ||
|   return r;
 | ||
| }
 | ||
| 
 | ||
| // Converts a row number in the correspondig record number
 | ||
| int TSpreadsheet::rec2row(int record)
 | ||
| {
 | ||
|   int rows;
 | ||
|   const long* rec = xi_get_list_info(_obj, &rows);
 | ||
|   int r = int(record - rec[0]);
 | ||
|   if (r < 0 || r >= rows) 
 | ||
|     r = -1;
 | ||
|   return r;
 | ||
| }
 | ||
| 
 | ||
| // Retrieves the corresponding field of the mask from a spredsheet cell
 | ||
| TOperable_field* TSpreadsheet::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;
 | ||
|   XI_OBJ** column = xi_get_member_list(_obj, &num);
 | ||
|   if (colonna <= 0 || colonna >= num) 
 | ||
|     colonna = 1;
 | ||
|   
 | ||
|   int c = colonna;
 | ||
|   do
 | ||
|   { 
 | ||
|     const short n = column[c]->cid - FIRST_FIELD;
 | ||
|     if (!cell_disabled(rec, n))
 | ||
|       return c;
 | ||
|     
 | ||
|     c += direction;  
 | ||
|     if (c >= num) 
 | ||
|       c = 1; 
 | ||
|     else
 | ||
|       if (c <= 0) 
 | ||
|         c = num-1;
 | ||
|   } 
 | ||
|   while (c != colonna);
 | ||
|   
 | ||
|   return 0;  
 | ||
| }
 | ||
| 
 | ||
| int TSpreadsheet::find_enabled_record(int rec, int direction) const
 | ||
| {
 | ||
|   for (int r = rec+direction; r >= 0 && r < items(); r += direction)
 | ||
|   {
 | ||
|     if (find_enabled_column(r, 1, +1) > 0)
 | ||
|       return r;
 | ||
|   }
 | ||
|   return -1;
 | ||
| }
 | ||
| 
 | ||
| // riga (da 0), colonna (0 = numero, 1 = prima cella, ...)
 | ||
| void TSpreadsheet::set_focus_cell(int riga, int colonna)
 | ||
| {                                  
 | ||
| //  xi_set_focus(get_interface());            
 | ||
| 
 | ||
|   const int rec = row2rec(riga);   
 | ||
|   colonna = find_enabled_column(rec, colonna, +1);
 | ||
| 
 | ||
|   if (colonna > 0)
 | ||
|   {               
 | ||
|     WINDOW win = xvt_scr_get_focus_vobj();     // Puo' essere NULL per cui poi non funziona ...
 | ||
|     WINDOW par = parent();                     // ... la xi_set_focus(&cell)
 | ||
|     if (win != par)
 | ||
|     {
 | ||
|       xvt_scr_set_focus_vobj(par);  
 | ||
|       xvt_vobj_raise(par);          
 | ||
|     }
 | ||
|   
 | ||
|     XI_OBJ cell;     
 | ||
|     XI_MAKE_CELL(&cell, _obj, riga, colonna);
 | ||
| 
 | ||
|     xi_set_focus(&cell);          
 | ||
|     
 | ||
|     if (rec != _cur_rec)
 | ||
|     {      
 | ||
|       _cur_rec = rec;
 | ||
|       _cur_row = riga;            
 | ||
|       _row_dirty = FALSE;
 | ||
|     }  
 | ||
|     _edit_field = col2field(_cur_col = colonna); // qui
 | ||
|   } 
 | ||
| }
 | ||
| 
 | ||
| // @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);
 | ||
|     
 | ||
|     _property.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();
 | ||
|     _property.destroy();
 | ||
|     set_dirty(_row_dirty = FALSE);
 | ||
|   }
 | ||
|   else
 | ||
|   {
 | ||
|     _property.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 (!_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 = _edit_field->is_kind_of(CLASS_LIST_FIELD) ? txt :
 | ||
|                       (const char*)((TEditable_field*)_edit_field)->win2raw(txt);
 | ||
|                         
 | ||
|     _edit_field->set(val);  
 | ||
|     _edit_field->set_dirty();        // Get it dirty!
 | ||
|   }
 | ||
|   return _edit_field->get();
 | ||
| }
 | ||
| 
 | ||
| bool TSpreadsheet::off_cell_handler(XI_OBJ *cell)
 | ||
| {
 | ||
|   bool ok = TRUE;
 | ||
|   if (_edit_field != NULL)
 | ||
|   {
 | ||
|     const char* nuo = copy_cell2field(cell);
 | ||
|     if (_edit_field->on_key(_edit_field->is_edit() ? K_TAB : K_SPACE) == FALSE)   // Test it
 | ||
|       ok = *nuo == '\0';             // Se e' vuoto lascia stare
 | ||
|     else      
 | ||
|       _cell_dirty = FALSE;
 | ||
|     if (_row_dirty)  
 | ||
|     {
 | ||
|       owner().mask().notify_focus_field(owner().dlg());  // 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 int maxlen = xiev->v.cell_request.len;
 | ||
|     char numrig[8];
 | ||
|     const char* src = NULL;
 | ||
|     int nm;
 | ||
|     XI_OBJ** obj = xi_get_member_list(xiev->v.cell_request.list, &nm);
 | ||
|     const int num = xiev->v.cell_request.col_nbr;
 | ||
|     const int cid = obj[num]->cid;
 | ||
| 
 | ||
|     if (cid >= FIRST_FIELD)
 | ||
|     {
 | ||
|       if (rec < items())
 | ||
|       {   
 | ||
|         const int col = cid - FIRST_FIELD;
 | ||
|         const int curr = _cur_rec;
 | ||
|         _cur_rec = rec;
 | ||
|         const TOperable_field* f = field(cid);
 | ||
|         _cur_rec = curr;
 | ||
|         if (f)
 | ||
|         {
 | ||
|           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: 
 | ||
|               break;          // Leave code as is
 | ||
|             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 TString16 codval = rowrec.get(pos); // Codice valuta
 | ||
|                   const TCurrency c(r, codval, ZERO, _exchange_undefined, 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) //qui
 | ||
| 							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.attrib &= ~XI_ATR_ENABLED;
 | ||
|           }  
 | ||
|           else
 | ||
|           {
 | ||
| 						get_back_and_fore_color(xiev->v.cell_request.back_color, 
 | ||
|                                     xiev->v.cell_request.color, rec, col);
 | ||
| 						if (xiev->v.cell_request.back_color == 0 && f->required())
 | ||
| 							xiev->v.cell_request.back_color = REQUIRED_BACK_COLOR;
 | ||
|           }
 | ||
|           
 | ||
|           
 | ||
|           if (e->has_query_button()) 
 | ||
|           {
 | ||
|             xiev->v.cell_request.button = TRUE;
 | ||
|             xiev->v.cell_request.button_on_focus = TRUE;
 | ||
|           }  
 | ||
|         }    
 | ||
|         else
 | ||
|           xiev->v.cell_request.back_color = DISABLED_BACK_COLOR;
 | ||
|       }  
 | ||
|     } 
 | ||
|     else
 | ||
|     {       
 | ||
|       sprintf(numrig, "%d", rec+1);   
 | ||
|       src = numrig;       
 | ||
|     } 
 | ||
| 
 | ||
|     char* dst = xiev->v.cell_request.s;
 | ||
|     if (src && *src)
 | ||
|     {
 | ||
|       strncpy(dst, src, maxlen);
 | ||
|       dst[maxlen-1] = '\0';
 | ||
|     }  
 | ||
|     else
 | ||
|       *dst = '\0';
 | ||
|   }
 | ||
|     break;
 | ||
|   case XIE_CHG_CELL:
 | ||
|     if (_edit_field && !_cell_dirty)
 | ||
|     {
 | ||
|       notify_change();
 | ||
|       _cell_dirty = TRUE;
 | ||
|       _edit_field->set_dirty();    
 | ||
|     }  
 | ||
|     break;
 | ||
|   case XIE_BUTTON:
 | ||
|     if (_check_enabled)
 | ||
|     {
 | ||
|       on_idle();    // Termina tutti gli eventuali update in corso
 | ||
|       
 | ||
|       if (xiev->v.xi_obj->type == XIT_CELL)   // Bottone della cella
 | ||
|       {                
 | ||
|         XI_CELL_DATA& cell = xiev->v.xi_obj->v.cell;
 | ||
|         int num;
 | ||
|         XI_OBJ** column = xi_get_member_list(_obj, &num);
 | ||
|         CHECK(cell.column < num, "Bad column");
 | ||
|         int rec = cell.row;
 | ||
|         rec = row2rec(rec);
 | ||
|         const int col = column[cell.column]->cid - FIRST_FIELD;
 | ||
|         if (!cell_disabled(rec, col))
 | ||
|         {
 | ||
|           if (xi_move_focus(xiev->v.xi_obj))  
 | ||
|             dispatch_e_char(parent(), K_F9);
 | ||
|         }    
 | ||
|       }  
 | ||
|       else
 | ||
|       {
 | ||
|         if (xiev->v.xi_obj->type == XIT_LIST)   // Bottone dello sheet
 | ||
|         {
 | ||
|           if (test_focus_change() && active())
 | ||
|           {     
 | ||
|             int rec = -1;      
 | ||
|             _cell_dirty = FALSE;
 | ||
|             
 | ||
|             if (items() > 0 && !owner().append())
 | ||
|             {
 | ||
|               // XI_OBJ* itf = get_interface();
 | ||
|               if (owner().mask().focus_field().dlg() == owner().dlg())
 | ||
|                 rec = _cur_rec + 1;
 | ||
|               else
 | ||
|                 rec = 0;
 | ||
|             }
 | ||
|             insert(rec, TRUE, TRUE); 
 | ||
|             owner().mask().notify_focus_field(owner().dlg());
 | ||
|           }  
 | ||
|         }  
 | ||
|       }
 | ||
|     }    
 | ||
|     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())))
 | ||
| 	      {
 | ||
|           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())
 | ||
|           { 
 | ||
|             if (!_row_dirty)                      
 | ||
|             {
 | ||
|               notify_change();                  
 | ||
|               _row_dirty = _cell_dirty = FALSE;
 | ||
|               for (int i = sm.fields() - 1; i >= 0; i--)
 | ||
|                 sm.fld(i).set_dirty(FALSE);
 | ||
|             }
 | ||
|           
 | ||
|             button.on_hit();   
 | ||
|             if (sm.dirty())
 | ||
|             {
 | ||
|               _row_dirty = TRUE;
 | ||
|               mask2str(_cur_rec);  
 | ||
|             }
 | ||
| 
 | ||
|           }
 | ||
|           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;
 | ||
|         set_focus_cell(cell.row, cell.column); 
 | ||
|       }
 | ||
|       
 | ||
|       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(owner().dlg());
 | ||
|     break;
 | ||
|   case XIE_OFF_LIST:              
 | ||
|     on_idle();
 | ||
|     break;
 | ||
|   case XIE_ON_ROW:
 | ||
|     if (_check_enabled)
 | ||
|     {                     
 | ||
|       const int row = xiev->v.xi_obj->v.row; // Riga in cui si sta entrando
 | ||
|       int rows;                              // Numero totale di righe attive
 | ||
|       const long* handle = xi_get_list_info(_obj, &rows);
 | ||
|       
 | ||
|       // Calcola il numero del record corrispondente alla riga
 | ||
|       const bool exist = row >= 0 && row < rows;
 | ||
|       int next_rec = exist ? (int)handle[row] : items()-1;
 | ||
|       
 | ||
|       // Se la riga non esiste o non ha nessuna cella valida abilitata ...
 | ||
|       // ... cerca la prossima riga valida e rifiuta l'ingresso in questa
 | ||
|       if (!exist || find_enabled_column(next_rec, 1, +1) <= 0)
 | ||
|       {
 | ||
|         next_rec = find_enabled_record(next_rec, next_rec >= _cur_rec ? +1 : -1);
 | ||
|         post_select(next_rec);
 | ||
|         refused = TRUE;
 | ||
|         break;
 | ||
|       }
 | ||
|     
 | ||
|       // Setta _cur_rec in base a alla riga e cella correnti
 | ||
|       set_pos(xiev->v.xi_obj->v.row, _cur_col);
 | ||
|       if (_cur_rec < items() && notify(_cur_rec, K_TAB))
 | ||
|       {
 | ||
|         /* Guy! str2mask(_cur_rec); */
 | ||
|         _row_dirty = _cell_dirty = FALSE;
 | ||
|       }
 | ||
|       else
 | ||
|       {
 | ||
|         _cur_row = _cur_rec = 0;
 | ||
|         refused = TRUE;
 | ||
|       }  
 | ||
|     }
 | ||
|     break;
 | ||
|   case XIE_OFF_ROW:
 | ||
|     if (_check_enabled)
 | ||
|     {                 
 | ||
|       _check_enabled = FALSE;                   // Avoid recursion!
 | ||
|       if (_row_dirty && active())
 | ||
|       {  
 | ||
|         bool ok = 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
 | ||
|       }  
 | ||
|       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;     
 | ||
|       XI_OBJ row;
 | ||
|       
 | ||
|       _cur_col = -1;
 | ||
|       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+'+';
 | ||
|         }
 | ||
|       }
 | ||
| 
 | ||
|       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();
 | ||
|             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
 | ||
|             { 
 | ||
|               XI_OBJ cell; XI_MAKE_CELL(&cell, _obj, _cur_row, _cur_col); 
 | ||
|               // droppa giu'       
 | ||
|               TList_field& lst = (TList_field&)(*_edit_field);
 | ||
|               TDropDownList ddl(&cell, lst.get_codes(), lst.get_values());
 | ||
|               ddl.open();   
 | ||
|               while (ddl.is_open()) 
 | ||
|                 do_events();      
 | ||
|               // sdroppa su
 | ||
|               copy_cell2field();
 | ||
|             }
 | ||
|             else // edit_field
 | ||
|             { 
 | ||
|               // Notifica il corretto campo col focus sulla maschera
 | ||
|               sheet_mask().notify_focus_field(_edit_field->dlg());
 | ||
|               
 | ||
|               ok = _edit_field->on_key(k); 
 | ||
|               _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
 | ||
|           if (test_focus_change())
 | ||
|           {
 | ||
|             int rec = -1;
 | ||
|             _cell_dirty = _row_dirty = FALSE;
 | ||
|             
 | ||
|             if (items() > 0 && !owner().append())
 | ||
|             {
 | ||
|               get_interface();  // verificare
 | ||
|               if (owner().mask().focus_field().dlg() == owner().dlg())
 | ||
|                 rec = _cur_rec + 1;
 | ||
|               else
 | ||
|                 rec = 0;
 | ||
|             }
 | ||
|             insert(rec, TRUE, TRUE); 
 | ||
|             owner().mask().notify_focus_field(owner().dlg());
 | ||
|             refused = TRUE;
 | ||
|           }
 | ||
| 					else 
 | ||
| 						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 (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();
 | ||
| 						}
 | ||
|           } else 
 | ||
|           if (_edit_field->is_kind_of(CLASS_LIST_FIELD))
 | ||
|           {      
 | ||
|             notify_change();    // Aggiorna valore corrente listbox
 | ||
|             
 | ||
|             TList_field& lst = ((TList_field&)*_edit_field);
 | ||
|             bool changed = FALSE;
 | ||
|             switch (k)         
 | ||
|             {        
 | ||
|             case K_RIGHT:
 | ||
|               changed = lst.select_next();
 | ||
|               break;
 | ||
|             case K_LEFT:
 | ||
|               changed = lst.select_prev();
 | ||
|               break;
 | ||
|             default:
 | ||
|               if (k >= ' ' && k <= 'z')        
 | ||
|                 changed = lst.select_by_initial(char(k));
 | ||
|               break;  
 | ||
|             }   
 | ||
|             if (changed)
 | ||
|             {
 | ||
|               XI_OBJ cell; XI_MAKE_CELL(&cell, _obj, _cur_row, _cur_col); 
 | ||
|               xi_set_text(&cell, (char*)(const char*)lst.get());
 | ||
|               _cell_dirty = TRUE;
 | ||
|             }
 | ||
|             refused = TRUE;
 | ||
|           }
 | ||
|       break;
 | ||
|       }
 | ||
|     }  
 | ||
|     break;
 | ||
|   case XIE_XVT_EVENT:
 | ||
|     if (xiev->v.xvte.type == E_CHAR)
 | ||
|     {
 | ||
|       const KEY k = e_char_to_key(&xiev->v.xvte);
 | ||
|       switch (k)
 | ||
|       {
 | ||
|       case K_ROWEDIT:
 | ||
|         xiev->type = XIE_DBL_CELL;
 | ||
|         xiev->v.xi_obj = NULL;
 | ||
|         event_handler(itf, xiev);
 | ||
|         break; 
 | ||
|       case K_ENTER:
 | ||
|       case K_SHIFT+K_ENTER:
 | ||
|         {
 | ||
|           const int next_rec = find_enabled_record(_cur_rec, k == K_ENTER ? +1 : -1);
 | ||
|           if (next_rec >= 0)
 | ||
|           {
 | ||
|             dispatch_e_char(parent(), K_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 ? col2field(_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 < 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);  
 | ||
| 
 | ||
|   if (back != COLOR_INVALID || fore != COLOR_INVALID)
 | ||
|   {
 | ||
|     int first, last;
 | ||
|     if (row < 0)
 | ||
|     {
 | ||
|       first = 0;
 | ||
|       last = items()-1;
 | ||
|     }  
 | ||
|     else
 | ||
|       first = last = row;
 | ||
|   
 | ||
|     const bool crea = back != NORMAL_BACK_COLOR || fore != NORMAL_COLOR;
 | ||
|     for (int r = first; r <= last; r++)
 | ||
|     {
 | ||
|       TRow_property* prop = get_property(r, crea);
 | ||
|       if (prop)
 | ||
|         prop->set(col, back, fore);
 | ||
|     }
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| void 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(col, back, fore);
 | ||
| }
 | ||
| 
 | ||
| // @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)
 | ||
| {
 | ||
|   _str.swap(fromindex, toindex);
 | ||
|   _property.swap(fromindex, toindex);
 | ||
| }
 | ||
| 
 | ||
| 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::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)
 | ||
| {
 | ||
|   TRow_property* p = (TRow_property*)_property.objptr(row);
 | ||
|   if (p == NULL && create)
 | ||
|   {
 | ||
|     p = new TRow_property;
 | ||
|     _property.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 == TRUE)      // 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(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);
 | ||
|   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;
 | ||
| }
 | ||
| 
 | ||
| ///////////////////////////////////////////////////////////
 | ||
| // 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);
 | ||
|   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;
 | ||
|       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();
 | ||
|   }  
 | ||
|   const TMask & s = sheet_mask();
 | ||
|   short id;
 | ||
|   
 | ||
|   for (id = FIRST_FIELD; ; id++)
 | ||
|     if (s.id2pos(id) < 0) break;
 | ||
|   _last_column_id = id - 1;
 | ||
|   
 | ||
|   ((TSpreadsheet*)_ctl)->load_columns_order();
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| // Certified 100%
 | ||
| TString_array& TSheet_field::rows_array() const
 | ||
| {
 | ||
|   return ((TSpreadsheet*)_ctl)->rows_array();
 | ||
| }
 | ||
| 
 | ||
| // Certified 100%
 | ||
| // Ritorna l'indice della prima riga vuota dello sheet
 | ||
| int TSheet_field::first_empty() const
 | ||
| {                             
 | ||
|   TSpreadsheet* s = (TSpreadsheet*)_ctl;
 | ||
|   const int max = (int)s->items();
 | ||
|   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)
 | ||
|     {                  
 | ||
|       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);
 | ||
| }
 | ||
| 
 | ||
| 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);
 | ||
| }
 | ||
| 
 | ||
| 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);
 | ||
| }
 | ||
| 
 | ||
| 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::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();
 | ||
| }
 | ||
| 
 | ||
| bool TSheet_field::on_hit()
 | ||
| {
 | ||
|   if (!mask().is_running())           // Inizializzazione maschera
 | ||
|   {
 | ||
|     force_update();               
 | ||
|     
 | ||
|     if (items() > 0)
 | ||
|     {
 | ||
|       mask().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);
 | ||
| }
 | ||
| 
 | ||
| void TSheet_field::set_focus_cell(int riga, int colonna)
 | ||
| { 
 | ||
|   TSpreadsheet* s = (TSpreadsheet*)_ctl;
 | ||
|   s->set_focus_cell(riga, colonna);
 | ||
| }  
 | ||
| 
 | ||
| bool TSheet_field::on_key(KEY k)
 | ||
| {                   
 | ||
|   if (k == K_TAB && items() > 0)  
 | ||
|   {               
 | ||
|     if (focusdirty())
 | ||
|     {
 | ||
|       TSpreadsheet* s = (TSpreadsheet*)_ctl;
 | ||
|       if (!s->test_focus_change())
 | ||
|         return FALSE;
 | ||
|     }
 | ||
|   }           
 | ||
|   
 | ||
|   if (k == K_ROWEDIT && items() > 0)
 | ||
|   {          
 | ||
|     select(items()-1);
 | ||
|     XI_EVENT xie;
 | ||
|     xie.type = XIE_DBL_CELL;
 | ||
|     xie.v.xi_obj = NULL;
 | ||
|     _ctl->event_handler(NULL, &xie);
 | ||
|     return TRUE;
 | ||
|   }
 | ||
|   
 | ||
|   return TOperable_field::on_key(k);
 | ||
| }
 | ||
| 
 | ||
| void TSheet_field::on_idle()
 | ||
| {
 | ||
|   ((TSpreadsheet*)_ctl)->on_idle();
 | ||
| }
 | ||
| 
 | ||
| // Ricopia i campi della maschera nel record dato 
 | ||
| void TSheet_field::mask2row(int n, TToken_string & rec)
 | ||
| {
 | ||
|   const TMask& m = sheet_mask();
 | ||
| 
 | ||
|   rec.cut(0);
 | ||
|   const TSpreadsheet& s = (const TSpreadsheet&)*_ctl;
 | ||
| 
 | ||
|   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)
 | ||
|           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() : " ");
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| // Ricopia i campi del record dato nella maschera 
 | ||
| void TSheet_field::row2mask(int n, TToken_string& r, int mode)
 | ||
| {
 | ||
|   TString val(80);   
 | ||
|   
 | ||
|   TMask& m = sheet_mask();
 | ||
|   const int campi = m.fields();
 | ||
|   const TSpreadsheet& s = (const TSpreadsheet&)*_ctl;
 | ||
|   int i;  // Contatore di tutti i cicli successivi
 | ||
|   
 | ||
|   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)
 | ||
|   {
 | ||
|     for (i = 0; i < campi; i++)
 | ||
|     {
 | ||
|       TMask_field& f = m.fld(i);
 | ||
|       const short id = f.dlg();
 | ||
| 
 | ||
|       if (id >= FIRST_FIELD && 
 | ||
|           !f.is_kind_of(CLASS_BUTTON_FIELD) &&
 | ||
|           (f.active() || f.ghost()))
 | ||
|       {
 | ||
|         if (f.has_check() && (mode & 0x1)) 
 | ||
|           f.check(STARTING_CHECK); 
 | ||
|         f.set_dirty(FALSE);
 | ||
|         if (mode & 0x2)
 | ||
|           f.on_hit();
 | ||
|       }
 | ||
|     }
 | ||
|   }  
 | ||
|   
 | ||
|   for (i = 0; i < campi; i++)
 | ||
|   {
 | ||
|     TMask_field& f = m.fld(i);
 | ||
|     if (f.dirty() == TRUE)
 | ||
|       f.set_dirty(FALSE);
 | ||
|   }
 | ||
|   
 | ||
|   val.format("Riga %d", n+1);
 | ||
|   m.set_caption(val);
 | ||
| }
 | ||
| 
 | ||
| KEY TSheet_field::run_editmask(int ) 
 | ||
| { 
 | ||
|   TMask& m = sheet_mask();
 | ||
|   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_mask();         
 | ||
|   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.not_empty(); 
 | ||
|          dbfieldname = _file_k_names.get()) 
 | ||
|     {
 | ||
|       TMask_field& f= mask().field(_file_k_ids.get_int());
 | ||
|       if (mask().edit_mode())
 | ||
|         ((TLoadable_field&)f).autoload(r);   // Molto probabilmente inutile!
 | ||
|       _sheetfile->put(dbfieldname, f.get()); 
 | ||
|     } 
 | ||
|     return &_sheetfile->curr();
 | ||
|   }
 | ||
|   return NULL;
 | ||
| }
 | ||
| 
 | ||
| // Certified: ...under debug..
 | ||
| bool TSheet_field::autoload_line(int i, const TRectype& rec)
 | ||
| {
 | ||
|   TToken_string &row= this->row(i-1);
 | ||
|         
 | ||
|   row = "";
 | ||
|   // riempie le colonne dello sheet i cui campi hanno attributo "FIELD"
 | ||
|   /*for (int f=FIRST_FIELD;  f<=_last_column_id; f++) {
 | ||
|     TFieldref const *dbfield=sheet_mask().field(f).field();
 | ||
|     if (dbfield) {
 | ||
|       row.add(dbfield->read(rec),cid2index(f));
 | ||
|     }
 | ||
|     // completa l'operazione con le funzioni definite dall'utente
 | ||
|   } */
 | ||
|   for (int j = 0; j < sheet_mask().fields(); j++)
 | ||
|   {
 | ||
|     TMask_field& mf = sheet_mask().fld(j);
 | ||
|     const short id = mf.dlg();
 | ||
|     const TFieldref* dbfield = mf.field();
 | ||
|     if (dbfield) 
 | ||
|     {
 | ||
|       if (id>=FIRST_FIELD && id<=_last_column_id) 
 | ||
|       {
 | ||
|         row.add(dbfield->read(rec),cid2index(id));
 | ||
|       } 
 | ||
|       else 
 | ||
|       {
 | ||
|         mf.set(dbfield->read(rec));
 | ||
|       }
 | ||
|     }
 | ||
|   } 
 | ||
|   // 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)
 | ||
| {
 | ||
|   for (int j = 0; j < sheet_mask().fields(); j++)
 | ||
|   {
 | ||
|     TMask_field& mf = sheet_mask().fld(j);
 | ||
|     const short id = mf.dlg();
 | ||
|     const TFieldref* dbfield=mf.field();
 | ||
|     if (dbfield)
 | ||
|     {
 | ||
|       if (id>=FIRST_FIELD && id<=_last_column_id) 
 | ||
|         dbfield->write(cell(i-1,cid2index(id)),rec);
 | ||
|       else
 | ||
|         dbfield->write(mf.get(), 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
 | ||
|         TString dbfieldname;
 | ||
|         TMask_field * f;
 | ||
|         restart_key();
 | ||
|         while ((f = get_key(dbfieldname)))
 | ||
|           _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 >= 1 && row(i-1).empty_items()) 
 | ||
|       i--;
 | ||
|     for (; i >= 1; i--)
 | ||
|     {
 | ||
|       TRectype &rec  = _linee_rec->row(i, TRUE);
 | ||
|       autosave_line(i,rec);
 | ||
|     }    
 | ||
|   }
 | ||
|   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;
 | ||
| }
 |