lffiles.h Tolto commento @M msksheet.cpp Eliminata possibilita di doppia notifica del K_ENTER git-svn-id: svn://10.65.10.50/trunk@2375 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			2108 lines
		
	
	
		
			55 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			2108 lines
		
	
	
		
			55 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
#include <msksheet.h>
 | 
						||
#include <urldefid.h>
 | 
						||
#include <utility.h>
 | 
						||
 | 
						||
const short FIRST_FIELD = 101;
 | 
						||
 | 
						||
#if XVT_OS == XVT_OS_WIN
 | 
						||
 | 
						||
#include <xil.h>
 | 
						||
#include <colors.h>
 | 
						||
#include <keys.h>
 | 
						||
 | 
						||
///////////////////////////////////////////////////////////
 | 
						||
// TSpreadsheet
 | 
						||
///////////////////////////////////////////////////////////
 | 
						||
 | 
						||
// @doc INTERNAL
 | 
						||
 | 
						||
// @class TSpreadsheet | Classe per la creazione di uno spreadsheet all'interno
 | 
						||
//                       di una maschera
 | 
						||
//
 | 
						||
// @base public | TWindow
 | 
						||
class TSpreadsheet : public TWindow
 | 
						||
{
 | 
						||
  // @author:(INTERNAL) Guido
 | 
						||
 | 
						||
  // @cfriend TSheet_field
 | 
						||
  friend class TSheet_field;
 | 
						||
 | 
						||
  // @access Private Member
 | 
						||
 | 
						||
  enum {
 | 
						||
    // @ccost ITF_CID | 0 | Identifica l'interfaccia dello spreadsheet
 | 
						||
    ITF_CID = 0,
 | 
						||
    // @ccost LIST_CID | 1 | Identifica il contenuto dello spreadsheet
 | 
						||
    LIST_CID = 1 };
 | 
						||
 | 
						||
  // @cmember Array di TToken_strings contenenti le righe
 | 
						||
  TString_array _str;
 | 
						||
  // @cmember Array delle colonne disattivate (solo visualizzazione)
 | 
						||
  TBit_array _column_disabled;
 | 
						||
  // @cmember Array dell celle disattivate (solo visualizzazione)
 | 
						||
  TArray _disabled;
 | 
						||
 | 
						||
  // @cmember Maschera in cui e' contenuto lo spreadsheet
 | 
						||
  TMask _mask;
 | 
						||
  // @cmember Numero di colonne presenti nello spreadsheet
 | 
						||
  int _columns;
 | 
						||
  // @cmember Trucco per evitare che lo sheet prenda il focus tutte le volte che parte la maschera
 | 
						||
  bool _firstfocus;
 | 
						||
  // @cmember Indica se e' attivo lo spreadsheet
 | 
						||
  bool _active;
 | 
						||
 | 
						||
  // @cmember Puntatore al contenuto dello spreadsheet
 | 
						||
  XI_OBJ *_list;
 | 
						||
  // @cmember Puntatore all'interfaccia dello spreadsheet
 | 
						||
  XI_OBJ *_itf;
 | 
						||
 | 
						||
 | 
						||
  // @cmember Funzione per la gestione di una riga dello sheet (vedi <t SPREADSHEET_NOTIFY>)
 | 
						||
  SPREADSHEET_NOTIFY _notify;
 | 
						||
  // @cmember Funzione per l'apertura della maschera di edit della riga
 | 
						||
  //              (vedi <t SPREADSHEET_GETMASK>)
 | 
						||
  SPREADSHEET_GETMASK _getmask;
 | 
						||
  
 | 
						||
  // @cmember Campo che possiede lo spreadsheet
 | 
						||
  TSheet_field* _owner;
 | 
						||
  
 | 
						||
  // @cmember Campo corrente che si sta editando
 | 
						||
  TMask_field* _edit_field;
 | 
						||
  // @cmember Coordinata della riga della cella corrente
 | 
						||
  int _cur_row;
 | 
						||
  // @cmember Numero del record sul file al quale fa riferimento la cella corrente
 | 
						||
  int _cur_rec;
 | 
						||
  // @cmember Coordinata della colonna della cella corrente
 | 
						||
  int _cur_col;
 | 
						||
  // @cmember Indica se la riga corrente e' stat modificata
 | 
						||
  bool _row_dirty;
 | 
						||
  // @cmember Permette di gestire i check OFF_ROW e OFF_CELL
 | 
						||
  bool _check_enabled;
 | 
						||
  // @cmember Numero della riga che necessita aggiornamento (vengono aggiornate 
 | 
						||
  //                                    nella <mf TSpreadsheet::on_idle>)
 | 
						||
  int _needs_update;
 | 
						||
 | 
						||
  // @cmember Inizializza lo spreadsheet
 | 
						||
  void init();
 | 
						||
  // @cmember 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>)
 | 
						||
  void list_handler(XI_EVENT* xiev);
 | 
						||
               
 | 
						||
  //@cmember Copia una cella nel corrispondente campo della maschera e ne ritorna il contenuto
 | 
						||
  const char* copy_cell2field(XI_OBJ* cell = NULL);
 | 
						||
               
 | 
						||
  //@cmember Gestisce l'uscita delle celle (chiamata dal <mf TSpreadsheet::list_handler>)
 | 
						||
  bool off_cell_handler(XI_OBJ* cell = NULL);
 | 
						||
  
 | 
						||
  // @cmember Ritorna il campo della maschera corrispondente alla cella dello
 | 
						||
  //          spreadsheet indicata da <p pos>
 | 
						||
  TMask_field* col2field(int pos) const;
 | 
						||
  // @cmember Ritorna il campo della maschera corrispondente alla cella dello
 | 
						||
  //          spreadsheet indicata da <p cell> (chiama <mf TMask::col2field>)
 | 
						||
  TMask_field* cell2field(const XI_OBJ* cell) const;
 | 
						||
  // @cmember Ritorna la posizione della colonna con identificatore <p cid>
 | 
						||
  int cid2col(short cid) const;
 | 
						||
  // @cmember Ritorna la colonna corrispondente al campo <p f> della maschera
 | 
						||
  int field2col(const TMask_field* f) const;
 | 
						||
 | 
						||
  // @cmember Aggiorna il record sullo spreadsheet
 | 
						||
  void update_rec(int rec);
 | 
						||
  TMask_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 riga nel corrispondente
 | 
						||
  //          numero della riga
 | 
						||
  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* TSpreadsheet::find_column(int col) const;
 | 
						||
 | 
						||
  // @access Public Member
 | 
						||
public:
 | 
						||
  // @cmember Modifica a video la riga
 | 
						||
  void update(int row);
 | 
						||
 | 
						||
  // @cmember Ritorna il contenuto della riga <p n>-esima
 | 
						||
  TToken_string& row(int n)
 | 
						||
  { return _str.row(n); }
 | 
						||
  // @cmember Aggiunge una riga allo spreadsheet passata come puntatore
 | 
						||
  //          (vedi <mf TArray::add>)
 | 
						||
  int add(const TToken_string& s)
 | 
						||
  { return _str.add(s); }
 | 
						||
  // @cmember Aggiunge una riga allo spreadsheet (vedi <mf TArray::add>)
 | 
						||
  int add(TToken_string* s)
 | 
						||
  { return _str.add(s); }
 | 
						||
  // @cmember Inserisce un record in una posizione stabilita
 | 
						||
  int insert(int rec);
 | 
						||
  // @cmember Elimina il record <p rec>
 | 
						||
  bool destroy(int rec = -1);
 | 
						||
  // @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 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/disabiltare una colonna
 | 
						||
  void enable_column(int col, bool on = TRUE);
 | 
						||
  // @cmember Permette di eliminare una colonna dallo spreadsheet
 | 
						||
  void delete_column(const int col) const;
 | 
						||
  // @cmember Sposta la colonna dalla posizione <p fromindex> alla posizione
 | 
						||
  //          <p toindex>
 | 
						||
  void move_column(const int fromindex, const int toindex) const;
 | 
						||
  // @cmember Permette di invertire la posiozne di due colonne
 | 
						||
  void swap_columns(const int fromid, const int toid) const;
 | 
						||
  // @cmember Permette di invertire la posiozne di due righe
 | 
						||
  void swap_rows(const int fromindex, const int toindex);
 | 
						||
 | 
						||
  // @cmember Setta la larghezza della colonna
 | 
						||
  void set_column_width(const int col, const int width) const;
 | 
						||
  // @cmember Setta il titolo della colonna
 | 
						||
  void set_column_header(const int col, const TString& header) const;
 | 
						||
  // @cmember Setta l'allinemento di una colonna
 | 
						||
  void set_column_justify(int col, bool right);
 | 
						||
  // @cmember Permette di abilitare/disabilitare una singola cella
 | 
						||
  void enable_cell(int row, int column, bool on = TRUE);
 | 
						||
  // @cmember Controlla se una cella e' disabilitata
 | 
						||
  bool cell_disabled(int row, int column) const;
 | 
						||
 | 
						||
  // @cmember Ritorna la maschera che appartiene allo spreadsheet
 | 
						||
  TMask& sheet_mask() const;
 | 
						||
 | 
						||
  // @cmember Ritorna la maschera cui appartiene lo spreadsheet
 | 
						||
  TMask& mask() const;
 | 
						||
  
 | 
						||
  // @cmember Ricopia i campi della maschera nel record <p n>-esimo ed
 | 
						||
  //          aggiorna il display
 | 
						||
  void mask2str(int n);
 | 
						||
  // @cmember Ricopia i campi del record <p n>-esimo nella maschera ed
 | 
						||
  //          aggiorna il display
 | 
						||
  void str2mask(int n);
 | 
						||
  // @cmember Apre la maschera della riga <p n>-esima editando la riga
 | 
						||
  KEY edit(int n);
 | 
						||
  
 | 
						||
  // @cmember Ritorna il numero di righe dello sheet
 | 
						||
  int items() const
 | 
						||
  { return _str.items(); }
 | 
						||
  // @cmember Ritorna il record corrente
 | 
						||
  int selected() const
 | 
						||
  { return _cur_rec; }
 | 
						||
  // @cmember Seleziona una riga dandogli il focus
 | 
						||
  void select(int r);
 | 
						||
  // @cmember Ritorna il numero di colonne presenti enllo spreadsheet
 | 
						||
  int columns() const
 | 
						||
  { return _columns; }
 | 
						||
  
 | 
						||
  // @cmember Controlla se e' stato modificato una cella dello spreadsheet
 | 
						||
  bool dirty() const
 | 
						||
  { return _owner->dirty(); }
 | 
						||
  // @cmember Permette di indicare se e' stata modificata una cella dello spreadsheet
 | 
						||
  void set_dirty(bool spork = TRUE)
 | 
						||
  { _owner->set_dirty(spork); }
 | 
						||
  
 | 
						||
  // @cmember Ritorna il valore della variabile active
 | 
						||
  bool active() const
 | 
						||
  { return _active; }
 | 
						||
  // @cmember Ritorna se e' possibile lasciare il focus dallo spreadsheet (TRUE se e' possibile)
 | 
						||
  bool test_focus_change();
 | 
						||
 | 
						||
  // @cmember Setta il membro <p _getmask> on il valore <p n>
 | 
						||
  void set_getmask(SPREADSHEET_GETMASK n)
 | 
						||
  { _getmask = n; }
 | 
						||
  
 | 
						||
  // @cmember Setta il membro <p _notify> on il valore <p n>
 | 
						||
  void set_notify(SPREADSHEET_NOTIFY n)
 | 
						||
  { _notify = n; }
 | 
						||
 | 
						||
  // @cmember Costruttore
 | 
						||
  TSpreadsheet(short x, short y, short dx, short dy, const char* maskname, int maskno, const char* head, WINDOW parent, TSheet_field* owner);
 | 
						||
  // @cmember Distruttore
 | 
						||
  virtual ~TSpreadsheet();
 | 
						||
};
 | 
						||
 | 
						||
