campo-sirio/cg/cg3600.cpp
guy b8028b2bf2 Patch level : 2.0 470
Files correlati     : cg1.exe cg2.exe cg3.exe cg3100a.msk cg3600a.msk cg3600b.msk cg4700a.msk
Ricompilazione Demo : [ ]
Commento            :

EP20036
Richiamo registrazione fatt. vendita già inserita, vado alla pagina IVA
col mouse mi posiziono sul campo "CR"cerco di entrare nella list box
associata al campo. Errore dell'applicazione cg2.exe* (l'errore può non
comparire subito ma dopo essere usciti dalla registrazione contabile avendo
eseguito quando descritto sopra e poi rientrati ripetendo il tutto.)Win 2000

EP20039
Compilo la maschera fino al group box "Intesta deleghe a", col mouse mi
posiziono sul campo Tipo e cerco di entrare nella list box associata al
campo: Errore CG1.exe

EP20040
Col mouse: mi posiziono  sul campo "Stampa dal registro IVA" entro nella
tabella registri associata al campo mi posiziono sulla riga del registro
iva vendite e clicco sul bottone collega: la procedura ritorna nella
maschera Lista movimenti anziché entrare nella tabella registri

EP20042
Lavoro col mouse: richiamo un movimento inserito con causale V01 abilitata
al saldaconto, vado alla pagina Scadenze e mi posiziono sul campo Ns. Banca
ABI.Entro nella tabella banche associata al campo, seleziono una banca
inserita e clicco sul bottone collega.Ritorno alla pagina scadenze del
movimento contabile.

EP20044
Se in file impostazione stampante è indicato stampa su... Visualizzazione,
la stampa viene visualizzata correttamente ma non esce stampa su carta.

