campo-sirio/cg/cg3600.cpp
guy 96f813af8d cg1200a.uml Allungato codice cliente/fornitore da 5 a 6
cg3.url        Aggiunto menu dei colori
cg3600.cpp     Completata visualizzazione mastrini a video
cg3600a.uml    Maschera di query mastrini
cglib.h        Migliorata gestione esercizi
cglib02.cpp    Resa statica la tabella degli esercizi
cg3600.h       Nomi dei campi per la visualizzazione mastrini
cg3600b.uml    Maschera di visualizzazione sheet mastrini


git-svn-id: svn://10.65.10.50/trunk@3931 c028cbd2-c16b-5b4b-a496-9718f37d4682
1996-11-27 11:51:03 +00:00

2537 lines
61 KiB
C++
Executable File

#include <stdlib.h>
#include <applicat.h>
#include <colors.h>
#include <controls.h>
#include <execp.h>
#include <mailbox.h>
#include <progind.h>
#include <relation.h>
#include <urldefid.h>
#include <utility.h>
#include <varmask.h>
#include "cg3.h"
#include "cglib.h"
#include "cg3600.h"
#include "causali.h"
#include "mov.h"
#include "pconti.h"
#include "rmov.h"
#include "saldi.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) const;
void change_step(long step);
public:
long items() const { return _items; }
TObject* objptr(long index) const;
TObject& obj(long index)
{ TObject* o = objptr(index); CHECK(o, "Null list item"); return *o; }
const TObject& obj(long index) const
{ const TObject* o = objptr(index); CHECK(o, "Null list item"); return *o; }
void destroy();
long insert(TObject* obj, long pos);
long append(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 = 128L);
virtual ~TList();
};
TList::TList(long expected_size)
: _items(0), _current(0)
{
_skip = new TList_object*[MAX_SKIP+1];
_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) const
{
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) const
{
const 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
{
if (_last_skip > 0)
{
TList_object* lo = _skip[_last_skip-1];
while (lo->_next != NULL)
lo = lo->_next;
_skip[_last_skip++] = lo;
_skip[_last_skip] = NULL;
}
else
_last_skip = 1;
}
}
return index;
}
long TList::append(TObject* obj, long index)
{
if (index < 0 || index >= _items)
index = _items;
else
index++;
return insert(obj, 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;
}
///////////////////////////////////////////////////////////
// TDecoder
///////////////////////////////////////////////////////////
class TDecoder : private TAssoc_array
{
TLocalisamfile* _file;
TString _if, _of;
public:
const TString& decode(const char* code);
const TString& decode(long code);
TDecoder(int num, const char* inf, const char* outf);
TDecoder(const char* table, const char* outf = "S0");
virtual ~TDecoder();
};
///////////////////////////////////////////////////////////
// TDecoder
///////////////////////////////////////////////////////////
TDecoder::TDecoder(int num, const char* inf, const char* outf)
: _file(new TLocalisamfile(num)), _if(inf), _of(outf)
{ }
TDecoder::TDecoder(const char* tab, const char* outf)
: _file(new TTable(tab)), _if("CODTAB"), _of(outf)
{ }
TDecoder::~TDecoder()
{
delete _file;
}
const TString& TDecoder::decode(const char* code)
{
if (code == NULL)
code = "";
TObject* obj = objptr(code);
if (obj == NULL)
{
int err = ~NOERR;
if (*code)
{
_file->setkey(1);
_file->put(_if, code);
err = _file->read();
}
if (err == NOERR)
obj = new TString(_file->get(_of)); // Found
else
obj = new TString(1); // Not found
add(code, obj);
}
const TString& s = (const TString&)*obj;
return s;
}
const TString& TDecoder::decode(long code)
{
TString16 c;
if (code > 0)
c << code;
return decode(c);
}
///////////////////////////////////////////////////////////
// TBalance
///////////////////////////////////////////////////////////
class TBalance : public TObject
{
TImporto _saldo_ini, _progr_dare, _progr_avere, _saldo_fin;
protected:
bool find(const TBill& b, int esercizio,
TImporto& si, TImporto& da, TImporto& av, TImporto& sf) const;
public:
void read(int g, int c, long s, int esercizio);
void read(const TBill& b, int esercizio);
void reread();
const TImporto& saldo_iniziale() const;
const real& progressivo_dare_iniziale() const;
const real& progressivo_avere_iniziale() const;
real progressivo_dare_finale() const;
real progressivo_avere_finale() const;
TImporto saldo_finale(bool chiusura = FALSE) const;
TImporto saldo_finale_chiusura() const;
TBalance();
TBalance(int g, int c, long s, int esercizio);
TBalance(const TBill& b, int esercizio);
virtual ~TBalance() { }
};
TBalance::TBalance()
{
}
TBalance::TBalance(int g, int c, long s, int esercizio)
{
read(g, c, s, esercizio);
}
TBalance::TBalance(const TBill& b, int esercizio)
{
read(b, esercizio);
}
bool TBalance::find(const TBill& b, int esercizio,
TImporto& si, TImporto& da, TImporto& av, TImporto& sf) const
{
CHECK(b.sottoconto() > 0L, "Sottoconto mancante");
TLocalisamfile saldi(LF_SALDI);
TRectype& curr = saldi.curr();
curr.put(SLD_GRUPPO, b.gruppo());
curr.put(SLD_CONTO, b.conto());
curr.put(SLD_SOTTOCONTO, b.sottoconto());
curr.put(SLD_ANNOES, esercizio);
curr.put(SLD_FLSCA, FALSE);
const bool ok = saldi.read() == NOERR;
if (ok)
{
si.set(curr.get_char(SLD_FLAGSALINI), curr.get_real(SLD_SALDO));
da.set('D', curr.get_real(SLD_PDARE));
av.set('A', curr.get_real(SLD_PAVERE));
sf.set(curr.get_char(SLD_FLAGSALFIN), curr.get_real(SLD_SALDOFIN));
}
else
{
si.set('D', ZERO);
da = av = sf = si;
}
return ok;
}
void TBalance::read(int gruppo, int conto, long sottoconto, int esercizio)
{
const TBill zio(gruppo, conto, sottoconto);
read(zio, esercizio);
}
void TBalance::read(const TBill& b, int esercizio)
{
TImporto si, sf, pd, pa;
find(b, esercizio, si, pd, pa, sf);
_saldo_ini = si;
_progr_dare = pd;
_progr_avere = pa;
_saldo_fin = sf;
if (_saldo_ini.is_zero())
{
TLocalisamfile pcon(LF_PCON);
TRectype& curr = pcon.curr();
curr.put(PCN_GRUPPO, b.gruppo());
curr.put(PCN_CONTO, b.conto());
const int err = pcon.read();
CHECK(err == NOERR, "Impossibile stabilire indicatore di bilancio");
const int indbil = curr.get_int(PCN_INDBIL);
if (indbil == 1 || indbil == 2 || indbil == 5)
{
TEsercizi_contabili esercizi;
const int precedente = esercizi.pred(esercizio);
if (find(b, precedente, si, pd, pa, sf))
{
_saldo_ini = si;
_saldo_ini += pd;
_saldo_ini += pa;
}
}
}
}
const TImporto& TBalance::saldo_iniziale() const
{ return _saldo_ini; }
const real& TBalance::progressivo_dare_iniziale() const
{
return _saldo_ini.sezione() == 'D' ? _saldo_ini.valore() : ZERO;
}
const real& TBalance::progressivo_avere_iniziale() const
{
return _saldo_ini.sezione() == 'A' ? _saldo_ini.valore() : ZERO;
}
real TBalance::progressivo_dare_finale() const
{
real pd = progressivo_dare_iniziale();
pd += _progr_dare.valore();
if (_saldo_fin.sezione() == 'D')
pd += _saldo_fin.valore();
return pd;
}
real TBalance::progressivo_avere_finale() const
{
real pa = progressivo_avere_iniziale();
pa += _progr_avere.valore();
if (_saldo_fin.sezione() == 'A')
pa += _saldo_fin.valore();
return pa;
}
TImporto TBalance::saldo_finale(bool chiusura) const
{
TImporto sf(_saldo_ini);
sf += _progr_dare;
sf += _progr_avere;
if (chiusura)
sf += _saldo_fin;
return sf;
}
TImporto TBalance::saldo_finale_chiusura() const
{
return saldo_finale(TRUE);
}
///////////////////////////////////////////////////////////
// TMastrino
///////////////////////////////////////////////////////////
enum tipo_riga_mastrino { riga_mastrino, riga_contropartita };
class TRiga_mastrino : public TObject
{
tipo_riga_mastrino _type;
TRecnotype _mov, _rmov;
TDate _data;
real _dare, _avere;
public:
tipo_riga_mastrino tipo() const { return _type; }
TRecnotype rmov() const { return _rmov; }
TRecnotype mov() const { return _mov; }
const TDate& data() const { return _data; }
const real& dare() const { return _dare; }
const real& avere() const { return _avere; }
TImporto saldo() const;
TRiga_mastrino(tipo_riga_mastrino trig,
TRecnotype rmov, TRecnotype mov,
const real& d, const real& a,
const TDate& datareg);
virtual ~TRiga_mastrino() { }
};
TRiga_mastrino::TRiga_mastrino(tipo_riga_mastrino trig,
TRecnotype rmov, TRecnotype mov,
const real& d, const real& a,
const TDate& datareg)
: _type(trig), _rmov(rmov), _mov(mov),
_dare(d), _avere(a), _data(datareg)
{ }
TImporto TRiga_mastrino::saldo() const
{
TImporto imp('D', _dare - _avere);
imp.normalize();
return imp;
}
class TMastrino : public TObject
{
static long _instances;
static TRelation* _rel;
static TLocalisamfile *_rmov; // File principale della relazione
static TLocalisamfile *_mov; // File secondario della relazione
TBill _conto; // Conto del mastrino
int _esercizio; // Esercizio di riferimento (eventualmente 0)
TDate _da_data, _a_data;
TString _da_caus, _a_caus;
real _pdare_ini, _pavere_ini;
real _pdare_per, _pavere_per;
real _pdare_fin, _pavere_fin;
TList _riga; // Righe del mastrino
protected:
TRelation& rel() { return *_rel; }
TLocalisamfile& rmov() { return *_rmov; }
TLocalisamfile& mov() { return *_mov; }
void position_rel(long n);
TRiga_mastrino& row(long n) const { return (TRiga_mastrino&)_riga.obj(n); }
public:
long items() const { return _riga.items(); }
void read(const TBill& conto,
int annoes, const TDate& dd, const TDate& ad,
const TString& dc, const TString& ac);
void reread();
TRiga_mastrino& operator[](long n) const { return row(n); }
const TRectype& riga(long n);
const TRectype& testata(long n);
long first(tipo_riga_mastrino tipo = riga_mastrino) const;
long pred(long rec, tipo_riga_mastrino tipo = riga_mastrino) const;
long succ(long rec, tipo_riga_mastrino tipo = riga_mastrino) const;
long last(tipo_riga_mastrino tipo = riga_mastrino) const;
void destroy() { _riga.destroy(); }
int esercizio() const { return _esercizio; }
const real& progressivo_dare_iniziale() const { return _pdare_ini; }
const real& progressivo_avere_iniziale() const { return _pavere_ini; }
TImporto saldo_iniziale() const;
const real& progressivo_dare_finale() const { return _pdare_fin; }
const real& progressivo_avere_finale() const { return _pavere_fin; }
TImporto saldo_finale() const;
real progressivo_dare_periodo() const { return _pdare_ini + _pdare_per; }
real progressivo_avere_periodo() const { return _pavere_ini + _pavere_per; }
TImporto saldo_periodo() const;
bool expandable(long rec) const;
bool expand(long rec);
bool collapse(long rec);
TMastrino();
virtual ~TMastrino();
};
long TMastrino::_instances = 0L;
TRelation* TMastrino::_rel = NULL;
TLocalisamfile* TMastrino::_rmov = NULL; // File principale della relazione
TLocalisamfile* TMastrino::_mov = NULL; // File secondario della relazione
TMastrino::TMastrino()
: _esercizio(0)
{
if (_instances == 0L)
{
_rel = new TRelation(LF_RMOV);
_rel->add(LF_MOV, "NUMREG=NUMREG");
_rmov = &_rel->lfile();
_mov = &_rel->lfile(LF_MOV);
}
_instances++;
}
TMastrino::~TMastrino()
{
_instances--;
if (_instances == 0L)
{
delete _rel;
_rel = NULL;
_rmov = _mov = NULL;
}
}
long TMastrino::succ(long rec, tipo_riga_mastrino tipo) const
{
const long ul = items();
for (long i = rec+1; i < ul; i++)
{
if (row(i).tipo() == tipo)
break;
}
return i;
}
long TMastrino::pred(long rec, tipo_riga_mastrino tipo) const
{
for (long i = rec-1; i >= 0; i--)
{
if (row(i).tipo() == tipo)
break;
}
return i;
}
long TMastrino::first(tipo_riga_mastrino tipo) const
{
return succ(-1, tipo);
}
long TMastrino::last(tipo_riga_mastrino tipo) const
{
return pred(items(), tipo);
}
void TMastrino::read(const TBill& conto,
int ae, const TDate& dd, const TDate& ad,
const TString& dc, const TString& ac)
{
TEsercizi_contabili esercizi;
_conto = conto;
_esercizio = ae;
_riga.destroy();
rmov().setkey(2);
TRectype& rmov_rec = rmov().curr();
const TRectype& mov_rec = mov().curr();
if (ae <= 0)
{
if (dd.ok())
ae = esercizi.date2esc(dd);
else
ae = esercizi.date2esc(ad);
}
CHECKD(esercizi.exist(ae), "Anno di esercizio fantasioso: ", ae);
const TDate& inizio_esercizio = esercizi[ae].inizio();
_da_data = dd.ok() ? dd : inizio_esercizio;
_a_data = ad.ok() ? ad : esercizi[ae].fine();
_da_caus = dc;
_a_caus = ac.blank() ? "zzz" : ac;
const TDate& min_data_reg = _da_data;
TDate max_data_reg;
long num_giorni = _a_data - _da_data + 1;
if (_esercizio > 0)
{
const int succ = esercizi.next(ae);
if (succ > 0)
{
max_data_reg = esercizi[succ].fine();
num_giorni += 30;
}
else
max_data_reg = esercizi[ae].fine();
}
else
max_data_reg = _a_data;
TString caption(80);
caption.format("Caricamento mastrino %03d.%03d.%06ld",
_conto.gruppo(), _conto.conto(), _conto.sottoconto());
TProgind pi(num_giorni, caption, FALSE, TRUE, 48);
// Valori dei saldi fino alla data di inizio stampa:
// Vengono inizializzati con i saldi iniziali dell'esercizio,
// poi verranno sommati gli importi dei movimenti che
// vanno dall'inizio dell'esercizio al giorno precedente
// la data di inizio stampa
const TBalance saldo(_conto, ae);
_pdare_ini = saldo.progressivo_dare_iniziale();
_pavere_ini = saldo.progressivo_avere_iniziale();
_pdare_fin = saldo.progressivo_dare_finale();
_pavere_fin = saldo.progressivo_avere_finale();
// Valori dei saldi del perido in esame:
// Vengono inizializzati a zero e poi si incrementa man mano
// coi valori degli importi dei movimenti compresi nei
// limiti della stampa
_pdare_per = _pavere_per = ZERO;
conto.put(rmov_rec);
rmov_rec.put(RMV_DATAREG, min_data_reg);
for (int err = rel().read(_isgteq); err == NOERR; err = rel().next())
{
// Controlla di non aver superato la data limite
const TDate data_reg = mov_rec.get(MOV_DATAREG);
if (data_reg > max_data_reg)
break;
// Controlla che il conto sia ancora quello selezionato
const TBill conto_corrente(rmov_rec);
if (conto_corrente != conto)
break;
const long giorno = data_reg - min_data_reg + 1;
pi.setstatus(giorno);
// Ignora i movimenti provvisori
if (mov_rec.get_char(MOV_PROVVIS) > ' ')
continue;
const TDate data_corrente(_esercizio <= 0 ? data_reg : mov_rec.get_date(MOV_DATADOC));
if (data_corrente > _a_data)
continue;
const char sezione = rmov_rec.get_char(RMV_SEZIONE);
const real importo = rmov_rec.get(RMV_IMPORTO);
if (data_corrente < _da_data)
{
if (data_corrente >= inizio_esercizio)
{
if (sezione == 'D')
_pdare_ini += importo;
else
_pavere_ini += importo;
}
else
continue;
}
else
{
if (sezione == 'D')
_pdare_per += importo;
else
_pavere_per += importo;
// Controlla che la causale sia nei limiti
const TString& causale = mov_rec.get(MOV_CODCAUS);
if (causale >= _da_caus && causale <= _a_caus)
{
TRiga_mastrino* r = new TRiga_mastrino(riga_mastrino,
rmov().recno(), mov().recno(),
_pdare_per, _pavere_per, data_reg);
_riga.append(r);
}
}
}
pi.setstatus(num_giorni); // Raramente arriva in fondo!
}
void TMastrino::reread()
{
read(_conto, _esercizio, _da_data, _a_data, _da_caus, _a_caus);
}
void TMastrino::position_rel(long n)
{
const TRiga_mastrino& r = row(n);
if (rmov().recno() != r.rmov())
rmov().readat(r.rmov());
if (mov().recno() != r.mov())
mov().readat(r.mov());
}
const TRectype& TMastrino::riga(long n)
{
position_rel(n);
return rmov().curr();
}
const TRectype& TMastrino::testata(long n)
{
position_rel(n);
return mov().curr();
}
TImporto TMastrino::saldo_iniziale() const
{
TImporto s('D', _pdare_ini - _pavere_ini);
return s.normalize();
}
TImporto TMastrino::saldo_finale() const
{
TImporto s('D', _pdare_fin - _pavere_fin);
return s.normalize();
}
TImporto TMastrino::saldo_periodo() const
{
TImporto s('D', progressivo_dare_periodo() - progressivo_avere_periodo());
return s.normalize();
}
bool TMastrino::expandable(long rec) const
{
bool e = FALSE;
if (row(rec).tipo() == riga_mastrino)
{
if (rec < items()-1)
e = row(rec+1).tipo() != riga_contropartita;
else
e = TRUE;
}
return e;
}
bool TMastrino::expand(long rec)
{
bool ok = expandable(rec);
if (ok)
{
const TRectype& head = testata(rec);
const long numreg = head.get_long(MOV_NUMREG);
rmov().setkey(1);
TRectype& curr = rmov().curr();
curr.zero();
curr.put(RMV_NUMREG, numreg);
for (int err = rmov().read(_isgteq); err == NOERR; err = rmov().next())
{
if (curr.get_long(RMV_NUMREG) != numreg)
break;
const TBill bill(curr, TRUE); // Legge il conto di contropartita
if (bill == _conto)
{
real dare, avere;
if (curr.get_char(RMV_SEZIONE) == 'D')
dare = curr.get_real(RMV_IMPORTO);
else
avere = curr.get_real(RMV_IMPORTO);
const TDate data(head.get(MOV_DATAREG));
TRiga_mastrino* r = new TRiga_mastrino(riga_contropartita,
rmov().recno(), mov().recno(),
dare, avere, data);
_riga.append(r, rec);
}
}
}
return ok;
}
bool TMastrino::collapse(long rec)
{
if (row(rec).tipo() != riga_mastrino)
rec = pred(rec, riga_mastrino);
bool ok = !expandable(rec);
if (ok)
{
rec++;
while (rec < items() && row(rec).tipo() != riga_mastrino)
_riga.remove(rec);
}
return ok;
}
///////////////////////////////////////////////////////////
// TGrid_control
///////////////////////////////////////////////////////////
class TGrid_control;
class TGrid_cell : public TObject
{
XI_EVENT* _xiev;
public:
void set(const char* txt);
void set(long num);
void set_icon(int id);
void show_button(bool on = TRUE);
void hide_button() { show_button(FALSE); }
void set_back_color(COLOR col);
void set_fore_color(COLOR col);
void set_colors(COLOR back, COLOR fore);
TGrid_cell(XI_EVENT* xiev) : _xiev(xiev) { }
virtual ~TGrid_cell() { }
};
class TGrid_field : public TOperable_field
{
protected: // TMask_field
virtual void create(WINDOW parent);
virtual void parse_head(TScanner& scanner);
virtual bool parse_item(TScanner& scanner);
TGrid_control& grid() const { return (TGrid_control&)*_ctl; }
public:
virtual bool handler(XI_EVENT* xiev);
virtual long items() const;
virtual void cell_request(long rec, short id, TGrid_cell& cell);
virtual bool on_rec(long rec) { return TRUE; }
virtual bool off_rec(long rec) { return TRUE; }
virtual bool on_resize_column(short cid, int new_size) { return TRUE; }
virtual void on_dbl_cell(long rec, short id) { }
virtual void on_button() { }
virtual void on_cell_button(long rec, short cid) { }
long selected() const;
void update(long n = -1);
int visible_rows() const;
bool select(long rec);
TGrid_field(TMask* m) : TOperable_field(m) { }
virtual ~TGrid_field() { }
};
class TGrid_control : public TControl
{
enum grid_control_constants { MAX_COL = 128 };
long _cur_rec;
bool _read_only;
// @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;
void update_selection(XI_EVENT* xiev);
public:
long selected() const { return _cur_rec; }
bool select(long n);
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);
bool is_visible(long rec) const;
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(-1)
{
_read_only = FALSE;
bool auto_num = FALSE;
bool multi_line = FALSE;
int lines_in_cell = 1;
for (const char* f = flags; *f; f++)
{
switch(*f)
{
case 'D':
_read_only = TRUE;
break;
case 'M':
multi_line = TRUE;
lines_in_cell = (int)xi_get_pref(XI_PREF_DEFAULT_MAX_LINES_IN_CELL);
break;
case '2':
case '3':
case '4':
case '5':
if (multi_line)
lines_in_cell = *f - '0';
break;
default:
break;
}
}
const int NUMBER_WIDTH = auto_num ? 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
// 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->max_lines_in_cell = lines_in_cell;
l->scroll_bar = TRUE;
l->scroll_bar_button = TRUE;
l->white_space_color = MASK_DARK_COLOR;
l->rule_color = MASK_DARK_COLOR;
if (_read_only)
l->single_select = TRUE;
else
l->active_back_color = FOCUS_BACK_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 = multi_line;
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;
if (_read_only)
attr |= XI_ATR_READONLY | 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 = TRUE;
if (multi_line)
{
cd->size_rows = TRUE;
cd->wrap_text = _type[i] != 'R';
}
}
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
{
CHECK(row >= 0, "Negative grid row?");
int rows;
const long* handle = xi_get_list_info(_obj, &rows);
long rec;
if (rows > 0)
{
if (row >= rows)
rec = handle[rows-1] + row - rows + 1;
else
rec = handle[row];
}
else
rec = -1;
if (rec < 0 || rec >= items())
rec = -1;
return rec;
}
int TGrid_control::visible_rows() const
{
return xi_get_visible_rows(_obj, NULL, NULL);
}
bool TGrid_control::is_visible(long rec) const
{
int first, last;
xi_get_visible_rows(_obj, &first, &last);
int rows;
const long* handle = xi_get_list_info(_obj, &rows);
bool yes = rec >= handle[first] && rec <= handle[last];
return yes;
}
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);
}
}
bool TGrid_control::select(long rec)
{
if (_cur_rec >= 0 && _cur_rec < items())
{
if (!_grid->off_rec(_cur_rec))
return FALSE;
}
const bool ok = rec >= 0 && rec < items();
if (ok)
{
if (!_grid->on_rec(rec))
return FALSE;
int first, last;
xi_get_visible_rows(_obj, &first, &last);
// Controllo che la nuova riga sia completamente visibile
int r = rec2row(rec);
if (r >= first && r <= last)
{
if (_read_only)
{
XI_OBJ riga; XI_MAKE_ROW(&riga, _obj, r);
long attr = xi_get_attrib(&riga);
attr |= XI_ATR_SELECTED;
xi_set_attrib(&riga, attr);
xi_dequeue();
}
}
else
{
long attr = XI_ATR_ENABLED;
if (_read_only)
attr |= XI_ATR_SELECTED;
xi_scroll_rec(_obj, rec, NORMAL_COLOR, attr, 0);
}
}
const int r = rec2row(_cur_rec);
if (r >= 0)
{
if (_read_only)
{
XI_OBJ riga; XI_MAKE_ROW(&riga, _obj, r);
long attr = xi_get_attrib(&riga);
attr &= ~XI_ATR_SELECTED;
xi_set_attrib(&riga, attr);
}
else
{
XI_OBJ cella; XI_MAKE_CELL(&cella, _obj, r, 1);
xi_set_focus(&cella);
}
xi_dequeue();
}
if (rec < 0 || rec >= items())
rec = -1;
_cur_rec = rec;
return ok;
}
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;
}
void TGrid_control::update_selection(XI_EVENT* xiev)
{
if (xiev->v.rec_request.data_rec == _cur_rec)
xiev->v.rec_request.attrib |= XI_ATR_SELECTED;
else
xiev->v.rec_request.attrib &= ~XI_ATR_SELECTED;
}
// 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;
update_selection(xiev);
}
else
refused = TRUE;
break;
case XIE_GET_LAST:
xiev->v.rec_request.data_rec = items()-1;
update_selection(xiev);
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->v.rec_request.data_rec = n;
update_selection(xiev);
}
else
refused = 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_COL_MOVE:
// Rifiuta di spostare una colonna nelle o dalle colonne fisse
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:
{
int num;
XI_OBJ** column = xi_get_member_list(xiev->v.column.list, &num);
const short cid = column[xiev->v.column.col_nbr]->cid - 1000;
refused = !_grid->on_resize_column(cid, xiev->v.column.new_col_width);
}
break;
case XIE_ROW_SIZE:
refused = xiev->v.row_size.new_row_height < XI_FU_MULTIPLE;
break;
case XIE_SELECT:
if (_read_only)
{
if (xiev->v.select.xi_obj->type == XIT_ROW && xiev->v.select.selected)
{
const long rec = row2rec(xiev->v.select.xi_obj->v.row_data.row);
if (rec >= 0 && _grid->on_rec(rec))
_cur_rec = rec;
else
refused = TRUE;
}
}
else
{
const long rec = row2rec(xiev->v.select.xi_obj->v.row_data.row);
if (rec >= 0 && rec < items())
_grid->on_cell_button(rec, FIRST_FIELD-1);
refused = TRUE;
}
break;
case XIE_CELL_REQUEST:
{
const long& rec = xiev->v.cell_request.rec;
if (rec < 0 || rec >= items())
{
refused = TRUE;
break;
}
int columns;
XI_OBJ** child = xi_get_member_list(xiev->v.cell_request.list, &columns);
XI_OBJ* column = child[xiev->v.cell_request.col_nbr];
const short cid = column->cid - 1000;
TGrid_cell cell(xiev);
if (cid >= FIRST_FIELD)
{
_grid->cell_request(rec, cid, cell);
}
else
{
if (xiev->v.cell_request.len > 2)
cell.set(rec);
}
}
break;
case XIE_ON_ROW:
{
const long rec = row2rec(xiev->v.xi_obj->v.row);
if (rec >= 0)
{
if (_grid->on_rec(rec))
_cur_rec = rec;
else
refused = TRUE;
}
else
{
NFCHECK("You are entering an invalid row: %d", xiev->v.xi_obj->v.row);
refused = TRUE;
}
}
break;
case XIE_OFF_ROW:
if (_cur_rec >= 0 && _cur_rec < items())
refused = !_grid->off_rec(_cur_rec);
break;
case XIE_ON_CELL:
break;
case XIE_DBL_CELL:
{
const long rec = row2rec(xiev->v.xi_obj->v.cell.row);
if (rec >= 0)
{
int num;
XI_OBJ** column = xi_get_member_list(_obj, &num);
const short cid = column[xiev->v.xi_obj->v.cell.column]->cid - 1000;
_grid->on_dbl_cell(rec, cid);
}
else
NFCHECK("You are clicking an invalid row: %d", xiev->v.xi_obj->v.cell.row);
}
break;
case XIE_BUTTON:
if (xiev->v.xi_obj->type == XIT_LIST)
{
_grid->on_button();
}
else
{
const XI_CELL_DATA& cell = xiev->v.xi_obj->v.cell;
const long rec = row2rec(cell.row);
if (rec >= 0)
{
int num;
XI_OBJ** column = xi_get_member_list(_obj, &num);
CHECKD(cell.column >= 0 && cell.column < num, "Invalid column:", cell.column);
const short cid = column[cell.column]->cid - FIRST_FIELD - 1000;
_grid->on_cell_button(rec, cid);
}
else
NFCHECK("You are clicking an invalid cell: %d", cell.row);
}
break;
default:
break;
}
return !refused;
}
///////////////////////////////////////////////////////////
// TGrid_cell
///////////////////////////////////////////////////////////
// Setta il testo di una cella (Mai piu' testo troppo lungo!)
// Se c'e' gia' un'icona la elimina
void TGrid_cell::set(const char* txt)
{
char* str = _xiev->v.cell_request.s;
if (txt)
{
const short& max = _xiev->v.cell_request.len;
strncpy(str, txt, max);
str[max-1] = '\0';
}
else
str[0] = '\0';
if (str[0])
{
int& icon = _xiev->v.cell_request.icon_rid;
if (icon)
icon = 0;
}
}
void TGrid_cell::set(long num)
{
char buff[16];
sprintf(buff, "%ld", num);
set(buff);
}
// Setta l'icona di una cella
// Se c'e' gia' un testo lo elimina
void TGrid_cell::set_icon(int id)
{
_xiev->v.cell_request.icon_rid = id;
if (id)
_xiev->v.cell_request.s[0] = '\0';
}
void TGrid_cell::show_button(bool on)
{
_xiev->v.cell_request.button = on;
_xiev->v.cell_request.button_on_focus = on;
}
void TGrid_cell::set_back_color(COLOR col)
{
if (col != NORMAL_BACK_COLOR)
_xiev->v.cell_request.back_color = col;
}
void TGrid_cell::set_fore_color(COLOR col)
{
if (col != NORMAL_COLOR)
_xiev->v.cell_request.color = col;
}
void TGrid_cell::set_colors(COLOR back, COLOR fore)
{
if (back != NORMAL_BACK_COLOR)
_xiev->v.cell_request.back_color = back;
if (fore != NORMAL_COLOR)
_xiev->v.cell_request.color = fore;
}
///////////////////////////////////////////////////////////
// TGrid_field
///////////////////////////////////////////////////////////
void TGrid_field::update(long n)
{ grid().update(n); }
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;
}
void TGrid_field::create(WINDOW parent)
{
_ctl = new TGrid_control(parent, dlg(),
_ctl_data._x, _ctl_data._y,
_ctl_data._width, _ctl_data._height,
_ctl_data._flags, _ctl_data._park,
this);
}
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)
{
return FALSE;
}
long TGrid_field::items() const
{
return 100000L;
}
int TGrid_field::visible_rows() const
{
return grid().visible_rows();
}
void TGrid_field::cell_request(long rec, short id, TGrid_cell& cell)
{
cell.set("Cell");
}
long TGrid_field::selected() const
{ return grid().selected(); }
bool TGrid_field::select(long rec)
{ return grid().select(rec); }
///////////////////////////////////////////////////////////
// Da qui in poi e' tutta roba specializzata del programma
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
// Maschere per colori
///////////////////////////////////////////////////////////
class TRow_mask : public TMask
{
public:
virtual void update();
TRow_mask();
virtual ~TRow_mask() { }
};
class TColor_mask : public TVariable_mask
{
static TRow_mask* _sheet_mask;
static TMask* get_mask(int, TMask&) { return _sheet_mask; }
COLOR _mas_back, _mas_fore;
COLOR _con_back, _con_fore;
protected:
static bool color_handler(TMask_field& f, KEY k);
void type2colors(char tipo, COLOR& back, COLOR& fore) const;
public:
void get_cur_colors(COLOR& back, COLOR& fore) const;
void set_cur_colors(COLOR back, COLOR fore);
void get_colors(COLOR& mb, COLOR& mf, COLOR& cb, COLOR& cf) const;
TColor_mask(COLOR mb, COLOR mf, COLOR cb, COLOR cf);
virtual ~TColor_mask();
};
///////////////////////////////////////////////////////////
// TRow_mask
///////////////////////////////////////////////////////////
TRow_mask* TColor_mask::_sheet_mask = NULL;
TRow_mask::TRow_mask()
: TMask("cg2100k", 1)
{
}
void TRow_mask::update()
{
TSheet_field* s = get_sheet();
TColor_mask& m = (TColor_mask&)s->mask();
COLOR back, fore;
m.get_cur_colors(back, fore);
set_pen(COLOR_BLACK);
set_brush(back);
frame(2, 4, 16, 6, 0);
set_brush(fore);
frame(20, 4, 34, 6, 0);
}
///////////////////////////////////////////////////////////
// TColor_mask
///////////////////////////////////////////////////////////
void TColor_mask::type2colors(char tipo, COLOR& back, COLOR& fore) const
{
if (toupper(tipo) == 'M')
{
back = _mas_back;
fore = _mas_fore;
}
else
{
back = _con_back;
fore = _con_fore;
}
}
void TColor_mask::get_cur_colors(COLOR& back, COLOR& fore) const
{
TSheet_field& s = (TSheet_field&)fld(0);
TToken_string& row = s.row(s.selected());
const char tipo = row[5];
type2colors(tipo, back, fore);
}
void TColor_mask::set_cur_colors(COLOR back, COLOR fore)
{
TSheet_field& s = (TSheet_field&)fld(0);
const int cur = s.selected();
TToken_string& row = s.row(cur);
const char tipo = toupper(row[5]);
if (tipo == 'M')
{
_mas_back = back;
_mas_fore = fore;
}
else
{
_con_back = back;
_con_fore = fore;
}
s.set_back_and_fore_color(back, fore, cur);
s.force_update(cur);
}
bool TColor_mask::color_handler(TMask_field& f, KEY k)
{
if (k == K_SPACE)
{
TMask& m = f.mask();
TColor_mask& cm = (TColor_mask&)m.get_sheet()->mask();
COLOR back, fore;
cm.get_cur_colors(back, fore);
const bool use_back = f.dlg() == 100;
const COLOR col = choose_color(use_back ? back : fore, m.win());
if (col != COLOR_INVALID)
{
if (use_back)
back = col;
else
fore = col;
cm.set_cur_colors(back, fore);
cm._sheet_mask->update();
}
}
return TRUE;
}
void TColor_mask::get_colors(COLOR& mb, COLOR& mf, COLOR& cb, COLOR& cf) const
{
mb = _mas_back;
mf = _mas_fore;
cb = _con_back;
cf = _con_fore;
}
TColor_mask::TColor_mask(COLOR mb, COLOR mf, COLOR cb, COLOR cf)
: TVariable_mask("cg2100k"),
_mas_back(mb), _mas_fore(mf), _con_back(cb), _con_fore(cf)
{
CHECK(_sheet_mask == NULL, "One color at time, please");
_sheet_mask = new TRow_mask;
_sheet_mask->set_handler(99, color_handler);
_sheet_mask->set_handler(100, color_handler);
TVariable_sheet_field& s = (TVariable_sheet_field&)fld(0);
s.set_getmask(get_mask);
const char* const tipi = "MC";
int row = 0;
for (const char* c = tipi; *c; c++)
{
COLOR back, fore;
type2colors(*c, back, fore);
TToken_string& riga = s.row(-1);
riga << "Riga " << (*c == 'M' ? "mastrino" : "contropartita");
s.set_back_and_fore_color(back, fore, row++);
}
}
TColor_mask::~TColor_mask()
{
delete _sheet_mask;
_sheet_mask = NULL;
}
///////////////////////////////////////////////////////////
// TMastrini_grid
///////////////////////////////////////////////////////////
class TMastrini_grid : public TGrid_field
{
TMastrino _mastrino;
TDecoder _causali;
TEsercizi_contabili _esercizi;
COLOR _mas_back, _mas_fore;
COLOR _con_back, _con_fore;
protected: // TGrid_field
virtual bool on_rec(long rec);
virtual void cell_request(long rec, short id, TGrid_cell& cell);
virtual void on_button();
virtual bool on_resize_column(short cid, int new_size);
void update_mask() const;
public:
virtual long items() const { return _mastrino.items(); }
void destroy();
void read(const TBill& conto,
int annoes, const TDate& dd, const TDate& ad,
const TString& dc, const TString& ac);
void reread();
TMastrino& mastrino() { return _mastrino; }
void save_colors();
void load_colors();
void set_colors();
TMastrini_grid(TMask* m);
virtual ~TMastrini_grid() { }
};
TMastrini_grid::TMastrini_grid(TMask* m)
: TGrid_field(m), _causali(LF_CAUSALI, CAU_CODCAUS, CAU_DESCR)
{
load_colors();
}
void TMastrini_grid::destroy()
{
_mastrino.destroy();
grid().select(-1);
}
HIDDEN void set_imp(TMask_field& f, const TImporto& imp)
{
if (!imp.is_zero())
{
TString80 str;
str = imp.valore().string(".");
str << ' ' << imp.sezione();
f.set(str);
}
}
void TMastrini_grid::cell_request(long rec, short id, TGrid_cell& cell)
{
const TRiga_mastrino& riga = _mastrino[rec];
switch (id)
{
case 101:
if (riga.tipo() == riga_mastrino)
{
const TRectype& mov = _mastrino.testata(rec);
TString80 text;
text = mov.get(MOV_DATAREG);
text << ' ' << mov.get(MOV_DATADOC);
cell.set(text);
}
break;
case 102:
if (riga.tipo() == riga_mastrino)
{
const TRectype& mov = _mastrino.testata(rec);
const int anno = _esercizi.date2esc(mov.get_date(MOV_DATAREG));
const int eser = mov.get_int(MOV_ANNOES);
const comp = anno == eser;
cell.set_icon(comp ? ICO_CHECK_ON : ICO_CHECK_OFF);
}
break;
case 103:
if (riga.tipo() == riga_mastrino)
{
const TRectype& mov = _mastrino.testata(rec);
cell.set(mov.get(MOV_DESCR));
}
else
{
const TRectype& rmov = _mastrino.riga(rec);
const char* text = rmov.get(RMV_DESCR);
if (*text == '\0')
{
const TBill conto(rmov);
text = conto.descrizione();
}
cell.set(text);
}
break;
case 104:
if (riga.tipo() == riga_mastrino)
{
const TRectype& mov = _mastrino.testata(rec);
cell.set(_causali.decode(mov.get(MOV_CODCAUS)));
}
else
{
const TRectype& rmov = _mastrino.riga(rec);
TString16 text;
text.format("%03d.%03d.%06ld",
rmov.get_int(RMV_GRUPPO),
rmov.get_int(RMV_CONTO),
rmov.get_long(RMV_SOTTOCONTO));
cell.set(text);
}
break;
case 105:
{
const TRectype& rmov = _mastrino.riga(rec);
if (rmov.get_char(RMV_SEZIONE) == 'D')
cell.set(rmov.get_real(RMV_IMPORTO).string("."));
}
break;
case 106:
{
const TRectype& rmov = _mastrino.riga(rec);
if (rmov.get_char(RMV_SEZIONE) == 'A')
cell.set(rmov.get_real(RMV_IMPORTO).string("."));
}
break;
case 107:
if (riga.tipo() == riga_mastrino)
{
const TRectype& mov = _mastrino.testata(rec);
TString80 text;
text = mov.get(MOV_NUMDOC); text.left_just(7);
text << ' ' << mov.get(MOV_PROTIVA);
cell.set(text);
}
break;
case 108:
{
const TRectype& rmov = _mastrino.riga(rec);
TString80 text;
text = rmov.get_real(RMV_IMPORTO).string(".");
text << ' ' << rmov.get(RMV_SEZIONE);
cell.set(text);
}
break;
case 109:
if (riga.tipo() == riga_mastrino)
{
const long next_row = _mastrino.succ(rec, riga_mastrino);
bool stampa = next_row >= _mastrino.items();
if (!stampa)
{
const TDate& data = _mastrino[next_row].data();
stampa = riga.data() < data;
}
if (stampa)
{
TImporto imp = riga.saldo();
imp += _mastrino.saldo_iniziale();
imp.normalize();
TString80 text;
text = imp.valore().string(".");
text << ' ' << imp.sezione();
cell.set(text);
}
}
break;
default:
break;
}
if (riga.tipo() == riga_mastrino)
cell.set_colors(_mas_back, _mas_fore);
else
cell.set_colors(_con_back, _con_fore);
}
bool TMastrini_grid::on_rec(long rec)
{
if (rec == selected())
{
if (_mastrino.expandable(rec))
_mastrino.expand(rec);
else
_mastrino.collapse(rec);
update();
}
else
{
if (_mastrino[rec].tipo() != riga_mastrino)
rec = _mastrino.pred(rec, riga_mastrino);
TRiga_mastrino& riga = _mastrino[rec];
TMask& gm = mask();
set_imp(gm.field(F_TOTRIG_SAL), riga.saldo());
gm.set(F_TOTRIG_DAR, riga.dare());
gm.set(F_TOTRIG_AVE, riga.avere());
}
return TRUE;
}
void TMastrini_grid::on_button()
{
begin_wait();
if (items() > 0)
{
long sample_rec = selected();
if (sample_rec < 0 || sample_rec >= items())
sample_rec = 0;
if (_mastrino.expandable(sample_rec))
{
for (long n = items()-1; n >= 0; n--)
if (_mastrino.expandable(n))
_mastrino.expand(n);
}
else
{
for (long n = 0; n < _mastrino.items(); n++)
if (_mastrino[n].tipo() != riga_mastrino)
_mastrino.collapse(--n);
}
update();
}
end_wait();
}
bool TMastrini_grid::on_resize_column(short cid, int new_size)
{
return cid == 103 || cid == 104;
}
void TMastrini_grid::read(const TBill& conto,
int annoes, const TDate& dd, const TDate& ad,
const TString& dc, const TString& ac)
{
destroy();
_mastrino.read(conto, annoes, dd, ad, dc, ac);
update();
update_mask();
}
void TMastrini_grid::reread()
{
destroy();
_mastrino.reread();
update();
update_mask();
}
void TMastrini_grid::update_mask() const
{
TMask& gm = mask();
set_imp(gm.field(F_TOTPRO_SAL), _mastrino.saldo_iniziale());
gm.set(F_TOTPRO_DAR, _mastrino.progressivo_dare_iniziale());
gm.set(F_TOTPRO_AVE, _mastrino.progressivo_avere_iniziale());
gm.reset(F_TOTRIG_SAL);
gm.reset(F_TOTRIG_DAR);
gm.reset(F_TOTRIG_AVE);
set_imp(gm.field(F_TOTPER_SAL), _mastrino.saldo_periodo());
gm.set(F_TOTPER_DAR, _mastrino.progressivo_dare_periodo());
gm.set(F_TOTPER_AVE, _mastrino.progressivo_avere_periodo());
set_imp(gm.field(F_TOTATT_SAL), _mastrino.saldo_finale());
gm.set(F_TOTATT_DAR, _mastrino.progressivo_dare_finale());
gm.set(F_TOTATT_AVE, _mastrino.progressivo_avere_finale());
gm.enable(DLG_LINK, _mastrino.items() > 0);
}
void TMastrini_grid::load_colors()
{
TConfig conf(CONFIG_USER, "cg3600b");
_mas_back = conf.get_color("ColorMB", NULL, -1, FOCUS_BACK_COLOR);
_mas_fore = conf.get_color("ColorMF", NULL, -1, FOCUS_COLOR);
_con_back = conf.get_color("ColorCB", NULL, -1, NORMAL_BACK_COLOR);
_con_fore = conf.get_color("ColorCF", NULL, -1, NORMAL_COLOR);
}
void TMastrini_grid::save_colors()
{
TConfig conf(CONFIG_USER, "cg3600b");
conf.set_color("ColorMB", _mas_back);
conf.set_color("ColorMF", _mas_fore);
conf.set_color("ColorCB", _con_back);
conf.set_color("ColorCF", _con_fore);
}
void TMastrini_grid::set_colors()
{
TColor_mask m(_mas_back, _mas_fore, _con_back, _con_fore);
if (m.run() == K_ENTER)
{
m.get_colors(_mas_back, _mas_fore, _con_back, _con_fore);
save_colors();
}
}
///////////////////////////////////////////////////////////
// TGrid_mask
///////////////////////////////////////////////////////////
class TGrid_mask : public TMask
{
TMastrini_grid* _grid;
protected: // TMask
virtual TMask_field* parse_field(TScanner& sc);
virtual bool on_key(KEY k);
static bool link_handler(TMask_field& f, KEY k);
public:
TMastrini_grid& grid() { CHECK(_grid, "What's grid?"); return *_grid; }
TGrid_mask();
virtual ~TGrid_mask() { }
};
TGrid_mask::TGrid_mask()
: _grid(NULL)
{
read_mask("cg3600b", 0, 0);
set_handler(DLG_LINK, link_handler);
}
TMask_field* TGrid_mask::parse_field(TScanner& sc)
{
TMask_field* f;
if (sc.key() == "SP")
f = _grid = new TMastrini_grid(this);
else
f = TMask::parse_field(sc);
return f;
}
bool TGrid_mask::link_handler(TMask_field& f, KEY k)
{
if (k == K_SPACE)
{
TGrid_mask& gm = (TGrid_mask&)f.mask();
TMastrini_grid& grid = gm.grid();
const long rec = grid.selected();
if (rec >= 0 && rec < grid.items())
{
begin_wait();
const TRectype& testata = grid.mastrino().testata(rec);
TString text;
text << "1|" << testata.get(MOV_NUMREG);
const char* const appname = "cg2 -0";
TMessage pn(appname, MSG_LN, text);
pn.send();
TExternal_app a(appname);
a.run();
TMailbox mail;
if (mail.next_s(MSG_LN) != NULL)
{
if (yesno_box("Si desidera aggiornare il mastrino?"))
gm.grid().reread();
}
end_wait();
}
}
return TRUE;
}
bool TGrid_mask::on_key(KEY k)
{
long rec = grid().selected();
switch (k)
{
case K_LHOME:
rec = 0;
break;
case K_PREV:
rec -= _grid->visible_rows();
if (rec < 0) rec = 0;
break;
case K_UP:
if (rec > 0)
rec--;
break;
case K_DOWN:
if (rec < _grid->items()-1)
rec++;
break;
case K_NEXT:
rec += _grid->visible_rows();
if (rec >= _grid->items())
rec = _grid->items()-1;
break;
case K_LEND:
rec = _grid->items()-1;
break;
default:
break;
}
if (rec != grid().selected())
{
grid().select(rec);
return TRUE;
}
return TMask::on_key(k);
}
///////////////////////////////////////////////////////////
// TQuery_mask
///////////////////////////////////////////////////////////
class TQuery_mask : public TMask
{
protected:
static bool data_handler(TMask_field& f, KEY k);
static bool find_handler(TMask_field& f, KEY k);
public:
void do_query(TGrid_mask& gm);
TQuery_mask();
virtual ~TQuery_mask() { }
};
TQuery_mask::TQuery_mask()
: TMask("cg3600a")
{
set_handler(F_DADATA, data_handler);
set_handler(F_ADATA, data_handler);
set_handler(DLG_FINDREC, find_handler);
}
bool TQuery_mask::data_handler(TMask_field& f, KEY k)
{
bool ok = TRUE;
if (f.to_check(k))
{
const TQuery_mask& qm = (const TQuery_mask&)f.mask();
const TEsercizi_contabili esercizi;
int codice_esercizio = qm.get_int(F_ESERCIZIO);
if (codice_esercizio == 0)
{
const short id_altra_data = f.dlg() == F_DADATA ? F_ADATA : F_DADATA;
const TDate d = qm.get(id_altra_data);
if (d.ok())
codice_esercizio = esercizi.date2esc(d);
}
if (f.empty())
{
if (codice_esercizio == 0)
return error_box("E' necessario specificare almeno una data.");
return TRUE;
}
const TDate d = f.get();
const int esercizio = 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;
}
bool TQuery_mask::find_handler(TMask_field& f, KEY k)
{
if (k == K_SPACE)
{
const TQuery_mask& qm = (const TQuery_mask&)f.mask();
short id;
switch (qm.get(F_TIPO)[0])
{
case 'C': id = F_CLIENTE; break;
case 'F': id = F_FORNITORE; break;
default : id = F_SOTTOCONTO; break;
}
qm.field(id).on_key(K_F9);
}
return TRUE;
}
void TQuery_mask::do_query(TGrid_mask& gm)
{
const char t = get(F_TIPO)[0];
const int g = get_int(F_GRUPPO);
const int c = get_int(F_CONTO);
const long s = get_long((t <= ' ') ? F_SOTTOCONTO : ((t == 'C') ? F_CLIENTE : F_FORNITORE));
const TBill conto(g, c, s, t);
const int annoes = get_int(F_ESERCIZIO);
TDate da_data(get(F_DADATA));
TDate a_data(get(F_ADATA));
TString da_caus(get(F_DACAUSALE));
TString a_caus(get(F_ACAUSALE));
conto.set(gm, F_GRUPPO, F_CONTO, F_SOTTOCONTO, 0, F_DESSOTTOC);
gm.set(F_ESERCIZIO, annoes);
gm.set(F_DADATA, da_data);
gm.set(F_ADATA, a_data);
gm.grid().read(conto, annoes, da_data, a_data, da_caus, a_caus);
gm.run();
}
///////////////////////////////////////////////////////////
// TMastrini_video
///////////////////////////////////////////////////////////
class TMastrini_video : public TApplication
{
TQuery_mask* _qm;
TGrid_mask* _gm;
TArray _file;
protected:
virtual bool create();
virtual bool destroy();
virtual bool menu(MENU_TAG);
virtual void on_firm_change();
public:
void open_files(int logicnum, ...);
};
void TMastrini_video::open_files(int logicnum, ...)
{
va_list marker;
va_start(marker, logicnum);
while (logicnum > 0)
{
if (_file.objptr(logicnum))
NFCHECK("File gia' aperto: %d", logicnum);
else
_file.add(new TLocalisamfile(logicnum), logicnum);
logicnum = va_arg(marker, int);
}
}
bool TMastrini_video::create()
{
open_files(LF_RMOV, LF_MOV);
open_files(LF_SALDI, LF_PCON);
_qm = new TQuery_mask;
_gm = new TGrid_mask;
dispatch_e_menu(BAR_ITEM(1));
return TRUE;
}
bool TMastrini_video::destroy()
{
delete _gm;
delete _qm;
_file.destroy();
return TRUE;
}
void TMastrini_video::on_firm_change()
{
TEsercizi_contabili::update();
}
bool TMastrini_video::menu(MENU_TAG mt)
{
if (mt == BAR_ITEM(1))
{
TQuery_mask& qm = *_qm;
const TEsercizi_contabili esercizi;
const int codice_ultimo_esercizio = esercizi.last();
if (codice_ultimo_esercizio > 0)
{
const TEsercizio& esercizio = esercizi.esercizio(codice_ultimo_esercizio);
qm.set(F_ESERCIZIO, codice_ultimo_esercizio);
qm.set(F_DADATA, esercizio.inizio());
qm.set(F_ADATA, esercizio.fine());
}
KEY key = 0;
while (key != K_QUIT)
{
qm.reset(F_SOTTOCONTO); // Azzera sottoconto
qm.reset(F_CLIENTE); // Azzera cliente
qm.reset(F_FORNITORE); // Azzera fornitore
qm.reset(F_DACAUSALE); // Azzera causali
qm.reset(F_ACAUSALE);
key = qm.run();
switch (key)
{
case K_ENTER:
disable_menu_item(M_FONT);
qm.do_query(*_gm);
enable_menu_item(M_FONT);
break;
default:
break;
}
}
return FALSE;
}
else
{
_gm->grid().set_colors();
}
return TRUE;
}
///////////////////////////////////////////////////////////
// Main
///////////////////////////////////////////////////////////
int cg3600(int argc, char* argv[])
{
TMastrini_video mv;
mv.run(argc, argv, "Mastrini");
return 0;
}