a cg2106.cpp (prima nota). git-svn-id: svn://10.65.10.50/trunk@5601 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			2927 lines
		
	
	
		
			75 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			2927 lines
		
	
	
		
			75 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| #include <applicat.h>
 | |
| #include <colors.h>
 | |
| #include <controls.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
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| 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;
 | |
| }   
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TBalance
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| class TBalance : public TObject
 | |
| {           
 | |
|   TImporto _saldo_ini, _progr_dare, _progr_avere, _saldo_fin;
 | |
| 
 | |
| protected:                
 | |
|   bool find(const TBill& b, int esercizio, 
 | |
|             TImporto& si, TImporto& da, TImporto& av, TImporto& sf) const;
 | |
| 
 | |
| public:
 | |
|   void read(int g, int c, long s, int esercizio, bool ignora_movap = FALSE);
 | |
|   void read(const TBill& b, int esercizio, bool ignora_movap = FALSE);
 | |
|   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 = FALSE);
 | |
|   TBalance(const TBill& b, int esercizio, bool ignora_movap = FALSE);
 | |
|   virtual ~TBalance() { }
 | |
| };
 | |
| 
 | |
| TBalance::TBalance()
 | |
| {
 | |
| }
 | |
| 
 | |
| TBalance::TBalance(int g, int c, long s, int esercizio, bool ignora_movap)
 | |
| {
 | |
|   read(g, c, s, esercizio, ignora_movap);
 | |
| }
 | |
| 
 | |
| TBalance::TBalance(const TBill& b, int esercizio, bool ignora_movap)
 | |
| {
 | |
|   read(b, esercizio, ignora_movap);
 | |
| }
 | |
| 
 | |
| bool TBalance::find(const TBill& b, int esercizio, 
 | |
|                     TImporto& si, TImporto& da, TImporto& av, TImporto& sf) const
 | |
| {   
 | |
|   CHECK(b.sottoconto() > 0L, "Sottoconto mancante");
 | |
|   
 | |
|   TLocalisamfile saldi(LF_SALDI);
 | |
|   TRectype& curr = saldi.curr();
 | |
|   curr.put(SLD_GRUPPO, b.gruppo());
 | |
|   curr.put(SLD_CONTO, b.conto());
 | |
|   curr.put(SLD_SOTTOCONTO, b.sottoconto());
 | |
|   curr.put(SLD_ANNOES, esercizio);
 | |
|   curr.put(SLD_FLSCA, FALSE);
 | |
|   const bool ok = saldi.read() == NOERR;
 | |
|   if (ok)
 | |
|   {
 | |
|     si.set(curr.get_char(SLD_FLAGSALINI), curr.get_real(SLD_SALDO));
 | |
|     da.set('D', curr.get_real(SLD_PDARE));
 | |
|     av.set('A', curr.get_real(SLD_PAVERE));
 | |
|     sf.set(curr.get_char(SLD_FLAGSALFIN), curr.get_real(SLD_SALDOFIN));
 | |
|   } 
 | |
|   else
 | |
|   {
 | |
|     si.set('D', ZERO);
 | |
|     da = av = sf = si;
 | |
|   }
 | |
|   return ok;
 | |
| }                    
 | |
| 
 | |
| 
 | |
| void TBalance::read(int gruppo, int conto, long sottoconto, int esercizio, bool ignora_movap)
 | |
| {
 | |
|   const TBill zio(gruppo, conto, sottoconto);
 | |
|   read(zio, esercizio, ignora_movap);
 | |
| }
 | |
| 
 | |
| void TBalance::read(const TBill& b, int esercizio, bool ignora_movap)
 | |
