campo-sirio/cg/cg3600.cpp
guy a341853e58 cg3600.cpp Mastrini a video
cglib.h          Aggiunti vari const agli esercizi
cglib02.cpp      Aggiunti vari const agli esercizi
cg3600a.*        Aggiunta maschera mastrini a video


git-svn-id: svn://10.65.10.50/trunk@3902 c028cbd2-c16b-5b4b-a496-9718f37d4682
1996-11-15 14:16:27 +00:00

871 lines
21 KiB
C++
Executable File

#include <stdlib.h>
#include <applicat.h>
#include <colors.h>
#include <controls.h>
#include <mask.h>
#include <urldefid.h>
#include <utility.h>
#include "cg3.h"
#include "cglib.h"
#include "cg3600a.h"
///////////////////////////////////////////////////////////
// TList
///////////////////////////////////////////////////////////
class TList : public TContainer
{
enum { MAX_SKIP = 8192 };
struct TList_object : public TObject
{
TObject* _obj;
TList_object* _next;
TList_object* _prev;
};
TList_object** _skip;
long _items, _current;
long _step, _last_skip;
protected:
// @cmember Ritorna un puntatore al primo oggetto del contenitore
virtual TObject* first_item( );
// @cmember Ritorna un puntatore all'ultimo oggetto del contenitore
virtual TObject* last_item( );
// @cmember Ritorna un puntatore all'oggetto successivo all'oggetto corrente
virtual TObject* succ_item( );
// @cmember Ritorna un puntatore all'oggetto che precede l'oggetto corrente
virtual TObject* pred_item( );
// @cmember Ritorna il numero di oggetti nel contenitore
virtual long objects( );
protected:
TList_object* detach_lstobj(long index);
TList_object* lstobjptr(long index);
void change_step(long step);
public:
TObject* TList::objptr(long index);
void destroy();
long insert(TObject* obj, long pos);
long add(TObject* obj, long pos = -1);
TObject* detach(long pos);
bool remove(long pos);
void choose_step(long expected_size); // Sceglie il passo per gli elemnti
TList(long expected_size);
virtual ~TList();
};
TList::TList(long expected_size)
: _items(0), _current(0)
{
_skip = new TList_object*[MAX_SKIP];
_skip[0] = NULL;
choose_step(expected_size);
}
TList::~TList()
{
destroy();
delete [] _skip;
}
long TList::objects( )
{
return _items;
}
TObject* TList::first_item()
{
return objptr(_current = 0);
}
TObject* TList::succ_item()
{
return objptr(++_current);
}
TObject* TList::pred_item()
{
return objptr(_current++);
}
TObject* TList::last_item()
{
return objptr(_current = _items-1);
}
void TList::destroy()
{
TList_object* head = _skip[0];
while (head)
{
TList_object* next = head->_next;
if (head->_obj)
delete head->_obj;
delete head;
head = next;
}
_items = _current = _last_skip = 0;
_skip[0] = NULL;
}
TList::TList_object* TList::lstobjptr(long index)
{
TList_object* lstobj = NULL;
const ldiv_t p = ldiv(index, _step);
if (p.quot >= 0 && p.quot < _last_skip)
{
TList_object* lo = _skip[p.quot];
for (long s = p.rem; lo && s > 0; s--)
lo = lo->_next;
lstobj = lo;
}
return lstobj;
}
TObject* TList::objptr(long index)
{
TList_object* lo = lstobjptr(index);
return lo ? lo->_obj : NULL;
}
void TList::change_step(long step)
{
CHECKD(step > 0 && step <= 16384, "Bad list step ", step);
_step = step;
_last_skip = 0;
step = 0;
for (TList_object* lo = _skip[0]; lo; lo = lo->_next, step--)
{
if (step == 0)
{
CHECK(_last_skip < MAX_SKIP, "Too many items");
_skip[_last_skip++] = lo;
step = _step;
}
}
}
void TList::choose_step(long expected_size)
{
long step = expected_size / MAX_SKIP + 1;
change_step(step);
}
long TList::insert(TObject* obj, long index)
{
if (index < 0)
index = 0;
else
{
if (index > _items)
index = _items;
}
const long pred = index-1;
TList_object* newobj = new TList_object;
newobj->_obj = obj;
if (pred < 0)
{
newobj->_prev = NULL;
newobj->_next = _skip[0];
if (_skip[0])
_skip[0]->_prev = newobj;
}
else
{
TList_object* lo = lstobjptr(pred);
CHECK(lo, "NULL insertion point");
newobj->_next = lo->_next;
newobj->_prev = lo;
if (lo->_next)
lo->_next->_prev = newobj;
lo->_next = newobj;
}
_items++;
ldiv_t p = ldiv(index, _step);
if (p.rem == 0 && p.quot < MAX_SKIP) // Cambia il capolista
_skip[p.quot] = newobj;
for (long i = p.quot + 1; i < _last_skip; i++)
_skip[i] = _skip[i]->_prev; // Aggiorna capilista successivi
// Siamo andati oltre l'ultimo skip
const long s = (_items - 1) / _step + 1;
if (s > _last_skip)
{
if (s > MAX_SKIP)
change_step(_step+1);
else
_last_skip++;
}
return index;
}
long TList::add(TObject* obj, long index)
{
if (index < 0 || index >= _items)
{
index = insert(obj, _items);
}
else
{
TList_object* lo = lstobjptr(index);
CHECK(lo, "NULL list object");
delete lo->_obj;
lo->_obj = obj;
}
return index;
}
TList::TList_object* TList::detach_lstobj(long index)
{
TList_object* lo = lstobjptr(index);
if (lo)
{
if (lo->_prev)
lo->_prev->_next = lo->_next;
if (lo->_next)
lo->_next->_prev = lo->_prev;
ldiv_t res = ldiv(index, _step);
if (res.rem == 0)
_skip[res.quot] = lo->_next;
long p;
for (p = res.quot + 1; p < _last_skip; p++)
_skip[p] = _skip[p]->_next;
_items--;
p = (_items - 1) / _step + 1;
if (p < _last_skip)
{
_last_skip--;
_skip[_last_skip] = NULL;
}
}
return lo;
}
TObject* TList::detach(long index)
{
TList_object* lo = detach_lstobj(index);
TObject* obj;
if (lo)
{
obj = lo->_obj;
delete lo;
}
else
obj = NULL;
return obj;
}
bool TList::remove(long index)
{
TObject* o = detach(index);
if (o)
delete o;
return o != NULL;
}
///////////////////////////////////////////////////////////
// TGrid_control
///////////////////////////////////////////////////////////
class TGrid_control;
class TGrid_field : public TOperable_field
{
long _to_select;
protected: // TMask_field
virtual void create(WINDOW parent);
virtual void parse_head(TScanner& scanner);
virtual bool parse_item(TScanner& scanner);
public:
virtual long items() const;
virtual bool handler(XI_EVENT* ep);
TGrid_control* grid() const { return (TGrid_control*)_ctl; }
TGrid_field(TMask* m) : TOperable_field(m) { }
virtual ~TGrid_field() { }
};
class TGrid_control : public TControl
{
enum { FIRST_FIELD = 101, MAX_COL = 128 };
long _cur_rec;
// @cmember:(INTERNAL) Tipo di ogni colonna
byte _type[MAX_COL];
TGrid_field* _grid;
protected: // TControl
//@cmember Gestisce gli eventi delle celle
virtual bool event_handler(XI_OBJ* itf, XI_EVENT* xiev);
protected:
long items() const { return _grid->items(); }
int rec2row(long rec) const;
long row2rec(int row) const;
XI_OBJ* find_column(int col) const;
public:
long selected() const { return _cur_rec; }
void select(long n);
void set_focus_rec(long rec);
int visible_rows() const;
byte& column_type(int c) { CHECKD(c >= 0 && c < MAX_COL, "Bad column ", c); return _type[c]; }
void update(long n = -1);
TGrid_control(WINDOW parent, short cid,
short x, short y, short dx, short dy,
const char* flags, const char* head,
TGrid_field* owner);
virtual ~TGrid_control() {}
};
TGrid_control::TGrid_control(
WINDOW parent, // @parm Finestra alla quale appartiene lo spreadsheet
short cid, // @parm Identificatore
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* flags, // @parm Flags di abilitazione
const char* head, // @parm Titolo delle colonne
TGrid_field* owner)
: _grid(owner), _cur_rec(0)
{
const int NUMBER_WIDTH = strchr(flags, 'A') ? 7 : 1;
short v_width[MAX_COL];
short m_width[MAX_COL];
int fixed_columns = 1; // Number of fixed columns
int lines_in_header = 1; // Number of header lines
const bool multiline = strchr(flags, 'M') != NULL;
const int lines_in_cell = multiline ? (int)xi_get_pref(XI_PREF_DEFAULT_MAX_LINES_IN_CELL) : 1;
// Calcolo larghezza massima tabella
TToken_string header(head);
TToken_string new_header(256);
int i = 0;
int f_width = NUMBER_WIDTH; // 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);
_type[i] = ' ';
TFixed_string testa(esc(h));
const bool multiple = testa.find('\n') > 0;
if (multiple)
lines_in_header = 2;
const int at = testa.find('@');
int v = testa.len(); // Video width
if (at >= 0)
{
const TString& wi = testa.mid(at+1);
const int video = atoi(wi);
if (video > 0) v = video;
if (wi.find('F') >= 0)
{
fixed_columns = i+2;
f_width += v+1;
}
if (wi.find('R') >= 0)
_type[i] = 'R';
testa.cut(at);
}
v++;
// memory width of column
m_width[i] = v * lines_in_cell;
if (v > 64) v = 64;
v_width[i] = v;
if (v_width[i] > max_width) max_width = v_width[i];
new_header.add(testa);
}
// Calcola rettangolo massimo per lo sheet
XI_RCT rct; coord2rct(parent, x, y, dx, dy, rct);
rct.right -= 2*XI_FU_MULTIPLE; // toglie scroll-bar
// Controlla se ci sono troppe colonne fisse
if ((f_width+max_width)*XI_FU_MULTIPLE > rct.right)
fixed_columns = 1;
XI_OBJ* itf = get_interface(parent);
XI_OBJ_DEF* listdef = xi_add_list_def(NULL, cid,
rct.top, rct.left, rct.bottom-rct.top,
XI_ATR_ENABLED | XI_ATR_VISIBLE,
NORMAL_COLOR, NORMAL_BACK_COLOR, // normal
DISABLED_COLOR, DISABLED_BACK_COLOR, // disabled
FOCUS_COLOR, // active
0);
listdef->app_data = (long)this;
XI_LIST_DEF* l = listdef->v.list;
l->min_heading_height = xi_button_calc_height_font_id(xvt_default_font()) * lines_in_header;
l->sizable_columns = TRUE;
l->movable_columns = TRUE;
l->fixed_columns = fixed_columns;
l->scroll_bar = TRUE;
l->scroll_bar_button = TRUE;
l->white_space_color = MASK_DARK_COLOR;
l->rule_color = MASK_DARK_COLOR;
// Definizione della prima colonna (numero di riga)
const long attr = XI_ATR_VISIBLE | XI_ATR_RJUST | XI_ATR_SELECTABLE;
XI_OBJ_DEF* coldef = xi_add_column_def(listdef, FIRST_FIELD+1000-1, attr, 0,
NUMBER_WIDTH * XI_FU_MULTIPLE, NUMBER_WIDTH , "");
coldef->app_data = (long)this;
XI_COLUMN_DEF* cd = coldef->v.column;
cd->heading_platform = TRUE;
cd->column_platform = TRUE;
cd->size_rows = multiline;
for (h = new_header.get(0), i = 0; h; h = new_header.get(), i++)
{
long attr = XI_ATR_VISIBLE | XI_ATR_ENABLED | XI_ATR_AUTOSCROLL | XI_ATR_READONLY;
if (_type[i] == 'C')
attr |= XI_ATR_SELECTABLE;
if (_type[i] == 'R')
attr |= XI_ATR_RJUST;
coldef = xi_add_column_def(listdef, FIRST_FIELD+i+1000, attr, i+1,
v_width[i] * XI_FU_MULTIPLE, m_width[i], (char*)h);
coldef->app_data = (long)this;
cd = coldef->v.column;
cd->heading_platform = TRUE;
cd->center_heading = strchr(h, '\n') == NULL;
if (multiline)
{
cd->size_rows = TRUE;
cd->wrap_text = TRUE;
}
}
RCT rd; xi_get_def_rect(listdef, &rd);
if ((rd.right - rd.left) > (rct.right - rct.left))
l->width = rct.right - rct.left;
_obj = xi_create(itf, listdef); // Create the whole thing!
xi_dequeue(); // Flush events in XOL
xi_tree_free(listdef); // Free definitions
CHECKD(_obj, "Can't create list control ", cid);
update_tab_cid();
}
// Converts a row number in the correspondig record number
int TGrid_control::rec2row(long record) const
{
int rows;
const long* rec = xi_get_list_info(_obj, &rows);
int r = int(record - rec[0]);
if (r < 0 || r >= rows)
r = -1;
return r;
}
// Converts a row number in the correspondig record number
long TGrid_control::row2rec(int row) const
{
int rows;
const long* handle = xi_get_list_info(_obj, &rows);
if (row < 0)
row = 0;
else
{
if (row >= rows)
row = rows-1;
}
const long r = handle[row];
CHECKD(r >= 0 && r < items(), "Sheet line out of range: ", row);
return r;
}
int TGrid_control::visible_rows() const
{
return xi_get_visible_rows(_obj, NULL, NULL);
}
void TGrid_control::update(long n)
{
if (n >= 0)
{
const int riga = rec2row(n);
if (riga >= 0)
{
XI_OBJ row;
XI_MAKE_ROW(&row, _obj, riga);
xi_cell_request(&row);
}
}
else
{
int num = 0;
const long* handle = xi_get_list_info(_obj, &num);
bool scroll_first = items() == 0;
if (!scroll_first)
{
int first = 0, last = 0;
xi_get_visible_rows(_obj, &first, &last);
n = handle[first];
scroll_first = n > items();
}
if (scroll_first)
xi_scroll(_obj, XI_SCROLL_FIRST);
else
xi_scroll_rec(_obj, n, NORMAL_COLOR, XI_ATR_ENABLED, 0);
}
}
void TGrid_control::select(long rec)
{
if (rec >= 0 && rec < items())
{
int rows;
const long* handle = xi_get_list_info(_obj, &rows);
int first = 0, last = 0;
xi_get_visible_rows(_obj, &first, &last);
if (rec < handle[first] || rec > handle[last])
xi_scroll_rec(_obj, rec, NORMAL_COLOR, XI_ATR_ENABLED, 0);
}
}
void TGrid_control::set_focus_rec(long rec)
{
if (rec < 0)
rec = selected();
int r = rec2row(rec);
if (r < 0)
{
select(rec);
r = rec2row(rec);
}
const int c = _type[0] == 'C' ? 2 : 1;
XI_OBJ cell; XI_MAKE_CELL(&cell, _obj, r, c);
xi_set_focus(&cell);
}
XI_OBJ* TGrid_control::find_column(
int col) const // @parm Indice o identificatore colonna
{
CHECKD(col >= 0, "Bad column ", col);
if (col < FIRST_FIELD) // Se e' un indice trasformalo in identificatore
col += FIRST_FIELD + 1000;
int num;
XI_OBJ** columns = xi_get_member_list(_obj, &num);
for (int c = num-1; c >= 0; c--)
{
if (columns[c]->cid == col)
break;
}
return c >= 0 ? columns[c] : NULL;
}
// Certified 75%
bool TGrid_control::event_handler(XI_OBJ* itf, XI_EVENT *xiev)
{
BOOLEAN& refused = xiev->refused;
const bool handled = _grid->handler(xiev);
if (handled)
return !refused;
switch (xiev->type)
{
case XIE_GET_FIRST:
if (items() > 0L)
{
long n = items() * (long)xiev->v.rec_request.percent / 100L;
if (n < 0L) n = 0L;
xiev->v.rec_request.data_rec = n;
}
else
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())
refused = TRUE;
else
xiev->v.rec_request.data_rec = n;
}
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_COL_MOVE:
if (xiev->v.column.in_fixed ||
xiev->v.column.col_nbr < xi_get_fixed_columns(xiev->v.column.list))
refused = TRUE;
break;
case XIE_COL_SIZE:
break;
case XIE_SELECT:
xiev->refused = TRUE;
break;
case XIE_CELL_REQUEST:
if (xiev->v.cell_request.col_nbr == 0)
{
if (xiev->v.cell_request.len > 1)
{
sprintf(xiev->v.cell_request.s, "%ld", xiev->v.cell_request.rec);
xiev->v.cell_request.color = NORMAL_COLOR;
}
}
break;
default:
break;
}
return !refused;
}
///////////////////////////////////////////////////////////
// TGrid_field
///////////////////////////////////////////////////////////
void TGrid_field::create(WINDOW parent)
{
_ctl = new TGrid_control(parent, dlg(),
_ctl_data._x, _ctl_data._y,
_ctl_data._width, _ctl_data._size,
_ctl_data._flags, _ctl_data._park,
this);
}
void TGrid_field::parse_head(TScanner& scanner)
{
_ctl_data._width = scanner.integer();
_ctl_data._height = scanner.integer();
if (_ctl_data._height == 0)
_ctl_data._height = -1;
}
bool TGrid_field::parse_item(TScanner& scanner)
{
if (scanner.key() == "IT")
{
_ctl_data._park.add(scanner.string());
return TRUE;
}
return TMask_field::parse_item(scanner);
}
bool TGrid_field::handler(XI_EVENT* xiev)
{
if (xiev->type == XIE_CELL_REQUEST)
{
const long& rec = xiev->v.cell_request.rec;
const short& col = xiev->v.cell_request.col_nbr;
if (col == 3)
{
strcpy(xiev->v.cell_request.s,
"Questa e' una descrizioncina sgarsolina sgarsolina,"
" che non doverebbe stare in una sola righina");
xiev->v.cell_request.back_color = rec % 7 ? COLOR_YELLOW : COLOR_CYAN;
return TRUE;
}
}
return FALSE;
}
long TGrid_field::items() const
{
return 30000L;
}
///////////////////////////////////////////////////////////
// TGrid_mask
///////////////////////////////////////////////////////////
class TGrid_mask : public TMask
{
TEsercizi_contabili _esercizi;
protected: // TMask
virtual TMask_field* parse_field(TScanner& sc);
static bool data_handler(TMask_field& f, KEY k);
public:
const TEsercizi_contabili& esercizi() const { return _esercizi; }
TEsercizi_contabili& esercizi() { return _esercizi; }
TGrid_mask(const char* name);
virtual ~TGrid_mask() { }
};
TGrid_mask::TGrid_mask(const char* name)
{
read_mask(name, 0, 0);
set_handler(F_DADATA, data_handler);
set_handler(F_ADATA, data_handler);
}
TMask_field* TGrid_mask::parse_field(TScanner& sc)
{
TMask_field* f;
if (sc.key() == "SP")
f = new TGrid_field(this);
else
f = TMask::parse_field(sc);
return f;
}
bool TGrid_mask::data_handler(TMask_field& f, KEY k)
{
bool ok = TRUE;
if (f.to_check(k) && !f.empty())
{
const TGrid_mask& gm = (const TGrid_mask&)f.mask();
int codice_esercizio = gm.get_int(F_ESERCIZIO);
if (codice_esercizio == 0)
{
const short id_altra_data = f.dlg() == F_DADATA ? F_ADATA : F_DADATA;
const TDate d = gm.get(id_altra_data);
if (d.ok())
codice_esercizio = gm.esercizi().date2esc(d);
}
const TDate d = f.get();
const int esercizio = gm.esercizi().date2esc(d);
if (codice_esercizio != 0)
{
if (esercizio != codice_esercizio)
ok = error_box("La data deve appartenere all'esercizio %d", codice_esercizio);
}
else
{
if (esercizio == 0)
ok = error_box("La data deve appartenere ad un esercizio contabile");
}
}
return ok;
}
///////////////////////////////////////////////////////////
// TMastrini_video
///////////////////////////////////////////////////////////
class TMastrini_video : public TApplication
{
TGrid_mask* _gm;
protected:
virtual bool create();
virtual bool menu(MENU_TAG);
virtual void on_firm_change();
};
bool TMastrini_video::create()
{
_gm = NULL;
dispatch_e_menu(BAR_ITEM(1));
return TRUE;
}
void TMastrini_video::on_firm_change()
{
if (_gm)
_gm->esercizi().update();
}
bool TMastrini_video::menu(MENU_TAG)
{
_gm = new TGrid_mask("cg3600a");
KEY key = 0;
while (key != K_QUIT)
{
if (key == 0)
{
const TEsercizi_contabili& esercizi = _gm->esercizi();
const int codice_ultimo_esercizio = esercizi.last();
if (codice_ultimo_esercizio > 0)
{
const TEsercizio& esercizio = esercizi.esercizio(codice_ultimo_esercizio);
_gm->set(F_ESERCIZIO, codice_ultimo_esercizio);
_gm->set(F_DADATA, esercizio.inizio());
_gm->set(F_ADATA, esercizio.fine());
}
}
else
{
_gm->reset(F_SOTTOCONTO); // Azzera sottoconto
_gm->reset(F_CLIENTE); // Azzera cliente
_gm->reset(F_FORNITORE); // Azzera fornitore
_gm->reset(F_DACAUSALE); // Azzera causali
_gm->reset(F_ACAUSALE);
}
key = _gm->run();
}
delete _gm;
return FALSE;
}
int cg3600(int argc, char* argv[])
{
TMastrini_video mv;
mv.run(argc, argv, "Mastrini");
return 0;
}