Files correlati : cg3.exe cg3600a.msk Ricompilazione Demo : [ ] Commento : Corretta gestione descrizioni in visualizzazione mastrini. Grazie ancora ad A.B. qualcosa! git-svn-id: svn://10.65.10.50/branches/R_10_00@22418 c028cbd2-c16b-5b4b-a496-9718f37d4682
2579 lines
68 KiB
C++
Executable File
2579 lines
68 KiB
C++
Executable File
#include <xinclude.h>
|
||
|
||
#include "cg3.h"
|
||
#include "cglib02.h"
|
||
#include "cg3600.h"
|
||
|
||
#include <applicat.h>
|
||
#include <colmask.h>
|
||
#include <controls.h>
|
||
#include <execp.h>
|
||
#include <progind.h>
|
||
#include <relation.h>
|
||
#include <recset.h>
|
||
#include <urldefid.h>
|
||
#include <utility.h>
|
||
|
||
#include <clifo.h>
|
||
#include <causali.h>
|
||
#include <mov.h>
|
||
#include <pconti.h>
|
||
#include <rmov.h>
|
||
#include <saldi.h>
|
||
|
||
class TGrid_mask;
|
||
|
||
class TQuery_mask : public TAutomask
|
||
{
|
||
TGrid_mask* _gm;
|
||
TString4 _last_tipo;
|
||
|
||
protected:
|
||
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
|
||
|
||
public:
|
||
void do_query();
|
||
|
||
TQuery_mask(TGrid_mask* gm);
|
||
virtual ~TQuery_mask() { }
|
||
};
|
||
|
||
|
||
class TMastrini_video : public TSkeleton_application
|
||
{
|
||
TQuery_mask* _qm;
|
||
TGrid_mask* _gm;
|
||
|
||
protected:
|
||
virtual bool create();
|
||
virtual void main_loop();
|
||
virtual bool destroy();
|
||
|
||
public:
|
||
TQuery_mask & query_mask() { return *_qm; }
|
||
|
||
};
|
||
HIDDEN inline TMastrini_video& app()
|
||
{ return (TMastrini_video&)main_app();}
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// TList
|
||
///////////////////////////////////////////////////////////
|
||
|
||
// 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( ) const { 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);
|
||
}
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// 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 movimento 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;
|
||
|
||
const TBill& conto() const { return _conto; }
|
||
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();
|
||
long i;
|
||
|
||
for (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();
|
||
long i;
|
||
for (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();
|
||
}
|
||
|
||
// 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("%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 (rec < 0)
|
||
{
|
||
for (long i = last(); i >= 0; i = pred(i))
|
||
collapse(i);
|
||
}
|
||
else
|
||
{
|
||
if (row(rec).tipo() != riga_mastrino) // Se non sono su una riga mastrino ...
|
||
rec = pred(rec, riga_mastrino); // ... mi sposto sulla precedente riga mastrino
|
||
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); }
|
||
|
||
XI_EVENT* event() { return _xiev; }
|
||
|
||
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;
|
||
|
||
public:
|
||
TGrid_control& grid() const { return (TGrid_control&)*_ctl; }
|
||
|
||
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(const char* head) const;
|
||
|
||
public:
|
||
long selected() const { return _cur_rec; }
|
||
bool select(long n);
|
||
|
||
int visible_rows() const;
|
||
|
||
XI_OBJ* find_column(short cid) 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
|
||
const char* h;
|
||
|
||
for (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_OBJ* itf = get_interface(parent);
|
||
XI_RCT rct = coord2rct(itf, x, y, dx, dy);
|
||
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;
|
||
|
||
|
||
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;
|
||
l->min_heading_height = xi_button_calc_height_font(xi_get_system_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;
|
||
|
||
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';
|
||
}
|
||
|
||
XI_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();
|
||
|
||
int num;
|
||
XI_OBJ** column = xi_get_member_list(_obj, &num);
|
||
for (i = 0; i < num; i++)
|
||
{
|
||
xi_get_rect(column[i], &rd);
|
||
_default_width[i] = rd.right - rd.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)
|
||
{
|
||
if (rec == _cur_rec) // Simulo intercettazione doppio click
|
||
_grid->on_record_button(rec);
|
||
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);
|
||
int i;
|
||
for (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;
|
||
int i;
|
||
for (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
|
||
///////////////////////////////////////////////////////////
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// Maschera per colori
|
||
///////////////////////////////////////////////////////////
|
||
|
||
class TColor_mask : public TSelect_color_mask
|
||
{
|
||
public:
|
||
void get_colors(COLOR& mb, COLOR& mf, COLOR& cb, COLOR& cf);
|
||
TColor_mask();
|
||
};
|
||
|
||
void TColor_mask::get_colors(COLOR& mb, COLOR& mf, COLOR& cb, COLOR& cf)
|
||
{
|
||
get_color("M", mb, mf);
|
||
get_color("C", cb, cf);
|
||
}
|
||
|
||
TColor_mask::TColor_mask() : TSelect_color_mask("cg3600b")
|
||
{
|
||
add_color_def("M", TR("Riga mastrino"), REQUIRED_BACK_COLOR, FOCUS_COLOR);
|
||
add_color_def("C", TR("Riga contropartita"), NORMAL_BACK_COLOR, NORMAL_COLOR);
|
||
}
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// TMastrini_grid
|
||
///////////////////////////////////////////////////////////
|
||
|
||
class TMastrini_grid : public TGrid_field
|
||
{
|
||
TMastrino _mastrino;
|
||
|
||
TDecoder _causali;
|
||
TEsercizi_contabili _esercizi;
|
||
|
||
TColor_mask _colmsk;
|
||
COLOR _mas_back, _mas_fore;
|
||
COLOR _con_back, _con_fore;
|
||
bool _primanoting, _contsep;
|
||
|
||
protected: // TGrid_field
|
||
virtual bool on_record(long rec);
|
||
virtual void on_grid_button();
|
||
virtual bool on_resize_column(short id, int new_size);
|
||
|
||
void update_mask() const;
|
||
|
||
public:
|
||
virtual void cell_request(long rec, short id, TGrid_cell& cell);
|
||
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();
|
||
void set_contsep(bool cs) { _contsep = cs; }
|
||
|
||
TMastrini_grid(TMask* m);
|
||
virtual ~TMastrini_grid() { }
|
||
};
|
||
|
||
TMastrini_grid::TMastrini_grid(TMask* m)
|
||
: TGrid_field(m), _causali(LF_CAUSALI, CAU_DESCR), _primanoting(false), _contsep(false)
|
||
{
|
||
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)
|
||
{
|
||
if (rec < 0) // testate
|
||
{
|
||
XI_OBJ* col = grid().find_column(short(1000+id%1000));
|
||
if (col != NULL)
|
||
{
|
||
TString head;
|
||
xi_get_text(col, head.get_buffer(), head.size());
|
||
cell = head;
|
||
|
||
}
|
||
return;
|
||
}
|
||
|
||
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: // Descrizione
|
||
{
|
||
const TRectype& rmov = _mastrino.riga(rec);
|
||
const TRectype& mov = _mastrino.testata(rec);
|
||
TString descr = rmov.get(RMV_DESCR);
|
||
if (riga.tipo() == riga_mastrino)
|
||
{
|
||
if (descr.empty())
|
||
{
|
||
const TRectype& mov = _mastrino.testata(rec);
|
||
descr = mov.get(MOV_DESCR);
|
||
if (descr.empty())
|
||
{
|
||
TBill uncle(rmov,true);
|
||
descr = uncle.descrizione();
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Bug 0001748: ignora descrizioni generate da contabilizzazione
|
||
if (descr.empty() || descr == _mastrino.conto().descrizione())
|
||
{
|
||
const TBill conto(rmov);
|
||
descr = conto.descrizione();
|
||
}
|
||
}
|
||
if (_contsep)
|
||
{
|
||
const TString16 cs = mov.get(MOV_CONTSEP);
|
||
if (cs.full())
|
||
descr << "\n" << cache().get("&NPENT", cs, "S0");
|
||
}
|
||
cell.set(descr);
|
||
}
|
||
break;
|
||
case 105: // Dare
|
||
{
|
||
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: // Avere
|
||
{
|
||
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)
|
||
{
|
||
if (!_primanoting)
|
||
{
|
||
_primanoting = true;
|
||
const TRectype& testata = _mastrino.testata(rec);
|
||
bool refresh = testata.edit();
|
||
if (refresh && yesno_box(TR("Si desidera aggiornare il mastrino?")))
|
||
reread();
|
||
_primanoting = false;
|
||
}
|
||
}
|
||
|
||
// 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());
|
||
|
||
const bool can_link = main_app().argc() <= 2; // NON sono stato chiamato dalla prima nota
|
||
gm.enable(DLG_LINK, can_link && _mastrino.items() > 0);
|
||
gm.enable(DLG_NEWREC, can_link);
|
||
}
|
||
|
||
void TMastrini_grid::load_colors()
|
||
{
|
||
_colmsk.get_colors(_mas_back, _mas_fore, _con_back, _con_fore);
|
||
}
|
||
|
||
void TMastrini_grid::set_colors()
|
||
{
|
||
if (_colmsk.run() == K_ENTER)
|
||
load_colors();
|
||
}
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// TMastrino_set
|
||
///////////////////////////////////////////////////////////
|
||
|
||
class TMastrino_set : public TRecordset
|
||
{
|
||
TMastrini_grid& _grid;
|
||
long _curr;
|
||
TArray _info;
|
||
|
||
protected:
|
||
void add_field(TFieldtypes t, short id, int width, const char* name = NULL);
|
||
long cell_request(long rec, short column, TString& str) const;
|
||
const TString& query_text() const { return EMPTY_STRING; }
|
||
|
||
public:
|
||
virtual TRecnotype items() const { return _grid.items(); }
|
||
virtual unsigned int columns() const { return _info.items(); }
|
||
virtual const TRecordset_column_info& column_info(unsigned int column) const;
|
||
virtual bool move_to(TRecnotype n);
|
||
virtual TRecnotype current_row() const { return _curr; }
|
||
virtual void requery() {}
|
||
virtual const TVariant& get(unsigned int column) const;
|
||
|
||
TMastrino_set(TMastrini_grid& g);
|
||
};
|
||
|
||
const TRecordset_column_info& TMastrino_set::column_info(unsigned int column) const
|
||
{
|
||
return (const TRecordset_column_info&)_info[column];
|
||
}
|
||
|
||
bool TMastrino_set::move_to(TRecnotype n)
|
||
{
|
||
const bool ok = n >= 0 && n < items();
|
||
_curr = n;
|
||
return ok;
|
||
}
|
||
|
||
long TMastrino_set::cell_request(long rec, short column, TString& str) const
|
||
{
|
||
XI_EVENT xiev; memset(&xiev, 0, sizeof(xiev));
|
||
xiev.type = XIE_CELL_REQUEST;
|
||
xiev.v.cell_request.s = str.get_buffer();
|
||
xiev.v.cell_request.len = str.size();
|
||
TGrid_cell cell(&xiev);
|
||
_grid.cell_request(rec, column, cell);
|
||
return xiev.v.cell_request.attrib;
|
||
}
|
||
|
||
|
||
const TVariant& TMastrino_set::get(unsigned int column) const
|
||
{
|
||
if (_curr >= 0 && _curr < items() && column >= 0 && column < columns())
|
||
{
|
||
const TRecordset_column_info& info = column_info(column);
|
||
|
||
TToken_string str;
|
||
cell_request(_curr, abs(info._pos), str);
|
||
if (str.full())
|
||
{
|
||
//decide se il campo appartiene ad una sottocella (es. numdoc / prot)
|
||
bool divide = info._pos < 0; //<2F> la prima parte di una sottocella
|
||
if (!divide && column < columns()-1)
|
||
divide = column_info(column+1)._pos < 0; //<2F> la seconda parte di una sottocella
|
||
//se deve splittare cerca lo spazio come carattere di separazione tra le sottocelle
|
||
if (divide)
|
||
{
|
||
const int cr = str.find(' ');
|
||
if (cr >= 0)
|
||
{
|
||
if (info._pos > 0)
|
||
str.cut(cr);
|
||
else
|
||
str.ltrim(cr);
|
||
str.trim();
|
||
}
|
||
}
|
||
|
||
TVariant& tmp = get_tmp_var();
|
||
switch (info._type)
|
||
{
|
||
case _realfld:
|
||
tmp = real(real::ita2eng(str));
|
||
break;
|
||
case _longfld:
|
||
tmp = atol(str);
|
||
break;
|
||
case _datefld:
|
||
tmp = TDate(str);
|
||
break;
|
||
default:
|
||
if (info._width == 1)
|
||
tmp = str.right(1);
|
||
else
|
||
tmp = str;
|
||
break;
|
||
}
|
||
return tmp;
|
||
}
|
||
}
|
||
return NULL_VARIANT;
|
||
}
|
||
|
||
void TMastrino_set::add_field(TFieldtypes tipo, short id, int width, const char* name)
|
||
{
|
||
TRecordset_column_info* i = new TRecordset_column_info;
|
||
|
||
TString& n = i->_name;
|
||
|
||
if (name && *name)
|
||
n = name;
|
||
else
|
||
{
|
||
cell_request(-1, abs(id), n);
|
||
const int cr = n.find('\n');
|
||
if (cr > 0)
|
||
{
|
||
if (id > 0)
|
||
n.cut(cr);
|
||
else
|
||
n.ltrim(cr+1);
|
||
n.trim();
|
||
}
|
||
}
|
||
|
||
i->_type = tipo;
|
||
i->_pos = id;
|
||
i->_width = width;
|
||
|
||
_info.add(i);
|
||
}
|
||
|
||
TMastrino_set::TMastrino_set(TMastrini_grid& g)
|
||
: _grid(g), _curr(-1)
|
||
{
|
||
_grid.mastrino().collapse(-1);// Nascondo tutte le righe di contropartita
|
||
|
||
add_field(_datefld, 101, 10); // Data reg
|
||
add_field(_datefld,-101, 10); // Data comp
|
||
add_field(_alfafld, 102, 1); // Movimento di competenza?
|
||
add_field(_alfafld, 103, 25); // Causale
|
||
add_field(_alfafld, 104, 50); // Descrizione
|
||
add_field(_realfld, 105, 13); // Dare
|
||
add_field(_realfld, 106, 13); // Avere
|
||
add_field(_alfafld, 107, 7); // Num doc
|
||
add_field(_longfld,-107, 7); // Num prot
|
||
add_field(_realfld, 108, 13); // Saldo
|
||
add_field(_alfafld,-108, 1, "Sezione"); // Sezione
|
||
add_field(_realfld, 109, 13); // Saldo giornaliero
|
||
add_field(_alfafld,-109, 1, "Sezione"); // Sezione giornaliera
|
||
}
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// 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 long handler(WINDOW win, EVENT* ep);
|
||
|
||
static bool link_handler(TMask_field& f, KEY k);
|
||
static bool new_handler(TMask_field& f, KEY k);
|
||
static bool edit_handler(TMask_field& f, KEY k);
|
||
static bool export_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);
|
||
set_handler(DLG_NEWREC, new_handler);
|
||
set_handler(DLG_EDIT, edit_handler);
|
||
set_handler(DLG_EXPORT, export_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::new_handler(TMask_field& f, KEY k)
|
||
{
|
||
if (k == K_SPACE)
|
||
{
|
||
TExternal_app app("cg2 -0");
|
||
const bool refresh = app.run() == 0;
|
||
if (refresh && yesno_box(TR("Si desidera aggiornare il mastrino?")))
|
||
{
|
||
TGrid_mask& gm = (TGrid_mask&)f.mask();
|
||
TMastrini_grid& grid = gm.grid();
|
||
grid.reread();
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
bool TGrid_mask::edit_handler(TMask_field& f, KEY k)
|
||
{
|
||
bool ok = true;
|
||
if (k == K_SPACE)
|
||
{
|
||
TGrid_mask& gm = (TGrid_mask&)f.mask();
|
||
TMastrini_grid& grid = gm.grid();
|
||
TMastrino_set ms(grid);
|
||
|
||
TFilename n; n.tempdir(); n.add("mastrino.xls");
|
||
ms.save_as(n);
|
||
ok = xvt_sys_goto_url(n, "open") != FALSE;
|
||
if (!ok)
|
||
ok = export_handler(f, k); // Se non parte Excel salvo altrove
|
||
}
|
||
return ok;
|
||
}
|
||
|
||
bool TGrid_mask::export_handler(TMask_field& f, KEY k)
|
||
{
|
||
bool ok = true;
|
||
if (k == K_SPACE)
|
||
{
|
||
TFilename n; n.tempdir(); n.add("mastrino.xls");
|
||
FILE_SPEC fs; xvt_fsys_convert_str_to_fspec(n, &fs);
|
||
if (xvt_dm_post_file_save(&fs, f.prompt()) == FL_OK)
|
||
{
|
||
xvt_fsys_convert_fspec_to_str(&fs, n.get_buffer(), n.size());
|
||
TGrid_mask& gm = (TGrid_mask&)f.mask();
|
||
TMastrini_grid& grid = gm.grid();
|
||
TMastrino_set ms(grid);
|
||
ms.save_as(n);
|
||
}
|
||
}
|
||
return ok;
|
||
}
|
||
|
||
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);
|
||
}
|
||
|
||
long 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;
|
||
MENU_ITEM* menu = xvt_res_get_menu(BROWSE_BAR);
|
||
|
||
if (menu != NULL)
|
||
{
|
||
const PNT& p = ep->v.mouse.where;
|
||
xvt_menu_popup(menu->child, win, p, XVT_POPUP_CENTER, 0);
|
||
xvt_res_free_menu_tree(menu);
|
||
}
|
||
return 0L;
|
||
}
|
||
}
|
||
if (ep->type == E_COMMAND)
|
||
{
|
||
if (_last_grid)
|
||
{
|
||
switch (ep->v.cmd.tag)
|
||
{
|
||
case BROWSE_BAR+1: _last_grid->save_columns_order(); break;
|
||
case BROWSE_BAR+2: _last_grid->reset_columns_order(); break;
|
||
case BROWSE_BAR+3: _last_grid->on_key(K_F11); break;
|
||
default: break;
|
||
}
|
||
return 0L;
|
||
}
|
||
}
|
||
return TMask::handler(win, ep);
|
||
}
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// TQuery_mask
|
||
///////////////////////////////////////////////////////////
|
||
|
||
bool TQuery_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
|
||
{
|
||
switch (o.dlg())
|
||
{
|
||
case F_TIPO:
|
||
if (e == fe_modify)
|
||
{
|
||
const TString& tipo = o.get();
|
||
|
||
if (tipo != _last_tipo)
|
||
{
|
||
_last_tipo = tipo;
|
||
if (tipo.full())
|
||
{
|
||
TWait_cursor hourglass;
|
||
TString query;
|
||
query << "USE " << LF_PCON << " SELECT " << PCN_TMCF << "=\"" << tipo << "\"";
|
||
TISAM_recordset conti(query);
|
||
if (conti.move_first())
|
||
{
|
||
set(F_GRUPPO, conti.get(PCN_GRUPPO).as_int(), 0x2);
|
||
set(F_CONTO, conti.get(PCN_CONTO).as_int(), 0x2);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
case F_CLIENTE:
|
||
case F_FORNITORE:
|
||
if (e == fe_modify && !o.empty())
|
||
{
|
||
const TRectype& rec = ((TEdit_field&)o).browse()->cursor()->curr();
|
||
const int g = rec.get_int(CLI_GRUPPO);
|
||
const int c = rec.get_int(CLI_CONTO);
|
||
if (g > 0 && c > 0)
|
||
{
|
||
set(F_GRUPPO, g, 0x2);
|
||
set(F_CONTO, c, 0x2);
|
||
}
|
||
}
|
||
break;
|
||
case F_ESERCIZIO:
|
||
if (e == fe_modify || e == fe_close)
|
||
{
|
||
TEsercizi_contabili esc;
|
||
const int anno = atoi(o.get());
|
||
if (esc.exist(anno))
|
||
{
|
||
TDate dd = get(F_DADATA);
|
||
if (esc.date2esc(dd) != anno)
|
||
set(F_DADATA, esc[anno].inizio());
|
||
dd = get(F_ADATA);
|
||
if (esc.date2esc(dd) != anno)
|
||
set(F_ADATA, esc[anno].fine());
|
||
}
|
||
else
|
||
{
|
||
if (anno > 0)
|
||
return error_box(FR("Esercizio inesistente: %d"), anno);
|
||
}
|
||
}
|
||
break;
|
||
case F_DADATA:
|
||
case F_ADATA:
|
||
if (e == fe_close)
|
||
{
|
||
const TEsercizi_contabili esercizi;
|
||
int codice_esercizio = get_int(F_ESERCIZIO);
|
||
if (codice_esercizio <= 0)
|
||
{
|
||
const short id_altra_data = o.dlg() == F_DADATA ? F_ADATA : F_DADATA;
|
||
const TDate d = get(id_altra_data);
|
||
if (d.ok())
|
||
codice_esercizio = esercizi.date2esc(d);
|
||
}
|
||
|
||
if (o.empty())
|
||
{
|
||
if (codice_esercizio == 0)
|
||
return error_box(TR("E' necessario specificare almeno una data."));
|
||
return true;
|
||
}
|
||
|
||
const TDate d = o.get();
|
||
const int esercizio = esercizi.date2esc(d);
|
||
if (get_int(F_ESERCIZIO) != 0)
|
||
{
|
||
if (esercizio != codice_esercizio)
|
||
return error_box(FR("La data deve appartenere all'esercizio %d"), codice_esercizio);
|
||
}
|
||
else
|
||
{
|
||
if (esercizio == 0)
|
||
return error_box(TR("La data deve appartenere ad un esercizio contabile"));
|
||
}
|
||
}
|
||
break;
|
||
case DLG_FINDREC:
|
||
if (e == fe_button)
|
||
{
|
||
short id;
|
||
switch (get(F_TIPO)[0])
|
||
{
|
||
case 'C': id = F_CLIENTE; break;
|
||
case 'F': id = F_FORNITORE; break;
|
||
default : id = F_SOTTOCONTO; break;
|
||
}
|
||
field(id).on_key(K_F9);
|
||
}
|
||
break;
|
||
case DLG_CONFIG:
|
||
if (e == fe_button)
|
||
_gm->grid().set_colors();
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
TQuery_mask::TQuery_mask(TGrid_mask* gm) : TAutomask("cg3600a"), _gm(gm), _last_tipo("")
|
||
{ }
|
||
|
||
void TQuery_mask::do_query()
|
||
{
|
||
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);
|
||
TMastrini_grid& gf = _gm->grid();
|
||
|
||
gf.set_contsep(get_bool(F_ST_CONTSEP));
|
||
gf.read(conto, annoes, da_data, a_data, da_caus, a_caus, provv);
|
||
gf.select(get_bool(F_END) ? gf.items() -1 : 0);
|
||
|
||
_gm->run();
|
||
}
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// TMastrini_video
|
||
///////////////////////////////////////////////////////////
|
||
|
||
bool TMastrini_video::create()
|
||
{
|
||
xvtil_statbar_set("", TRUE);
|
||
open_files(LF_RMOV, LF_MOV, LF_CAUSALI, LF_SALDI, LF_PCON, 0);
|
||
|
||
_gm = new TGrid_mask;
|
||
_qm = new TQuery_mask(_gm);
|
||
|
||
return TSkeleton_application::create();
|
||
}
|
||
|
||
bool TMastrini_video::destroy()
|
||
{
|
||
delete _qm;
|
||
delete _gm;
|
||
return TSkeleton_application::destroy();
|
||
}
|
||
|
||
void TMastrini_video::main_loop()
|
||
{
|
||
TQuery_mask& qm = *_qm;
|
||
|
||
if (argc() > 2)
|
||
{
|
||
TFilename ininame = argv(2)+2;
|
||
if (ininame.exist())
|
||
{
|
||
TConfig ini(ininame, "24");
|
||
qm.set(F_ESERCIZIO, ini.get(RMV_ANNOES));
|
||
qm.set(F_TIPO, ini.get(RMV_TIPOC));
|
||
qm.set(F_GRUPPO, ini.get(RMV_GRUPPO));
|
||
qm.set(F_CONTO, ini.get(RMV_CONTO));
|
||
qm.set(F_SOTTOCONTO, ini.get(RMV_SOTTOCONTO));
|
||
qm.set(F_CLIENTE, ini.get(RMV_SOTTOCONTO));
|
||
qm.set(F_FORNITORE, ini.get(RMV_SOTTOCONTO));
|
||
qm.send_key(K_SPACE, DLG_OK);
|
||
}
|
||
}
|
||
|
||
const TEsercizi_contabili esercizi;
|
||
TDate inies, fines;
|
||
int codesc = qm.get_int(F_ESERCIZIO);
|
||
if (!esercizi.exist(codesc))
|
||
codesc = esercizi.last();
|
||
esercizi.code2range(codesc, inies, fines);
|
||
qm.set(F_ESERCIZIO, codesc);
|
||
qm.set(F_DADATA, inies);
|
||
qm.set(F_ADATA, fines);
|
||
|
||
while (qm.run() == K_ENTER)
|
||
qm.do_query();
|
||
}
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// Main
|
||
///////////////////////////////////////////////////////////
|
||
|
||
int cg3600(int argc, char* argv[])
|
||
{
|
||
TMastrini_video mv;
|
||
mv.run(argc, argv, TR("Mastrini"));
|
||
return 0;
|
||
}
|