| {
 | |
|   TImporto si, sf, pd, pa;
 | |
|   
 | |
|   find(b, esercizio, si, pd, pa, sf);
 | |
|   _saldo_ini   = si;
 | |
|   _progr_dare  = pd;
 | |
|   _progr_avere = pa;
 | |
|   _saldo_fin   = sf;
 | |
| 
 | |
|   if (_saldo_ini.is_zero())
 | |
|   {
 | |
|     TLocalisamfile pcon(LF_PCON);
 | |
|     TRectype& curr = pcon.curr();
 | |
|     curr.put(PCN_GRUPPO, b.gruppo());
 | |
|     curr.put(PCN_CONTO, b.conto());
 | |
|     const int err = pcon.read();
 | |
|     CHECK(err == NOERR, "Impossibile stabilire indicatore di bilancio");
 | |
|     const int indbil = curr.get_int(PCN_INDBIL);
 | |
|     if (indbil == 1 || indbil == 2 || indbil == 5)
 | |
|     {                                                 
 | |
|       TEsercizi_contabili esercizi;
 | |
|       const int precedente = esercizi.pred(esercizio);
 | |
|       if (precedente > 0 && find(b, precedente, si, pd, pa, sf))
 | |
|       {
 | |
|         _saldo_ini = si;
 | |
|         _saldo_ini += pd;
 | |
|         _saldo_ini += pa;
 | |
|       }  
 | |
|     }  
 | |
|   }
 | |
|   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 TRelation* _rel;
 | |
|   static TLocalisamfile *_rmov;   // File principale della relazione
 | |
|   static TLocalisamfile *_mov;    // File secondario della relazione
 | |
|   
 | |
|   TBill _conto;                   // Conto del mastrino
 | |
|   int _esercizio;                 // Esercizio di riferimento (eventualmente 0)
 | |
|   TDate _da_data, _a_data;
 | |
|   TString _da_caus, _a_caus;
 | |
|   
 | |
|   real _pdare_ini, _pavere_ini;
 | |
|   real _pdare_per, _pavere_per;
 | |
|   real _pdare_fin, _pavere_fin;
 | |
| 
 | |
|   TList _riga;                    // Righe del mastrino
 | |
| 
 | |
| protected:
 | |
|   TRelation& rel() { return *_rel; }
 | |
|   TLocalisamfile& rmov() { return *_rmov; }
 | |
|   TLocalisamfile& mov() { return *_mov; }
 | |
|   
 | |
|   void position_rel(long n);
 | |
|   TRiga_mastrino& row(long n) const { return (TRiga_mastrino&)_riga.obj(n); }
 | |
|  
 | |
| public:
 | |
|   long items() const { return _riga.items(); }
 | |
| 
 | |
|   void read(const TBill& conto, 
 | |
|             int annoes, const TDate& dd, const TDate& ad,
 | |
|             const TString& dc, const TString& ac);
 | |
|   void reread();
 | |
|   
 | |
|   TRiga_mastrino& operator[](long n) const { return row(n); }
 | |
|   const TRectype& riga(long n);
 | |
|   const TRectype& testata(long n);
 | |
|   
 | |
|   long first(tipo_riga_mastrino tipo = riga_mastrino) const; 
 | |
|   long pred(long rec, tipo_riga_mastrino tipo = riga_mastrino) const;
 | |
|   long succ(long rec, tipo_riga_mastrino tipo = riga_mastrino) const;
 | |
|   long last(tipo_riga_mastrino tipo = riga_mastrino) const;
 | |
|   
 | |
|   void destroy() { _riga.destroy(); }
 | |
|   
 | |
|   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;
 | |
| TRelation* TMastrino::_rel = NULL;
 | |
| TLocalisamfile* TMastrino::_rmov = NULL;   // File principale della relazione
 | |
| TLocalisamfile* TMastrino::_mov = NULL;    // File secondario della relazione
 | |
| 
 | |
| 
 | |
| TMastrino::TMastrino()
 | |
|          : _esercizio(0)
 | |
| {          
 | |
|   if (_instances == 0L)
 | |
|   {            
 | |
|     _rel = new TRelation(LF_RMOV);
 | |
|     _rel->add(LF_MOV, "NUMREG=NUMREG");
 | |
|     _rmov = &_rel->lfile();
 | |
|     _mov = &_rel->lfile(LF_MOV);
 | |
|   }
 | |
|   _instances++;  
 | |
| }
 | |
| 
 | |
| TMastrino::~TMastrino()
 | |
| {
 | |
|   _instances--;  
 | |
|   if (_instances == 0L)
 | |
|   { 
 | |
|     delete _rel;
 | |
|     _rel = NULL;
 | |
|     _rmov = _mov = NULL;
 | |
|   }
 | |
| }
 | |
| 
 | |
| long TMastrino::succ(long rec, tipo_riga_mastrino tipo) const
 | |
| { 
 | |
|   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)
 | |
| {
 | |
|   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
 | |
|   
 | |
|   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();
 | |
|   }
 | |
|   
 | |
|   TString caption(80);
 | |
|   caption.format("Caricamento mastrino %03d.%03d.%06ld", 
 | |
|                  _conto.gruppo(), _conto.conto(), _conto.sottoconto());
 | |
|   TProgind pi(num_giorni, caption, FALSE, TRUE, 48);
 | |
|   
 | |
|   // Stima dimensione mastrino
 | |
|   _riga.choose_step(num_giorni);
 | |
|   
 | |
|   // 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);
 | |
|   _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);
 | |