// @doc EXTERNAL
 | 
						||
 | 
						||
// Certified 100%
 | 
						||
void TSpreadsheet::init()
 | 
						||
{
 | 
						||
  static bool first = TRUE;
 | 
						||
  if (!first) return;
 | 
						||
  
 | 
						||
  XVT_FNTID font = xvt_dwin_get_font(TASK_WIN);               
 | 
						||
  xi_set_font_id(font);
 | 
						||
 | 
						||
  xi_init();
 | 
						||
  xi_set_pref(XI_PREF_3D_LOOK, TRUE);
 | 
						||
  first = FALSE;
 | 
						||
}                             
 | 
						||
 | 
						||
 | 
						||
// @mfunc Costruttore
 | 
						||
TSpreadsheet::TSpreadsheet(
 | 
						||
  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 della maschera
 | 
						||
  WINDOW parent,         // @parm Finestra alla quale appartiene lo spreadsheet
 | 
						||
  TSheet_field* o)       // @parm Indica il campo della maschera che contiene lo spreadsheet
 | 
						||
: _mask(maskname, maskno), _notify(NULL), _getmask( NULL ), _owner(o),
 | 
						||
  _cur_row(0), _cur_col(1), _cur_rec(0), _edit_field(NULL), _active(TRUE),
 | 
						||
  _row_dirty(FALSE), _check_enabled(TRUE), _firstfocus(TRUE),
 | 
						||
  _needs_update(-1)
 | 
						||
{
 | 
						||
  const int NUMBER_WIDTH = 3;
 | 
						||
  const int MAX_COL = 32;
 | 
						||
  int m_width[MAX_COL], v_width[MAX_COL];
 | 
						||
  int fixed_columns = 1;                               // Number of fixed columns
 | 
						||
 | 
						||
  init();
 | 
						||
  
 | 
						||
  sheet_mask().set_sheet(o);
 | 
						||
  
 | 
						||
  // Calcolo larghezza massima tabella
 | 
						||
 | 
						||
  TToken_string header(head);
 | 
						||
  TToken_string new_header(256);
 | 
						||
  int i = 0, tot_width = NUMBER_WIDTH+1;
 | 
						||
  int f_width = tot_width<<1;                          // Stima larghezza colonne fisse
 | 
						||
  int max_width = f_width;                             // Stima larghezza della colonna piu' grande
 | 
						||
  
 | 
						||
  for (const char* h = header.get(); h; h = header.get(), i++)
 | 
						||
  {
 | 
						||
    CHECKD(i < MAX_COL, "Tu meni calumns in scit: ", i);
 | 
						||
 | 
						||
    const int cid = FIRST_FIELD+i;                    // Column & Field ID
 | 
						||
    const TMask_field* f = field(cid);                // Field on mask
 | 
						||
    CHECKD(f, "The spreadsheet mask needs ALSO field ", cid);
 | 
						||
 | 
						||
    TString80 testa(h);
 | 
						||
    const int at = testa.find('@');
 | 
						||
    int m, v;                                         // Memory and video width
 | 
						||
    if (at >= 0)
 | 
						||
    {
 | 
						||
      const TString& wi = testa.mid(at+1);
 | 
						||
      m = atoi(wi);
 | 
						||
      if (wi.find('F') >= 0) 
 | 
						||
      {
 | 
						||
        fixed_columns++;
 | 
						||
        f_width += m+1;
 | 
						||
      }  
 | 
						||
      testa.cut(at);
 | 
						||
      v = max(at, m+(f->has_query() ? 1 : 0));
 | 
						||
    } 
 | 
						||
    else 
 | 
						||
    {                                                     
 | 
						||
      m = testa.len();
 | 
						||
      v = m+(f->has_query() ? 1 : 0);
 | 
						||
    }
 | 
						||
    
 | 
						||
    if (f->is_edit())
 | 
						||
      m = f->size();
 | 
						||
    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;
 | 
						||
  
 | 
						||
  if (x < 0) x = 0; 
 | 
						||
  if (y < 0) y = 0;
 | 
						||
  if (dx == 0) 
 | 
						||
  {
 | 
						||
    dx = tot_width;                  
 | 
						||
    if (dx > 76) dx = -x;
 | 
						||
  }  
 | 
						||
  
 | 
						||
  RCT rct = resize_rect(x, y, dx, dy, WO_TE, parent);
 | 
						||
  rct.bottom -= 12;
 | 
						||
  rct.right  -= 28;
 | 
						||
  
 | 
						||
  if ((f_width+max_width)*CHARX > rct.right)
 | 
						||
    fixed_columns = 1;
 | 
						||
 | 
						||
  XI_OBJ_DEF* itfdef = xi_create_itf_def(ITF_CID,
 | 
						||
                                         (XI_EVENT_HANDLER)xiev_handler, &rct, (char*)maskname,
 | 
						||
                                         PTR_LONG(this));
 | 
						||
  itfdef->v.itf->automatic_back_color = FALSE;
 | 
						||
  itfdef->v.itf->back_color = MASK_BACK_COLOR;
 | 
						||
 | 
						||
  XI_OBJ_DEF* listdef = xi_add_list_def(itfdef, LIST_CID,
 | 
						||
                                        0, 0, rct.bottom-rct.top,
 | 
						||
                                        XI_ATR_ENABLED | XI_ATR_VISIBLE,
 | 
						||
                                        NORMAL_COLOR, NORMAL_BACK_COLOR,    // normal
 | 
						||
                                        NORMAL_COLOR, DISABLED_BACK_COLOR,  // disabled
 | 
						||
                                        COLOR_RED,                          // active
 | 
						||
                                        LIST_CID);
 | 
						||
  listdef->v.list->sizable_columns = TRUE;
 | 
						||
  listdef->v.list->movable_columns = TRUE;
 | 
						||
  listdef->v.list->scroll_bar = TRUE;
 | 
						||
  listdef->v.list->scroll_bar_button = TRUE;
 | 
						||
  listdef->v.list->fixed_columns = fixed_columns;
 | 
						||
  listdef->v.list->width = rct.right-rct.left;
 | 
						||
  listdef->v.list->min_cell_height = CHARY;
 | 
						||
  listdef->v.list->min_heading_height = CHARY;
 | 
						||
  listdef->v.list->white_space_color = MASK_DARK_COLOR;
 | 
						||
  
 | 
						||
  word attr = XI_ATR_RJUST;                                            
 | 
						||
  if (sheet_mask().id2pos(FIRST_FIELD -1) != -1)
 | 
						||
    attr |= XI_ATR_SELECTABLE;                         
 | 
						||
  
 | 
						||
  XI_OBJ_DEF* coldef = xi_add_column_def(listdef, 0, attr, 0, NUMBER_WIDTH, NUMBER_WIDTH+1, 
 | 
						||
                                         attr & XI_ATR_SELECTABLE ? "X" : "");
 | 
						||
  
 | 
						||
  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; 
 | 
						||
    listdef->v.list->min_heading_height = 16;
 | 
						||
  }  
 | 
						||
  else
 | 
						||
    coldef->v.column->center_heading = TRUE; 
 | 
						||
 | 
						||
 | 
						||
  for (h = new_header.get(0), i = 0; h; h = new_header.get(), i++)
 | 
						||
  {                  
 | 
						||
    const TString80 testo(h);
 | 
						||
    const int cid = FIRST_FIELD+i;                     // Column & Field ID
 | 
						||
    const TMask_field* f = field(cid);                 // Field on mask
 | 
						||
    const int acqua = f->class_id();
 | 
						||
 | 
						||
    long flags =  XI_ATR_EDITMENU | XI_ATR_AUTOSCROLL;
 | 
						||
    switch (acqua)
 | 
						||
    {
 | 
						||
    case CLASS_EDIT_FIELD:
 | 
						||
      if (f->right_justified())    
 | 
						||
        flags |= XI_ATR_RJUST;
 | 
						||
      break;
 | 
						||
    case CLASS_REAL_FIELD:
 | 
						||
      flags |= XI_ATR_RJUST; 
 | 
						||
      break;
 | 
						||
    case CLASS_BUTTON_FIELD:
 | 
						||
      flags |= XI_ATR_SELECTABLE; 
 | 
						||
      break;
 | 
						||
    default:
 | 
						||
      break;
 | 
						||
    }      
 | 
						||
    if (f->active()) flags |= XI_ATR_ENABLED | XI_ATR_FOCUSBORDER | XI_ATR_AUTOSELECT;
 | 
						||
    else _column_disabled.set(i);
 | 
						||
 | 
						||
    coldef = xi_add_column_def(listdef, cid, flags, cid, v_width[i], m_width[i], 
 | 
						||
                               (char*)(const char*)testo);
 | 
						||
    coldef->v.column->heading_platform = TRUE;
 | 
						||
    coldef->v.column->center_heading = TRUE;
 | 
						||
  }
 | 
						||
 | 
						||
  RCT itfrct;
 | 
						||
  xi_get_def_rect(itfdef, &itfrct);
 | 
						||
  xvt_rect_offset(&itfrct, rct.left, rct.top);
 | 
						||
  itfrct.bottom++;
 | 
						||
 | 
						||
  WINDOW win = xvt_win_create(W_NO_BORDER, &itfrct, "", 0, parent,
 | 
						||
                              0, EM_ALL, (EVENT_HANDLER)xi_event, 0L);
 | 
						||
  CHECK(win, "Can't create a window for the spreadsheet");
 | 
						||
 | 
						||
  set_win(win);                       // Set TWindow::_win
 | 
						||
  itfdef->v.itf->win = win;           // Link interface to win
 | 
						||
 | 
						||
  xi_create(XI_NULL_OBJ, itfdef);     // Create the whole thing!
 | 
						||
  xi_tree_free(itfdef);               // Free definitions
 | 
						||
 | 
						||
  _itf  = xi_get_itf(win);            // Store useful references for later use
 | 
						||
  _list = xi_get_obj(_itf, LIST_CID);
 | 
						||
}
 | 
						||
 | 
						||