EP20045
Correzione righe di prima nota, digito la password e clicco su conferma,
mi propone la ditta 1 e clicco su selezione, compare maschera righe di
prima nota errata vuota clicco sul bottone tutti errore dell'applicazione
cg1.exe n.b. anche nella versione1.7(E' corretto che il bottone Tutti sia attivo?)

EP20051
Col mouse: clicco sul bottone di ricerca richiamo conto 1 1 1 mi posiziono
sul campo "codice tabella analisi" ed entro nella tabella associata al
campo clicco sul bottone nuovo errore: impossibile trovare CB5.DLL

EP20053
Se in file impostazione stampante è indicato stampa su... Visualizzazione
la stampa viene visualizzata correttamente ma non esce stampa su carta.

EP20059
Ho inserito n clienti. Clicco sul bottone di ricerca e richiamo un cliente
già registrato. Clicco sulla freccina singola a sx del botone ricerca
(e anche sulle altre freccie): messaggo "vuoi registrare dati inseriti?"

EP20060
Il bottone ricerca non ha "freccie avanti-dietro"
NON DEVE AVERLO!  NON E' UN PROGRAMMA DI IMMISSIONE DATI

EP20061
Il bottone ricerca non ha "freccie avanti-dietro"
NON DEVE AVERLO!  NON E' UN PROGRAMMA DI IMMISSIONE DATI

EP20063
entrando nella voce tabella piano dei conti errore impossibile trovare CB5.DLL

EP20073
all'interno dei campi (es.numero protocollo) il comando di tastiera "canc" non funziona

EP20076
Richiamo un'anagrafica già inserita clicco su nuovo messaggio :"registrare le modifiche?"


git-svn-id: svn://10.65.10.50/trunk@11127 c028cbd2-c16b-5b4b-a496-9718f37d4682
2003-05-14 13:12:14 +00:00

3010 lines
77 KiB
C++
Executable File

#include <xinclude.h>
#include <applicat.h>
#include <colors.h>
#include <controls.h>
#include <currency.h>
#include <execp.h>
#include <mailbox.h>
#include <progind.h>
#include <recarray.h>
#include <relation.h>
#include <urldefid.h>
#include <utility.h>
#include <varmask.h>
#include "cg3.h"
#include "cglib01.h"
#include "cg3600.h"
#include <causali.h>
#include <mov.h>
#include <pconti.h>
#include <rmov.h>
#include <saldi.h>
///////////////////////////////////////////////////////////
// TList
///////////////////////////////////////////////////////////
#ifdef USE_OBSOLETE_LIST
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;
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 change_step(long step); // Forza il passo per gli elementi
long 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;
}
}
}
long TList::choose_step(long expected_size)
{
long step = expected_size / MAX_SKIP + 1;
if (step < 8)
step = 8;
change_step(step);
return 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;
}
#else
// Simpler and faster 32 bit implemetation
class TList : public TContainer
{
TArray _data;
protected:
// @cmember Ritorna un puntatore al primo oggetto del contenitore
virtual TObject* first_item( ) { return _data.first_item(); }
// @cmember Ritorna un puntatore all'ultimo oggetto del contenitore
virtual TObject* last_item( ) { return _data.last_item(); }
// @cmember Ritorna un puntatore all'oggetto successivo all'oggetto corrente
virtual TObject* succ_item( ) { return _data.succ_item(); }
// @cmember Ritorna un puntatore all'oggetto che precede l'oggetto corrente
virtual TObject* pred_item( ) { return _data.pred_item(); }
// @cmember Ritorna il numero di oggetti nel contenitore
virtual long objects( ) { return _data.objects(); }
public:
long items() const { return _data.items(); }
void destroy() { _data.destroy(); }
long insert(TObject* obj, long pos) { return _data.insert(obj, pos); }
long append(TObject* obj, long pos = -1);
bool remove(long pos) { _data.remove(pos, TRUE); return TRUE; }
const TObject& obj(long index) const
{ const TObject* o = _data.objptr(index); CHECK(o, "Null list item"); return *o; }
};
long TList::append(TObject* obj, long index)
{
if (index < 0 || index >= items())
index = items();
else
index++;
return insert(obj, index);
}
#endif
///////////////////////////////////////////////////////////
// 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,
TImporto& pd, TImporto& pa) const;
int indicatore_bilancio(const TBill& b) const;
public:
void read(int g, int c, long s, int esercizio, bool ignora_movap, bool provvis);
void read(const TBill& b, int esercizio, bool ignora_movap, bool provvis);
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, bool ignora_movap, bool provvis);
TBalance(const TBill& b, int esercizio, bool ignora_movap, bool provvis);
virtual ~TBalance() { }
};
TBalance::TBalance()
{
}
TBalance::TBalance(int g, int c, long s, int esercizio, bool ignora_movap, bool provvis)
{
read(g, c, s, esercizio, ignora_movap, provvis);
}
TBalance::TBalance(const TBill& b, int esercizio, bool ignora_movap, bool provvis)
{
read(b, esercizio, ignora_movap, provvis);
}
bool TBalance::find(const TBill& b, int esercizio,
TImporto& si, TImporto& da, TImporto& av, TImporto& sf,
TImporto& pd, TImporto& pa) const
{
CHECK(b.sottoconto() > 0L, "Sottoconto mancante");
TString key(30);
key.format("%d||%d|%d|%ld", esercizio, b.gruppo(), b.conto(), b.sottoconto());
const TRectype & saldi = cache().get(LF_SALDI, key);
if (!saldi.empty())
{
si.set(saldi.get_char(SLD_FLAGSALINI), saldi.get_real(SLD_SALDO));
da.set('D', saldi.get_real(SLD_PDARE));
av.set('A', saldi.get_real(SLD_PAVERE));
sf.set(saldi.get_char(SLD_FLAGSALFIN), saldi.get_real(SLD_SALDOFIN));
pd.set('D', saldi.get_real(SLD_PDAREPRO));
pa.set('A', saldi.get_real(SLD_PAVEREPRO));
}
else
{
si.set('D', ZERO);
da = av = sf = pd = pa = si;
}
return ok;
}
void TBalance::read(int gruppo, int conto, long sottoconto, int esercizio, bool ignora_movap, bool provvis)
{
const TBill zio(gruppo, conto, sottoconto);
read(zio, esercizio, ignora_movap, provvis);
}
int TBalance::indicatore_bilancio(const TBill& b) const
{
TString16 str;
str.format("%d|%d", b.gruppo(), b.conto());
const int ib = atoi(cache().get(LF_PCON, str, PCN_INDBIL));
if (ib == 0)
NFCHECK("Impossibile stabilire l'indicatore di bilancio");
return ib;
}
void TBalance::read(const TBill& b, int esercizio, bool ignora_movap, bool provvis)
{
TImporto si, sf, pd, pa, prd, pra;
find(b, esercizio, si, pd, pa, sf, prd, pra);
if (provvis)
{
pd += prd;
pa += pra;
}
_saldo_ini = si;
_progr_dare = pd;
_progr_avere = pa;
_saldo_fin = sf;
if (_saldo_ini.is_zero())
{
const int indbil = indicatore_bilancio(b);
if (indbil == 1 || indbil == 2 || indbil == 5)
{
TEsercizi_contabili esercizi;
const int precedente = esercizi.pred(esercizio);
if (precedente > 0 && find(b, precedente, si, pd, pa, sf, prd, pra))
{
if (provvis)
{
pd += prd;
pa += pra;
}
_saldo_ini = si;
_saldo_ini += pd;
_saldo_ini += pa;
_saldo_ini += sf;
}
}
}
else
{
if (ignora_movap)
_saldo_ini.set('D', ZERO);
}
}
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; // Tipo della riga
TRecnotype _mov, _rmov; // Numero fisico di record movivento e riga movimento
real _dare, _avere; // Progressivi dare ed avere
TDate _data; // Data di registrazione (Ottimizzazione)
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; // Dare-Avere normalizzato
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 TCursor* _cur;
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; // Date limite
TString _da_caus, _a_caus; // Causali limite
bool _provvis; // Includi provvisori
real _pdare_ini, _pavere_ini;
real _pdare_per, _pavere_per;
real _pdare_fin, _pavere_fin;
TList _riga; // Righe del mastrino
protected:
TCursor& cur() { return *_cur; }
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, bool provvis);
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(); }
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;
int esercizio() const { return _esercizio; }
const TDate& inizio_periodo() const { return _da_data; }
const TDate& fine_periodo() const { return _a_data; }
void periodo(TDate& dd, TDate& ad) const { dd = _da_data; ad = _a_data; }
bool expandable(long rec) const;
bool expand(long rec);
bool collapse(long rec);
TMastrino();
virtual ~TMastrino();
};
long TMastrino::_instances = 0L;
TCursor* TMastrino::_cur = NULL;
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 _cur; _cur = NULL;
delete _rel; _rel = NULL;
_rmov = _mov = NULL;
}
}
long TMastrino::succ(long rec, tipo_riga_mastrino tipo) const
{
if (rec < 0) rec = -1;
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
{
if (rec > items()) rec = items();
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,
bool provvis)
{
TEsercizi_contabili esercizi;
_conto = conto;
_esercizio = ae;
_riga.destroy();
rmov().setkey(2);
TRectype& rmov_rec = rmov().curr();
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();
const bool test_caus = !(dc.blank() && ac.blank());
_da_caus = dc;
_a_caus = ac.blank() ? "zzz" : ac; // Se vuota sceglie la massima causale
_provvis = provvis;
TDate max_data_reg = _a_data;
long num_giorni = _a_data - inizio_esercizio + 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();
}
#ifdef USE_OBSOLETE_LIST
// Stima dimensione mastrino
_riga.choose_step(num_giorni);
#endif
// 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
TBalance saldo(_conto, ae, TRUE, provvis);
_pdare_ini = saldo.progressivo_dare_iniziale();
_pavere_ini = saldo.progressivo_avere_iniziale();
// Valori dei saldi finali:
// Comprendono i movimenti di apertura, chiusura ed i progressivi attuali
saldo.read(_conto, ae, FALSE, provvis);
_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;
const TRecfield rmov_datareg (rmov_rec, RMV_DATAREG);
const TRecfield rmov_numreg (rmov_rec, RMV_NUMREG);
const TRecfield rmov_gruppo (rmov_rec, RMV_GRUPPO);
const TRecfield rmov_conto (rmov_rec, RMV_CONTO);
const TRecfield rmov_sottoconto(rmov_rec, RMV_SOTTOCONTO);
const TRecfield rmov_sezione (rmov_rec, RMV_SEZIONE);
const TRecfield rmov_importo (rmov_rec, RMV_IMPORTO);
const TRecfield mov_datacomp (mov_rec, MOV_DATACOMP);
const TRecfield mov_provvis (mov_rec, MOV_PROVVIS);
const TRecfield mov_codcaus (mov_rec, MOV_CODCAUS);
#ifdef DBG
long num_rec = 0;
const clock_t clock_start = clock();
#endif
rmov_rec.zero();
conto.put(rmov_rec);
TRectype darow(rmov_rec), arow(rmov_rec);
darow.put(RMV_DATAREG, inizio_esercizio);
arow.put(RMV_DATAREG, max_data_reg);
TCursor cur(&rel(), "", 2, &darow, &arow);
const TRecnotype totrows = cur.items();
cur.freeze();
TString caption(80);
caption.format(FR("Caricamento mastrino %03d.%03d.%06ld"),
_conto.gruppo(), _conto.conto(), _conto.sottoconto());
TProgind pi(totrows, caption, FALSE, TRUE);
for (cur = 0L; cur.pos() < totrows; ++cur)
{
pi.addstatus(1);
#ifdef DBG
num_rec++;
if ((num_rec & 0x7F) == 0)
{
const double sec = (clock() - clock_start) / CLOCKS_PER_SEC;
if (sec > 0.0)
{
TString80 msg;
msg.format(FR("%ld records at %ld rec/sec"), num_rec, long(num_rec/sec));
pi.set_text(msg);
}
}
#endif
// Ignora eventualmente i movimenti provvisori
if (!_provvis)
{
const char is_provvis = *(const char*)mov_provvis;
if (is_provvis > ' ')
continue;
}
const TDate data_corrente = _esercizio <= 0 ? rmov_datareg : TDate((const char*)mov_datacomp);
if (data_corrente > _a_data)
continue;
const char sezione = *((const char*)rmov_sezione);
const real importo((const char*)rmov_importo);
if (data_corrente < _da_data)
{
if (data_corrente >= inizio_esercizio)
{
if (sezione == 'D')
_pdare_ini += importo;
else
_pavere_ini += importo;
}
}
else
{
if (sezione == 'D')
_pdare_per += importo;
else
_pavere_per += importo;
// Controlla che la causale sia nei limiti
if (test_caus)
{
const bool ok = _da_caus <= mov_codcaus && _a_caus >= mov_codcaus;
if (!ok)
continue;
}
TRiga_mastrino* r = new TRiga_mastrino(riga_mastrino,
rmov().recno(), mov().recno(),
_pdare_per, _pavere_per, rmov_datareg);
_riga.append(r);
}
}
// Mi sposto all'inizio per far funzionare bene da subito il metodo riga(0)
mov().first();
rmov().first();
}
void TMastrino::reread()
{
read(_conto, _esercizio, _da_data, _a_data, _da_caus, _a_caus, _provvis);
}
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 (rec >= 0 && rec < items())
{
if (row(rec).tipo() == riga_mastrino)
{
if (rec < items()-1)
e = row(rec+1).tipo() != riga_contropartita;
else
e = TRUE;
}
}
return e;
}
// Genera le righe di contropartita di una riga del mastrino
bool TMastrino::expand(long rec)
{
bool ok = expandable(rec);
if (ok)
{
const TRectype& head = testata(rec); // Testata movimento
const long numreg = head.get_long(RMV_NUMREG); // Numero di registrazione
const int numrig = riga(rec).get_int(RMV_NUMRIG); // Numero riga contabile
const TDate datareg = head.get(MOV_DATAREG); // Data di registrazione
rmov().setkey(1); // Usa chiave NUMREG+NUMRIG
TRectype& curr = rmov().curr(); // Record corrente
const TRecfield rnumreg (curr, RMV_NUMREG); // Numero di registrazione corrente
const TRecfield rnumrig (curr, RMV_NUMRIG); // Numero di riga corrente
const TRecfield rsezione(curr, RMV_SEZIONE); // Sezione Dare/Avere
const TRecfield rimporto(curr, RMV_IMPORTO); // Importo della riga
int err = NOERR;
if (numrig != 1) // Se non e' gia' posizionato grazie a riga(rec)
{
curr.zero(); // Azzera record corrente
curr.put(RMV_NUMREG, numreg); // Inizializza la chiave parziale
err = rmov().read(_isgteq); // Cerca la prima riga del movimento
}
for (; err == NOERR; err = rmov().next()) // Scandisce righe movimento
{
if (numreg != (long)rnumreg) // Controlla validita' numero
break;
if (numrig != (int)rnumrig) // Ignora la riga gia' presente
{
real dare, avere; // Costruisce importo della riga
if (*(const char*)rsezione == 'D')
dare = rimporto;
else
avere = rimporto;
// Aggiunge una riga di contropartita al mastrino
TRiga_mastrino* r = new TRiga_mastrino(riga_contropartita,
rmov().recno(), mov().recno(),
dare, avere, datareg);
_riga.append(r, rec++);
}
}
}
return ok;
}
// Elimina le righe di contropartita di una riga del mastrino
bool TMastrino::collapse(long rec)
{
bool ok = TRUE; // Posso eliminare?
if (row(rec).tipo() != riga_mastrino) // Se non sono su una riga mastrino ...
rec = pred(rec, riga_mastrino); // ... mi sposto sulla precedente riga mastrino
else
ok = !expandable(rec); // Controlla che sia possibile
if (ok) // Posso effetivamente procedere
{
rec++; // Elimino ogni riga contropartita successiva
while (rec < items() && row(rec).tipo() != riga_mastrino)
_riga.remove(rec);
}
return ok;
}
///////////////////////////////////////////////////////////
// TGrid_control
///////////////////////////////////////////////////////////
class TGrid_control;
class TGrid_cell : public TFixed_string
{
XI_EVENT* _xiev;
public:
TString& set(const char* txt);
TString& 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);
short get_column() const { return _xiev->v.cell_request.col_nbr; }
TString& operator = (const char* str) { return set(str); }
TString& operator = (const TString& str) { return set(str); }
TGrid_cell(XI_EVENT* 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);
virtual word class_id() const;
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_record(long rec) { return TRUE; }
virtual bool off_record(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_grid_button() { }
virtual void on_record_button(long rec) { }
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);
void reset_columns_order();
void save_columns_order() const;
TGrid_field(TMask* 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;
int _default_width[MAX_COL];
int _columns_order;
protected: // TControl
//@cmember Gestisce gli eventi delle celle
virtual bool event_handler(XI_OBJ* itf, XI_EVENT* xiev);
//@cmember Chiama gli handlers opportuni per verificare il cambio record
bool try_to_select(long rec) const;
protected:
//@cmember Ritorna il numero totale di righe
long items() const { return _grid->items(); }
//@cmember Converte un record nella eventuale riga corrispondente a video
int rec2row(long rec) const;
//@cmember Converte una riga a video nell'eventuale record corrispondente
long row2rec(int row) const;
//@cmember Converte un indice di colonna nel corrispondente id
short int col2cid(int pos) const;
void update_selection(XI_EVENT* xiev);
void set_columns_order(TToken_string* order);
XI_OBJ* find_column(short cid) const;
XI_OBJ* find_column(const char* head) const;
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;
void load_columns_order();
void save_columns_order() const;
void reset_columns_order() { set_columns_order(NULL); }
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), _columns_order(0)
{
_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 'A':
auto_num = TRUE;
break;
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
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);
long list_attr = XI_ATR_ENABLED | XI_ATR_VISIBLE;
// if (_read_only) list_attr |= XI_ATR_NAVIGATE;
XI_OBJ_DEF* listdef = xi_add_list_def(NULL, cid,
rct.top, rct.left, rct.bottom-rct.top,
list_attr,
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;
#ifdef XI_R4
l->min_heading_height = xi_button_calc_height_font(xi_get_system_font()) * lines_in_header;
#else
l->min_heading_height = xi_button_calc_height_font_id(xvt_default_font()) * lines_in_header;
#endif
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;
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->wrap_text = _type[i] != 'R';
}
RCT rd; xi_get_def_rect(listdef, (XinRect*)&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();
int num;
XI_OBJ** column = xi_get_member_list(_obj, &num);
for (i = 0; i < num; i++)
{
RCT rct; xi_get_rect(column[i], (XinRect*)&rct);
_default_width[i] = rct.right - rct.left;
}
}
// Converts a record number in the correspondig row number
int TGrid_control::rec2row(long record) const
{
int rows;
const long* rec = xi_get_list_info(_obj, &rows);
int r = rows > 0 ? int(record - rec[0]) : -1;
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)
{
bool ok, sel;
if (rec >= 0)
{
ok = try_to_select(rec);
sel = ok;
}
else
{
ok = _cur_rec >= 0 && _cur_rec < items() && _grid->off_record(_cur_rec);
sel = FALSE;
}
if (ok)
{
if (sel)
{
int first, last;
xi_get_visible_rows(_obj, &first, &last);
// Controllo che la nuova riga sia completamente visibile
const int next_row = rec2row(rec);
if (next_row >= first && next_row <= last)
{
if (_read_only)
{
XI_OBJ riga; XI_MAKE_ROW(&riga, _obj, next_row);
long attr = xi_get_attrib(&riga);
attr |= XI_ATR_SELECTED;
xi_set_attrib(&riga, attr);
}
}
else
{
long attr = XI_ATR_ENABLED;
if (_read_only)
attr |= XI_ATR_SELECTED;
xi_scroll_rec(_obj, rec, NORMAL_COLOR, attr, 0);
}
if (!_read_only)
{
const int next_row = rec2row(rec);
XI_OBJ cella; XI_MAKE_CELL(&cella, _obj, next_row, 1);
xi_set_focus(&cella);
}
} // end if (sel)
// Deseleziona record precedente se ancora visibile
if (_read_only)
{
const int cur_row = rec2row(_cur_rec);
if (cur_row >= 0)
{
XI_OBJ riga; XI_MAKE_ROW(&riga, _obj, cur_row);
long attr = xi_get_attrib(&riga);
attr &= ~XI_ATR_SELECTED;
xi_set_attrib(&riga, attr);
}
xi_dequeue();
}
if (rec < 0 || rec >= items())
rec = -1;
_cur_rec = rec;
} // end if (ok)
return ok;
}
short TGrid_control::col2cid(int pos) const
{
int num;
XI_OBJ** column = xi_get_member_list(_obj, &num);
CHECKD(pos >= 0 && pos < num, "Bad column ", pos);
const short cid = column[pos]->cid - 1000;
return cid;
}
bool TGrid_control::try_to_select(long rec) const
{
bool ok = rec >= 0 && rec < items();
if (ok && rec != _cur_rec)
{
if (_cur_rec >= 0 && _cur_rec < items())
ok = _grid->off_record(_cur_rec);
if (ok)
ok = _grid->on_record(rec);
}
return ok;
}
void TGrid_control::update_selection(XI_EVENT* xiev)
{
const bool is_curr = xiev->v.rec_request.data_rec == _cur_rec;
if (_read_only)
{
/*
if (is_curr)
xiev->v.rec_request.attrib |= XI_ATR_SELECTED;
else
xiev->v.rec_request.attrib &= ~XI_ATR_SELECTED;
*/
}
else
xiev->v.rec_request.has_focus = is_curr;
}
// 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 = short(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;
else
_columns_order = 1;
break;
case XIE_COL_SIZE:
{
const short cid = col2cid(xiev->v.column.col_nbr);
if (_grid->on_resize_column(cid, xiev->v.column.new_col_width))
_columns_order = 1;
else
refused = TRUE;
}
break;
case XIE_SELECT:
if (xiev->v.select.xi_obj->type == XIT_ROW) // Considero solo le righe
{
if (xiev->v.select.selected) // Sto selezionando
{
const long rec = row2rec(xiev->v.select.xi_obj->v.row_data.row);
if (try_to_select(rec))
{
if (xiev->v.select.column == 0)
{
#ifndef XI_R4
_cur_rec = rec; // Assegno subito il record corrente
_grid->on_record_button(rec);
#endif
if (_read_only)
refused = TRUE;
}
else
{
if (_read_only && rec == _cur_rec)
{
const short cid = col2cid(xiev->v.select.column);
_grid->on_dbl_cell(rec, cid);
refused = TRUE;
}
_cur_rec = rec; // Assegno solo ora il record corrente
}
}
else
refused = TRUE;
}
}
break;
case XIE_CELL_REQUEST:
{
const long& rec = xiev->v.cell_request.rec;
if (rec >= 0 && rec < items())
{
TGrid_cell cell(xiev);
const short cid = col2cid(cell.get_column());
if (cid >= FIRST_FIELD)
{
_grid->cell_request(rec, cid, cell);
}
else
{
if (cell.size() > 2)
{
cell.set(rec+1);
// Setto il colore del testo altrimenti verrebbe grigio:
// non uso la set_color perche' ignora NORMAL_COLOR
xiev->v.cell_request.color = NORMAL_COLOR;
}
}
}
else
refused = TRUE; // Ogni tanto succede
}
break;
case XIE_ON_ROW:
{ // Qui ci passa solo se non e' _read_only
const long rec = row2rec(xiev->v.xi_obj->v.row);
if (rec >= 0)
{
if (_grid->on_record(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:
// Qui ci passa solo se non e' _read_only
if (_cur_rec >= 0 && _cur_rec < items())
refused = !_grid->off_record(_cur_rec);
break;
case XIE_ON_CELL:
break;
case XIE_DBL_CELL:
{
const long rec = row2rec(xiev->v.xi_obj->v.cell.row);
if (try_to_select(rec))
{
const short cid = col2cid(xiev->v.xi_obj->v.cell.column);
_grid->on_dbl_cell(rec, cid);
}
}
break;
case XIE_BUTTON:
if (xiev->v.xi_obj->type == XIT_LIST)
{
_grid->on_grid_button();
}
else
{
const XI_CELL_DATA& cell = xiev->v.xi_obj->v.cell;
const long rec = row2rec(cell.row);
if (try_to_select(rec))
{
const short cid = col2cid(cell.column);
_grid->on_cell_button(rec, cid);
}
else
NFCHECK("You are clicking an invalid cell: %d", cell.row);
}
break;
default:
break;
}
return !refused;
}
XI_OBJ* TGrid_control::find_column(short cid) const
{
int num;
XI_OBJ** column = xi_get_member_list(_obj, &num);
for (int i = num-1; i >= 0; i--)
{
if (column[i]->cid == cid)
break;
}
return i >= 0 ? column[i] : NULL;
}
XI_OBJ* TGrid_control::find_column(const char* head) const
{
int num;
XI_OBJ** column = xi_get_member_list(_obj, &num);
TString80 text;
for (int i = num-1; i >= 0; i--)
{
xi_get_text(column[i], text.get_buffer(), text.size());
if (text == head)
break;
}
return i >= 0 ? column[i] : NULL;
}
void TGrid_control::set_columns_order(TToken_string* order)
{
XI_OBJ* itf = get_interface();
XI_OBJ* focus = xi_get_focus(itf);
xi_set_focus(itf);
int num_cols;
XI_OBJ** column = xi_get_member_list(_obj, &num_cols);
// Costante da sottrarre nella xi_column_set_pixel_width altrimenti la somma due volte!
const int offset = 2 * (int)xi_get_pref(XI_PREF_COLUMN_OFFSET);
const int fixed = xi_get_fixed_columns(_obj);
if (fixed > 1)
xi_set_fixed_columns(_obj, 1);
if (order == NULL)
{
for (int index = 1; index < num_cols; index++)
{
const short cid = FIRST_FIELD + 1000 + index - 1;
XI_OBJ* col = find_column(cid);
if (col)
{
xi_move_column(col, index);
RCT rct; xi_get_rect(col, (XinRect*)&rct);
if (_default_width[index] != rct.right - rct.left)
xi_column_set_pixel_width(col, _default_width[index]-offset);
}
}
_columns_order = 0x3;
}
else
{
TToken_string col(8, ',');
int pos = 0;
for (col = order->get(0); !col.blank(); col = order->get(), pos++)
{
const char* head = esc(col.get(0));
const int width = col.get_int();
XI_OBJ* column = find_column(head);
if (column) // Controlla che esista ancora
{
if (pos > 0 && pos < num_cols)
xi_move_column(column, pos); // Sposta la colonna se possibile
if (width > XI_FU_MULTIPLE) // Se ha una larghezza valida
xi_column_set_pixel_width(column, width - offset);
}
}
}
if (fixed > 1)
xi_set_fixed_columns(_obj, fixed);
if (focus)
xi_set_focus(focus);
}
HIDDEN TFilename& field2parag(const TMask_field& f, TFilename& name)
{
const TMask& m = f.mask();
name = m.source_file();
name.ext(""); // Nome della maschera senza estensione
const int index = m.number();
CHECKD(index >= 0 && index <= 8, "Bad mask index:", index);
if (index > 0) // Aggiunge l'eventuale numero di sotto-maschera
name << '(' << index << ')';
return name;
}
void TGrid_control::load_columns_order()
{
TFilename parag; field2parag(*_grid, parag);
TConfig config(CONFIG_USER, parag);
TToken_string order = config.get("Browse", NULL, id());
if (order.empty_items())
config.remove("Browse", id());
else
set_columns_order(&order);
_columns_order = 0;
}
void TGrid_control::save_columns_order() const
{
if (_columns_order)
{
TFilename parag; field2parag(*_grid, parag);
TConfig config(CONFIG_USER, parag); // Apre il file di configurazione
TToken_string order(127); // Nuovo ordine delle colonne
if (_columns_order == 1) // Se vale 3 devo solo resettare
{
int num;
XI_OBJ** column = xi_get_member_list(_obj, &num);
TString80 head;
for (int i = 0; i < num; i++) // Scorre tutte le colonne
{
xi_get_text(column[i], head.get_buffer(), head.size());
const int acapo = head.find('\n');
if (acapo > 0)
{
head[acapo] = '\\';
head.insert("n", acapo+1);
}
order.add(head);
RCT rct; xi_get_rect(column[i], (XinRect*)&rct);
order << ',' << rct.right - rct.left;
}
config.set("Browse", order, NULL, TRUE, id());
}
else
config.remove("Browse", id());
}
}
///////////////////////////////////////////////////////////
// TGrid_cell
///////////////////////////////////////////////////////////
TGrid_cell::TGrid_cell(XI_EVENT* xiev)
: TFixed_string(xiev->v.cell_request.s, xiev->v.cell_request.len),
_xiev(xiev)
{ }
// Setta il testo di una cella (Mai piu' testo troppo lungo!)
// Se c'e' gia' un'icona la elimina
TString& TGrid_cell::set(const char* txt)
{
strncpy(txt, size());
if (not_empty())
{
int& icon = _xiev->v.cell_request.icon_rid;
if (icon)
icon = 0;
}
return *this;
}
TString& TGrid_cell::set(long num)
{
char buff[16];
sprintf(buff, "%ld", num);
return 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
///////////////////////////////////////////////////////////
TGrid_field::TGrid_field(TMask* m)
: TOperable_field(m)
{ }
word TGrid_field::class_id() const
{
return CLASS_GRID_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);
grid().load_columns_order();
}
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); }
void TGrid_field::reset_columns_order()
{
grid().reset_columns_order();
}
void TGrid_field::save_columns_order() const
{
grid().save_columns_order();
}
///////////////////////////////////////////////////////////
// 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);
static bool reset_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);
_pixmap = TRUE;
set_pen(COLOR_BLACK);
RCT rct; field(100).get_rect(rct);
set_brush(back);
frame(rct.left, 2*rct.top - rct.bottom - CHARY/2, rct.right, rct.top - CHARY/2, 0);
field(99).get_rect(rct);
set_brush(fore);
frame(rct.left, 2*rct.top - rct.bottom - CHARY/2, rct.right, rct.top - CHARY/2, 0);
_pixmap = FALSE;
}
///////////////////////////////////////////////////////////
// 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();
m.set_focus();
}
}
return TRUE;
}
bool TColor_mask::reset_handler(TMask_field& f, KEY k)
{
if (k == K_SPACE && f.yesno_box(TR("Si desidera azzerare tutti i colori?")))
{
TColor_mask& m = (TColor_mask&) f.mask();
m._mas_back = NORMAL_BACK_COLOR;
m._mas_fore = NORMAL_COLOR;
m._con_back = NORMAL_BACK_COLOR;
m._con_fore = NORMAL_COLOR;
TSheet_field& s = (TSheet_field&)f.mask().field(101);
s.set_back_and_fore_color(NORMAL_BACK_COLOR, NORMAL_COLOR, -1);
s.force_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)
{
set_handler(102, reset_handler);
set_caption("Colori delle righe mastrini");
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 << TR("Riga ") << (*c == 'M' ? TR("mastrino") : TR("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_record(long rec);
virtual void cell_request(long rec, short id, TGrid_cell& cell);
virtual void on_grid_button();
virtual bool on_resize_column(short id, int new_size);
void update_mask() const;
public:
virtual void on_dbl_cell(long rec, short id);
virtual void on_record_button(long rec);
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, bool provv);
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_DESCR)
{
load_colors();
}
void TMastrini_grid::destroy()
{
_mastrino.destroy();
grid().select(-1);
}
HIDDEN const char* real2string(const real& r)
{
TCurrency cur(r);
return cur.string(TRUE);
}
HIDDEN void set_imp(TMask_field& f, const TImporto& imp)
{
if (!imp.is_zero())
{
TString80 str;
str.format("%s %c", real2string(imp.valore()), imp.sezione());
f.set(str);
}
else
f.reset();
}
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);
cell = riga.data().string();
cell << ' ' << mov.get(MOV_DATADOC);
}
break;
case 102:
if (riga.tipo() == riga_mastrino)
{
const TRectype& mov = _mastrino.testata(rec);
const int anno = _esercizi.date2esc(riga.data());
const int eser = mov.get_int(MOV_ANNOES);
TString8 str;
if (anno != eser)
str = "C"; // Di competenza vecchia
if (mov.get(MOV_PROVVIS).not_empty())
{
if (str.not_empty())
str << '/';
str << 'P';
}
cell = str;
}
break;
case 103:
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);
cell.format("%03d.%03d.%06ld",
rmov.get_int(RMV_GRUPPO),
rmov.get_int(RMV_CONTO),
rmov.get_long(RMV_SOTTOCONTO));
}
break;
case 104:
if (riga.tipo() == riga_mastrino)
{
const TRectype& rmov = _mastrino.riga(rec);
cell.set(rmov.get(RMV_DESCR));
if (cell.empty())
{
const TRectype& mov = _mastrino.testata(rec);
cell.set(mov.get(MOV_DESCR));
if (cell.empty())
{
TBill uncle(rmov,TRUE);
cell.set(uncle.descrizione());
}
}
}
else
{
const TRectype& rmov = _mastrino.riga(rec);
cell.set(rmov.get(RMV_DESCR));
if (cell.empty())
{
const TBill conto(rmov);
cell.set(conto.descrizione());
}
}
break;
case 105:
{
const TRectype& rmov = _mastrino.riga(rec);
const char sez = rmov.get_char(RMV_SEZIONE);
if (sez == 'D')
cell = real2string(rmov.get_real(RMV_IMPORTO));
}
break;
case 106:
{
const TRectype& rmov = _mastrino.riga(rec);
const char sez = rmov.get_char(RMV_SEZIONE);
if (sez == 'A')
cell = real2string(rmov.get_real(RMV_IMPORTO));
}
break;
case 107:
if (riga.tipo() == riga_mastrino)
{
const TRectype& mov = _mastrino.testata(rec);
cell = mov.get(MOV_NUMDOC); cell.left_just(7);
cell << ' ' << mov.get(MOV_PROTIVA);
}
break;
case 108:
{
const TRectype& rmov = _mastrino.riga(rec);
cell = real2string(rmov.get_real(RMV_IMPORTO));
cell << ' ' << rmov.get(RMV_SEZIONE);
}
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();
cell = real2string(imp.valore());
cell << ' ' << imp.sezione();
}
}
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_record(long rec)
{
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_dbl_cell(long rec, short id)
{
if (rec >= 0 && rec < items())
{
if (_mastrino.expandable(rec))
_mastrino.expand(rec);
else
_mastrino.collapse(rec);
update();
}
}
void TMastrini_grid::on_grid_button()
{
const long total = _mastrino.items();
if (total > 0)
{
TProgind* pi = NULL;
if (total > 50)
pi = new TProgind(total, TR("Aggiornamento contropartite ..."), FALSE, TRUE, 48);
else
begin_wait();
// Cerca l'ultima contropartita
const long last_con = _mastrino.last(riga_contropartita);
// Se non esistono contropartite devo espandere le righe
const bool expand = last_con < 0;
#ifdef DBG
const clock_t clock_start = clock();
#endif
if (expand)
{
long step = 0;
for (long n = _mastrino.first(riga_mastrino);
n < _mastrino.items(); n = _mastrino.succ(n, riga_mastrino))
{
if (_mastrino.expandable(n))
_mastrino.expand(n);
if (pi)
{
pi->setstatus(++step);
#ifdef DBG
if ((step & 0x7F) == 0)
{
const double sec = (clock() - clock_start) / CLOCKS_PER_SEC;
if (sec > 0.0)
{
TString80 msg;
msg.format(FR("%ld records at %ld rec/sec"), step, long(step/sec));
pi->set_text(msg);
}
}
#endif
}
}
}
else
{
for (long n = last_con; n > 0; n = _mastrino.pred(n, riga_contropartita))
{
_mastrino.collapse(n);
if (pi)
pi->setstatus(total - n + 1);
}
}
if (pi)
delete pi;
else
end_wait();
update();
}
}
void TMastrini_grid::on_record_button(long rec)
{
TWait_cursor hourglass;
const TRectype& testata = _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();
mask().set_focus();
TMailbox mail;
if (mail.next_s(MSG_LN) != NULL)
{
if (yesno_box(TR("Si desidera aggiornare il mastrino?")))
reread();
}
}
// Posso ridimensionare solo le descrizioni, le altre devono rimanere fisse per
// non perdere la formattazione su due righe
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, bool provv)
{
destroy();
_mastrino.read(conto, annoes, dd, ad, dc, ac, provv);
update();
update_mask();
}
void TMastrini_grid::reread()
{
destroy();
_mastrino.reread();
update();
update_mask();
}
void TMastrini_grid::update_mask() const
{
TMask& gm = mask();
gm.set(F_ESERCIZIO, _mastrino.esercizio());
gm.set(F_DADATA, _mastrino.inizio_periodo());
gm.set(F_ADATA, _mastrino.fine_periodo());
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);
virtual void handler(WINDOW win, EVENT* ep);
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())
grid.on_record_button(rec);
}
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;
case K_ENTER:
case K_CTRL+'+':
case K_CTRL+'-':
if (focus_field().dlg() == _grid->dlg())
_grid->on_dbl_cell(rec, DLG_USER);
break;
default:
break;
}
if (rec != grid().selected())
{
grid().select(rec);
return TRUE;
}
return TMask::on_key(k);
}
void TGrid_mask::handler(WINDOW win, EVENT* ep)
{
static TGrid_field* _last_grid = NULL;
if (ep->type == E_MOUSE_DOWN && ep->v.mouse.button == 1)
{
_last_grid = NULL;
RCT rct; _grid->get_rect(rct);
if (xvt_rect_has_point(&rct, ep->v.mouse.where))
_last_grid = _grid;
if (_last_grid)
{
TGrid_field& sht = (TGrid_field&)*_last_grid;
#if (XVT_PTK_VERSION_MAJOR > 4) || (XVT_PTK_VERSION_MAJOR == 4 && XVT_PTK_VERSION_MINOR >= 50)
MENU_ITEM* menu = xvt_res_get_menu(BROWSE_BAR);
if (menu)
{
const PNT& p = ep->v.mouse.where;
RCT cr; xvt_vobj_get_client_rect(win, &cr);
XVT_POPUP_ALIGNMENT pa = XVT_POPUP_CENTER;
if (p.h < cr.right / 3)
pa = XVT_POPUP_LEFT_ALIGN;
else
if (p.h > 2 * cr.right / 3)
pa = XVT_POPUP_RIGHT_ALIGN;
xvt_menu_popup(menu->child, win, p, pa, NULL);
xvt_res_free_menu_tree(menu);
}
#else
ASK_RESPONSE r = xvt_dm_post_ask(TR("Annulla"), TR("Ripristina"), TR("Salva"),
TR("Ordinamento delle colonne"));
if (r == RESP_2)
sht.reset_columns_order();
if (r == RESP_2 || r == RESP_3)
sht.save_columns_order();
#endif
return;
}
}
if (ep->type == E_COMMAND)
{
if (_last_grid)
{
switch (ep->v.cmd.tag)
{
case M_EDIT_UNDO:
_last_grid->reset_columns_order();
case M_EDIT_COPY:
_last_grid->save_columns_order();
break;
case M_EDIT_SEARCH:
_last_grid->on_key(K_F11);
break;
default:
break;
}
return;
}
}
TMask::handler(win, ep);
}
///////////////////////////////////////////////////////////
// TQuery_mask
///////////////////////////////////////////////////////////
class TQuery_mask : public TMask
{
protected:
static bool esercizio_handler(TMask_field& f, KEY k);
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_ESERCIZIO, esercizio_handler);
set_handler(F_DADATA, data_handler);
set_handler(F_ADATA, data_handler);
set_handler(DLG_FINDREC, find_handler);
}
bool TQuery_mask::esercizio_handler(TMask_field& f, KEY k)
{
if (k == K_TAB && f.focusdirty())
{
TEsercizi_contabili esc;
const int anno = atoi(f.get());
if (esc.exist(anno))
{
TMask& m = f.mask();
TDate dd = m.get(F_DADATA);
if (esc.date2esc(dd) != anno)
m.set(F_DADATA, esc[anno].inizio());
dd = m.get(F_ADATA);
if (esc.date2esc(dd) != anno)
m.set(F_ADATA, esc[anno].fine());
}
else
{
if (anno > 0)
return error_box(FR("Esercizio inesistente: %d"), anno);
}
}
return TRUE;
}
bool TQuery_mask::data_handler(TMask_field& f, KEY k)
{
bool ok = TRUE;
if (k == K_ENTER)
{
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(TR("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(FR("La data deve appartenere all'esercizio %d"), codice_esercizio);
}
else
{
if (esercizio == 0)
ok = error_box(TR("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);
const TDate da_data(get(F_DADATA));
const TDate a_data(get(F_ADATA));
const TString& da_caus = get(F_DACAUSALE);
const TString& a_caus = get(F_ACAUSALE);
const bool provv = get_bool(F_PROVVIS);
conto.set(gm, F_GRUPPO, F_CONTO, F_SOTTOCONTO, 0, F_DESSOTTOC);
gm.grid().read(conto, annoes, da_data, a_data, da_caus, a_caus, provv);
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);
public:
};
bool TMastrini_video::create()
{
xvt_statbar_set("", TRUE);
open_files(LF_RMOV, LF_MOV, LF_CAUSALI, 0);
open_files(LF_SALDI, LF_PCON, 0);
_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;
}
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(-5); // Azzera causali
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, TR("Mastrini"));
return 0;
}