|   _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;
 | |
|   
 | |
|   rmov_rec.zero();
 | |
|   conto.put(rmov_rec);
 | |
|   rmov_rec.put(RMV_DATAREG, inizio_esercizio);
 | |
| 
 | |
|   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  
 | |
|   
 | |
|   TDate ultimo_giorno;  // memorizza ultima data registrazione utilizzata
 | |
|   
 | |
|   for (int err = rel().read(_isgteq); err == NOERR; err = rel().next())
 | |
|   {
 | |
|     // Controlla di non aver superato la data limite  
 | |
|     const TDate data_reg((TDate)rmov_datareg);
 | |
|     if (data_reg > max_data_reg)
 | |
|       break;
 | |
| 
 | |
|     // Controlla che il conto sia ancora quello selezionato
 | |
|     if (_conto.sottoconto() != long(rmov_sottoconto) ||
 | |
|         _conto.conto() != int(rmov_conto) || 
 | |
|         _conto.gruppo() != int(rmov_gruppo))
 | |
|       break;
 | |
|     
 | |
| #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 i movimenti provvisori
 | |
|     const char provvis = *(const char*)mov_provvis;
 | |
|     if (provvis > ' ')  
 | |
|       continue;
 | |
|     
 | |
|     const TDate data_corrente = _esercizio <= 0 ? data_reg : (TDate)mov_datacomp;
 | |
|     if (data_corrente > _a_data)
 | |
|       continue;
 | |
|       
 | |
|     // Aggiorna la barra solo una volta al giorno
 | |
|     if (data_reg > ultimo_giorno)
 | |
|     {
 | |
|       const long giorno = data_reg - inizio_esercizio + 1;
 | |
|       pi.setstatus(giorno);
 | |
|       ultimo_giorno = data_reg;
 | |
|     }  
 | |
|                      
 | |
|     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, data_reg);  
 | |
|       _riga.append(r);
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   pi.setstatus(num_giorni);    // Raramente arriva in fondo!
 | |
| }
 | |
| 
 | |
| void TMastrino::reread()
 | |
| {
 | |
|   read(_conto, _esercizio, _da_data, _a_data, _da_caus, _a_caus);
 | |
| } 
 | |
| 
 | |
| 
 | |
| void TMastrino::position_rel(long n)
 | |
| {
 | |
|   const TRiga_mastrino& r = row(n);
 | |
|   if (rmov().recno() != r.rmov())
 | |
|     rmov().readat(r.rmov());
 | |
|   if (mov().recno() != r.mov())
 | |
|     mov().readat(r.mov());
 | |
| }
 | |
| 
 | |
| const TRectype& TMastrino::riga(long n)
 | |
| {
 | |
|   position_rel(n);
 | |
|   return rmov().curr();  
 | |
| }
 | |
| 
 | |
| const TRectype& TMastrino::testata(long n)
 | |
| {
 | |
|   position_rel(n);
 | |
|   return mov().curr();  
 | |
| }
 | |
| 
 | |
| TImporto TMastrino::saldo_iniziale() const
 | |
| {
 | |
|   TImporto s('D', _pdare_ini - _pavere_ini);
 | |
|   return s.normalize();
 | |
| }
 | |
| 
 | |
| TImporto TMastrino::saldo_finale() const
 | |
| {
 | |
|   TImporto s('D', _pdare_fin - _pavere_fin);
 | |
|   return s.normalize();
 | |
| }
 | |