TSpreadsheet::~TSpreadsheet() 
 | 
						||
{                    
 | 
						||
  if (_getmask != NULL)
 | 
						||
    _getmask(0, _mask, TRUE);   // Distrugge la maschera customizzata
 | 
						||
    
 | 
						||
  set_win(NULL_WIN); 
 | 
						||
}             
 | 
						||
 | 
						||
TMask& TSpreadsheet::sheet_mask() const
 | 
						||
{ 
 | 
						||
  TMask& m = ((TSpreadsheet*)this)->_mask;
 | 
						||
  if (_getmask != NULL && _cur_rec >= 0 && _cur_rec < items())
 | 
						||
    return *_getmask((int)_cur_rec, m, FALSE);
 | 
						||
  return m;
 | 
						||
}                                  
 | 
						||
 
 | 
						||
 | 
						||
// Converts a row number in the correspondig record number
 | 
						||
int TSpreadsheet::row2rec(int& row)
 | 
						||
{
 | 
						||
  int rows;
 | 
						||
  const long* rec = xi_get_list_info(_list, &rows);
 | 
						||
  
 | 
						||
  int r = -1;
 | 
						||
  if (row < 0) 
 | 
						||
  {
 | 
						||
    row = 0;
 | 
						||
    r = (int)rec[row] /* -1 */; 
 | 
						||
  }  
 | 
						||
  else 
 | 
						||
    if (row >= rows) 
 | 
						||
    { 
 | 
						||
      row = rows-1;
 | 
						||
      r = (int)rec[row] /* +1 */; 
 | 
						||
    }  
 | 
						||
    else 
 | 
						||
      r = (int)rec[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(_list, &rows);
 | 
						||
  int r = int(record - rec[0]);
 | 
						||
  if (r < 0 || r >= rows) 
 | 
						||
    r = -1;
 | 
						||
  
 | 
						||
  return r;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
// Retrieves the corresponding field of the mask from a spredsheet cell
 | 
						||
TMask_field* TSpreadsheet::col2field(int pos) const
 | 
						||
{
 | 
						||
  int num;
 | 
						||
  XI_OBJ** column = xi_get_member_list(_list, &num);
 | 
						||
  CHECKD(pos >= 0 && pos < num, "Bad column number", pos);
 | 
						||
 | 
						||
  TMask_field* good = NULL;
 | 
						||
  for (short id = column[pos]->cid; ; id += 100)
 | 
						||
  {
 | 
						||
    TMask_field* f = field(id);
 | 
						||
    if (f == NULL) break;             // Search failed
 | 
						||
    good = f;                         // We've found a field with the proper ID ...
 | 
						||
    if (f->active()) break;           // ... and it's active: end of search
 | 
						||
  }
 | 
						||
 | 
						||
  CHECKD(good, "Can't find field corresponding to column ", pos);
 | 
						||
  return good;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
// Retrieves the corresponding field of the mask from a spredsheet cell
 | 
						||
TMask_field* TSpreadsheet::cell2field(const XI_OBJ* cell) const
 | 
						||
{
 | 
						||
  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(_list, &num);
 | 
						||
  for (int c = num-1; c > 1; c--)
 | 
						||
  {
 | 
						||
    if (column[c]->cid == cid)
 | 
						||
      break;
 | 
						||
  }
 | 
						||
  return c;
 | 
						||
}
 | 
						||
 | 
						||
int TSpreadsheet::field2col(const TMask_field* f) const
 | 
						||
{         
 | 
						||
  const short cid = FIRST_FIELD + (f->dlg() % 100) - 1;
 | 
						||
  return cid2col(cid);
 | 
						||
}
 | 
						||
 | 
						||
void TSpreadsheet::update_rec(int rec)
 | 
						||
{                 
 | 
						||
  const int riga = rec2row(rec);
 | 
						||
  if (riga >= 0)
 | 
						||
  {                 
 | 
						||
    const bool has_focus = rec == selected() && 
 | 
						||
                           mask().focus_field().dlg() == _owner->dlg();
 | 
						||
    if (has_focus)
 | 
						||
      xi_set_focus(_itf);          
 | 
						||
    
 | 
						||
    XI_OBJ row;
 | 
						||
    XI_MAKE_ROW(&row, _list, riga);
 | 
						||
    xi_cell_request(&row);              // Update internal values
 | 
						||
    
 | 
						||
    if (has_focus)  
 | 
						||
    {
 | 
						||
      str2mask(_cur_rec);
 | 
						||
      set_focus_cell(riga, _cur_col);
 | 
						||
    }  
 | 
						||
  }  
 | 
						||
}
 | 
						||
 | 
						||
// Cerca una colonna abilitata a partire da colonna
 | 
						||
// La prima cella utilizzabile ha indice 1
 | 
						||
// rec e' un numero di record assoluto
 | 
						||
// colonna e' un numero di colonna a video: puo' succedere che la 3 corrisponda al campo 107
 | 
						||
int TSpreadsheet::find_enabled_column(int rec, int colonna, int direction) const
 | 
						||
{                      
 | 
						||
  CHECKD(direction == +1 || direction == -1, "Bad column search direction", direction);
 | 
						||
 | 
						||
  int num;
 | 
						||
  XI_OBJ** column = xi_get_member_list(_list, &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;  
 | 
						||
}
 | 
						||
 | 
						||
// riga (da 0), colonna (0 = numero, 1 = prima cella, ...)
 | 
						||
void TSpreadsheet::set_focus_cell(int riga, int colonna)
 | 
						||
{                                  
 | 
						||
  xvt_scr_set_focus_vobj(win());
 | 
						||
  mask().set_focus_win(win(), FALSE);
 | 
						||
 | 
						||
  const int rec = row2rec(riga);   
 | 
						||
  colonna = find_enabled_column(rec, colonna, +1);
 | 
						||
 | 
						||
  if (colonna > 0)
 | 
						||
  {          
 | 
						||
    XI_OBJ cell;     
 | 
						||
    XI_MAKE_CELL(&cell, _list, riga, colonna);
 | 
						||
    xi_set_focus(&cell);          
 | 
						||
    
 | 
						||
    _edit_field = col2field(_cur_col = colonna);
 | 
						||
    if (rec != _cur_rec)
 | 
						||
    {      
 | 
						||
      _cur_rec = rec;
 | 
						||
      _cur_row = riga;            
 | 
						||
      str2mask(_cur_rec);
 | 
						||
      _row_dirty = FALSE;
 | 
						||
    }  
 | 
						||
  } 
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
// @mfunc Inserisce un record in una posizione stabilita
 | 
						||
//
 | 
						||
// @rdesc Ritorna la posizione nella quale e' stato inserito il record. Se non riesce ad inserirlo
 | 
						||
//                              ritorna -1.
 | 
						||
int TSpreadsheet::insert(
 | 
						||
  int rec) // @parm Numero del record da inserire nello spreadsheet
 | 
						||
  
 | 
						||
  // @comm Non e' possibile inserire un nuovo record nel caso nello spreadsheet vi siano
 | 
						||
  //                     almeno 999 righe oppure se lo spreadsheet non e' attivo.
 | 
						||
{ 
 | 
						||
  static bool ininsert = FALSE;
 | 
						||
  
 | 
						||
  if (ininsert || items() >= 999)
 | 
						||
    return -1;
 | 
						||
  
 | 
						||
  if (rec < 0 && items() > 0 && !_owner->append() )
 | 
						||
    rec = _cur_rec + 1;
 | 
						||
 | 
						||
  ininsert = TRUE;
 | 
						||
  int r = _str.insert(new TToken_string(80), rec);
 | 
						||
 | 
						||
  const bool ok = notify(r, K_INS);
 | 
						||
  if (ok) 
 | 
						||
  {
 | 
						||
    _disabled.insert(NULL, r);  
 | 
						||
    xi_insert_row(_list, INT_MAX);
 | 
						||
    xi_cell_request(_list);             
 | 
						||
  
 | 
						||
    // Notifica che l'inserimento <20> terminato
 | 
						||
    notify(r, K_CTRL + K_INS);
 | 
						||
  } 
 | 
						||
  else
 | 
						||
  {
 | 
						||
    _str.destroy(r);
 | 
						||
    r = -1;
 | 
						||
  }
 | 
						||
 | 
						||
  ininsert = FALSE;
 | 
						||
  return r;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
// @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
 | 
						||
  
 | 
						||
  // @comm Se il parametro <p rec> assume valore -1 vengono eliminate tutte le righe presenti
 | 
						||
  //             nello spreadsheet       
 | 
						||
{   
 | 
						||
  static bool indestroy = FALSE;
 | 
						||
  
 | 
						||
  if ( indestroy )
 | 
						||
    return FALSE;
 | 
						||
 | 
						||
  indestroy = TRUE;
 | 
						||
  bool ok = TRUE;
 | 
						||
  
 | 
						||
  if (rec < 0)
 | 
						||
  {
 | 
						||
    _disabled.destroy();
 | 
						||
    _str.destroy();
 | 
						||
    set_dirty(_row_dirty = FALSE);
 | 
						||
  }
 | 
						||
  else
 | 
						||
  {
 | 
						||
    _disabled.destroy(rec, TRUE);       // Destroy enable info
 | 
						||
    ok = _str.destroy(rec, TRUE);       // Destroy line
 | 
						||
  }  
 | 
						||
 | 
						||
  if (ok && mask().is_running()) 
 | 
						||
    update(-1);
 | 
						||
 | 
						||
  indestroy = FALSE;
 | 
						||
  return ok;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
// @mfunc Modifica a video la riga
 | 
						||
void TSpreadsheet::update(
 | 
						||
  int row) // @parm Numero della riga da modificare
 | 
						||
  
 | 
						||
  // @comm Se il valore di <p row> e' minore di 0 viene aggiornato l'intero spreadsheet          
 | 
						||
{                        
 | 
						||
  if (row < 0)
 | 
						||
  {                 
 | 
						||
    _needs_update = -1;                     // Clear pending row update
 | 
						||
    xi_cell_request(_list);                 // Force updatde
 | 
						||
    xi_scroll(_list, XI_SCROLL_FIRST);
 | 
						||
  }
 | 
						||
  else
 | 
						||
    update_rec(row);  
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
void TSpreadsheet::notify_change()
 | 
						||
{
 | 
						||
  if (!_row_dirty)
 | 
						||
  {
 | 
						||
    notify(_cur_rec, K_SPACE);
 | 
						||
    _row_dirty = TRUE;
 | 
						||
    set_dirty();
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
bool TSpreadsheet::test_focus_change()
 | 
						||
{
 | 
						||
  bool ok = dirty() != 3;
 | 
						||
  if (ok && _row_dirty)   
 | 
						||
    ok = xi_move_focus(_itf) ? TRUE : FALSE;
 | 
						||
  return ok;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
HIDDEN void XVT_CALLCONV1 xiev_handler(XI_OBJ *itf, XI_EVENT *xiev)
 | 
						||
{
 | 
						||
  TSpreadsheet* es = (TSpreadsheet*)xi_get_app_data(itf);
 | 
						||
  CHECK(es, "NULL Edit sheet in xi event");
 | 
						||
  es->list_handler(xiev);
 | 
						||
}                 
 | 
						||
 | 
						||
const char* TSpreadsheet::copy_cell2field(XI_OBJ* cell)
 | 
						||
{       
 | 
						||
  const char* val;
 | 
						||
  
 | 
						||
  if (cell == NULL)
 | 
						||
  {
 | 
						||
    XI_OBJ cella;
 | 
						||
    XI_MAKE_CELL(&cella, _list, _cur_row, _cur_col);
 | 
						||
    val = _edit_field->picture_data(xi_get_text(&cella, NULL, -1), TRUE);
 | 
						||
  }
 | 
						||
  else
 | 
						||
    val = _edit_field->picture_data(xi_get_text(cell, NULL, -1), TRUE);
 | 
						||
  _edit_field->set(val);  
 | 
						||
  _edit_field->set_dirty();        // Get it dirty!
 | 
						||
  
 | 
						||
  return val;
 | 
						||
}
 | 
						||
 | 
						||
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';
 | 
						||
    mask2str(_cur_rec);              // Update sheet row
 | 
						||
  }  
 | 
						||
  return ok;
 | 
						||
}
 | 
						||
 | 
						||
// Certified 75%
 | 
						||
void TSpreadsheet::list_handler(XI_EVENT *xiev)
 | 
						||
{
 | 
						||
  static KEY _lastab = K_TAB;
 | 
						||
  static bool _cell_dirty;
 | 
						||
 | 
						||
  switch (xiev->type)
 | 
						||
  {
 | 
						||
  case XIE_GET_FIRST:
 | 
						||
    if (items() > 0L)
 | 
						||
    {
 | 
						||
      long n = items() * (long)xiev->v.rec_request.percent / 100L;
 | 
						||
      if (n < 0L) n = 0L;
 | 
						||
      xiev->v.rec_request.data_rec = n;
 | 
						||
    }
 | 
						||
    else
 | 
						||
      xiev->refused = TRUE;
 | 
						||
    break;
 | 
						||
  case XIE_GET_LAST:
 | 
						||
    xiev->v.rec_request.data_rec = items()-1;
 | 
						||
    break;
 | 
						||
  case XIE_GET_PREV:
 | 
						||
  case XIE_GET_NEXT:
 | 
						||
  {
 | 
						||
    const long n = xiev->v.rec_request.spec_rec + (xiev->type == XIE_GET_NEXT ? +1 : -1) ;
 | 
						||
    if (n < 0 || n >= items())
 | 
						||
      xiev->refused = TRUE;
 | 
						||
    else
 | 
						||
      xiev->v.rec_request.data_rec = n;
 | 
						||
  }
 | 
						||
    break;
 | 
						||
  case XIE_CELL_REQUEST:
 | 
						||
  {
 | 
						||
    const int rec = (int)xiev->v.cell_request.rec;
 | 
						||
    const char* src = NULL;
 | 
						||
    int nm;
 | 
						||
    XI_OBJ** obj = xi_get_member_list(xiev->v.cell_request.list, &nm);
 | 
						||
    const int num = xiev->v.cell_request.col_nbr;
 | 
						||
    const int cid = obj[num]->cid;
 | 
						||
 | 
						||
    if (cid >= FIRST_FIELD)
 | 
						||
    {
 | 
						||
      if (rec < items())
 | 
						||
      {   
 | 
						||
        const int col = cid - FIRST_FIELD;
 | 
						||
        TMask_field* f = field(cid);
 | 
						||
        
 | 
						||
        src = row(rec).get(col);                  // Set value for cell
 | 
						||
        
 | 
						||
        if (f->is_edit())
 | 
						||
        {
 | 
						||
          if (src && *src)
 | 
						||
            src = f->picture_data(src, FALSE);    // Get formatted string
 | 
						||
          if (f->has_query())
 | 
						||
          {
 | 
						||
            xiev->v.cell_request.button = TRUE;
 | 
						||
            xiev->v.cell_request.button_on_focus = TRUE;
 | 
						||
          }
 | 
						||
        }  
 | 
						||
        if (cell_disabled(rec, col))
 | 
						||
          xiev->v.cell_request.back_color = DISABLED_BACK_COLOR;
 | 
						||
      }  
 | 
						||
    } 
 | 
						||
    else
 | 
						||
    { 
 | 
						||
      src = format("%d", rec+1);   
 | 
						||
    } 
 | 
						||
 | 
						||
    char* dst = xiev->v.cell_request.s;
 | 
						||
    if (src && *src)
 | 
						||
    {
 | 
						||
      const int& len = xiev->v.cell_request.len;
 | 
						||
      strncpy(dst, src, len);
 | 
						||
    }  
 | 
						||
    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 (xiev->v.xi_obj->type == XIT_CELL)
 | 
						||
      dispatch_e_char(win(), K_F9);
 | 
						||
    else
 | 
						||
      if (xiev->v.xi_obj->type == XIT_LIST)
 | 
						||
        insert(-1);
 | 
						||
    break;
 | 
						||
  case XIE_SELECT:
 | 
						||
    if (xiev->v.xi_obj->type == XIT_ROW)
 | 
						||
    {          
 | 
						||
      _check_enabled = FALSE;    
 | 
						||
      if (_cell_dirty)
 | 
						||
        off_cell_handler();
 | 
						||
      
 | 
						||
      const int oldrec = _cur_rec;
 | 
						||
      set_pos(xiev->v.select.xi_obj->v.row, 1 /* xiev->v.select.column */);
 | 
						||
      if (oldrec != _cur_rec)
 | 
						||
      {
 | 
						||
        _row_dirty = FALSE;
 | 
						||
        on_idle();            // Forces update delayed by str2mask
 | 
						||
      }
 | 
						||
      
 | 
						||
      const int button_pos = sheet_mask().id2pos(FIRST_FIELD-1);
 | 
						||
      if (button_pos >= 0)
 | 
						||
      {
 | 
						||
        TMask_field& button = sheet_mask().fld(button_pos);  
 | 
						||
        if (button.active())
 | 
						||
        {
 | 
						||
          str2mask(_cur_rec);
 | 
						||
          button.on_hit();   
 | 
						||
          if (sheet_mask().dirty())
 | 
						||
          { 
 | 
						||
            notify_change();
 | 
						||
            mask2str(_cur_rec);
 | 
						||
          } 
 | 
						||
        }  
 | 
						||
      }
 | 
						||
      _check_enabled = TRUE;    
 | 
						||
      _owner->highlight();
 | 
						||
    }    
 | 
						||
    xiev->refused = TRUE;
 | 
						||
    break;
 | 
						||
  case XIE_DBL_CELL:
 | 
						||
  {
 | 
						||
    _check_enabled = FALSE;
 | 
						||
    
 | 
						||
    const int oldrec = _cur_rec;
 | 
						||
    if ( xiev->v.xi_obj != NULL )
 | 
						||
    {
 | 
						||
      set_pos(xiev->v.xi_obj->v.cell.row, xiev->v.xi_obj->v.cell.column);
 | 
						||
    }
 | 
						||
    
 | 
						||
    if (oldrec != _cur_rec || !_row_dirty)
 | 
						||
    {
 | 
						||
      _row_dirty = FALSE;
 | 
						||
      notify_change();
 | 
						||
    }
 | 
						||
    const KEY k = edit(_cur_rec);
 | 
						||
    if (k == K_ENTER)
 | 
						||
    {
 | 
						||
      update_rec(_cur_rec);
 | 
						||
      _row_dirty = TRUE;
 | 
						||
    } else
 | 
						||
      if (k == K_DEL) 
 | 
						||
      {
 | 
						||
        _row_dirty = _cell_dirty = FALSE;
 | 
						||
      }
 | 
						||
 | 
						||
    if (_cur_rec >= items())
 | 
						||
    {
 | 
						||
      _row_dirty = _cell_dirty = FALSE;
 | 
						||
      set_pos(0, 1);        
 | 
						||
    }
 | 
						||
    if (_cur_rec >= 0)
 | 
						||
      set_focus_cell(_cur_row, _cur_col);
 | 
						||
    _check_enabled = TRUE;
 | 
						||
  }
 | 
						||
    break;
 | 
						||
  case XIE_ON_LIST:
 | 
						||
    if (_firstfocus)          // Trick to avoid the sheet to keep the focus forever ...
 | 
						||
    {                         // .. it costed me two day worth of hard work!
 | 
						||
      xiev->refused = TRUE;
 | 
						||
      _firstfocus = FALSE;                                                  
 | 
						||
    } 
 | 
						||
    else 
 | 
						||
      mask().set_focus_win(win(), FALSE);
 | 
						||
    break;
 | 
						||
  case XIE_OFF_LIST:
 | 
						||
    on_idle();
 | 
						||
    break;
 | 
						||
  case XIE_ON_ROW:
 | 
						||
    if (_check_enabled)
 | 
						||
    {
 | 
						||
      set_pos(xiev->v.xi_obj->v.row, _cur_col);
 | 
						||
      if (_cur_rec < items() && notify(_cur_rec, K_TAB))
 | 
						||
      {
 | 
						||
        str2mask(_cur_rec);
 | 
						||
        _row_dirty = FALSE;
 | 
						||
      }
 | 
						||
      else
 | 
						||
      {
 | 
						||
        _cur_row = _cur_rec = 0;
 | 
						||
        xiev->refused = TRUE;
 | 
						||
      }  
 | 
						||
    }
 | 
						||
    break;
 | 
						||
  case XIE_OFF_ROW:
 | 
						||
    if (_check_enabled)
 | 
						||
    {                 
 | 
						||
      _check_enabled = FALSE;                   // Avoid recursion!
 | 
						||
      if (_row_dirty && active())
 | 
						||
      {  
 | 
						||
        bool ok = sheet_mask().check_fields();
 | 
						||
        if (ok) 
 | 
						||
        {                   
 | 
						||
          mask2str(_cur_rec);                   // Update sheet with mask contents
 | 
						||
          ok = notify(_cur_rec, K_ENTER);       // Notify edit
 | 
						||
          _row_dirty = FALSE;                   // Avoid double notifications!
 | 
						||
        } 
 | 
						||
        if (ok)
 | 
						||
        {
 | 
						||
          xvt_statbar_refresh();
 | 
						||
        }  
 | 
						||
        else
 | 
						||
        {
 | 
						||
          xiev->refused = TRUE;
 | 
						||
        }  
 | 
						||
      }                                 
 | 
						||
      if (!xiev->refused)
 | 
						||
      {
 | 
						||
        // Notifica l'abbandono della riga
 | 
						||
        notify(_cur_rec, K_CTRL+K_TAB);
 | 
						||
      }  
 | 
						||
      _check_enabled = TRUE; 
 | 
						||
    }
 | 
						||
    break;
 | 
						||
  case XIE_ON_CELL:
 | 
						||
    if (_check_enabled)
 | 
						||
    {                 
 | 
						||
      TMask_field* f = cell2field(xiev->v.xi_obj);
 | 
						||
      const int logical_column = (f->dlg()-FIRST_FIELD) % 100;
 | 
						||
      const int physical_column = xiev->v.xi_obj->v.cell.column;
 | 
						||
      if (cell_disabled(_cur_rec, logical_column))     // If the cell is disabled ...
 | 
						||
      {                                              
 | 
						||
        const int dir = _lastab == K_TAB ? +1 : -1;
 | 
						||
        const int nex = find_enabled_column(_cur_rec, physical_column, dir);
 | 
						||
        if (nex > 0)      // If at least one enabled cell exists
 | 
						||
        {                        
 | 
						||
          // _edit_field = NULL;
 | 
						||
          set_focus_cell(_cur_row, nex);
 | 
						||
        }
 | 
						||
        else
 | 
						||
          xiev->refused = TRUE;
 | 
						||
      }
 | 
						||
      else
 | 
						||
      {  
 | 
						||
        _edit_field = f;
 | 
						||
        _cur_col = physical_column;
 | 
						||
        _edit_field->set_focusdirty(_cell_dirty = FALSE);
 | 
						||
      }  
 | 
						||
    }
 | 
						||
    break;
 | 
						||
  case XIE_OFF_CELL:
 | 
						||
    if (_edit_field && _check_enabled && _cell_dirty)
 | 
						||
    {
 | 
						||
      _check_enabled = FALSE;
 | 
						||
      XI_OBJ* cell = xiev->v.xi_obj;
 | 
						||
      xiev->refused = !off_cell_handler(cell);
 | 
						||
      _check_enabled = TRUE;
 | 
						||
    }
 | 
						||
    break;
 | 
						||
  case XIE_GET_PERCENT:
 | 
						||
  {
 | 
						||
    const long rec = xiev->v.get_percent.record;
 | 
						||
    long n = items(); if (n <= 0) n = 1;
 | 
						||
    xiev->v.get_percent.percent = int(rec * 100L / n);
 | 
						||
  }
 | 
						||
    break;
 | 
						||
  case XIE_CLEANUP:
 | 
						||
    break;
 | 
						||
  case XIE_XVT_EVENT:
 | 
						||
  {
 | 
						||
    EVENT* ep = &xiev->v.xvte;
 | 
						||
    switch (ep->type)
 | 
						||
    {
 | 
						||
    case E_FOCUS:
 | 
						||
      if (_check_enabled && ep->v.active == FALSE)
 | 
						||
      {                                
 | 
						||
        if (!mask().is_running())
 | 
						||
          _row_dirty = _cell_dirty = FALSE;
 | 
						||
          
 | 
						||
        const bool ok = (bool)xi_move_focus(_itf);
 | 
						||
        if (!ok)
 | 
						||
        {
 | 
						||
          set_dirty(3);
 | 
						||
          xiev->refused = TRUE;
 | 
						||
        }  
 | 
						||
      }
 | 
						||
      break;  
 | 
						||
    case E_CHAR:
 | 
						||
      if (_edit_field)
 | 
						||
      {
 | 
						||
        const KEY k = e_char_to_key(ep);
 | 
						||
        switch(k)
 | 
						||
        {
 | 
						||
        case K_ROWEDIT:
 | 
						||
          xiev->type = XIE_DBL_CELL;
 | 
						||
          xiev->v.xi_obj = NULL;
 | 
						||
          list_handler( xiev );
 | 
						||
          break;
 | 
						||
        case K_TAB:
 | 
						||
        case K_BTAB:
 | 
						||
          _lastab = k;
 | 
						||
          break;
 | 
						||
        case K_UP:       
 | 
						||
        case K_DOWN:
 | 
						||
          _lastab = (_cur_col == 2) ? K_BTAB : K_TAB;
 | 
						||
          break;
 | 
						||
        case K_F1:
 | 
						||
        case K_SHIFT+K_F1:
 | 
						||
          _check_enabled = FALSE;                               // Disable checks
 | 
						||
          _edit_field->on_key(k);
 | 
						||
          set_focus_cell(_cur_row, _cur_col);
 | 
						||
          _check_enabled = TRUE;                                // Enable checks
 | 
						||
          break;
 | 
						||
        case K_F8:
 | 
						||
        case K_F9:
 | 
						||
          if (_edit_field != NULL)
 | 
						||
            copy_cell2field();
 | 
						||
        case K_F2:
 | 
						||
        case K_F3:
 | 
						||
        case K_F11: 
 | 
						||
          if (_check_enabled && active())
 | 
						||
          {
 | 
						||
            _check_enabled = FALSE;                             // Disable checks
 | 
						||
            notify_change();                                                             
 | 
						||
            const bool ok = _edit_field->on_key(k);
 | 
						||
            if (!ok && k == K_F9)                               // Ricerca non completata?
 | 
						||
            {
 | 
						||
              _edit_field = &sheet_mask().focus_field();
 | 
						||
              const int col = field2col(_edit_field);
 | 
						||
              if (col != _cur_col)                   // Ricerca alternativa
 | 
						||
              {
 | 
						||
                _cur_col = col;
 | 
						||
                dispatch_e_char(win(), K_F9);
 | 
						||
              }  
 | 
						||
            }  
 | 
						||
            if (ok)
 | 
						||
            {
 | 
						||
              mask2str(_cur_rec);
 | 
						||
              on_idle();                               // Update immediately!
 | 
						||
            }  
 | 
						||
            _check_enabled = TRUE;                     // Re-enable checks
 | 
						||
          }  
 | 
						||
          break;
 | 
						||
        case K_PREV:
 | 
						||
        case K_NEXT:
 | 
						||
        case K_ESC:  
 | 
						||
          if (xi_move_focus(_itf))
 | 
						||
            dispatch_e_char(parent(), k);
 | 
						||
          break;
 | 
						||
        case K_ENTER:
 | 
						||
        case K_SHIFT+K_ENTER:
 | 
						||
          if (xi_move_focus(_itf))
 | 
						||
            dispatch_e_char(parent(), k == K_ENTER ? K_TAB : K_BTAB);
 | 
						||
          break;  
 | 
						||
        case K_CTRL+K_PREV:                
 | 
						||
          xi_scroll(_list, XI_SCROLL_PGUP);
 | 
						||
          break;
 | 
						||
        case K_CTRL+K_NEXT:
 | 
						||
          xi_scroll(_list, XI_SCROLL_PGDOWN);
 | 
						||
          break;
 | 
						||
        case K_CTRL+K_HOME:
 | 
						||
          xi_scroll(_list, XI_SCROLL_FIRST);
 | 
						||
          break;
 | 
						||
        case K_CTRL+K_END:
 | 
						||
          xi_scroll(_list, XI_SCROLL_LAST);
 | 
						||
          break;
 | 
						||
        default:
 | 
						||
          break;
 | 
						||
        }
 | 
						||
      }
 | 
						||
      break;
 | 
						||
    default:
 | 
						||
      break;
 | 
						||
    }
 | 
						||
  }
 | 
						||
    break;
 | 
						||
  default:
 | 
						||
    break;
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
void TSpreadsheet::activate(bool on)
 | 
						||
{
 | 
						||
  _active = on;
 | 
						||
  
 | 
						||
  const dword old = xi_get_attrib(_list);
 | 
						||
  dword att = on ? (old & ~XI_ATR_NAVIGATE) : (old | XI_ATR_NAVIGATE);
 | 
						||
  if (old != att) 
 | 
						||
  {
 | 
						||
    int num;
 | 
						||
    XI_OBJ** columns = xi_get_member_list(_list, &num);
 | 
						||
    
 | 
						||
    xi_move_focus(_itf);                  // Set focus to interface
 | 
						||
    if (on)
 | 
						||
      att |= XI_ATR_TABWRAP;
 | 
						||
    else 
 | 
						||
      att &= ~XI_ATR_TABWRAP;
 | 
						||
    
 | 
						||
    xi_set_attrib(_list, att);        
 | 
						||
    
 | 
						||
    for (int col = 1; col < num; col++)
 | 
						||
    {
 | 
						||
      XI_OBJ* column = columns[col];
 | 
						||
      att = xi_get_attrib(column);
 | 
						||
      if (on) 
 | 
						||
      {
 | 
						||
        att &= ~XI_ATR_READONLY;
 | 
						||
        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 row = rec2row(rec);
 | 
						||
  if (row < 0)
 | 
						||
  {
 | 
						||
    xi_scroll_rec(_list, rec, NORMAL_COLOR, XI_ATR_ENABLED | XI_ATR_AUTOSELECT, 0);
 | 
						||
    row = 0;
 | 
						||
  }  
 | 
						||
  _cur_rec = -1;
 | 
						||
  set_focus_cell(row, 1);
 | 
						||
}
 | 
						||
 | 
						||
void TSpreadsheet::on_idle()
 | 
						||
{
 | 
						||
  if (_needs_update >= 0)
 | 
						||
  {
 | 
						||
    if (_needs_update < items()) 
 | 
						||
      update_rec(_needs_update);
 | 
						||
    _needs_update = -1;
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
// @mfunc Cerca la colonna col
 | 
						||
XI_OBJ* TSpreadsheet::find_column(
 | 
						||
  int col) const    // @param  Indice o identificatore colonna
 | 
						||
{     
 | 
						||
  CHECKD(col >= 0, "Bad column ", col);
 | 
						||
  if (col < FIRST_FIELD)         // Se e' un indice trasformalo in identificatore
 | 
						||
    col += FIRST_FIELD;
 | 
						||
  else
 | 
						||
    if (col >= FIRST_FIELD+100)  // Riportalo nel range 101 - 199
 | 
						||
      col = FIRST_FIELD + (col % 100) -1;
 | 
						||
  
 | 
						||
  int num;
 | 
						||
  XI_OBJ** columns = xi_get_member_list(_list, &num);
 | 
						||
  for (int c = num-1; c > 0; c--)
 | 
						||
  {          
 | 
						||
    if (columns[c]->cid == col)
 | 
						||
      break;
 | 
						||
  }  
 | 
						||
 | 
						||
  if (c <= 0)
 | 
						||
  {
 | 
						||
    yesnofatal_box("Can't find column with id=%d", col);
 | 
						||
    c = 1;
 | 
						||
  }  
 | 
						||
  
 | 
						||
  return columns[c];
 | 
						||
}
 | 
						||
 | 
						||
#else
 | 
						||
 | 
						||
#include <sheet.h>
 | 
						||
 | 
						||
///////////////////////////////////////////////////////////
 | 
						||
// TSpreadsheet
 | 
						||
///////////////////////////////////////////////////////////
 | 
						||
 | 
						||
class TSpreadsheet : public TArray_sheet
 | 
						||
{
 | 
						||
  TMask _mask;
 | 
						||
  SPREADSHEET_NOTIFY _notify;
 | 
						||
  // Matteo  
 | 
						||
  SPREADSHEET_GETMASK _getmask;
 | 
						||
  
 | 
						||
  TSheet_field * _owner;
 | 
						||
 | 
						||
  TBit_array _column_disabled;
 | 
						||
  TArray _disabled;           // Array di TBit_array
 | 
						||
  
 | 
						||
protected:
 | 
						||
  virtual bool on_key(KEY key);
 | 
						||
  KEY edit(int n, KEY tasto);
 | 
						||
  bool notify(int r, KEY k);
 | 
						||
 | 
						||
  TMask_field* field(short id) const;
 | 
						||
 | 
						||
public:
 | 
						||
  TSpreadsheet(short x, short y, short dx, short dy, const char* maskname, int maskno,
 | 
						||
               const char* head, WINDOW parent, TSheet_field * o);
 | 
						||
 | 
						||
  TMask& sheet_mask() const { return ((TSpreadsheet*)this)->_mask; }
 | 
						||
  TMask& mask() const;
 | 
						||
 | 
						||
  void swap_columns(const int fromid, const int toid) const;
 | 
						||
  void swap_rows( const int fromindex, const int toindex);
 | 
						||
 | 
						||
  void set_getmask(SPREADSHEET_GETMASK n) { _getmask = n; }
 | 
						||
  
 | 
						||
  void set_notify(SPREADSHEET_NOTIFY n) { _notify = n; }
 | 
						||
  void set_dirty(bool spork = TRUE) { _owner->set_dirty(spork);}
 | 
						||
  bool dirty() const { return _owner->dirty(); }
 | 
						||
  bool test_focus_change() { return TRUE; }
 | 
						||
 | 
						||
  void mask2str(int riga);
 | 
						||
  void str2mask(int riga);
 | 
						||
 | 
						||
  void enable_column(int col, bool on);
 | 
						||
  // Matteo 
 | 
						||
  void delete_column( const int col ) const;  
 | 
						||
  void move_column( const int fromindex, const int toindex ) const;
 | 
						||
  void set_column_width( const int col, const int width ) const;
 | 
						||
  void set_column_header( const int col, const TString& header ) const;
 | 
						||
  void set_column_justify(int col, bool right);
 | 
						||
  
 | 
						||
  void enable_cell(int row, int column, bool on = TRUE);
 | 
						||
  bool cell_disabled(int row, int column) const;
 | 
						||
  virtual ~TSpreadsheet() {}
 | 
						||
};
 | 
						||
 | 
						||
TSpreadsheet::TSpreadsheet(short x, short y, short dx, short dy, 
 | 
						||
                           const char* maskname, int maskno,
 | 
						||
                           const char* head, WINDOW parent,
 | 
						||
                           TSheet_field* o)
 | 
						||
: TArray_sheet(x, y, dx, dy, maskname, head, 0, parent), _owner(o),
 | 
						||
  _mask(maskname, maskno), _notify(NULL), _getmask( NULL )
 | 
						||
{
 | 
						||
  sheet_mask().set_sheet(o);
 | 
						||
}
 | 
						||
 | 
						||
bool TSpreadsheet::on_key(KEY k)
 | 
						||
{
 | 
						||
  switch(k)
 | 
						||
  {
 | 
						||
  case K_CTRL_ENTER:
 | 
						||
  case K_ESC: 
 | 
						||
    mask().send_key(k, 0);
 | 
						||
    return TRUE;
 | 
						||
  case K_ENTER:                             // Selezione riga per editing
 | 
						||
    if (items() < 1) k = K_INS;             // Se vuoto crea riga da editare 
 | 
						||
  case K_INS:
 | 
						||
  case 'A':                                 // Aggiunge dopo
 | 
						||
  case 'I':                                 // Aggiunge prima
 | 
						||
  {
 | 
						||
    int n = (int)selected();
 | 
						||
    if (k != K_ENTER)
 | 
						||
    {
 | 
						||
      if (k == K_INS) n = (int)items(); else   // Aggiunge alla fine
 | 
						||
        if (k == 'A') n++;                  
 | 
						||
      
 | 
						||
      if (n < 0) n = 0; else
 | 
						||
        if (n > (int)items()) n = (int)items();     // Controlla range n 
 | 
						||
      
 | 
						||
      if (notify(n, K_INS) == FALSE)      // Chiede l'ok alla applicazione
 | 
						||
        return FALSE;
 | 
						||
      
 | 
						||
      insert(TToken_string(80), n);       // Aggiunge una riga vuota
 | 
						||
      k = K_INS;                          // Inserimento in corso
 | 
						||
    }  
 | 
						||
    
 | 
						||
    notify(n, K_TAB);                     // Notifica selezione
 | 
						||
    notify(n, K_SPACE);                   // Notifica inizio cambiamento
 | 
						||
    k = edit(n, k);                       // Edita riga selezionata o creata
 | 
						||
    if (k == K_ENTER)
 | 
						||
      notify(n, K_ENTER);                 // Notifica avvenuto cambiamento
 | 
						||
 | 
						||
    xvt_vobj_raise(win());                // Aggiorna sheet a video
 | 
						||
    open();
 | 
						||
  }
 | 
						||
    break;
 | 
						||
  case K_TAB:
 | 
						||
  case K_BTAB:
 | 
						||
  case K_SHIFT_TAB:
 | 
						||
    dispatch_e_char(xvt_vobj_get_parent(win()), k);
 | 
						||
    return TRUE;
 | 
						||
  default:
 | 
						||
    break;
 | 
						||
  }
 | 
						||
 | 
						||
  return TArray_sheet::on_key(k);
 | 
						||
}
 | 
						||
 | 
						||
#endif
 | 
						||
 | 
						||
///////////////////////////////////////////////////////////
 | 
						||
// Metodi di TSpreadsheet comuni a tutte le piattaforme
 | 
						||
///////////////////////////////////////////////////////////
 | 
						||
 | 
						||
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
 | 
						||
TMask_field* TSpreadsheet::field(short id) const
 | 
						||
{
 | 
						||
  const int pos = sheet_mask().id2pos(id);
 | 
						||
  return pos < 0 ? NULL : &sheet_mask().fld(pos);
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
// Ricopia i campi della maschera nel record dato ed aggiorna il display
 | 
						||
void TSpreadsheet::mask2str(int rec)
 | 
						||
{                 
 | 
						||
  const TMask& m = sheet_mask();
 | 
						||
  TToken_string& r = row(rec);
 | 
						||
  r.cut(0);
 | 
						||
  for (short id = FIRST_FIELD; ; id++)
 | 
						||
  {                                 
 | 
						||
    int pos = m.id2pos(id);
 | 
						||
    if (pos < 0) break;
 | 
						||
    
 | 
						||
    for(int dlg = id; pos >= 0; pos = m.id2pos(dlg += 100))
 | 
						||
    {
 | 
						||
      const TMask_field& f = m.fld(pos);
 | 
						||
      if (f.shown() || f.ghost())
 | 
						||
      {       
 | 
						||
        r.add(f.get());       
 | 
						||
#if XVT_OS == XVT_OS_WIN        
 | 
						||
        const bool on = f.enabled();
 | 
						||
        enable_cell(rec, id-FIRST_FIELD, on);
 | 
						||
#endif        
 | 
						||
        break;
 | 
						||
      }  
 | 
						||
    }  
 | 
						||
    if (pos < 0) 
 | 
						||
    {
 | 
						||
#ifdef DBG
 | 
						||
      yesnofatal_box("Mask2str: Non e' visibile il campo %d", dlg);
 | 
						||
#endif    
 | 
						||
      r.add(" ");
 | 
						||
    }
 | 
						||
  }
 | 
						||
#if XVT_OS == XVT_OS_WIN
 | 
						||
  if (_needs_update != rec)
 | 
						||
  {
 | 
						||
    if (_needs_update >= 0)
 | 
						||
    {
 | 
						||
      // Double update!
 | 
						||
      update_rec(_needs_update);      
 | 
						||
    }  
 | 
						||
    _needs_update = rec;
 | 
						||
  }  
 | 
						||
#endif
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
// Certified 50%
 | 
						||
// @mfunc Permette di abilitare/disabilitare una singola cella
 | 
						||
void TSpreadsheet::enable_cell(
 | 
						||
  int row,    // @parm Riga della cella da abilitare/disabilitare
 | 
						||
  int column, // @parm Colonna della cella da abilitare/disabilitare
 | 
						||
  bool on)    // @parm Indica l'operazione da effettuare sulla cella:
 | 
						||
  //
 | 
						||
  // @flag TRUE | La cella viene abilitata (default)
 | 
						||
  // @flag FALSE| La cella viene disabilitata
 | 
						||
{
 | 
						||
  TBit_array* ba = (TBit_array*)_disabled.objptr(row);
 | 
						||
  if (ba == NULL)
 | 
						||
  {
 | 
						||
    if (on) return;   // Don't waste time and memory
 | 
						||
    ba = new TBit_array(column);
 | 
						||
    _disabled.add(ba, row);
 | 
						||
  }
 | 
						||
 | 
						||
  if (column >= 0)
 | 
						||
  {
 | 
						||
    ba->set(column, !on);
 | 
						||
  }  
 | 
						||
  else
 | 
						||
  {
 | 
						||
    if (on)
 | 
						||
      _disabled.destroy(row, FALSE);  // Let's save some memory!
 | 
						||
    else
 | 
						||
    {
 | 
						||
#if XVT_OS == XVT_OS_WIN
 | 
						||
      ba->set(_columns); // Force right array size
 | 
						||
#else
 | 
						||
      ba->set(32);       // Force array size
 | 
						||
#endif
 | 
						||
      ba->set();         // Set all bits
 | 
						||
    }
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
// @mfunc Permette di abilitare/disabiltare una colonna
 | 
						||
void TSpreadsheet::enable_column(
 | 
						||
  int col,  // @parm Numero della colonna da abilitare/disabilitare
 | 
						||
  bool on)  // @parm Indica l'operazione da effettuare sulla colonna:
 | 
						||
  //
 | 
						||
  // @flag TRUE | Abilita la colonna (default)
 | 
						||
  // @flag FALSE| Disabilita la colonna
 | 
						||
{
 | 
						||
  if (col >= FIRST_FIELD)
 | 
						||
    col = cid2col(col);
 | 
						||
  const bool change = _column_disabled[col] == on;
 | 
						||
  _column_disabled.set(col, !on);
 | 
						||
#if XVT_OS == XVT_OS_WIN
 | 
						||
  if (change)
 | 
						||
  {
 | 
						||
    XI_OBJ* column = find_column(col);
 | 
						||
    dword attr = xi_get_attrib(column);
 | 
						||
    if (on) attr |= XI_ATR_ENABLED;
 | 
						||
    else    attr &= ~XI_ATR_ENABLED;
 | 
						||
 | 
						||
//    xi_move_focus(_itf);                  // Set focus to interface
 | 
						||
    xi_set_attrib(column, attr);          // Set new attributes
 | 
						||
    update(-1);
 | 
						||
  }
 | 
						||
#endif 
 | 
						||
}
 | 
						||
         
 | 
						||
void TSpreadsheet::delete_column( const int col ) const
 | 
						||
{   
 | 
						||
#if XVT_OS == XVT_OS_WIN
 | 
						||
  XI_OBJ* column = find_column(col);
 | 
						||
  xi_delete( column );
 | 
						||
#endif   
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
void TSpreadsheet::move_column( const int fromindex, const int toindex) const
 | 
						||
{
 | 
						||
#if XVT_OS == XVT_OS_WIN
 | 
						||
  int num;
 | 
						||
  XI_OBJ** columns = xi_get_member_list(_list, &num);
 | 
						||
  CHECKD(fromindex+1 < num, "Can't move column ", fromindex);
 | 
						||
  XI_OBJ* column = columns[fromindex+1];
 | 
						||
  
 | 
						||
  xi_move_column( column, toindex );
 | 
						||
#endif   
 | 
						||
}
 | 
						||
 | 
						||
void TSpreadsheet::swap_columns(const int fromid, const int toid) const
 | 
						||
{
 | 
						||
#if XVT_OS == XVT_OS_WIN
 | 
						||
  int num;
 | 
						||
  XI_OBJ** columns = xi_get_member_list(_list, &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);
 | 
						||
#endif   
 | 
						||
} 
 | 
						||
 | 
						||
void TSpreadsheet::swap_rows( const int fromindex, const int toindex)
 | 
						||
{
 | 
						||
#if XVT_OS == XVT_OS_WIN      
 | 
						||
  _str.swap(fromindex, toindex);
 | 
						||
  _disabled.swap(fromindex, toindex);
 | 
						||
#endif  
 | 
						||
}
 | 
						||
 | 
						||
void TSpreadsheet::set_column_width(const int col, const int width) const
 | 
						||
{
 | 
						||
#if XVT_OS == XVT_OS_WIN      
 | 
						||
  XI_OBJ* column = find_column(col);
 | 
						||
  xi_set_column_width(column, width);   // Force redraw
 | 
						||
#endif   
 | 
						||
}
 | 
						||
 | 
						||
void TSpreadsheet::set_column_header(const int col, const TString&  header) const
 | 
						||
{
 | 
						||
#if XVT_OS == XVT_OS_WIN
 | 
						||
  XI_OBJ* column = find_column(col);
 | 
						||
  xi_set_text(column, (char *)(const char *)header );
 | 
						||
  RCT r; xi_get_rect(column, &r); 
 | 
						||
  xi_set_column_width(column, (r.right-r.left+1) / CHARX);   // Force redraw
 | 
						||
#endif   
 | 
						||
}
 | 
						||
 | 
						||
void TSpreadsheet::set_column_justify(int col, bool right)
 | 
						||
{
 | 
						||
#if XVT_OS == XVT_OS_WIN
 | 
						||
  XI_OBJ* column = find_column(col);
 | 
						||
  dword attr = xi_get_attrib(column);
 | 
						||
  if (right)
 | 
						||
    attr |= XI_ATR_RJUST;
 | 
						||
  else
 | 
						||
    attr &= ~XI_ATR_RJUST;  
 | 
						||
  xi_set_attrib(column, attr);          // Set new attribute
 | 
						||
  update(-1);
 | 
						||
#endif
 | 
						||
}
 | 
						||
 | 
						||
// Certified 99%
 | 
						||
// @mfunc Controlla se una cella o un'intera riga e' disabilitata
 | 
						||
//                                
 | 
						||
// @rdesc Se column e' minore di zero si considera l'intera riga
 | 
						||
// @rdesc Ritorna lo stato della cella indicata:
 | 
						||
//
 | 
						||
// @flag TRUE | Se la cella e' disabilitata
 | 
						||
// @flag FALSE| Se la cella e' abilitata
 | 
						||
bool TSpreadsheet::cell_disabled(int row, int column) const
 | 
						||
{
 | 
						||
  TBit_array* ba = (TBit_array*)_disabled.objptr(row);
 | 
						||
  bool d;
 | 
						||
  if (column < 0)
 | 
						||
    d = (ba == NULL) ? FALSE : (ba->ones() >= columns()-1); 
 | 
						||
  else   
 | 
						||
  {                                                       
 | 
						||
    d = _column_disabled[column];  // Controlla la colonna
 | 
						||
    if (d == FALSE && ba != NULL)  // Se la colonna e' disabilitata e' inutile proseguire
 | 
						||
      d = (*ba)[column];           // Controlla la cella
 | 
						||
  }
 | 
						||
  return d;  
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
// Certified 75%
 | 
						||
void TSpreadsheet::str2mask(int riga)
 | 
						||
{
 | 
						||
  if (riga == items())
 | 
						||
  {
 | 
						||
    sheet_mask().reset();
 | 
						||
    mask2str(riga);
 | 
						||
    return;
 | 
						||
  }
 | 
						||
 | 
						||
  TToken_string& r = row(riga);
 | 
						||
  TString val(80);   
 | 
						||
  
 | 
						||
  TMask& m = sheet_mask();
 | 
						||
  const int campi = m.fields();
 | 
						||
  
 | 
						||
  for (int i = 0; i < campi; i++)
 | 
						||
  {
 | 
						||
    TMask_field& f = m.fld(i);
 | 
						||
    const short id = f.dlg();
 | 
						||
    if (id >= FIRST_FIELD)
 | 
						||
    {             
 | 
						||
      const int index = (id % 100)-1;
 | 
						||
      val = r.get(index);
 | 
						||
      f.set(val);
 | 
						||
      const bool on = !cell_disabled(riga, index);
 | 
						||
      if (f.enabled() != on)
 | 
						||
        f.enable(on);
 | 
						||
    }
 | 
						||
  }
 | 
						||
  
 | 
						||
  for (i = 0; i < campi; i++)
 | 
						||
  {
 | 
						||
    TMask_field& f = m.fld(i);
 | 
						||
    const short id = f.dlg();
 | 
						||
    if (id >= FIRST_FIELD && 
 | 
						||
        f.class_id() != CLASS_BUTTON_FIELD &&
 | 
						||
        (f.active() || f.ghost()))
 | 
						||
    {
 | 
						||
      if (f.has_check()) 
 | 
						||
        f.check(STARTING_CHECK);
 | 
						||
      f.set_dirty(FALSE);
 | 
						||
      f.on_hit();
 | 
						||
    }
 | 
						||
  }
 | 
						||
  
 | 
						||
  for (i = 0; i < campi; i++)
 | 
						||
  {
 | 
						||
    TMask_field& f = m.fld(i);
 | 
						||
    const short id = f.dlg();
 | 
						||
    if (id > FIRST_FIELD)
 | 
						||
    {
 | 
						||
      if (f.dirty() == TRUE)
 | 
						||
        f.set_dirty(FALSE);
 | 
						||
    }    
 | 
						||
  }
 | 
						||
 | 
						||
  m.set_caption(format("Riga %d", riga+1));
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
// Certified 100%
 | 
						||
bool TSpreadsheet::notify(int rec, KEY k)
 | 
						||
{
 | 
						||
  const bool ok = _notify ? _notify(*_owner, rec, k) : TRUE;
 | 
						||
  if (k == K_ENTER)
 | 
						||
    set_dirty(ok ? TRUE : 3);
 | 
						||
  return ok;  
 | 
						||
}
 | 
						||
 | 
						||
// Certified 99%
 | 
						||
#if XVT_OS != XVT_OS_WIN
 | 
						||
KEY TSpreadsheet::edit(int n, KEY tasto)
 | 
						||
#else
 | 
						||
  KEY TSpreadsheet::edit(int n)
 | 
						||
#endif
 | 
						||
{
 | 
						||
  KEY k;
 | 
						||
  const int olditems = (int)items();
 | 
						||
  str2mask(n);
 | 
						||
 | 
						||
  if( _getmask )
 | 
						||
  {
 | 
						||
    TMask& totalmask = sheet_mask();
 | 
						||
    TMask& usermask = *_getmask( n, totalmask, FALSE );
 | 
						||
    
 | 
						||
    // Carico la maschera dell'utente con la maschera totale
 | 
						||
    for( int i = 0; i < usermask.fields(); i ++ )
 | 
						||
    {   
 | 
						||
      TMask_field& dest_field = usermask.fld( i );
 | 
						||
      if ( dest_field.dlg( ) > 100 )
 | 
						||
      { 
 | 
						||
        const TMask_field& source_field = totalmask.field( dest_field.dlg( ) );
 | 
						||
        dest_field.set( source_field.get( ) ); 
 | 
						||
      }
 | 
						||
    }              
 | 
						||
    k = usermask.run();
 | 
						||
    if (k == K_ENTER)
 | 
						||
      // Carico la maschera totale con la maschera dell'utente
 | 
						||
      for( i = 0; i < usermask.fields(); i ++ )
 | 
						||
      {   
 | 
						||
        const TMask_field& source_field = usermask.fld( i );
 | 
						||
        if ( source_field.dlg( ) > 100 )
 | 
						||
        { 
 | 
						||
          TMask_field& dest_field = totalmask.field( source_field.dlg() );
 | 
						||
          dest_field.set( source_field.get( ) ); 
 | 
						||
        }
 | 
						||
      }
 | 
						||
    _getmask( n, totalmask, TRUE );
 | 
						||
    
 | 
						||
  }
 | 
						||
  else
 | 
						||
    k = sheet_mask().run();
 | 
						||
  
 | 
						||
  if (k == K_ENTER)
 | 
						||
  {
 | 
						||
    mask2str(n);
 | 
						||
  } 
 | 
						||
  else
 | 
						||
  {
 | 
						||
    if (k == K_DEL)
 | 
						||
    {
 | 
						||
      const bool ok = notify(n, K_DEL); // Notifica intenzione di cancellare
 | 
						||
      if (ok) 
 | 
						||
      {
 | 
						||
        destroy(n);
 | 
						||
        if (n < items())
 | 
						||
          str2mask(n);
 | 
						||
        notify(n, K_CTRL+K_DEL);        // Notifica l'avvenuta cancellazione
 | 
						||
      }           
 | 
						||
    } 
 | 
						||
    else
 | 
						||
      if (k == K_ESC)
 | 
						||
      {            
 | 
						||
#if XVT_OS == XVT_OS_WIN
 | 
						||
        str2mask(n);
 | 
						||
#else        
 | 
						||
        if (tasto == K_INS) destroy(n);
 | 
						||
#endif
 | 
						||
      }
 | 
						||
  }
 | 
						||
  return k;
 | 
						||
}
 | 
						||
 | 
						||
///////////////////////////////////////////////////////////
 | 
						||
// TSheet_field
 | 
						||
///////////////////////////////////////////////////////////
 | 
						||
 | 
						||
// Certified 100%
 | 
						||
TSheet_field::TSheet_field(TMask* m)
 | 
						||
: TMask_field(m), _sheet(NULL), _append(TRUE)
 | 
						||
{}
 | 
						||
 | 
						||
// Certified 100%
 | 
						||
word TSheet_field::class_id() const
 | 
						||
{
 | 
						||
  return CLASS_SHEET_FIELD;
 | 
						||
}
 | 
						||
 | 
						||
// Certified 100%
 | 
						||
TSheet_field::~TSheet_field()
 | 
						||
{
 | 
						||
  CHECK(_sheet, "Can't delete NULL sheet");
 | 
						||
  delete _sheet;
 | 
						||
}
 | 
						||
 | 
						||
// Certified 100%
 | 
						||
void TSheet_field::reset()
 | 
						||
{
 | 
						||
  _sheet->destroy();
 | 
						||
  _sheet->sheet_mask().reset();
 | 
						||
  force_update();
 | 
						||
}
 | 
						||
 | 
						||
// Certified 100%
 | 
						||
void TSheet_field::destroy(int r)
 | 
						||
{
 | 
						||
  _sheet->destroy(r);
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
void TSheet_field::parse_head(TScanner& scanner)
 | 
						||
{
 | 
						||
  _width = scanner.integer();
 | 
						||
  _size  = scanner.integer();
 | 
						||
  if (_size == 0) _size = -1;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
// Certified 100%
 | 
						||
bool TSheet_field::parse_item(TScanner& scanner)
 | 
						||
{
 | 
						||
  if (scanner.key() == "IT")
 | 
						||
  {
 | 
						||
    _head.add(scanner.string());
 | 
						||
    return TRUE;
 | 
						||
  }
 | 
						||
  return TMask_field::parse_item(scanner);
 | 
						||
}
 | 
						||
 | 
						||
// Certified 100%
 | 
						||
void TSheet_field::create(WINDOW parent)
 | 
						||
{
 | 
						||
  const TMask& m = mask();
 | 
						||
  _sheet = new TSpreadsheet(_x, _y, _width, _size, m.source_file(), 
 | 
						||
                            m.sheets(), _head, parent, this);
 | 
						||
 | 
						||
  _win = _sheet->win();
 | 
						||
  xvt_vobj_set_visible(_win, shown());
 | 
						||
  if (!_flags.enable_default)
 | 
						||
  {
 | 
						||
    _flags.enabled = TRUE;  // Lo sheet e' sempre operabile anche se non editabile
 | 
						||
    disable();
 | 
						||
  }  
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
// Certified 100%
 | 
						||
TString_array& TSheet_field::rows_array() const
 | 
						||
{
 | 
						||
  return _sheet->rows_array();
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
// Certified 100%
 | 
						||
// Ritorna l'indice della prima riga vuota dello sheet
 | 
						||
int TSheet_field::first_empty() const
 | 
						||
{
 | 
						||
  const int max = (int)_sheet->items();
 | 
						||
  for (int n = 0; n < max; n++)
 | 
						||
    if (_sheet->row(n).empty_items())
 | 
						||
      break;
 | 
						||
  return n;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
// @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>)
 | 
						||
{
 | 
						||
  const int max = (int)_sheet->items();
 | 
						||
  if (n < 0 || n >= max)
 | 
						||
  {
 | 
						||
    if (n < 0) n = first_empty();
 | 
						||
    if (n >= max) 
 | 
						||
    {
 | 
						||
      n = (int)_sheet->add(new TToken_string(80));
 | 
						||
    }  
 | 
						||
  }
 | 
						||
  return _sheet->row(n);
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
// @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       
 | 
						||
  
 | 
						||
{
 | 
						||
#if XVT_OS == XVT_OS_WIN
 | 
						||
  _sheet->update(r);
 | 
						||
#else
 | 
						||
  _sheet->open(); 
 | 
						||
#endif
 | 
						||
}
 | 
						||
 | 
						||
int TSheet_field::items() const
 | 
						||
{
 | 
						||
  return (int)_sheet->items();
 | 
						||
}
 | 
						||
 | 
						||
int TSheet_field::selected() const
 | 
						||
{
 | 
						||
  return (int)_sheet->selected();
 | 
						||
}
 | 
						||
 | 
						||
void TSheet_field::set_notify(SPREADSHEET_NOTIFY n)
 | 
						||
{
 | 
						||
  _sheet->set_notify(n);
 | 
						||
}
 | 
						||
 | 
						||
void TSheet_field::set_getmask(SPREADSHEET_GETMASK n)
 | 
						||
{ 
 | 
						||
  _sheet->set_getmask( n ); 
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
// Certified 50%
 | 
						||
void TSheet_field::highlight() const
 | 
						||
{
 | 
						||
  TMask_field::highlight();
 | 
						||
#if XVT_OS == XVT_OS_WIN
 | 
						||
  if (_sheet->_check_enabled)
 | 
						||
  {
 | 
						||
    int rows; xi_get_list_info(_sheet->_list, &rows);
 | 
						||
    if (rows > 0)
 | 
						||
    {                  
 | 
						||
      if (_sheet->notify(_sheet->_cur_rec, K_TAB))
 | 
						||
      {
 | 
						||
        _sheet->set_focus_cell(_sheet->_cur_row, _sheet->_cur_col);
 | 
						||
        _sheet->str2mask(selected());
 | 
						||
      }  
 | 
						||
    }  
 | 
						||
  }    
 | 
						||
#endif
 | 
						||
}
 | 
						||
 | 
						||
void TSheet_field::enable(bool on)
 | 
						||
{
 | 
						||
  _sheet->activate(on);
 | 
						||
}
 | 
						||
 | 
						||
bool TSheet_field::enabled() const
 | 
						||
{
 | 
						||
  return items() > 0;
 | 
						||
}
 | 
						||
 | 
						||
void TSheet_field::enable_column(int column, bool on)
 | 
						||
{
 | 
						||
  _sheet->enable_column(column, on);
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
void TSheet_field::enable_cell(int row, int column, bool on)
 | 
						||
{                          
 | 
						||
  _sheet->enable_cell(row, column, on);
 | 
						||
}
 | 
						||
 | 
						||
bool TSheet_field::cell_disabled(int row, int column) const
 | 
						||
{
 | 
						||
  return _sheet->cell_disabled(row, column);
 | 
						||
}
 | 
						||
 | 
						||
// Matteo
 | 
						||
void TSheet_field::delete_column( const int col ) const
 | 
						||
{
 | 
						||
  _sheet->delete_column( col );
 | 
						||
}
 | 
						||
 | 
						||
void TSheet_field::move_column( const int fromindex, const int toindex ) const
 | 
						||
{
 | 
						||
  _sheet->move_column(fromindex, toindex);
 | 
						||
}
 | 
						||
 | 
						||
void TSheet_field::swap_columns(const int fromid, const int toid) const
 | 
						||
{
 | 
						||
  _sheet->swap_columns(fromid, toid);
 | 
						||
}
 | 
						||
 | 
						||
void TSheet_field::swap_rows( const int fromindex, const int toindex)
 | 
						||
{                                            
 | 
						||
  _sheet->swap_rows(fromindex, toindex);
 | 
						||
}
 | 
						||
 | 
						||
void TSheet_field::set_column_width( const int col, const int width ) const
 | 
						||
{
 | 
						||
  _sheet->set_column_width(col, width);
 | 
						||
}
 | 
						||
 | 
						||
void TSheet_field::set_column_header( const int col, const TString& header ) const
 | 
						||
{
 | 
						||
  _sheet->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);
 | 
						||
  _sheet->set_column_justify(col, right);
 | 
						||
}
 | 
						||
 | 
						||
TMask& TSheet_field::sheet_mask() const
 | 
						||
{
 | 
						||
  return _sheet->sheet_mask();
 | 
						||
}
 | 
						||
 | 
						||
bool TSheet_field::on_hit()
 | 
						||
{
 | 
						||
  if (!mask().is_running())
 | 
						||
  {
 | 
						||
    force_update();
 | 
						||
    set_dirty(FALSE);
 | 
						||
  }
 | 
						||
  return TRUE;  
 | 
						||
}  
 | 
						||
 | 
						||
void TSheet_field::select(int r)
 | 
						||
{ 
 | 
						||
  _sheet->select(r);
 | 
						||
}  
 | 
						||
 | 
						||
 | 
						||
bool TSheet_field::test_focus_change()
 | 
						||
{
 | 
						||
  return _sheet->test_focus_change();
 | 
						||
}                       
 | 
						||
 | 
						||
bool TSheet_field::on_key(KEY k)
 | 
						||
{                
 | 
						||
  if (k == K_ENTER)
 | 
						||
  {          
 | 
						||
    if (!test_focus_change()) 
 | 
						||
      return FALSE;
 | 
						||
  }
 | 
						||
 | 
						||
  if (k == K_TAB && !focusdirty() && items() > 0)
 | 
						||
  {
 | 
						||
    select(0);
 | 
						||
  }           
 | 
						||
 | 
						||
#if XVT_OS == XVT_OS_WIN
 | 
						||
  if (k == K_ROWEDIT && items() > 0)
 | 
						||
  {          
 | 
						||
    select(items()-1);
 | 
						||
    XI_EVENT xie;
 | 
						||
    xie.type = XIE_DBL_CELL;
 | 
						||
    xie.v.xi_obj = NULL;
 | 
						||
    _sheet->list_handler( &xie );
 | 
						||
    return TRUE;
 | 
						||
  }
 | 
						||
#endif
 | 
						||
  
 | 
						||
  return TMask_field::on_key(k);
 | 
						||
}
 | 
						||
 | 
						||
void TSheet_field::on_idle()
 | 
						||
{
 | 
						||
#if XVT_OS == XVT_OS_WIN
 | 
						||
  _sheet->on_idle();
 | 
						||
#endif
 | 
						||
}
 | 
						||
 | 
						||
void TSheet_field::exchange(bool show_value, const real& nuo)
 | 
						||
{        
 | 
						||
  TMask& m = sheet_mask();
 | 
						||
 | 
						||
  const real& vec = mask().exchange();
 | 
						||
  
 | 
						||
  if (vec != nuo)
 | 
						||
  {
 | 
						||
    TBit_array valuta(32);
 | 
						||
    int i = 0;
 | 
						||
    for (int f = FIRST_FIELD; ;f++, i++)
 | 
						||
    {
 | 
						||
      const int pos = m.id2pos(f);
 | 
						||
      if (pos < 0) break;
 | 
						||
      if (m.fld(pos).class_id() == CLASS_REAL_FIELD)
 | 
						||
      {
 | 
						||
        if (m.fld(pos).exchangeable())
 | 
						||
          valuta.set(i);
 | 
						||
      }
 | 
						||
    }  
 | 
						||
    
 | 
						||
    for (int riga = 0; riga < items(); riga++)
 | 
						||
    {
 | 
						||
      TToken_string& r = row(riga);
 | 
						||
      for (const char* s = r.get(i = 0); s; s = r.get(++i))
 | 
						||
        if (*s > ' ' && valuta[i])
 | 
						||
        {
 | 
						||
          real v(s); 
 | 
						||
          v *= nuo;
 | 
						||
          v /= vec;
 | 
						||
          v.round();
 | 
						||
          r.add(v.string(), i);
 | 
						||
        }
 | 
						||
    }    
 | 
						||
  }  
 | 
						||
  
 | 
						||
  m.set_exchange(show_value, nuo);
 | 
						||
  
 | 
						||
  if (mask().is_running()) 
 | 
						||
    force_update();
 | 
						||
}
 |