#include #include #include #include const short FIRST_FIELD = 101; #if XVT_OS == XVT_OS_WIN #include #include extern "C" { #include } /////////////////////////////////////////////////////////// // TSpreadsheet /////////////////////////////////////////////////////////// class TSpreadsheet : public TWindow { friend class TSheet_field; enum { ITF_CID = 0, LIST_CID = 1 }; TString_array _str; // Array di TToken_strings TBit_array _column_disabled; TArray _disabled; // Array di TBit_array TMask _mask; int _columns; bool _firstfocus, _active; XI_OBJ *_list, *_itf; SPREADSHEET_NOTIFY _notify; TSheet_field* _owner; // Owner TMask_field* _edit_field; // Current edit field int _cur_row, _cur_rec, _cur_col; // Current cell bool _row_dirty; // Current row changed bool _check_enabled; // Perform OFF_ROW checks TString16 _button; static void xiev_handler(XI_OBJ *itf, XI_EVENT *xiev); void init(); protected: void list_handler(XI_EVENT *xiev); TMask_field* col2field(int pos) const; TMask_field* cell2field(const XI_OBJ* cell) const; void update_rec(int rec); TMask_field* field(short id) const; int rec2row(int rec); int row2rec(int row); int set_pos(int row, int col) { _cur_col = col; return _cur_rec = row2rec(_cur_row = row); } bool notify(int row, KEY k); void notify_change(); public: void update(int row); TToken_string& row(int n) { return _str.row(n); } int add(const TToken_string& s) { return _str.add(s); } int add(TToken_string* s) { return _str.add(s); } int insert(int rec); bool destroy(int rec = -1); TString_array& rows_array() { return _str; } void set_focus_cell(int riga, int colonna); void activate(bool on); 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() const; void mask2str(int n); void str2mask(int n); KEY edit(int n); int items() const { return _str.items(); } int selected() const { return _cur_rec; } int columns() const { return _columns; } bool dirty() const { return _owner->dirty(); } void set_dirty(bool spork = TRUE) { _owner->set_dirty(spork); } bool active() const { return _active; } void set_notify(SPREADSHEET_NOTIFY n) { _notify = n; } TSpreadsheet(short x, short y, short dx, short dy, const char* maskname, int maskno, const char* head, WINDOW parent, TSheet_field* owner); virtual ~TSpreadsheet(); }; // Certified 100% void TSpreadsheet::init() { static bool first = TRUE; if (!first) return; 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, TSheet_field* o) : _mask(maskname, maskno), _notify(NULL), _edit_field(NULL), _owner(o), _cur_row(0), _cur_col(0), _active(TRUE), _row_dirty(FALSE), _check_enabled(TRUE), _firstfocus(TRUE) { 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(); // 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; 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); } 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 = 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 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_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; if (acqua == CLASS_BUTTON_FIELD) { const TFixed_string testa(header.get(i)); const int diesis = testa.find('#'); if (diesis > 0) { _button = testa.mid(diesis+1); coldef->v.column->icon_x = (v_width[i]*CHARX-16) >> 1; coldef->v.column->icon_y = (CHARY-16) >> 1; coldef->v.column->column_platform = TRUE; } else _button = testo; } } 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; // Link interface to win xi_create(NULL, 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() { set_win(NULL_WIN); } // 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::col2field(int pos) const { 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; // End of search 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); } 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 const int r = rec2row(riga); XI_OBJ cell; XI_MAKE_CELL(&cell, _list, r, colonna); xi_set_focus(&cell); } int TSpreadsheet::insert(int rec) { const bool ok = notify(rec, K_INS); if (!ok) return -1; TToken_string s(80); // 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); } else update_rec(row); } void TSpreadsheet::notify_change() { if (!_row_dirty) { notify(_cur_rec, K_SPACE); _row_dirty = TRUE; } } 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) { static KEY _lastab = K_TAB; static bool _cell_dirty; switch (xiev->type) { case XIE_GET_FIRST: { const long max = items(); if (max > 0L) { long n = max * (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); const int acqua = f->class_id(); if (acqua == CLASS_BUTTON_FIELD) { if (isdigit(_button[0])) xiev->v.cell_request.icon_rid = atoi(_button); else src = _button; } else { src = row(rec).get(col); // Set value for cell if (src && *src && f->is_edit()) { 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(); } TBR } else *dst = '\0'; } break; case XIE_CHG_CELL: notify_change(); _cell_dirty = TRUE; 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; const int oldrec = _cur_rec; set_pos(xiev->v.select.xi_obj->v.row, xiev->v.select.column); if (oldrec != _cur_rec) { str2mask(_cur_rec); _row_dirty = FALSE; } update(_cur_rec); TMask_field* button = col2field(_cur_col); notify_change(); button->on_hit(); mask2str(_cur_rec); _check_enabled = TRUE; } xiev->refused = TRUE; break; case XIE_DBL_CELL: { _check_enabled = FALSE; const int oldrec = _cur_rec; 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; } if (!cell_disabled(_cur_rec, _cur_col)) 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: break; case XIE_ON_ROW: if (_check_enabled) { set_pos(xiev->v.xi_obj->v.row, _cur_col); if (_cur_rec < items()) { str2mask(_cur_rec); _row_dirty = FALSE; } else { _cur_row = _cur_rec = 0; xiev->refused = TRUE; } } break; case XIE_OFF_ROW: if (_row_dirty && _check_enabled) { _check_enabled = FALSE; // Avoid recursion! str2mask(_cur_rec); // It shouldn't have to be necessary bool ok = sheet_mask().check_fields(); if (ok) { mask2str(_cur_rec); ok = notify(_cur_rec, K_ENTER); // Notify edit } if (!ok) { xiev->refused = TRUE; } else { set_dirty(); xvt_statbar_refresh(); } _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_rec, col)) // If the cell is disabled ... { dispatch_e_char(win(), _lastab); // ... skip to the next one. } else { _edit_field = f; _cur_col = xiev->v.xi_obj->v.cell.column; _cell_dirty = FALSE; } } break; case XIE_OFF_CELL: if (_edit_field && _check_enabled) { _check_enabled = FALSE; if (_cell_dirty) { TMask_field* c = _edit_field; // Save field, it could turn out to be NULL on error const char* nuo = c->picture_data(xi_get_text(xiev->v.xi_obj, NULL, -1), TRUE); c->set(nuo); // Set new mask value c->set_dirty(); // Get it dirty! if (c->on_key(c->is_edit() ? K_TAB : K_SPACE) == FALSE) // Test it { xiev->refused = *nuo != '\0'; } else { mask2str(_cur_rec); // 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: break; case XIE_XVT_EVENT: { EVENT* ep = &xiev->v.xvte; switch (ep->type) { case E_FOCUS: if (_check_enabled && ep->v.active == 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_TAB: case K_BTAB: _lastab = k; break; 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: case K_F11: if (_check_enabled && active()) { _check_enabled = FALSE; // Disable checks notify_change(); if (_edit_field->on_key(k)) { mask2str(_cur_rec); } else { if (k == K_F9) { _edit_field = &_mask.fld(_mask.focus_field()); const short foca = _edit_field->dlg(); const int col = (foca - FIRST_FIELD) % 100 +1; if (col > 0 && col != _cur_col) { _cur_col = col; dispatch_e_char(win(), K_F9); } } } set_focus_cell(_cur_row, _cur_col); _check_enabled = TRUE; // Enable checks } break; case K_PREV: case K_NEXT: if (xi_move_focus(_itf)) dispatch_e_char(parent(), k); break; case K_ESC: xi_set_focus(_itf); dispatch_e_char(parent(), K_ESC); 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 } } } #else #include /////////////////////////////////////////////////////////// // TSpreadsheet /////////////////////////////////////////////////////////// class TSpreadsheet : public TArray_sheet { TMask _mask; SPREADSHEET_NOTIFY _notify; 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() { return _mask; } TMask& mask() const; void set_notify(SPREADSHEET_NOTIFY n) { _notify = n; } void set_dirty(bool spork = TRUE) { _owner->set_dirty(spork);} bool dirty() const { return _owner->dirty(); } void mask2str(int riga); void str2mask(int riga); 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; 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) {} 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 } 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 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() const { 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++) { int pos = sheet_mask().id2pos(id); if (pos < 0) break; for(int dlg = id; pos >= 0; pos = sheet_mask().id2pos(dlg += 100)) { const TMask_field& f = sheet_mask().fld(pos); if (f.shown()) { r.add(f.get()); break; } } #ifdef DBG if (pos < 0) { yesnofatal_box("Non e' visibile il campo %d per lo sheet", dlg); r.add(" "); } #endif } #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) { const bool change = _column_disabled[col] == on; _column_disabled.set(col, !on); #if XVT_OS == XVT_OS_WIN if (change) { int num; XI_OBJ** columns = xi_get_member_list(_list, &num); CHECKD(col+1 < num, "Can't enable column ", col); XI_OBJ* column = columns[col+1]; 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 RCT r; xi_get_rect(column, &r); xi_set_column_width(column, (r.right-r.left+1) / CHARX); // Force redraw } #endif } // 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()) { sheet_mask().reset(); mask2str(riga); return; } TToken_string& r = row(riga); r.restart(); TString80 val; for (short id = FIRST_FIELD; ; id++) { int pos = sheet_mask().id2pos(id); if (pos < 0) break; val = r.get(); // Value to set int rid = id; while (pos >= 0) { TMask_field& f = sheet_mask().fld(pos); f.set(val); const bool on = active() ? !cell_disabled(riga, id-FIRST_FIELD) : FALSE; f.enable(on); if (f.dirty() <= TRUE) { if (f.active() || f.ghost()) { if (f.has_check()) f.check(STARTING_CHECK); f.set_dirty(FALSE); f.on_hit(); } f.set_dirty(FALSE); } else sheet_mask().first_focus(-rid); rid += 100; pos = sheet_mask().id2pos(rid); } } sheet_mask().set_caption(format("Riga %d", riga+1)); } // Certified 100% bool TSpreadsheet::notify(int rec, KEY k) { const bool ok = _notify ? _notify(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 { const int olditems = items(); str2mask(n); const KEY 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); } } #if XVT_OS != XVT_OS_WIN else if (k == K_ESC) { if (tasto == K_INS) 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(); _sheet->sheet_mask().reset(); } // 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(); show_window(_win, shown()); if (!enabled()) disable(); } // 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(new TToken_string(80)); } return _sheet->row(n); } void TSheet_field::force_update(int r) { #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 _sheet->selected(); } void TSheet_field::set_notify(SPREADSHEET_NOTIFY n) { _sheet->set_notify(n); } void TSheet_field::highlight() const { #if XVT_OS == XVT_OS_WIN if (_sheet->_firstfocus && items()) { _sheet->_firstfocus = FALSE; _sheet->set_focus_cell(0, 1); } #else TMask_field::highlight(); #endif } void TSheet_field::enable(bool on) { _sheet->activate(on); } 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); } 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; } bool TSheet_field::on_key(KEY k) { if (k == K_TAB || k == K_ENTER) { if (dirty() > TRUE) return FALSE; if (k == K_ENTER && dirty()) { _sheet->str2mask(selected()); const bool ok = sheet_mask().check_fields(); if (!ok) return FALSE; } } return TMask_field::on_key(k); } 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(); }