| 
 | |
| TImporto TMastrino::saldo_periodo() const
 | |
| {
 | |
|   TImporto s('D', progressivo_dare_periodo() - progressivo_avere_periodo());
 | |
|   return s.normalize();
 | |
| }
 | |
| 
 | |
| bool TMastrino::expandable(long rec) const
 | |
| {   
 | |
|   bool e = FALSE;
 | |
|   if (row(rec).tipo() == riga_mastrino)
 | |
|   {
 | |
|     if (rec < items()-1)
 | |
|       e = row(rec+1).tipo() != riga_contropartita;
 | |
|     else
 | |
|       e = TRUE;  
 | |
|   }  
 | |
|   return e;
 | |
| }
 | |
| 
 | |
| // 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
 | |
|   XI_RCT rct; coord2rct(parent, x, y, dx, dy, rct);
 | |
|   rct.right -= 2*XI_FU_MULTIPLE;           // toglie scroll-bar
 | |
|  
 | |
|   // Controlla se ci sono troppe colonne fisse
 | |
|   if ((f_width+max_width)*XI_FU_MULTIPLE > rct.right)
 | |
|     fixed_columns = 1;
 | |
|     
 | |
|   XI_OBJ* itf = get_interface(parent);     
 | |
| 
 | |
|   XI_OBJ_DEF* listdef = xi_add_list_def(NULL, cid,
 | |
|                                         rct.top, rct.left, rct.bottom-rct.top,
 | |
|                                         XI_ATR_ENABLED | XI_ATR_VISIBLE,
 | |
|                                         NORMAL_COLOR, NORMAL_BACK_COLOR,     // normal
 | |
|                                         DISABLED_COLOR, DISABLED_BACK_COLOR, // disabled
 | |
|                                         FOCUS_COLOR,                         // active
 | |
|                                         0);
 | |
|                                         
 | |
|   listdef->app_data = (long)this;
 | |
|   
 | |
|   XI_LIST_DEF* l = listdef->v.list;
 | |
|   l->min_heading_height = xi_button_calc_height_font_id(xvt_default_font()) * lines_in_header;
 | |
|   l->sizable_columns    = TRUE;
 | |
|   l->movable_columns    = TRUE;
 | |
|   l->fixed_columns      = fixed_columns;
 | |
|   l->max_lines_in_cell  = lines_in_cell;
 | |
|   l->scroll_bar         = TRUE;
 | |
|   l->scroll_bar_button  = TRUE;
 | |
|   l->white_space_color  = MASK_DARK_COLOR;
 | |
|   l->rule_color         = MASK_DARK_COLOR;
 | |
|   
 | |
|   if (_read_only)
 | |
|     l->single_select = TRUE;
 | |
|   else
 | |
|     l->active_back_color = FOCUS_BACK_COLOR;
 | |
| 
 | |
|   // Definizione della prima colonna (numero di riga)
 | |
|   const long attr = XI_ATR_VISIBLE | XI_ATR_RJUST | XI_ATR_SELECTABLE;                                            
 | |
|   XI_OBJ_DEF* coldef = xi_add_column_def(listdef, FIRST_FIELD+1000-1, attr, 0, 
 | |
|                                          NUMBER_WIDTH * XI_FU_MULTIPLE, NUMBER_WIDTH , "");
 | |
|   
 | |
|   coldef->app_data = (long)this;            
 | |
|   XI_COLUMN_DEF* cd = coldef->v.column;
 | |
|   cd->heading_platform = TRUE;
 | |
|   cd->column_platform  = TRUE;
 | |
| 
 | |
|   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, &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], &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)
 | |
|           {
 | |
|              _cur_rec = rec;  // Assegno subito il record corrente
 | |
|              _grid->on_record_button(rec);
 | |
|           }  
 | |
|           else
 | |
|           {  
 | |
|             if (_read_only && rec == _cur_rec)
 | |
|             {                                    
 | |
|               const short cid = col2cid(xiev->v.select.column);
 | |
|               _grid->on_dbl_cell(rec, cid);
 | |
|             }
 | |
|             _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, &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], &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("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 << "Riga " << (*c == 'M' ? "mastrino" : "contropartita");
 | |
|     s.set_back_and_fore_color(back, fore, row++); 
 | |
|   }
 | |
