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