| }
 | |
| 
 | |
| TColor_mask::~TColor_mask() 
 | |
| {
 | |
|   delete _sheet_mask;
 | |
|   _sheet_mask = NULL;
 | |
| }
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TMastrini_grid
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| class TMastrini_grid : public TGrid_field
 | |
| {                      
 | |
|   TMastrino _mastrino;    
 | |
|   
 | |
|   TDecoder _causali;
 | |
|   TEsercizi_contabili _esercizi;
 | |
|   
 | |
|   COLOR _mas_back, _mas_fore;
 | |
|   COLOR _con_back, _con_fore;
 | |
|   
 | |
| protected: // TGrid_field  
 | |
|   virtual bool on_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);
 | |
|   virtual void on_dbl_cell(long rec, short id);
 | |
|                 
 | |
|   void update_mask() const;
 | |
| 
 | |
| public:                                                   
 | |
|   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);
 | |
|   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 void set_imp(TMask_field& f, const TImporto& imp)
 | |
| {
 | |
|   if (!imp.is_zero())
 | |
|   {
 | |
|     TString80 str;
 | |
|     str.format("%s %c", imp.valore().string("."), 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);
 | |
|       const comp = anno != eser;         
 | |
|       cell.set_icon(comp ? ICO_CHECK_ON : ICO_CHECK_OFF);
 | |
|     }
 | |
|     break;
 | |
|   case 103:
 | |
|     if (riga.tipo() == riga_mastrino)
 | |
|     {
 | |
|       const TRectype& mov = _mastrino.testata(rec);
 | |
|       cell.set(_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& mov = _mastrino.testata(rec);
 | |
|       cell.set(mov.get(MOV_DESCR));
 | |
|       if (cell.empty())
 | |
|       {
 | |
|         const TRectype& rmov = _mastrino.riga(rec);
 | |
|         cell.set(rmov.get(RMV_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);
 | |
|       if (rmov.get_char(RMV_SEZIONE) == 'D')
 | |
|         cell = rmov.get_real(RMV_IMPORTO).string(".");
 | |
|     }    
 | |
|     break;
 | |
|   case 106:    
 | |
|     {
 | |
|       const TRectype& rmov = _mastrino.riga(rec);
 | |
|       if (rmov.get_char(RMV_SEZIONE) == 'A')
 | |
|         cell = rmov.get_real(RMV_IMPORTO).string(".");
 | |
|     }    
 | |
|     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 = rmov.get_real(RMV_IMPORTO).string(".");
 | |
|       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 = imp.valore().string(".");
 | |
|         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 (_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, "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("%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)
 | |
| {
 | |
|   begin_wait();
 | |
|     
 | |
|   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("Si desidera aggiornare il mastrino?"))
 | |
|       reread();
 | |
|   }                
 | |
| 
 | |
|   end_wait();
 | |
| }
 | |
| 
 | |
| // 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)
 | |
| {
 | |
|   destroy();
 | |
|   _mastrino.read(conto, annoes, dd, ad, dc, ac);
 | |
|   update();    
 | |
|   update_mask();
 | |
| }                          
 | |
| 
 | |
| void TMastrini_grid::reread()
 | |
| {
 | |
|   destroy();
 | |
|   _mastrino.reread();
 | |
|   update();
 | |
|   update_mask();
 | |
| }
 | |
| 
 | |
| void TMastrini_grid::update_mask() const
 | |
| {
 | |
|   TMask& gm = mask();    
 | |
|   
 | |
|   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;
 | |
|   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("Annulla", "Ripristina", "Salva", 
 | |
|                                        "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("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("E' necessario specificare almeno una data.");
 | |
|       return TRUE;  
 | |
|     }
 | |
| 
 | |
|     const TDate d = f.get();
 | |
|     const int esercizio = esercizi.date2esc(d);
 | |
|     if (codice_esercizio != 0)
 | |
|     {
 | |
|       if (esercizio != codice_esercizio)
 | |
|         ok = error_box("La data deve appartenere all'esercizio %d", codice_esercizio);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       if (esercizio == 0)
 | |
|         ok = error_box("La data deve appartenere ad un esercizio contabile");
 | |
|     }    
 | |
|   }
 | |
|   return ok;
 | |
| }
 | |
| 
 | |
| bool TQuery_mask::find_handler(TMask_field& f, KEY k)
 | |
| {
 | |
|   if (k == K_SPACE)
 | |
|   {
 | |
|     const TQuery_mask& qm = (const TQuery_mask&)f.mask();
 | |
|     short id;
 | |
|     switch (qm.get(F_TIPO)[0])
 | |
|     {
 | |
|     case 'C': id = F_CLIENTE;    break;
 | |
|     case 'F': id = F_FORNITORE;  break;
 | |
|     default : id = F_SOTTOCONTO; break;
 | |
|     }
 | |
|     qm.field(id).on_key(K_F9);
 | |
|   }
 | |
|   return TRUE;
 | |
| }
 | |
|    
 | |
| void TQuery_mask::do_query(TGrid_mask& gm)
 | |
| { 
 | |
|   const char t = get(F_TIPO)[0];
 | |
|   const int  g = get_int(F_GRUPPO);
 | |
|   const int  c = get_int(F_CONTO);
 | |
|   const long s = get_long((t <= ' ') ? F_SOTTOCONTO : ((t == 'C') ? F_CLIENTE : F_FORNITORE));
 | |
|   const TBill conto(g, c, s, t);
 | |
| 
 | |
|   const int annoes = get_int(F_ESERCIZIO);
 | |
|   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);
 | |
| 
 | |
|   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);
 | |
|         
 | |
|   gm.run();
 | |
| } 
 | |
|    
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TMastrini_video
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| class TMastrini_video : public TApplication
 | |
| {
 | |
|   TQuery_mask* _qm;
 | |
|   TGrid_mask* _gm;
 | |
|   
 | |
|   TArray _file;
 | |
| 
 | |
| protected:
 | |
|   virtual bool create();
 | |
|   virtual bool destroy();
 | |
|   virtual bool menu(MENU_TAG);
 | |
|   virtual void on_firm_change();
 | |
|   
 | |
| public:
 | |
|   void open_files(int logicnum, ...);
 | |
| };
 | |
| 
 | |
| void TMastrini_video::open_files(int logicnum, ...)  
 | |
| {  
 | |
|   va_list marker;
 | |
|   va_start(marker, logicnum);
 | |
|   while (logicnum > 0)
 | |
|   {                                
 | |
|     if (_file.objptr(logicnum))
 | |
|       NFCHECK("File gia' aperto: %d", logicnum);
 | |
|     else  
 | |
|       _file.add(new TLocalisamfile(logicnum), logicnum);
 | |
|     logicnum = va_arg(marker, int);
 | |
|   }  
 | |
|   va_end(marker);
 | |
| }
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| void TMastrini_video::on_firm_change()
 | |
| {
 | |
|   TEsercizi_contabili::update();
 | |
| }
 | |
| 
 | |
| bool TMastrini_video::menu(MENU_TAG mt)
 | |
| {                    
 | |
|   if (mt == BAR_ITEM(1))
 | |
|   {
 | |
|     TQuery_mask& qm = *_qm;
 | |
|     
 | |
|     const TEsercizi_contabili esercizi;
 | |
|     const int codice_ultimo_esercizio = esercizi.last();
 | |
|     if (codice_ultimo_esercizio > 0)
 | |
|     {
 | |
|       const TEsercizio& esercizio = esercizi.esercizio(codice_ultimo_esercizio);
 | |
|       qm.set(F_ESERCIZIO, codice_ultimo_esercizio);
 | |
|       qm.set(F_DADATA, esercizio.inizio());
 | |
|       qm.set(F_ADATA, esercizio.fine());
 | |
|     }
 | |
|      
 | |
|     KEY key = 0;
 | |
|     while (key != K_QUIT)
 | |
|     {
 | |
|       qm.reset(F_SOTTOCONTO);  // Azzera sottoconto
 | |
|       qm.reset(F_CLIENTE);     // Azzera cliente
 | |
|       qm.reset(F_FORNITORE);   // Azzera fornitore
 | |
|       qm.reset(-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, "Mastrini");
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| 
 |