#include <colmask.h>
#include <dongle.h>
#include <execp.h>
#include <multirel.h>
#include <postman.h>
#include <recset.h>
#include <smartcard.h>
#include <treectrl.h>
#include <toolfld.h>
#include <urldefid.h>
#include <utility.h>

#include "../db/dblib.h" 
#include "velib04.h"
#include "vepriv.h"
#include "verig.h"

#include "ve0100.h"
#include "ve0100b1.h"
#include "ve0100c.h"
#include "ve0100o.h"
#include "veuml.h"
#include "veuml1.h"
#include "veini.h"

#include "../cg/cfban.h" 
#include "../ca/cfcms.h"
#include "condv.h"
#include "rcondv.h"
#include "sconti.h"

#include <occas.h> 

///////////////////////////////////////////////////////////
// TOriginal_row_mask
///////////////////////////////////////////////////////////

class TOriginal_row_mask : public TAutomask
{
protected:
	virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
	virtual bool on_key(KEY key);

public:
	TOriginal_row_mask() : TAutomask("ve0100c") { }
};

bool TOriginal_row_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{	return true; }

bool TOriginal_row_mask::on_key(KEY key)
{
	if (key == K_SHIFT + K_F12)
		enable(-1);
	return TAutomask::on_key(key);
}

///////////////////////////////////////////////////////////
// TColor_rule
///////////////////////////////////////////////////////////


TColor_rule::TColor_rule(const char* desc, const char* expr, TTypeexp type, COLOR back, COLOR fore)
           : TExpr_documento(expr, type), _back(back), _fore(fore), _def_back(back), _def_fore(fore)
{
  _desc = dictionary_translate(desc);
  _key = desc; _key.trim(); _key.strip_double_spaces();
  _key.replace(' ', '_');
}

///////////////////////////////////////////////////////////
// Gestione campi CONAI su maschera righe
///////////////////////////////////////////////////////////

short conai_peso_id(TCONAI_class type)
{ return type >= CONAI_FIRST && type <= CONAI_LAST ? FR_PUNACC + 2 * type : DLG_NULL; }

short conai_sottocat_id(TCONAI_class type)
{ return type >= CONAI_FIRST && type <= CONAI_LAST ? FR_SCAACC + 2*type : DLG_NULL; }

TCONAI_class conai_id2class(short id)
{ 
  const TCONAI_class t = TCONAI_class((id-FR_SCAACC) / 2);
  return t >= CONAI_FIRST && t <= CONAI_LAST ? t : CONAI_NONE;
}

///////////////////////////////////////////////////////////
// TDocumento_mask
///////////////////////////////////////////////////////////

TDocumento_mask::TDocumento_mask(const char* td)
							 : TVariable_mask(), _progs_page(-1), _condv(NULL), _smartcard(NULL),
								 _cms_start(-1), _cms_end(-1), _cms_start_sh(-1), _cms_end_sh(-1),
								 _cdc_start(-1), _cdc_end(-1), _cdc_start_sh(-1), _cdc_end_sh(-1)
{
	CHECK(td && *td && strlen(td) <= 4, "TDocumento_mask(TipoDocumento) not (MaskName)");
	{
		TMagazzini m;
		_ges_mag = m.gestmag();
		_ges_dep = m.gestdep();
		_std_mag = m.standardmag();
		_std_dep = m.standarddep();
	}
	TDocumento& d = doc();
	d.set_tipo(td);
	const TString16 mname = d.tipo().mask_name();
	read_mask(mname, 0, MAX_PAGES);

	_sheet = &sfield(F_SHEET);			
  //_sheet->set_handler( ss_handler );
	set_field_handler(F_SHEET, ss_handler );
	_sheet->set_notify( ss_notify );
	_sheet->set_append(FALSE);
	
	TList_field& listbox = lfield(F_LBTIPORIGA);
	
	const TTipo_documento& tdoc = d.tipo();
	const TToken_string& keys = tdoc.keys_descrs().row(0);
	const TToken_string& desc = tdoc.keys_descrs().row(1);
	listbox.replace_items(keys, desc);

	// Controlla se deve generare la pagina di analitica
  _ges_ca = ca_config().get_int("Authorizations") != 0;
  if (_ges_ca)
    insert_anal_page();

	configura_sheet(*_sheet);
	
	((TVariable_sheet_field*)_sheet)->set_getmask( ss_getmask );
	if (_doc.tipo().clifo_optional()) 
	{
		field(F_CODCF).check_type(CHECK_NORMAL);
		field(F_RAGSOC).check_type(CHECK_NORMAL);
	}
	
	int i;
	for (i = fields() - 1; i >= 0; i--)
	{
		TMask_field& f = fld(i);
    if (f.is_operable())
			f.set_handler(universal_handler);
	}
	
	set_field_handler( F_OCCASEDIT, occas_handler );
	set_field_handler( F_CODCF, clifo_handler );
	set_field_handler( F_CODPAG, condpag_hndl );
	set_field_handler( F_DATAINSC, condpag_hndl );
	set_field_handler( F_CODNOTE, note_hndl );
	set_field_handler( F_DATADOC, data_hndl );
	set_field_handler( F_CODLIST, codlist_handler ); 
	set_field_handler( F_CODCONT, codcont_handler ); 
	set_field_handler( F_CODCAMP, codcamp_handler ); 
	set_field_handler( F_CODVAL, codval_handler );
	set_field_handler( F_CODVAL1, codval_handler );
	set_field_handler( F_NUMDOCRIF, datadocrif_handler);
	set_field_handler( F_DATADOCRIF, datadocrif_handler);
	set_field_handler( F_LIQDIFF, liqdiff_handler);
	
  set_handler( DLG_ELABORA, elabora_handler );			
	set_handler( DLG_PRINT, print_handler );
  set_handler( DLG_PREVIEW, print_handler );
  set_handler( DLG_EMAIL, print_handler );
  set_handler( DLG_CONFERMA, confirm_handler );
	set_handler( DLG_SORT, sort_row_handler );
  set_handler( DLG_BARCODE, barcode_handler );
  	
	const TPointer_array& handlers = tdoc.handlers();
	FOR_EACH_ARRAY_ITEM(handlers, r, riga)
		user_set_handler( r, (int)riga);

	_livelli_giac = new TCodgiac_livelli;

	for (i = 4; i > 0; i--)
	{
		const short pos = _sheet->cid2index(FR_LIV1 + i -1);
		if (_livelli_giac->enabled(i))
		{
			const TString& header = _livelli_giac->name(i);
			const int len = header.len() + 1;
			const int f_len = _livelli_giac->code_length(i);
			_sheet->set_column_header(pos, header);
			_sheet->set_column_width(pos, (len > f_len ? len : f_len) * 8);
		}
		else
		{
			_sheet->sheet_mask().hide(FR_LIV1 + i -1);
			_sheet->delete_column(pos);
		}
	}

// configurazione campi

	TConfig cfg(CONFIG_DITTA, "ve");
	const bool gesval	 = cfg.get_bool("GESVAL");
	const bool gescambi = cfg.get_bool("GESVALAC");

	if (gesval)
	{
		//const bool enable_controeuro	 =	cfg.get_bool("CONTROEURO");
    //enable(F_CONTROEURO, enable_controeuro);

    show(F_CODVAL, !gescambi);
		show(F_DATACAMBIO, !gescambi);
		show(F_NOMEVAL, !gescambi);
		show(F_CODVAL1, gescambi);
		show(F_DATACAMBIO1, gescambi);
		show(F_NOMEVAL1, gescambi);
		show(F_CAMBIO);
	}
	else
	{
		disable(F_CODVAL);
		disable(F_DATACAMBIO);
		// disable(F_CONTROEURO);
		disable(F_NOMEVAL);
		hide(F_CODVAL1);
		hide(F_DATACAMBIO1);
		hide(F_NOMEVAL1);
		disable(F_CAMBIO);
	}

	const bool geslin	=	cfg.get_bool("GESLIN");

	enable(F_CODLIN, geslin);
	enable(F_DESLIN, geslin);

	const bool geslis =	cfg.get_bool("GES", NULL, 1);

	show(F_CODLIST, geslis);
	show(F_DESLIST, geslis);
	enable(F_CODLIST, geslis);
	enable(F_DESLIST, geslis);
	
	hide(203);
	disable(203);

	hide(204);
	disable(204);

  for (int n = 0; n < 2; n++)
  {
    const short id = n == 0 ? F_CODNOTE : F_NOTECLI;
    if (id2pos(id) >= 0) // Alcuni profili NON hanno le note
    {
      TBrowse* nb = efield(id).browse();
      if (nb != NULL)
      {
  		  nb->set_output_fields(TOSTRING(F_CODNOTE));
        nb->set_output_field_names("CODTAB");
      }
    }
    else
      break;
  }

	if  (cfg.get_bool("GESLISCV") && id2pos(F_CODLIST) > 0)
	{
		TBrowse * b = efield(F_CODLIST).browse();
		if  (b != NULL)
		{
			b->remove_input_field();
			b->add_input_field("\"L\"", RCONDV_TIPO);
			b->add_input_field(TOSTRING(F_CATVEN), DOC_CATVEN, -1, true);
			b->add_input_field("\"\"", DOC_TIPOCF);
			b->add_input_field("\"\"", DOC_CODCF);
			b->add_input_field(TOSTRING(F_CODLIST), RCONDV_COD);
		}
    if (id2pos(F_DESLIST) > 0)
    {
		  b = efield(F_DESLIST).browse();
		  if  (b != NULL)
		  {
			  TString filter;
			  filter << DOC_CATVEN << "==#" << F_CATVEN;
			  b->set_filter(filter);
      }
		}
	}

	const bool gescontr = cfg.get_bool("GES", "ve", 2);

	show(F_CODCONT, gescontr);
	show(F_DESCONT, gescontr);
	enable(F_CODCONT, gescontr);
	enable(F_DESCONT, gescontr);
	if  (cfg.get_bool("GESCONCC") && id2pos(F_CODCONT) > 0)
	{
		TBrowse * b = efield(F_CODCONT).browse();
		if  (b != NULL)
		{
			b->remove_input_field();
			b->add_input_field("\"C\"", RCONDV_TIPO);
			b->add_input_field("\"\"", RCONDV_CATVEN);
			b->add_input_field(TOSTRING(F_TIPOCF), RCONDV_TIPOCF, -1, true);
			b->add_input_field(TOSTRING(F_CODCF), RCONDV_CODCF, -1, true);
			b->add_input_field(TOSTRING(F_CODCONT), RCONDV_COD);
		}
    if (id2pos(F_DESCONT) > 0)
    {
		  b = efield(F_DESCONT).browse();
		  if  (b != NULL)
		  {
			  TString filter;
			  filter << "(" << DOC_TIPOCF << "==#" << F_TIPOCF << ")&&(" << DOC_CODCF << "==#" << F_CODCF << ")";
			  b->set_filter(filter);
		  }
    }
	}

	if (main_app().has_module(CTAUT))
	{
		if (_ges_ca && id2pos(F_CUP) > 0)
		{
			TBrowse * bp = efield(F_CUP).browse();
			TRelation * rp = new TRelation(LF_CFCMS);

			rp->add("%CUP", "CODTAB==" CFCMS_CUP);
			rp->add(LF_CLIFO, "TIPOCF==TIPOCF|CODCF==CODCF");
			bp->set_cursor(new TCursor(rp, "", 2));
			bp->set_filter("TIPOCF==\"C\"");
			bp->remove_input_field();
			bp->add_input_field(TOSTRING(F_CMSH), CFCMS_COMMESSA, -1, true);
			bp->add_input_field(TOSTRING(F_CUP), CFCMS_CUP);
			bp->remove_display_field();
			bp->add_display_field("Codice CUP@15", CFCMS_CUP);
			bp->add_display_field("Descrizione@50", "%CUP->S0");
			bp->add_display_field("Codice Cliente", CFCMS_CODCF);
			bp->add_display_field("Ragione Sociale@50", TOSTRING(LF_CLIFO) "->" CLI_RAGSOC);
			bp->remove_output_field();
			bp->add_output_field(TOSTRING(F_CUP), CFCMS_CUP);
			bp->add_output_field(TOSTRING(F_CIG), CFCMS_CIG);
			bp->add_output_field(TOSTRING(F_DESCRCUP), "%CUP->S0");

			TBrowse * bpd = efield(F_DESCRCUP).browse();
			
			bpd->set_cursor(new TSorted_cursor(rp, CFCMS_COMMESSA "|%CUP->S0"));
			bpd->set_filter("TIPOCF==\"C\"");
			bpd->remove_input_field();
			bpd->add_input_field(TOSTRING(F_CMSH), CFCMS_COMMESSA, -1, true);
			bpd->add_input_field(TOSTRING(F_DESCRCUP), "%CUP->S0");
			bpd->remove_display_field();
			bpd->add_display_field("Descrizione@50", "%CUP->S0");
			bpd->add_display_field("Codice CUP@15", CFCMS_CUP);
			bpd->add_display_field("Codice Cliente", CFCMS_CODCF);
			bpd->add_display_field("Ragione Sociale@50", TOSTRING(LF_CLIFO) "->" CLI_RAGSOC);
			bpd->copy_output(bp);

			TBrowse * bg = efield(F_CIG).browse();
			TRelation * rg = new TRelation(LF_CFCMS);

			rg->add("%CIG", "CODTAB==" CFCMS_CIG);
			rg->add(LF_CLIFO, "TIPOCF==TIPOCF|CODCF==CODCF");
			bg->set_cursor(new TCursor(rg, "", 3));
			bg->set_filter("TIPOCF==\"C\"");
			bg->remove_input_field();
			bg->add_input_field(TOSTRING(F_CMSH), CFCMS_COMMESSA, -1, true);
			bg->add_input_field(TOSTRING(F_CIG), CFCMS_CIG);
			bg->remove_display_field();
			bg->add_display_field("Codice CIG@15", CFCMS_CIG);
			bg->add_display_field("Descrizione@50", "%CIG->S0");
			bg->add_display_field("Codice Cliente", CFCMS_CODCF);
			bg->add_display_field("Ragione Sociale@50", TOSTRING(LF_CLIFO) "->" CLI_RAGSOC);
			bg->remove_output_field();
			bg->add_output_field(TOSTRING(F_CIG), CFCMS_CIG);
			bg->add_output_field(TOSTRING(F_CUP), CFCMS_CUP);
			bg->add_output_field(TOSTRING(F_DESCRCIG), "%CIG->S0");

			TBrowse * bgd = efield(F_DESCRCIG).browse();
			
			bgd->set_cursor(new TSorted_cursor(rg, CFCMS_COMMESSA "|%CIG->S0"));
			bgd->set_filter("TIPOCF==\"C\"");
			bgd->remove_input_field();
			bgd->add_input_field(TOSTRING(F_CMSH), CFCMS_COMMESSA, -1, true);
			bgd->add_input_field(TOSTRING(F_DESCRCIG), "%CIG->S0");
			bgd->remove_display_field();
			bgd->add_display_field("Descrizione@50", "%CIG->S0");
			bgd->add_display_field("Codice CIG@15", CFCMS_CIG);
			bgd->add_display_field("Codice Cliente", CFCMS_CODCF);
			bgd->add_display_field("Ragione Sociale@50", TOSTRING(LF_CLIFO) "->" CLI_RAGSOC);
			bgd->copy_output(bg);
		}
	}
	else
	{
		hide(F_CUP);
		hide(F_DESCRCUP);
		hide(F_CIG);
		hide(F_DESCRCIG);
	}

	const bool gesoff				= cfg.get_bool("GES", "ve", 3);
	enable(F_CODCAMP, gesoff);
 	enable(F_DESCAMP, gesoff);
	const bool gessco				= cfg.get_char("GESSCO") != 'N';
	enable(F_SCONTOPERC, gessco);

	const bool gesage				= cfg.get_bool("GESAGE");
	enable(F_CODAG, gesage);
	enable(F_DESAG, gesage);
	enable(F_CODAGVIS, gesage);
	enable(F_DESAGVIS, gesage);

	const bool has_movmag = dongle().active(MGAUT) && _doc.tipo().mov_mag();
	int pos = id2pos(F_CAUSMAG);
	if (pos >= 0)
		fld(pos).show(has_movmag);
	pos = id2pos(F_DESCRMAG);
	if (pos >= 0)
		fld(pos).show(has_movmag);
	pos = id2pos(F_CAUSMAGC);
	if (pos >= 0)
		fld(pos).show(has_movmag);
	pos = id2pos(F_DESCRMAGC);
	if (pos >= 0)
		fld(pos).show(has_movmag);
	pos = id2pos(F_CURGIAC);
	if (pos >= 0)
		fld(pos).show(has_movmag);
	pos = id2pos(F_CURDISP);
	if (pos >= 0)
		fld(pos).show(has_movmag);

  FOR_EACH_MASK_FIELD((*this), j, f)
	{	
		if (f->dlg() > BASE_PIEDE)
			_calculated_pages.set(f->page());
	}

  TFilename pn;	d.tipo().profile_name(pn);
  TConfig prof(pn, "Colors");
	prof.write_protect(true);

  COLOR back = prof.get_color("BgCol", NULL, 0, COLOR_YELLOW); // FOCUS_BACK_COLOR
  COLOR fore = prof.get_color("FgCol", NULL, 0, COLOR_BLACK);  // FOCUS_COLOR
	color_rules().add(new TColor_rule("Righe collegate a documento", "", _numexpr, back, fore));

	for (int i = 1; ; i++)
	{
		const TString& name = prof.get("RuleName", NULL, i);
		if (name.full())
		{
			const TString& expr = prof.get("Rule", NULL, i);
      const TTypeexp type = prof.get_char("RuleType", NULL, i, 'N') == 'S' ? _strexpr : _numexpr ;
			back = prof.get_color("BgCol", NULL, i, NORMAL_BACK_COLOR);
			fore = prof.get_color("FgCol", NULL, i, NORMAL_COLOR);
			color_rules().add(new TColor_rule(name, expr, type, back, fore));
		}
		else 
			break;
	}
	_sh_y = prof.get_int("SHEET_LINE", "MAIN");

  // Legge i colori personalizzati dal .ini gestito dalla TSelect_color_mask
  TString tmp; tmp << doc().tipo().mask_name() << "_0"; tmp.lower();
	TConfig conf(CONFIG_GUI, tmp);
 	conf.write_protect();
	FOR_EACH_ARRAY_ITEM(color_rules(), j, o)
	{
		TColor_rule& c = *(TColor_rule*)o;
    tmp = c.key();
  	COLOR fore = conf.get_color(tmp);
		tmp << "_Bg";
	  COLOR back = conf.get_color(tmp);
		if (back != fore)
			c.set_colors(back, fore);
	}

  if (gestione_note_per_articolo())
    set_handler(F_NAR, nar_handler);
}

TDocumento_mask::~TDocumento_mask()
{
	if (_condv)
		delete _condv;
	if (_livelli_giac)
		delete _livelli_giac;
	if (_smartcard)
		delete _smartcard;
}

int TDocumento_mask::insert_anal_fields(TMask& m, int page, int lf, int& y,
																				short& dlg, short& dlgd, bool required)
{
	const int h = ca_create_fields(m, page, lf, 2, y, dlg, dlgd);

	const bool main_mask = m.id2pos(F_SHEET) > 0;

	for (int i = 0; i < h; i++)
	{
		TEdit_field& fld = m.efield(dlg+i);
		int logic = lf;
		if (logic == LF_FASI)
		{
			const TMultilevel_code_info& fasinfo = ca_multilevel_code_info(LF_FASI);
			if (fasinfo.parent() != 0)
			{
				const TMultilevel_code_info& parinfo = ca_multilevel_code_info(fasinfo.parent());
				if (i < parinfo.levels())
					logic = fasinfo.parent();
			}
		}

		const char* fieldname = NULL;
		switch(logic)
		{
		case LF_COMMESSE: fieldname = DOC_CODCMS; break;
		case LF_FASI		: fieldname = DOC_FASCMS; break;
		default				  : fieldname = DOC_CODCOSTO; break;
		}
		TFieldref* f = (TFieldref*)fld.field();
		f->set_name(fieldname);
		
		fld.check_type(required ? CHECK_REQUIRED : CHECK_NORMAL);

		TEdit_field& dfld = m.efield(dlgd+i);
		dfld.set_field(EMPTY_STRING); // Toglie campi che fan saltare gli output!

		if (main_mask)
		{
			TSheet_field& sf = sfield(F_SHEET);
			const TFixed_string head = fld.prompt();
			const int colid = FR_CDC1+(fld.dlg()-F_CDC1);
			sf.set_column_header(colid, head);
			if (fld.size() > head.len())
				sf.set_column_width(colid, fld.size()*8); // XI_FU_MULTIPLE

			TMask& sm = sf.sheet_mask();
			TString80 str; str << *fld.field();
			sm.efield(colid).set_field(str);		 // Ricopia il campo nella maschera di riga per poterlo salvare!
		}
	}

	y += h+1;
	dlg += h; dlgd += h;
	return h;
}

void TDocumento_mask::insert_anal_page()
{
	if (id2pos(F_CDC1) >= 0)
		return;
	int newpage = win2page(_sheet->parent());
	if (newpage == 0)
		newpage++;
	create_page("Analitica", newpage);						 // Inserisce una pagina vuota con un titolo a caso
  
	add_groupbox(DLG_NULL, newpage, "", 1, 0, 78, 6);
	add_string(DLG_NULL, newpage, TR("Cod. num.	"), 2, 1, 4, "D").set_group(2);
	add_string(DLG_NULL, newpage, "", 24, 1, 50, "D").set_group(3);
	add_string(DLG_NULL, newpage, TR("Tipo doc.	"), 2, 2, 4, "D").set_group(4);
	add_string(DLG_NULL, newpage, "", 24, 2, 50, "D").set_group(5);
	add_number(DLG_NULL, newpage, TR("Esercizio	"), 2, 3, 4, "D").set_group(9);
	add_number(DLG_NULL, newpage, TR("Numero doc. "), 24, 3, 6, "D").set_group(6);
	add_date(DLG_NULL, newpage, TR("Data "), 46, 3, "D").set_group(7);
	add_string(DLG_NULL, newpage, TR("Stato "), 67, 3, 1, "D").set_group(8);
	add_number(DLG_NULL, newpage, TR("Cliente		"), 2, 4, 6, "D").set_group(10);
	add_string(DLG_NULL, newpage, "", 24, 4, 50, "D").set_group(11);

	add_groupbox(DLG_NULL, newpage, TR("Contabilit� Analitica"), 1, 6, 78, 14);
	
	const TMultilevel_code_info& fasinfo = ca_multilevel_code_info(LF_FASI);
	const bool use_fsc = fasinfo.levels() > 0;
	TConfig& ini = ca_config();
	const bool fsc_req = use_fsc && ini.get_bool("FscRequired");

	int y = 7;
	short dlg = F_CDC1; // id del primo campo da generare
	short dlgd = F_DESCDC1;

	for (int i = 0; i < 2; i++)
	{
		const TString& level = ini.get("Level", NULL, i+1);	// Legge il livello 1 o 2
		if (level == "CDC")																	// Crea centro di costo 
		{
			_cdc_start = dlg;
			_cdc_end = dlg + ca_multilevel_code_info(LF_CDC).levels()-1;
			if (use_fsc && fasinfo.parent() == LF_CDC)
				insert_anal_fields(*this, newpage, LF_FASI, y, dlg, dlgd, fsc_req && doc().tipo().head_ca_required());
			else
			{
				const bool cdc_req = ini.get_bool("CdcRequired");
				insert_anal_fields(*this, newpage, LF_CDC, y, dlg, dlgd, cdc_req && doc().tipo().head_ca_required());
			}
		} else
		if (level == "CMS")																	 // Crea commessa
		{
		  _cms_start = dlg;
			_cms_end = dlg + ca_multilevel_code_info(LF_COMMESSE).levels()-1;
			if (use_fsc && fasinfo.parent() == LF_COMMESSE)
				insert_anal_fields(*this, newpage, LF_FASI, y, dlg, dlgd, fsc_req && doc().tipo().head_ca_required());
			else
			{
				const bool cms_req = ini.get_bool("CmsRequired");

				insert_anal_fields(*this, newpage, LF_COMMESSE, y, dlg, dlgd, cms_req && doc().tipo().head_ca_required());
			}
		}
	}
  if (_cms_start > 0)
    set_field_handler(_cms_end, codcms_handler);

	if (use_fsc && fasinfo.parent() <= 0)
		insert_anal_fields(*this, newpage, LF_FASI, y, dlg, dlgd, fsc_req && doc().tipo().head_ca_required());

  //aggiunge campi per date di competenza (inizio e fine)
  add_groupbox(DLG_NULL, newpage, TR("Date di competenza"), 1, 20, 78, 3);
  const TFixed_string f_datacomp = DOC_DATACOMP;
  add_date(F_DATACOMP, newpage, "Inizio ", 2, 21).set_field(f_datacomp);
  const TFixed_string f_datafcomp = DOC_DATAFCOMP;
  add_date(F_DATAFCOMP, newpage, "Fine ", 25, 21).set_field(f_datafcomp);
  set_field_handler(F_DATACOMP, datacomp_handler);    //gestore del campo inizio competenza..
  set_field_handler(F_DATAFCOMP, datafcomp_handler);  //..e della fine competenza
}

void TDocumento_mask::configura_sheet(TSheet_field& sheet)
{
	TBit_array to_delete(MAX_COLUMNS);
	to_delete.set();
	const TTipo_documento& tdoc = _doc.tipo();
	const TString_array& sheet_columns = tdoc.sheet_columns();
	const int ncols = sheet_columns.items();

	TToken_string colonne;
	int i;
	
	colonne = "0";
	for (i = 0; i < ncols; i ++ )
	{
		TToken_string& sheet_col = (TToken_string&)sheet_columns.row(i);
		const int field_id = sheet_col.get_int(0);
		const int coltomove = sheet.cid2index(field_id);
		to_delete.reset(coltomove);

		const TString80 descr(sheet_col.get(1));
		if (descr.not_empty() )
			sheet.set_column_header( field_id, descr);

		const int size = sheet_col.get_int(2) * 8; // XI_FU_MULTIPLE
		if (size != 0)
			sheet.set_column_width( field_id, size);
		 
		if (field_id != FR_LORDO)
			colonne.add(field_id);
		if (field_id == FR_CODIVA && tdoc.is_costo())
		{
			const int col = sheet.cid2index(FR_TIPODET);

			to_delete.reset(col);
			colonne.add(col);
		}
	}
	
	to_delete.set(0L);
	to_delete.reset(1);

	FOR_EACH_CONAI_CLASS(ct)
	{
		const short posc = conai_sottocat_id(ct);
		const short posp = conai_peso_id(ct);
		const int colc = sheet.cid2index(posc);
		const int colp = sheet.cid2index(posp);

		if (conai_configured_class(ct))
		{
			to_delete.reset(colc);
			if (colonne.find(format("%d", posc)) < 0)
				colonne.add(posc);
			to_delete.reset(colp);
			if (colonne.find(format("%d", posp)) < 0)
				colonne.add(posp);
		}
		else
		{
			to_delete.set(colc);
			int p = colonne.find(format("%d", posc));

			if (p > 0)
				p--;
			if (p >= 0)
			{
				int p1 = p;
				while (isdigit(colonne[p1]))
					p1++;
				if (colonne[p1] == '|')
					p1++;
				else
					if (colonne[p] == '|')
						p--;
				const TString c(colonne.mid(p1));
				colonne.cut(p);
				colonne << c;
			}

			to_delete.set(colp);
			p = colonne.find(format("%d", posp));

			if (p > 0)
				p--;
			if (p >= 0)
			{
				int p1 = p;
				while (isdigit(colonne[p1]))
					p1++;
				if (colonne[p1] == '|')
					p1++;
				else
					if (colonne[p] == '|')
						p--;
				const TString c(colonne.mid(p1));
				colonne.cut(p);
				colonne << c;
			}
		}
	}

	if (!to_delete[sheet.cid2index(FR_CODDEP)])
		sheet.enable_column(FR_CODDEP, _ges_dep && _ges_mag);
	if (!to_delete[sheet.cid2index(FR_CODMAG)])
		sheet.enable_column(FR_CODMAG, _ges_mag);
	if (!to_delete[sheet.cid2index(FR_CODDEPC)])
		sheet.enable_column(FR_CODDEPC, _ges_dep && _ges_mag);
	if (!to_delete[sheet.cid2index(FR_CODMAGC)])
		sheet.enable_column(FR_CODMAGC, _ges_mag);
	to_delete.set(sheet.cid2index(FR_CODARTMAG));
	to_delete.set(sheet.cid2index(FR_CHECKED));

	if (_ges_ca)
	{
		const TMultilevel_code_info& cdc = ca_multilevel_code_info(LF_CDC);
		const TMultilevel_code_info& cms = ca_multilevel_code_info(LF_COMMESSE);
		const TMultilevel_code_info& fas = ca_multilevel_code_info(LF_FASI);
		const int levels = cdc.levels() + cms.levels() + fas.levels();
		for (short cid = FR_CDC1; cid <= FR_CDC12; cid++)
		{
			const int level = cid-FR_CDC1;
			to_delete.set(sheet.cid2index(cid), level >= levels);
			if (level < levels)
				colonne.add(cid);
		}
	}

	for ( i = MAX_COLUMNS - 1; i >= 0; i-- )
	{
		if( to_delete[i] )
		{
			sheet.enable_column( i + FIRST_FIELD, false);
			sheet.delete_column( i + FIRST_FIELD);
		}
	}

	if (!sheet.user_saved_columns_order())
		sheet.set_columns_order(&colonne);
}

TCond_vendita& TDocumento_mask::condv() const
{
	if (_condv == NULL)
	{
		TDocumento_mask* myself = (TDocumento_mask*)this;
		myself->_condv = new TCond_vendita(myself, NULL);
	}
	return *_condv;
}

void TDocumento_mask::update_progs(bool stop_run)
{
	static bool updating_progs = false;

	if (!updating_progs)
	{
		updating_progs = true;
		TWait_cursor hourglass;
		const int page = curr_page();
		const int last_field = fields() - 1;

		for (int f = last_field; f >= 0; f--)
		{
			const TMask_field & mf = fld(f);
			const int id = mf.dlg();
			const int field_page = mf.page();

			if ((page == field_page || stop_run) && id > BASE_PIEDE)
			{
				const TFieldref* recfld = mf.field();
				if (recfld != NULL)
				{
					const TString & name = recfld->name();
					const TString& val = doc().get(name);
					set(id, val, true);
				}
			}
		}
		updating_progs = false;
	}
}

void TDocumento_mask::next_page(int p)
{		 
	TMask::next_page(p);

	if (is_calculated_page(curr_page()))
		update_progs();
}

void TDocumento_mask::start_run()
{														 
	TSmart_card * s = smartcard();

	if (s != NULL)
	{
		if (edit_mode() && s->with_card(*this))
			disable(DLG_SAVEREC);
		if (s->card_connected())
		{
			disable(F_CODCF);
			disable(F_RAGSOC);
			s->disable_prot_fields(*this);
			if (s->with_card(*this))
				enable(DLG_SAVEREC);

			smartcard_error err = s->read();
			if (err == no_smarterror)
				s->card2mask(*this);
			else
				s->display_error(err);
		}
	}
	TVariable_mask::start_run();
}

bool TDocumento_mask::stop_run(KEY key)
{														 
	if (key != K_ESC && key != K_QUIT)
		update_progs(true);
	else
		if (key == K_ESC)
		{
			TSmart_card * s = smartcard();

			if (s != NULL)
			{
				if (s->card_connected())
				{
					s->disconnect_card();
					enable(F_CODCF);
					enable(F_RAGSOC);
				}	
			}
		}

	return TVariable_mask::stop_run(key);
}

bool TDocumento_mask::on_key(KEY key)
{ 
	if (key == K_SHIFT + K_F12)
	{
		TRelation r(LF_DOC);
		r.curr()=doc();
		bool can_save = !doc().bloccato() && !doc().chiuso();
    if (can_save && ::user_can_write(&r))
		{
			TMask_field& stato = field(F_STATO);
			stato.enable();
			enable(DLG_SAVEREC);
			enable(DLG_DELREC);
			TSmart_card * s = smartcard();
      xvtil_statbar_set(TR("Modifica"));
			if (s != NULL && s->card_connected())
				s->enable_prot_fields(*this);
		}
		else
			warning_box("L'utente %s non puo' modificare questo documento", 
														(const char*)user());
		return TRUE;
	}
	else
		if (key == K_F7)
		{
			const TSheet_field & sf = sfield(F_SHEET);
			TDocumento & d = doc();
			TRiga_documento & riga = d[sf.selected() + 1];
			TOriginal_row_mask sm;
			const TRectype * or_row = riga.find_original_rdoc();

			if (or_row != NULL)
			{
				sm.set(F_DACODNUM, or_row->get(RDOC_CODNUM));
				sm.set(F_DAANNO, or_row->get(RDOC_ANNO));
				sm.set(F_DAPROVV, or_row->get(RDOC_PROVV));
				sm.set(F_DANDOC, or_row->get(RDOC_NDOC));
				sm.set(F_DANRIGA, or_row->get(RDOC_NRIGA));
				sm.disable(-1);
			}

			if (sm.run() == K_ENTER && sm.field(F_DACODNUM).enabled())
			{
				TToken_string key(sm.get(F_DACODNUM));
				key.add(sm.get(F_DAANNO));
				key.add(sm.get(F_DAPROVV));
				key.add(sm.get(F_DANDOC));
				key.add(sm.get(F_DANRIGA));

				const TRectype & or_row_mod = cache().get(LF_RIGHEDOC, key);
				if (or_row_mod.empty())
					riga.reset_original_rdoc_key();
				else
					riga.set_original_rdoc_key(or_row_mod);
			}
		return true;
	}

	return TVariable_mask::on_key(key); 
}

void TDocumento_mask::occ2mask()
{	
	const TOccasionale& o = doc().occas();

	reset(F_COFI);
	reset(F_PAIVA);
	set(F_OCFPI, o.get(OCC_CFPI));	 
	const TString & ragsoc = o.get(OCC_RAGSOC);
	set(F_RAGSOC, ragsoc);
	set(F_RAGSOCSP, ragsoc);
	const TString & indir = o.get(OCC_INDIR);
	set(F_INDCF, indir);
	set(F_INDSP, indir);
	const TString & civ = o.get(OCC_CIV);
	set(F_CIVCF, civ);
	set(F_CIVSP, civ);
	const TString & cap = o.get(OCC_CAP);
	set(F_CAPCF, cap);
	set(F_CAPSP, cap);
	const TString & com = o.get(OCC_COM);
	set(F_COMCF, com);		
	set( F_COMSP, com);
	const TString & stato = o.get(OCC_STATO);
	set(F_STATOCF, stato);	
	set( F_STATOSP, stato);
	if (id2pos(F_CODINDSP) >= 0)
		reset(F_CODINDSP);
	// Sugli occasionali non c'� la localit�
	const TString & localita = o.get(OCC_LOCALITA);
	set(F_LOCALITACF, localita);
	set(F_LOCALITASP, localita);
	check_field(F_COMSP);
	check_field(F_STATOSP);
}

// Proposta automatica contratto
void TDocumento_mask::contr2mask()
{
  const TCli_for& c = doc().clifor(); 
  const TRectype& ven_rec = c.vendite();
	
  const bool gescontr = ven_rec.get_bool(CFV_GESTCONTR) && ini_get_bool(CONFIG_DITTA, "ve", "GES", false, 2);					
	enable(F_CODCONT, gescontr);
	enable(F_DESCONT, gescontr);
  
  if (gescontr && insert_mode())
  {
    const TDate datadoc = get(F_DATADOC);
    TString str;
    str << CONDV_TIPO << "=C " << CONDV_TIPOCF << '=' << c.tipo() << ' ' << CONDV_CODCF << '=' << c.codice();
    TString query;
    query << "USE CONDV\nFROM " << str << "\nTO " << str;
    TISAM_recordset contr(query);

    str.cut(0);
    for (bool ok = contr.move_first(); ok; ok = contr.move_next())
    {
      const TDate data_ini = contr.get(CONDV_VALIN).as_date();
      const TDate data_fin = contr.get(CONDV_VALFIN).as_date();
      if (datadoc.between(data_ini, data_fin))
      {
        str = contr.get(CONDV_COD).as_string();
        break;
      }
    }
    set(F_CODCONT, str, 0x3);
  }
}

void TDocumento_mask::set_or_def(short id, const TString& val)
{
  TMask_field* fld = find_by_id(id);
  if (fld != NULL)
  {
    if (val.blank())
    {
      const TString_array& def = doc().tipo().get_defaults();
      const TString* str = (const TString*)def.objptr(id);
      if (str != NULL && str->full())
        fld->set(*str);
      else
        fld->reset();
    }
    else
      fld->set(val);
  }
}

void TDocumento_mask::cli2mask(bool force_load)
{	
	const TCli_for& c = doc().clifor(); 

	const bool onload = !is_running();
	
	// Setta i campi che appartengono al file LF_CLIFO	
	const bool occas = c.occasionale();

	show(F_OCCASEDIT, occas);
	if (!occas)
		reset(F_OCFPI);
	show(F_OCFPI, occas);
	// In forse per l'Occasionale, sicuri per il Normale
	show(F_COFI, !occas);
	show(F_STATOPAIVA, !occas);
	show(F_PAIVA, !occas);		
	set(F_RAGSOC, c.get(CLI_RAGSOC));
	enable(F_RAGSOC, !occas);
	
	const TRectype& ven_rec = c.vendite();

	if (force_load || !onload)		
	{											 
		short pos = id2pos(F_CODVAL);								
		const TString4 codval = c.get(CLI_CODVAL);	// Attenzione: Non usare TString& qui!
		
		if (pos >= 0)
			set(F_CODVAL, codval, TRUE);
		pos = id2pos(F_CODVAL1);							
		if (pos >= 0)
			set(F_CODVAL1, codval, TRUE);
		pos = id2pos(F_CODLIN);							
		if (pos >= 0 && fld(pos).active())
			fld(pos).set(c.get(CLI_CODLIN));
		set(F_CODPAG, c.get(CLI_CODPAG));

		TToken_string key;
		key.add(c.get(CLI_TIPOCF));
		key.add(c.get(CLI_CODCF));
		key.add("V");
		key.add("1");

		const TRectype& cfban = cache().get(LF_CFBAN, key);
		TString80 iban;

		if (cfban.empty() || id2pos(F_CODABIA1) < 0)
		{
			hide(-GR_APPOGGIOCLI);
			show(-GR_APPOGGIO);
			if (cfban.empty())
			{
				set(F_CODABIA, c.get(CLI_CODABI));
				set(F_CODCABA, c.get(CLI_CODCAB), 0x2);
				iban = c.get(CLI_IBAN);
			}
			else
			{
				set(F_CODABIA, cfban.get(CFBAN_ABI));
				set(F_CODCABA, cfban.get(CFBAN_CAB), 0x2);
				iban = cfban.get(CFBAN_IBAN);
			}
		}
		else
		{
			hide(-GR_APPOGGIO);
			show(-GR_APPOGGIOCLI);
			set(F_CODABIA1, cfban.get(CFBAN_ABI));
			set(F_CODCABA1, cfban.get(CFBAN_CAB), 0x2);
			iban = cfban.get(CFBAN_IBAN);
		}
		if (id2pos(F_IBAN_STATO) > 0)
		{
			set(F_IBAN, iban);
			if (iban.full())
			{
  			efield(F_IBAN_STATO).validate(K_TAB);
				set(F_IBAN_STATO, iban.left(2));
				set(F_IBAN_CHECK, iban.mid(2,2));
				set(F_BBAN			, iban.mid(4));
				set(F_BBAN_CIN	, iban.mid(4,1));
				set(F_BBAN_ABI	, iban.mid(5,5));
				set(F_BBAN_CAB	, iban.mid(10,5));
				set(F_BBAN_CONTO, iban.mid(15,12));
			}
      else
      {
				reset(F_IBAN_STATO);
				reset(F_IBAN_CHECK);
				reset(F_BBAN			);
				reset(F_BBAN_CIN	);
				reset(F_BBAN_ABI	);
				reset(F_BBAN_CAB	);
				reset(F_BBAN_CONTO);
      }
		}

		key.cut(0);
		key.add(c.get(CLI_TIPOCF));
		key.add(c.get(CLI_CODCF));
		key.add("N");
		key.add("1");

		const TRectype & cfbanpr = cache().get(LF_CFBAN, key);

		// Setta i campi che appartengono al file LF_CFVEN
		if (cfbanpr.empty() || id2pos(F_CODABIP1) < 0)
		{
			hide(-GR_PRESENTCLI);
			show(-GR_PRESENT);
			if (cfbanpr.empty() || id2pos(F_CODABIP1) < 0)
			{
				set(F_CODABIP, ven_rec.get(CFV_CODABIPR), 0x3);
				set(F_CODCABP, ven_rec.get(CFV_CODCABPR), 0x3);
			}
			else
			{
				set(F_CODABIP, cfbanpr.get(CFBAN_ABI), 0x3);
				set(F_CODCABP, cfbanpr.get(CFBAN_CAB), 0x3);
				set(F_PROGBNP, cfbanpr.get(CFBAN_PROGPR), 0x3);
			}
		}
		else
		{
			hide(-GR_PRESENT);
			show(-GR_PRESENTCLI);
			set(F_CODABIP1, cfbanpr.get(CFBAN_ABI));
			set(F_CODCABP1, cfbanpr.get(CFBAN_CAB), 0x2);
			set(F_PROGBNP1, cfbanpr.get(CFBAN_PROGPR));
		}

		set_or_def(F_RAGGR, ven_rec.get(CFV_RAGGDOC));
		set_or_def(F_RAGGREFF, ven_rec.get(CFV_RAGGEFF));
		set_or_def(F_CODINDSP, ven_rec.get(CFV_CODINDSP));
		set_or_def(F_CODAG, ven_rec.get(CFV_CODAG));
		set_or_def(F_CODAGVIS, ven_rec.get(CFV_CODAG1));
		set_or_def(F_CODSPMEZZO, ven_rec.get(CFV_CODSPMEZZO));
		set_or_def(F_CODPORTO, ven_rec.get(CFV_CODPORTO));
		set_or_def(F_CODNOTESP1, ven_rec.get(CFV_CODNOTESP1));
		set_or_def(F_CODNOTESP2, ven_rec.get(CFV_CODNOTESP2));
		set_or_def(F_CODNOTE, ven_rec.get(CFV_CODNOTE));
		set_or_def(F_CODVETT1, ven_rec.get(CFV_CODVETT1));
		set_or_def(F_CODVETT2, ven_rec.get(CFV_CODVETT2));
		set_or_def(F_CODVETT3, ven_rec.get(CFV_CODVETT3));
		set_or_def(F_SPESEINC, ven_rec.get(CFV_PERCSPINC));	
		set_or_def(F_ADDBOLLI, ven_rec.get(CFV_ADDBOLLI));
		set_or_def(F_CATVEN, ven_rec.get(CFV_CATVEN));

    const int alleg = c.get_int(CLI_ALLEG);
    const bool ivadiff = (alleg == 7) && ven_rec.get_bool(CFV_FATTSOSP);
		set(F_LIQDIFF, ivadiff ? "X" : "");

    const TDate datadoc = doc().get(DOC_DATADOC);
    const bool IVAxCassa = !ivadiff && (alleg < 5 || alleg == 7) && gestione_IVAxCassa(datadoc); 
		set(F_IVAXCASSA, IVAxCassa ? "X" : "");

		pos = id2pos(F_CODLIST);	

		const TString8 codlist = ven_rec.get(CFV_CODLIST);  //ATTENZIONE: su file il CODLIST � 5 caratteri
		if (pos >= 0 && fld(pos).active())
		{	 
			TEdit_field & f = (TEdit_field&) fld(pos);
			
			f.set(codlist);
			f.check();
			f.on_hit();
		}
		set(F_CODZON, ven_rec.get(CFV_CODZONA), 0x3);
		set(F_RAGGR, ven_rec.get(CFV_RAGGDOC));
		sconto_testa2mask();
		spese2mask();
	}
	else
		if (onload)
		{
			TToken_string key;

			key.add(c.get(CLI_TIPOCF));
			key.add(c.get(CLI_CODCF));
			key.add("V");
			key.add("1");

			const TRectype & cfban = cache().get(LF_CFBAN, key);

			if (cfban.empty() || id2pos(F_CODABIA1) < 0)
			{
				show(-GR_APPOGGIO);
				hide(-GR_APPOGGIOCLI);
			}
			else
			{
				show(-GR_APPOGGIOCLI);
				hide(-GR_APPOGGIO);
			}
			key.cut(0);
			key.add(c.get(CLI_TIPOCF));
			key.add(c.get(CLI_CODCF));
			key.add("N");
			key.add("1");

			const TRectype & cfbanpr = cache().get(LF_CFBAN, key);

			if (cfbanpr.empty() || id2pos(F_CODABIP1) < 0)
			{
				show(-GR_PRESENT);
				hide(-GR_PRESENTCLI);
			}
			else
			{
				show(-GR_PRESENTCLI);
				hide(-GR_PRESENT);
			}
		}
	enable( F_CODINDSP , !occas);			
	if (occas) 
		occ2mask();
	else					 
	{				
		set(F_COFI, c.get(CLI_COFI));
		set(F_INDCF, c.get(CLI_INDCF));
		set(F_CIVCF, c.get(CLI_CIVCF));
		set(F_STATOPAIVA, c.get(CLI_STATOPAIV));
		set(F_PAIVA, c.get(CLI_PAIV));
		set(F_LOCALITACF, c.get(CLI_LOCCF));
		set(F_CAPCF, c.get(CLI_CAPCF));
		set(F_COMCF, c.get(CLI_COMCF));
		set(F_STATOCF, c.get(CLI_STATOCF));
		check_field( F_CODINDSP );
	}
	const TString4 newcodval = get(F_CODVAL);

	short pos = id2pos(F_CAMBIO);													 
	if ((pos >= 0) && newcodval.empty())
		fld(pos).reset();	
	pos = id2pos(F_CODVAL);													 
	if (pos >= 0 && fld(pos).active())
		fld(pos).check(STARTING_CHECK);
	pos = id2pos(F_CODVAL1);													 
	if (pos >= 0 && fld(pos).active())
		fld(pos).check(STARTING_CHECK);
	check_field(F_COMCF);
	check_field(F_STATOCF);
	check_field( F_CODPAG );
	pos = id2pos(F_CODLIN);													 
	if (pos >= 0 && fld(pos).active())
		fld(pos).check();
	pos = id2pos(F_CODLIST);													 
	if (pos >= 0 && fld(pos).active())
		fld(pos).check();
	pos = id2pos(F_CODAG);													 
	if (pos >= 0 && fld(pos).active())
		fld(pos).check();
	pos = id2pos(F_CODAGVIS);													 
	if (pos >= 0 && fld(pos).active())
		fld(pos).check();

	check_field( F_CODSPMEZZO );
	check_field( F_CODPORTO );
	check_field( F_CODNOTESP1 );
	check_field( F_CODNOTESP2 );
	check_field( F_CODNOTE );
	check_field( F_CODVETT1 );
	check_field( F_CODVETT2 );
	check_field( F_CODVETT3 );		
	check_field( F_CATVEN );		
	check_field( F_CODZON );
	
  contr2mask();

  if (gestione_note_per_articolo())
    send_key(K_F8, F_NAR, &field(F_CODCF));

  // Accendi bottone mail se possibile
  const TString& email = c.get(CLI_DOCMAIL);
  enable(DLG_EMAIL, email.full());
}

void TDocumento_mask::sconto_testa2mask()
{
	const TCli_for& c = doc().clifor(); 

  TConfig ditta(CONFIG_DITTA, "ve");
	const char tipogestione = ditta.get("GESSCO")[ 0 ];
	switch( tipogestione )
	{
		case 'N':	// Sconti non gestiti: pussa via!
			break;
		case 'P':	// Percentuale su anagrafica cliente
			set( F_SCONTOPERC, c.vendite().get(CFV_SCONTO));
			break;
		case 'T':	// Gestione tabella sconti
			{
				const TString16 codsconto(c.vendite().get(CFV_CODSCC));
				
				if (codsconto.not_empty())
				{
					TTable sconti("%SCC");
					sconti.setkey(1);
					sconti.zero();
					sconti.put("CODTAB", codsconto);
					if (sconti.read( ) == NOERR)
						set(F_SCONTOPERC, sconti.get("S1"));
				}
			}
			break;
		case 'A':	// Gestione archivio sconti
			{
				TString16 cod;							 
				const TRectype & ven_rec = c.vendite();
				TLocalisamfile sconti(LF_SCONTI );
																		 
				sconti.setkey(1);
				sconti.zero();
				sconti.put("TIPO", "I");

				if(ditta.get_bool("SCOKEY", "ve", 1))
					sconti.put("CODCAT", ven_rec.get(CFV_CATVEN));
				if(ditta.get_bool("SCOKEY", "ve", 2))
					cod.format("%-2s", (const char *)ven_rec.get(CFV_CODSCC));
				else
					cod = "	";
				if( ditta.get_bool("SCOKEY", "ve", 3))
				{
					TString8 cz; cz.format("%-2s", (const char*)ven_rec.get(CFV_CODZONA));
					cod << cz;
				}
				else
					cod << "	";
				if( ditta.get_bool("SCOKEY", "ve", 4))
					cod << c.get(CLI_CODPAG);
				sconti.put("CODART", cod);
				if(sconti.read() == NOERR)
					set(F_SCONTOPERC, sconti.get( "SCONTO"));
			}
			break;		
		default:
			break;	
	}	
	return;
}

void TDocumento_mask::spese2mask()
{
	TSheet_field & sh = (TSheet_field &) field(F_SHEET);
	TCli_for & c = doc().clifor(); 
	
	TString16 name("CODSP0");
	TString_array spese;				
	const TRectype & ven_rec = c.vendite();
	for (int i = 1; i <= 4; i++)
	{										 
		name.rtrim(1); name << i;
		const TString16 s(ven_rec.get(name));
		
		if (s.not_empty()) 
			spese.add(s);
	}							 

  doc().put(DOC_SPESEUPD, false);
	doc().put(DOC_CODVAL, get(F_CODVAL));
	doc().put(DOC_CAMBIO, get(F_CAMBIO));
//	doc().put(DOC_CONTROEURO, get(F_CONTROEURO));
	
	doc().update_spese_aut(spese, false, &sh);
	sh.force_update();
} 

void TDocumento_mask::reset_masks(const TString& tipo_doc)
{
	static TString4 last_tipo_doc;

	if (tipo_doc != last_tipo_doc)
	{
		FOR_EACH_ASSOC_OBJECT(_maskriga, h, k, o)
		{
			TMask* m = (TMask*)o;
			m->enable_default(); 
			if (!_sheet->exist_column(FR_PREZZO))
				m->hide(FR_PREZZO);
		}
		last_tipo_doc = tipo_doc;
	}
}

void TDocumento_mask::doc2mask(bool reload_clifo, bool force_load, bool update)
{ 
	for (int p = fields()-1; p >= 0; p--)
	{
		TMask_field& f = fld(p);
		const TFieldref* fr = f.field();
		if (fr)
    {
  		f.set(fr->read(doc()));
      if (f.ghost() && !f.active())
        f.on_hit(); // Forza il MESSAGE COPY dei campi di testata come DOC_STATO
	  }
//		else
//			f.reset(); // Perch� non lascio stare questi campi?
	}
	if (reload_clifo)
		cli2mask(force_load);			
	else
  {
		if (force_load)
	  {
		  check_field(F_CODCF);
		  check_field(F_CODINDSP);
    }
/*
	  if (id2pos(F_IBAN_STATO) > 0)
	  {
		  const TString80 iban = doc().get(DOC_IBAN);
		  set(F_IBAN, iban);
		  efield(F_IBAN_STATO).validate(K_TAB);
		  if (iban.not_empty())
		  {
			  set(F_IBAN_STATO, iban.left(2));
			  set(F_IBAN_CHECK, iban.mid(2,2));
			  set(F_BBAN			, iban.mid(4));
			  set(F_BBAN_CIN	, iban.mid(4,1));
			  set(F_BBAN_ABI	, iban.mid(5,5));
			  set(F_BBAN_CAB	, iban.mid(10,5));
			  set(F_BBAN_CONTO, iban.mid(15,12));
		  }
    }
*/
  }

	if (id2pos(F_IBAN_STATO) > 0)
	{
		const TString80 iban = doc().get(DOC_IBAN);
		set(F_IBAN, iban);
		if (iban.full())
		{
			set(F_IBAN_STATO, iban.left(2));
			set(F_IBAN_CHECK, iban.mid(2,2));
			set(F_BBAN			, iban.mid(4));
			set(F_BBAN_CIN	, iban.mid(4,1));
			set(F_BBAN_ABI	, iban.mid(5,5));
			set(F_BBAN_CAB	, iban.mid(10,5));
			set(F_BBAN_CONTO, iban.mid(15,12));
  		efield(F_IBAN_STATO).validate(K_TAB);
		}
    else
    {
			reset(F_IBAN_STATO);
			reset(F_IBAN_CHECK);
			reset(F_BBAN			);
			reset(F_BBAN_CIN	);
			reset(F_BBAN_ABI	);
			reset(F_BBAN_CAB	);
			reset(F_BBAN_CONTO);
    }
  }


  TSheet_field& s = sfield(F_SHEET);
  s.destroy();
	const int righe = doc().physical_rows();
	for (int i = 0; i < righe; i++)
	{
    TRiga_documento & r = doc()[i + 1];

		doc()[i+1].autoload(s);
		s.check_row(i, 0x3);
		if (r.tipo().tipo() == RIGA_PRESTAZIONI)
		{
			const TSpesa_prest & spesa = r.spesa();
			if (spesa.tipo() == 'V')
				s.disable_cell(i, s.cid2index(FR_QTA));
		}
	}

	reset_masks(get(F_TIPODOC));
	//aggiorna i colori delle righe e forza l'update dello sheet
	if (update)
		highlight();
}

void TDocumento_mask::mask2doc()
{
	for (int p = fields()-1; p >= 0; p--)
	{
		const TMask_field& f = fld(p);
		const TFieldref* fr = f.field();
		if (fr)
			fr->write(f.get(), doc());
	}
}

bool TDocumento_mask::new_mask(int numriga) const
{ 
  const TRiga_documento& riga = doc()[numriga + 1];
  const TTipo_riga_documento& tiporiga = riga.tipo();
  TString16 name; tiporiga.mask_name(name);

	return _maskriga.objptr(name) == NULL;
}

TVariable_mask* TDocumento_mask::riga_mask(int numriga)
{ 
	const TRiga_documento& riga = doc()[numriga + 1];
	const TTipo_riga_documento& tiporiga = riga.tipo();
	TString16 name; tiporiga.mask_name(name);

	TVariable_mask* m = (TVariable_mask*)_maskriga.objptr(name);
	if (m == NULL)
	{
		m = new TVariable_mask(name); 
		m->set_handler(FR_TIPORIGA, tipo_riga_handler);
		m->set_handler( FR_QTA, qta_handler );
		m->set_handler( FR_UMQTA, um_handler );
		m->set_handler( FR_DATACONS, dcons_handler);

		_maskriga.add(name, m);		
		
    TList_field & htr = lfield(F_LBTIPORIGA);
		const TString codes(htr.get_codes());
		const TString values(htr.get_values());

		m->lfield(FR_TIPORIGA).replace_items(codes, values);
		
		int pos = m->id2pos(FR_CODART);
		if (pos >= 0)
		{
			const TMask_field & f = m->fld(pos);
			if (f.is_edit())
			{
				TBrowse * browse = ((TEdit_field &) f).browse();
				const char tipo_r = tiporiga.tipo();
				
				if (browse )
				{								 
					const TCursor* cur = browse->cursor();
					if (cur)
					{
						const int num = cur->file().num();
						if (num == LF_ANAMAG || num == LF_CODCORR)
						{
							m->set_handler( FR_CODMAG, codmag_handler ); 
							m->set_handler( FR_CODMAGC, codmag_coll_handler ); 
							m->set_handler( FR_CODART, codart_handler );
							m->set_handler( FR_LIV1, liv_handler );
							m->set_handler( FR_LIV2, liv_handler );
							m->set_handler( FR_LIV3, liv_handler );
							m->set_handler( FR_LIV4, liv_handler );
							m->set_handler( FR_UMQTA, umart_handler );
							m->set_handler( FR_CODARTMAG, codartmag_handler );
							m->set_handler( FR_DESCR, descr_handler ); 
							m->set_handler( FR_QTA, qtaart_handler ); 
							if (livelli().autoinsert(1))
								m->field(FR_LIV1).check_type(CHECK_NONE);
							if (livelli().autoinsert(2))
								m->field(FR_LIV2).check_type(CHECK_NONE);
							if (livelli().autoinsert(3))
								m->field(FR_LIV3).check_type(CHECK_NONE);
							if (livelli().autoinsert(4))
								m->field(FR_LIV4).check_type(CHECK_NONE);
						 }
						else
							if (tipo_r == RIGA_SPESEDOC || tipo_r == RIGA_PRESTAZIONI ||
									tipo_r == RIGA_RISORSE || tipo_r == RIGA_ATTREZZATURE)
								m->set_handler( FR_CODART, sppr_handler ); 
					}
				}
			}
		}
		m->set_handler(FR_QTAEVASA, qta_evasa_handler);
		m->set_handler(FR_CAUS, causmag_handler);
		
		if (m->id2pos(FR_CODIVA) >= 0)
		{
			m->set_handler(FR_CODIVA, iva_handler);
			const TString& tipiva = doc().tipo().tipi_iva_validi();
			if (tipiva.not_empty())
			{
				TBrowse& browse = *(m->efield(FR_CODIVA)).browse();
				TString filter = browse.get_filter();

				bool close_filter = FALSE;
				if (filter.not_empty()) 
				{ 
					filter.insert("("); 
					filter << ")&&("; 
					close_filter = TRUE;
				}	
				bool firstor = TRUE;
				for (int i = tipiva.len()-1; i >= 0; i--) if (tipiva[i] != ' ')
				{
					if (firstor) 
						firstor = FALSE; 
					else 
						filter << "||"; 
					filter << "(S1==\"";
					switch(i)
					{
						case 1: filter << "VE"; break;
						case 2: filter << "ES"; break;
						case 3: filter << "NI"; break;
						case 4: filter << "NS"; break;
						default: break;
					}
					filter << "\")";
				}
				if (close_filter) filter << ')';
				browse.set_filter(filter);
			}
		}    
		m->set_handler(DLG_USER, link_handler);

    // Quasi qualsiasi cosa analitica va bene
		const bool ca_active = _ges_ca && !(riga.is_descrizione() || riga.is_sconto() /*|| riga.is_omaggio()*/);
		if (ca_active)
		{
			const int page = m->win2page(m->fld(m->fields()-1).parent()); // Calcolo bastardo dell'ultima pagina

			TConfig& ini = ca_config();
			const TMultilevel_code_info& fasinfo = ca_multilevel_code_info(LF_FASI);
			const bool use_fsc = fasinfo.levels() > 0;

			int y = 1;
      int i;
			short dlg = FR_CDC1; // id del primo campo da generare
			short dlgd = FR_DESCDC1;

			_cdc_start_sh = _cdc_end_sh = -1 ;
			_cms_start_sh = _cms_end_sh = -1 ;
			for (i = 0; i < 2; i++)
			{
				const TString& level = ini.get("Level", NULL, i+1);	// Legge il livello 1 o 2
				if (level == "CDC")																	// Crea centro di costo 
				{
					if (_cdc_start_sh < 0)
					{
						_cdc_start_sh = dlg;
						_cdc_end_sh = dlg + ca_multilevel_code_info(LF_CDC).levels()-1;
					}
					if (use_fsc && fasinfo.parent() == LF_CDC)
						insert_anal_fields(*m, page, LF_FASI, y, dlg, dlgd, false);
					else
						insert_anal_fields(*m, page, LF_CDC, y, dlg, dlgd, false);
					m->set_handler( _cdc_end_sh, cdc_mag_handler);

				} else
				if (level == "CMS")																	 // Crea commessa
				{
					if (_cms_start_sh < 0)
					{
						_cms_start_sh = dlg;
						_cms_end_sh = dlg + ca_multilevel_code_info(LF_COMMESSE).levels()-1;
					}
					if (use_fsc && fasinfo.parent() == LF_COMMESSE)
						insert_anal_fields(*m, page, LF_FASI, y, dlg, dlgd, false);
					else
					{
						insert_anal_fields(*m, page, LF_COMMESSE, y, dlg, dlgd, false);
					}
					m->set_handler(_cms_end_sh, cms_mag_handler);
				}
			}
			if (use_fsc && fasinfo.parent() <= 0)
				insert_anal_fields(*m, page, LF_FASI, y, dlg, dlgd, false);
		} 

    TFilename proname; tiporiga.profile_name(proname);
  	TConfig pro( proname, "HANDLERS" );
    TAssoc_array& handlers = pro.list_variables();
    FOR_EACH_ASSOC_STRING(handlers, obj, key, str)
    {
      int id = 0, hd = 0;
      if (*key == 'H' && strchr(str, '|') == NULL)  // Provo a gestire il caso Handler(105) = 3
      {
        const TFixed_string k(key);
        id = atoi(k.after('('));
        hd = atoi(str);
      }
      else                                          // Provo a gestire il caso 1 = 105|3
      {
        const TToken_string riga = str;
        riga.get(0, id); 
        riga.get(1, hd);
      }
      if (id >= DLG_USER && hd > 0)
        user_set_row_handler(*m, id, hd);
    }

	  if (m->id2pos(FR_PREZZO) >= 0)
	  {
		  TEditable_field& f = (TEditable_field&)m->efield(FR_PREZZO);
		  f.reset_driver(F_CODVAL); 
		  f.add_driver(-F_CODVAL);
	  }
  			
	  if (m->id2pos(FR_IMPFISSO) >= 0)
	  {
		  TEditable_field& f = m->efield(FR_IMPFISSO);
		  f.reset_driver();          // Perche' qui non c'e' scritto f.reset_driver(F_CODVAL) ?
		  f.add_driver(-F_CODVAL);
	  }

		FOR_EACH_CONAI_CLASS(type)
		{
			const short posc = conai_sottocat_id(type);
			const short posp = conai_peso_id(type);
			if (conai_configured_class(type))
			{
				m->show(posc);
				m->set_handler(posc, sottocat_conai_handler);
				m->show(posp);
				m->set_handler(posp, peso_conai_handler);
			}
			else
			{
				m->hide(posc);
				m->hide(posp);
			}
		}

		// Impostiamo gli eventuali drivers
    FOR_EACH_MASK_FIELD((*m), i, f) if (f->is_edit())
			((TEdit_field*)f)->test_drivers();
	}
  m->set_sheet(&sfield(F_SHEET)); 
	return m;
}

void TDocumento_mask::update_giacenza()
{																	
  if (id2pos(F_CURGIAC)<0 || !is_running())
		return;

  TSheet_field& sf = sfield(F_SHEET);
	TToken_string& row = sf.row(sf.selected());			 
	TString80 codart = row.get(sf.cid2index(FR_CODARTMAG));
	if (codart.blank())
	{
		reset(F_CURGIAC);
		reset(F_CURDISP);														
		return;
	}

	TString16 livello;
	const int db_liv = doc().tipo().dbliv();

	for (int i = 0; i < 4; i++)
	{
		const char* liv = row.get(sf.cid2index(FR_LIV1+i));

		if (*liv > ' ')
			livello << liv;
		else
			break;  
	}

  TString8 causmag = row.get(sf.cid2index(FR_CAUS));
	if (causmag.blank())
    causmag = get(F_CAUSMAG);
  
	if (causmag.full())
	{
		const TCausale_magazzino& c = cached_causale_magazzino(causmag);

		_fconv_qta = UNO;
		if (c.scarica_alternativi())
		{
			const TString& alt = cached_article(codart).get(ANAMAG_CODARTALT);
			if (alt.full())
				codart = alt;
		}
		if (db_liv > 0)
		{
			const int expl_row = doc().tipo().dbrow()-1; // Sul file .ini l'indice parte da 1!
			if (expl_row >= 0)                           // Evito esplosioni inutili in primis
			{
				TDistinta_tree db;     
				TArray components;
				db.set_root(codart, "", 1, livello);

				const int items = db.explode(components, false, RAGGR_EXP_NONE, db_liv);
				if (items > 0 && expl_row < items)         // Controllo se la riga esplosione desiderata e' valida
				{
					const TRiga_esplosione& r = (const TRiga_esplosione &)components[expl_row];
					codart = r.articolo();                   // Cambio il codice articola da elaborare
					_fconv_qta = r.val();
				}
			}
		}
	}
		
	real giac, disp;
	TString8 codmag = row.get(sf.cid2index(FR_CODMAG));

	if (codmag.full())
	{
		const TString4 coddep = row.get(sf.cid2index(FR_CODDEP));    
		if (coddep.full())
			codmag << coddep;
	}
	else
	{ // Cerca di determinare il magazzino di default, se manca sulla riga
		if (causmag.full())
		{
			const TCausale_magazzino& c = cached_causale_magazzino(causmag);
			if (c.has_default_mag())
			{
				codmag = c.default_mag();
				if (c.has_default_dep())
					codmag << c.default_dep();  
			}
		}
	}
	
  TString4 annoes = get(F_ANNO);
  const TDate datadoc = get(F_DATADOC);
  if (datadoc.ok())
  {
    TEsercizi_contabili esc;
    annoes.format("%04d", esc.date2esc(datadoc));
  }

	TArticolo_giacenza& art = cached_article_balances(codart);

	giac = art.disponibilita(annoes, codmag, livello, TRUE);
	disp = art.disponibilita(annoes, codmag, livello, FALSE);
			
	if (db_liv == 0)
	{
		const TString4 um = row.get(sf.cid2index(FR_UMQTA));
		art.convert_to_um(giac, um);
		art.convert_to_um(disp, um);
	}
	set(F_CURGIAC, giac.string());
	set(F_CURDISP, disp.string());														
}

///////////////////////////////////////////////////////////
// Handlers and notifiers
///////////////////////////////////////////////////////////				
																 
bool TDocumento_mask::ss_handler(TMask_field& f, KEY key)
{					
	bool ok = true;
	if (key == K_ENTER )
	{
		const TSheet_field& ss = (TSheet_field&)f;
    TDocumento_mask& mask = (TDocumento_mask&)ss.mask();

    TConfig& ini = ca_config();
    const short cme = mask.cms_end();
    if (mask.id2pos(cme) > 0 && mask.get(cme).empty() && (ini.get_int("Authorizations") & 0x6))
    {
      if (ini.get_bool("CmsRequired") || ini.get("FathFasi").full())
      {
        const int col = ss.cid2index(mask.cms_end_sh());
        FOR_EACH_SHEET_ROW(ss, r, riga)
        {
          if (ss.cell_enabled(r, col))
          {
            const char* cms = riga->get(col);
            if (!(cms && *cms > ' '))
            {
              ss.error_box(FR("La commessa � obbligatoria alla riga %d"), r+1);
              break;
            }
          }
        }
      }
    }
    /*
		if (ok && ss.empty() && mask.insert_mode() && !app().is_transaction())
			ok = yesno_box(TR("Il documento � privo di righe:\nSi desidera continuare ugualmente?"));
    */
	}
	return ok;
}

bool TDocumento_mask::ss_notify( TSheet_field& ss, int r, KEY key )
{
  static bool selecting = false;

	TDocumento_mask& m = (TDocumento_mask&)ss.mask();
	TDocumento& doc = m.doc();

  switch (key)
  {
  case K_ENTER: // modifica
	  {
		  TRiga_documento& riga = doc[r + 1];
		  riga.autosave(ss);

		  if (m.is_calculated_page(m.curr_page()))
			  m.update_progs();
			m.highlight_row(r);
      if (doc.tipo().check_double_art())
      {
        const int rows = doc.physical_rows();
        const TString80 codart = riga.get(RDOC_CODART);
        for (int i = 1; i <= rows; i++)
          if (i != r + 1 && codart == doc[i].get(RDOC_CODART))
            if (!yesno_box(FR("L'articolo %s � presente alla riga %d, si desidera continuare?"), (const char*)codart, i))
              return false;
      }
	  }
    break;
  case K_CTRL + K_ENTER: // inizio modifica
	  {
		  const TRiga_documento& riga = doc[r + 1];
			m.codcms_sh() = riga.get(RDOC_CODCMS);
		}
  case K_DEL: // Cancellazione
		{
			doc.destroy_row(r + 1, TRUE);
			if (r < doc.rows())
			{
				TRiga_documento& riga = doc[r + 1];
				if (riga.is_omaggio() && riga.is_generata())
				{
					ss.destroy(r + 1);
					doc.destroy_row(r + 1, true);
				}
			}
			doc.dirty_fields();
			if (m.is_calculated_page(ss.page()))
				m.update_progs();
		}
    break;
	case K_INS: // Inserimento
		{
			if (r < doc.rows())
			{
				TRiga_documento & riga = doc[r + 1];
				if (riga.is_omaggio() && riga.is_generata())
				{
					const bool enabled = ss.cell_enabled(r, 0);
					
					if (!enabled) ss.enable_row(r);
					ss.force_update(r);
					ss.select(r);
					m.send_key(K_CTRL + '+', 0);
					if (!enabled) ss.disable_row(r);
					ss.force_update(r);
					return false;
				}
			}
			doc.insert_row(r + 1, m.get( F_LBTIPORIGA ));
		}
		break;
  case K_CTRL + K_INS:
    {
      TRiga_documento & riga = doc[r + 1];
      TRectype & ven_rec = doc.clifor().vendite();
      TString8 s(ven_rec.get(CFV_CODMAG));
			const TTipo_riga_documento & t = riga.tipo();
		
      if (s.full())
      {  
        s.left_just(3);
        s << ven_rec.get(CFV_CODDEP);
      } 
      else 
      {
        s = m.get(F_CAUSMAG);
        if (s.full())
        {
          const TCausale_magazzino & c = cached_causale_magazzino(s);
          if (!c.empty() && c.get_char("S10") > ' ') // Ignora magazzini non validi
            s = c.get("S10");
          else
          {
            s = m._std_mag;
            s.left_just(3);
            s << m._std_dep;
          }
        }
      }
			if (s.full())
				riga.put(RDOC_CODMAG, s);

      riga.autoload(ss);
      ss.check_row(r);			
			t.set_defaults(ss, r + 1);		
			m.highlight_row(r);
    }
    break;
  case K_TAB: // ingresso nella riga
		if (!selecting && m.is_running())
		{
			const TRiga_documento& rdoc = doc[r + 1];
			TMask& riga_mask = ss.sheet_mask();

			if (r < doc.physical_rows())
			{	
				m.update_giacenza();
     		const TRectype& rdoc = doc[r + 1];
				set_curr_um(rdoc.get(RDOC_UMQTA));
				const bool on = rdoc.get(RDOC_DACODNUM).full();
				riga_mask.enable(DLG_USER, on);
			}
			const bool merce = TRiga_documento::tipo(riga_mask.get(FR_TIPORIGA)).is_merce();
			const bool artmag = merce && riga_mask.get(FR_CODARTMAG).full();

			riga_mask.show(FR_UMQTA, artmag);
			riga_mask.show(FR_UMQTA2, !artmag);

			if (rdoc.get(RDOC_CODART).empty() && rdoc.get(RDOC_DESCR).empty())
			{
				selecting = true;   // semaforo per impedire l'evento di selezione doppio
				ss.select(r, 1, false);
				selecting = false;
			}

      if (m.gestione_note_per_articolo())
        m.send_key(K_F8, F_NAR, &ss);
		}
		break;
	case K_CTRL + K_TAB: // uscita dalla riga
		{
	    static const bool checkgiac = ini_get_bool(CONFIG_DITTA, "ve", "LIVPERART");
			bool ok = true;
			if (checkgiac)
			{
				TString livello;
				TToken_string & row = ss.row(r);

				for (int l = 0; l<4 ; l++)
					doc.livelli().pack_grpcode(livello, row.get(ss.cid2index(FR_LIV1+l)), l+1);
				if (livello.full())
				{
					const TString80 codart(row.get(ss.cid2index(FR_CODART)));
					const TRectype & rec = cache().get(LF_ANAMAG, codart);
					const bool check_art = rec.get_bool(ANAMAG_LIVPERART);

					if (check_art)
					{
						TLocalisamfile fl(LF_MULTIREL); 
						TRectype & r = fl.curr();

						r.put(MULTI_COD, "ARTLV");
						r.put(MULTI_FIRST, codart);
						r.put(MULTI_SECOND, livello);
                            
						TRectype new_rec(r);
						if (fl.read() != NOERR)
						{
							ok = yesno_box("Il codice di giacenza %s non e' legato all' articolo. Si desidera legarlo", (const char *)livello);
							if (ok) 
							{        
								r = new_rec;
								const int err = new_rec.write(fl);
								if (err != NOERR)
									return error_box("Impossibile legare il codice di giacenza. Errore %d", err);
							}
							else
								return false;
						}
					}
				}
			}
		}
    break;		
	default:
		break;
  }
	return true;
}

// Funzione che dato il profilo di riga ottiene la maschera
// Serve per ottenere una maschera diversa per ogni riga
TMask* TDocumento_mask::ss_getmask(int numriga, TMask& fullmask)
{
	TSheet_field* sf = fullmask.get_sheet();
	TDocumento_mask& m = (TDocumento_mask&)sf->mask();
	const TDocumento& doc = m.doc();

	if (numriga < doc.physical_rows())
		return m.riga_mask(numriga);
	else
		return &fullmask;
}

bool TDocumento_mask::occas_code_handler(TMask_field& f, KEY key)
{
  TMask& m = f.mask();
  if (key == K_TAB && (f.dirty() || !m.is_running()))
  {
    const TString& code = f.get();
    if (code.full())
    {
      TRelation occas(LF_OCCAS);
      occas.curr().put(OCC_CFPI, code);
      if (occas.read(_isequal) == NOERR)
      {                     
        m.autoload(occas);      
        m.send_key(K_TAB, O_COMUNE);         // Forza decodifica comuni
        m.send_key(K_TAB, O_COMUNENAS);
      } 
    }
  } 
  return true;
}

bool TDocumento_mask::occas_cfpi_handler(TMask_field& f, KEY key)
{
  if (key == K_ENTER)
  {
    const TMask& om = f.mask();
    if (om.field(O_COFI).empty() && om.field(O_PAIV).empty())
      return f.error_box(TR("E' necessario specificare il codice fiscale o la partita IVA"));
  } 
  return true;
}

bool TDocumento_mask::occas_handler( TMask_field& f, KEY key )
{
	TDocumento_mask & m = (TDocumento_mask &)f.mask();
	if ( key == K_SPACE && m.is_running( ) )
	{
		TDocumento& doc = m.doc();
		TOccasionale& occ = doc.occas();
		  
		TMask occas_mask("ve0100o");
		occas_mask.set_handler(O_CODICE, occas_code_handler );
    occas_mask.set_handler(O_COFI,   occas_cfpi_handler );
    occas_mask.set_handler(O_PAIV,   occas_cfpi_handler );

		for (int i = occas_mask.fields() - 1; i >= 0; i--)
		{
			TMask_field& f = occas_mask.fld(i);
			const TFieldref* c = f.field();
			if (c)
				f.set(c->read(occ));
		}

    const TString& cf = occas_mask.get(O_COFI);
    if (cf.full() && atoi(cf.mid(9, 2)) > 40)
      occas_mask.set(O_SESSO, "F");

		if (occas_mask.run() != K_ESC)
		{
			const TString ocfpi(occas_mask.get(O_CODICE));
			doc.put(DOC_OCFPI, ocfpi);
			m.set(F_OCFPI, ocfpi);
	
			for (int i = occas_mask.fields() - 1; i >= 0; i--)
			{
				const TMask_field& f = occas_mask.fld(i);
				const TFieldref* c = f.field();
				if (c)
				{
					const char* val = f.get();
					c->write(val, occ);
				}	
			}
			m.occ2mask();
		}
		f.set_focus( );
	}
	return TRUE;
}

bool TDocumento_mask::clifo_handler( TMask_field& f, KEY key )
{
	if (key != K_ENTER && f.to_check(key, true))
	{
		TDocumento_mask& m = (TDocumento_mask&)f.mask();
		TDocumento& d = m.doc();

		const TTipo_documento& tdoc = d.tipo();
    d.put(DOC_TIPOCF, tdoc.tipocf());
		d.put(DOC_CODCF, f.get());

		const TCli_for& cli_for = d.clifor(true); // force reload
		if ( cli_for.get_bool(CLI_SOSPESO) )
			return f.error_box( "Il codice '%ld' e' sospeso e non puo' essere utilizzato", atol(f.get()));

		m.cli2mask();

		if (m.id2pos(F_CODCONT) >= 0)
		{
			TEdit_field & e = m.efield(F_CODCONT);
			if (e.active())
			{
				e.set_dirty();
				e.check();
				e.on_hit();
			}
		}
	
    if (cli_for.occasionale())
    {
      const TOccasionale& occas = d.occas();
      if(m.id2pos(F_OCCASEDIT) > 0 && f.to_check(key) && occas.codice().blank())
        m.send_key( K_SPACE, F_OCCASEDIT );   // Lancia maschera occasionali
    }
    else
      d.zero(DOC_OCFPI);
  }
	return true;
}

void TDocumento_mask::highlight_row(int row, COLOR back, COLOR fore, bool dirty, bool update)
{			 
	TRiga_documento& rigadoc = doc()[row + 1];
	TSheet_field& sf = sfield(F_SHEET);

//	COLOR back = COLOR_INVALID, fore = COLOR_INVALID;

  FOR_EACH_ARRAY_ITEM_BACK(color_rules(), rule, o)
	{
		TColor_rule& expr = *(TColor_rule*)o;
    bool on = false;
		if (rule == 0)
			on = rigadoc.linked(); // Regola standard
		else
		{
      expr.set_row(&rigadoc);
		  // SET VARS
			const int vars = expr.numvar();
      TString name;
			for (int i = 0; i < vars; i++)
			{
				name = expr.varname(i);
				if (name.starts_with("DIRTY"))
					expr.setvar(i, dirty ? UNO : ZERO);
				else
					if (name.starts_with("#"))
					{
						const short id = atoi(name.mid(1));
						if (id > 0)
						{
							TToken_string& sheet_row = sf.row(row);
							expr.setvar(i, sheet_row.get(sf.cid2index(id)));
						}
						else
							expr.setvar(i, get(-id));
					}
					else
						if (name.starts_with("33.") || name.starts_with("DOC."))
						{
							const TString& fldname = name.after('.');
							expr.setvar(i, doc().get(fldname));
						}
						else
						{
							const TString& fldname = name.find('.') > 0 ? name.after('.') : name;
							expr.setvar(i, rigadoc.get(fldname));
						}
			}
			on = expr.as_bool();
		}
    if (on)
    {
      expr.colors(back, fore);
      break;
    }
	}

  sf.set_back_and_fore_color(back, fore, row);
  if (update)
		sf.force_update(row);
}

void TDocumento_mask::highlight()
{			 
	TSheet_field& sf = sfield(F_SHEET);
  FOR_EACH_SHEET_ROW(sf, i, r)
    highlight_row(i, COLOR_INVALID, COLOR_INVALID, false, false);
	sf.force_update();
}

///////////////////////////////////////////////////////////
// TLista_elaborazioni
///////////////////////////////////////////////////////////

class TLista_elaborazioni : public TObject	// velib04
{		
	TAssoc_array * _elab;						
	
protected:
	void read();
		
public:																		 
	TElaborazione & operator [](const char * key) const;
	int select(TString_array & result, const char * tipo_iniziale = NULL, const char * stato_iniziale = NULL, const char * tipo_finale = NULL, const char * stato_finale = NULL);
	void update(); 
	TLista_elaborazioni() : _elab(NULL) {}
	virtual ~TLista_elaborazioni();
};

void TLista_elaborazioni::read()
{												
	if (_elab == NULL)
	{ 
		_elab = new TAssoc_array();
		
		TTable eld("%ELD");
	
		for (int err = eld.first(); err == NOERR; err = eld.next()) 
		{ 
			TElaborazione* el = NULL;	
			switch (eld.curr().get_int("I0"))
			{
			case _esterna :
				el = new TElaborazione_esterna(eld.curr());
				break;
			case _consegna_ordini:
				el = new TConsegna_ordini(eld.curr());
				break;	
			case _fatturazione_bolle :
				el = new TFatturazione_bolle(eld.curr());
				break;
			case _contabilizzazione :
				el = new TContabilizzazione(eld.curr());
				break;
			case _copia_documento :
				el = new TCopia_documento(eld.curr());
				break;
			case _generazione_effetti :
				el = new TGenerazione_effetti(eld.curr());
				break;
			case _consuntivazione_produzione :
				el = new TConsuntivazione_produzione(eld.curr());
				break;
			case _contabilizzazione_analitica :
				el = new TContabilizzazione_analitica(eld.curr());
				break;
			default :
				break;				 
			}
      if (el != NULL)
			  _elab->add(el->codice(), el);	
		}
	}
}	

int TLista_elaborazioni::select(TString_array & result, const char * tipo_iniziale, const char * stato_iniziale, const char * tipo_finale, const char * stato_finale)
{ 
	read();										 
	_elab->restart();
	result.destroy();
	for (TElaborazione* el = (TElaborazione*)_elab->get(); el != NULL; el = (TElaborazione*)_elab->get())
	{						 
		bool ok = false;
		if ((tipo_iniziale && *tipo_iniziale) && (stato_iniziale && *stato_iniziale))
    {
			for (int i = 0; !ok && i < TElaborazione::_max_tipi_doc_elab; i++)					
			{
				const char si = el->stato_iniziale(i);
				const TString& ti = el->tipo_iniziale(i);
				ok |= ti == tipo_iniziale && si == *stato_iniziale;
			}
    }
		else 
			ok = true;			
		if ((tipo_finale && *tipo_finale) && (stato_finale && *stato_finale))																								 
			ok &= el->tipo_finale() == tipo_finale &&	el->stato_finale() == stato_finale;
		if (ok)
			result.add(el->codice());
	}
  result.sort();
	return result.items();
} 
	
TElaborazione& TLista_elaborazioni::operator[](const char * key) const
{
	((TLista_elaborazioni *)this)->read();
	return (TElaborazione&)(*_elab)[key];
}

void TLista_elaborazioni::update()
{
	delete _elab; _elab = NULL;
	read();
}	

TLista_elaborazioni::~TLista_elaborazioni()
{							
	if (_elab)
		delete _elab;
}	

///////////////////////////////////////////////////////////
// Filtro per articolo
///////////////////////////////////////////////////////////

static TCodice_articolo _art_filter;

static bool rdoc_article_filter(const TRectype& rdoc)
{
  bool good = rdoc.get(RDOC_CODART) == _art_filter;
  if (good)
    good = !rdoc.get_bool(RDOC_RIGAEVASA);
  return good;
}

static bool doc_article_filter(const TRelation* rel)
{													
	bool yes = false;
  const TRectype& doc = rel->curr();

  TLocalisamfile rdoc(LF_RIGHEDOC); rdoc.setkey(5);
  rdoc.put(RDOC_CODART, _art_filter);
	rdoc.put(RDOC_CODNUM, doc.get(DOC_CODNUM));
	rdoc.put(RDOC_ANNO,	  doc.get(DOC_ANNO));
	rdoc.put(RDOC_PROVV,	doc.get(DOC_PROVV));
	rdoc.put(RDOC_NDOC,	  doc.get(DOC_NDOC));
	
	for (int err = rdoc.read(); err == NOERR; err = rdoc.next())
	{
		const TString& codart = rdoc.get(RDOC_CODART);
    if (codart != _art_filter || rdoc.get(RDOC_NDOC) != doc.get(DOC_NDOC))
			break;
		if (rdoc_article_filter(rdoc.curr()))
		{	 
			yes = true;
			break;
		}
	}
	return yes;
}

///////////////////////////////////////////////////////////
// TDocument_tree
///////////////////////////////////////////////////////////

class TDocument_tree : public TBidirectional_tree
{
	TRelation* _relation;
	TCursor* _cursor;
	TToken_string _curnode;
	bool _multiple_selection;
	TAssoc_array _selected_docs;
	TString _selected;
	
protected:				 
	virtual void node2id(const TObject* node, TString& id) const;
	bool on_head() const;
	bool on_row() const;
	
	void format_field(const TRectype& rec, const TString& field, TString& str) const;
	void append_custom_fields(const TTipo_documento& tipo, const TRectype& rec, TString& str) const;

public:	
	void multiple_selection(bool on);
	bool multiple_selection() const { return _multiple_selection;}
	bool node_selected(const TObject* node = NULL) const;
	void select_node(const TObject* node = NULL, bool on = true);
  bool toggle_all_nodes();

	real select_doc(long numdoc);
	void build_doc_list(TLista_documenti & docs);
	void unselect_node(const TObject* node) { select_node(node, false);}
	virtual bool goto_root();
	virtual bool goto_firstson();
	virtual bool goto_rbrother(); 
	virtual bool goto_node(const TString &id);
  virtual bool could_have_son() const;
	virtual bool has_son() const;
	virtual bool has_rbrother() const;
	virtual bool has_father() const;
	virtual bool has_lbrother() const;
	virtual bool goto_father();
	virtual bool goto_lbrother();
	virtual TObject* curr_node() const { return &(TToken_string&)_curnode; }
	virtual bool get_description(TString& str) const;
	virtual TImage* image(bool selected) const;

 	void select(TString & id) { _selected = id;}
 	const TString & selected() const { return _selected;}

	const TRectype& testata() const;
	const TRectype& riga() const;
	const TRectype& record() const;
	const real totale_doc() const { TDocumento d(testata()); return d.totale_doc();}

	void set_cursor(char tipocf, long codcf, int anno, const TString& codnum, 
                  const char* filter, bool allow_zero_cf);
	TCursor* get_cursor() { return _cursor; }

	TDocument_tree();	
	~TDocument_tree();	
};

const TRectype& TDocument_tree::testata() const
{																						 
	TDocument_tree& me = (TDocument_tree&)*this;
	const TRecnotype pos = me._curnode.get_long(0);
	if (_cursor->pos() != pos || _relation->curr(LF_RIGHEDOC).empty())
		*me._cursor = pos;
	return _relation->curr();
}

const TRectype& TDocument_tree::riga() const
{
	TDocument_tree& me = (TDocument_tree&)*this;
	const TRectype& rec = _relation->curr(LF_RIGHEDOC);
	const TRecnotype pos = me._curnode.get_long(0);
	const int nriga = me._curnode.get_int(1);
	if (_cursor->pos() != pos || rec.get_int(RDOC_NRIGA) > nriga)
		*me._cursor = pos;
	for (int i = rec.get_int(RDOC_NRIGA); i < nriga; i++)
		_relation->next_match(LF_RIGHEDOC);
	return rec;	
}

const TRectype& TDocument_tree::record() const
{
	return on_row() ? riga() : testata();
}

void TDocument_tree::node2id(const TObject* node, TString& id) const
{
	id = *(TString*)node;			 
}

bool TDocument_tree::on_head() const
{
	TDocument_tree& me = (TDocument_tree&)*this;
	return me._curnode.get_int(1) == 0;
}

bool TDocument_tree::on_row() const
{
	TDocument_tree& me = (TDocument_tree&)*this;
	return me._curnode.get_int(1) > 0;
}

void TDocument_tree::multiple_selection(bool on)
{
	_multiple_selection = on;
	if (!_multiple_selection)
		_selected_docs.destroy();

}

bool TDocument_tree::node_selected(const TObject* node) const
{
	TToken_string id;

	if (node == NULL)
		node = curr_node();
	
	node2id(node, id);
	id = id.get(0);
	return _selected_docs.is_key(id);
}

void TDocument_tree::select_node(const TObject* node, bool on)
{
	if (node == NULL)
		node = curr_node();
	
	TToken_string id;
	node2id(node, id);
	id = id.get(0);
	if (on)
		_selected_docs.add(id);
	else
		_selected_docs.remove(id);
	select(id);
}

bool TDocument_tree::toggle_all_nodes()
{
  bool on = _selected_docs.empty() && _multiple_selection;
  _selected_docs.destroy();
  if (on)
  {
     for (bool ok = goto_root(); ok; ok = goto_rbrother())
       select_node(NULL, on);
     on = !_selected_docs.empty();
  }
  return on;
}

static bool find_doc(TTree& tree, void* jolly, word flags)
{
	TDocument_tree& t = (TDocument_tree&)tree;
	if (!t.node_selected() && t.testata().get_long(DOC_NDOC) == *((long*)jolly))
	{
		t.select_node();
		return true;
	}
	return false;
}

real TDocument_tree::select_doc(long numdoc)
{
	real val;
	if (goto_root() && scan_depth_first(find_doc, &numdoc, SCAN_PRE_ORDER | SCAN_IGNORING_LEAVES))
	  val = totale_doc();
	return val;
}

static bool add_to_list(TTree& tree, void* jolly, word flags)
{
	TDocument_tree & t = (TDocument_tree &) tree;
	if (t.node_selected())
	{
		TLista_documenti & docs = *((TLista_documenti *) jolly);
		docs.add(new TDocumento(t.testata()));
	}
	return false;
}

void TDocument_tree::build_doc_list(TLista_documenti & docs)
{
	if (goto_root())
		scan_depth_first(add_to_list, &docs, SCAN_PRE_ORDER | SCAN_IGNORING_LEAVES);
}

bool TDocument_tree::goto_root()
{
	const bool ok = _cursor != NULL && _cursor->items()>0;
	_curnode = ok ? "0" : "";
	*_cursor = 0;
	return ok;
}

// Fundamental method working also when _art_filter.full()
bool TDocument_tree::goto_firstson()
{
	bool ok = has_son();
	if (ok)
  {
    int nriga = 1;
    if (_art_filter.full())
    {
      const TRectype& rec = _relation->curr(LF_RIGHEDOC);
      nriga = rec.get_int(RDOC_NRIGA);
    }
		_curnode.add(nriga,1); 
  }
	return ok;
}

// Fundamental method working also when _art_filter.full()
bool TDocument_tree::goto_rbrother()
{
	bool ok = has_rbrother();
	if (ok)
	{
		if (on_head())
		{						 
			 const long pos = _curnode.get_long(0);
			 _curnode.add(pos+1, 0);
		} 
		else
		{
			const int nriga = _curnode.get_int(1);
			_curnode.add(nriga+1, 1);
		}
	}
	return ok;
}

bool TDocument_tree::goto_node(const TString &id)
{						
	_curnode = id;			
	return true;
}

// Drawing speedup
bool TDocument_tree::could_have_son() const
{ return on_head(); }

// Fundamental method working also when _art_filter.full()
bool TDocument_tree::has_son() const
{
	bool ok = could_have_son();
	if (ok)
	{	 
		testata();
		const TRectype& rec = _relation->curr(LF_RIGHEDOC);
		ok = rec.get_int(RDOC_NRIGA) > 0;
    if (_art_filter.full())
    {
      ok = rdoc_article_filter(rec);
      while (!ok && _relation->next_match(LF_RIGHEDOC))
        ok = rdoc_article_filter(rec);
    }
	}
	return ok;
}

// Fundamental method working also when _art_filter.full()
bool TDocument_tree::has_rbrother() const
{
	bool ok = false;
	if (on_head())
	{
		long pos = 0; _curnode.get(0, pos);
		ok = pos < _cursor->items()-1;
	} 
	else
	{
		riga(); // Posizionati sulla riga corrente
    if (_art_filter.full())
    {
      const TRectype& rec = _relation->curr(LF_RIGHEDOC);
      while (!ok && _relation->next_match(LF_RIGHEDOC))
        ok = rdoc_article_filter(rec);
    }
    else
		  ok = _relation->next_match(LF_RIGHEDOC);
	}
	return ok;
} 

// Pleonastic method working also when _art_filter.full()
bool TDocument_tree::has_father() const
{	return on_row(); }

// Pleonastic method not working when _art_filter.full()
bool TDocument_tree::has_lbrother() const
{
	bool ok = false;
	if (on_head())
	{
		long pos = 0; _curnode.get(0, pos);
		ok = pos > 0L;
	} 
	else
	{
		int nriga = 0; _curnode.get(1, nriga);
		ok = nriga > 1;
	}
	return ok;
}

// Pleonastic method not working when _art_filter.full()
bool TDocument_tree::goto_father()
{
	bool ok = on_row();
	if (ok)			 
		_curnode.add(0, 1);
	return ok;
}

// Pleonastic method not working when _art_filter.full()
bool TDocument_tree::goto_lbrother()
{
	bool ok = has_lbrother();
	if (ok)
	{
		if (on_head())
		{						 
			 const long pos = _curnode.get_long(0);
			 _curnode.add(pos-1, 0);
		} 
		else
		{
			const int nriga = _curnode.get_int(1);
			_curnode.add(nriga-1, 1);
		}
	}
	return ok;
}

void TDocument_tree::format_field(const TRectype& rec, const TString& field, TString& str) const
{
	const TFieldref fld(field, rec.num());
	const TString& value = fld.read(rec);
	const TFieldtypes ft = rec.type(fld.name());
	if (ft == _realfld)
	{																			 
		const int len = rec.length(fld.name());
		const int ndec = rec.ndec(fld.name());
		TString8 pic; pic.format(".%d", ndec);
		const real r(value);
		str = r.string(pic);
		str.right_just(len);
	}
	else
		str = value;
}

void TDocument_tree::append_custom_fields(const TTipo_documento& tipo, const TRectype& rec, TString& str) const
{ 
	const TString& format = rec.num() == LF_DOC ? tipo.stringa_descrizione_documento() 
																							: tipo.stringa_descrizione_riga();
	if (format.not_empty())
	{ 
		str << ' ';
		int ch = -1;
		TString tmp;
		for (int ap = format.find('{'); ap >= 0; ap = format.find('{', ch+1))
		{		 
			str << format.sub(ch+1, ap);
			ch = format.find('}', ap);
			const TString16 field = format.sub(ap+1, ch);
			if (!field.blank())
			{
				format_field(rec, field, tmp);
				str << tmp;
			}
		}
		str << format.mid(ch+1);
	}
}

TImage* TDocument_tree::image(bool selected) const
{								
	if (on_row()) 
	{
		const TRectype& rec = riga();
		if (rec.get_bool(RDOC_RIGAEVASA))
			return get_res_icon(10203);
	}
	else
  {
		if (multiple_selection())
		{
			const bool sel = node_selected();
			if (sel)
			{
				if (selected)
					return get_res_image(BMP_DIRDNSEL);
				else
					return get_res_image(BMP_DIRSEL);
			}
		}
  }
	return TTree::image(selected);
}

bool TDocument_tree::get_description(TString& str) const
{
	if (on_head())
	{
		const TRectype& rec = testata();
		str = rec.get(DOC_ANNO);
		str << ' ' << rec.get(DOC_CODNUM);
		TString16 tmp;
		tmp.format("%6ld", rec.get_long(DOC_NDOC));
		str << ' ' << tmp << ' ' << rec.get(DOC_DATADOC);
		const char tipocf = rec.get_char(DOC_TIPOCF);
		const long codcf = rec.get_long(DOC_CODCF);
		tmp.format(" %c%6ld ", tipocf, codcf);
		str << tmp;
		tmp.format("%c|%6ld", tipocf, codcf);
		str << cache().get(LF_CLIFO, tmp, CLI_RAGSOC);
		str.left_just(63);
		
		const TString& tipodoc = rec.get(DOC_TIPODOC);
		const TTipo_documento& tipo = cached_tipodoc(tipodoc);
		append_custom_fields(tipo, rec, str);
	}
	else
	{
		const TRectype& rec = riga();
		const TRectype& testata = _relation->curr();
		
		const TString80 codart = rec.get(RDOC_CODART);
		str = codart;
		str.left_just(21);
		str << rec.get(RDOC_DESCR).left(30);
		str.left_just(52);
		
		const TString& tipodoc = testata.get(DOC_TIPODOC);
		const TTipo_documento& tipo = cached_tipodoc(tipodoc);
		if (codart.not_empty())
		{
			const real qta = rec.get_real(tipo.field_qta());
			str << qta.string("###.###.##@,@@@");

			if (tipo.is_ordine())
			{
				const real qta_evasa = rec.get_real(tipo.field_qtaevasa());
				const real residuo = qta_evasa < qta ? (qta-qta_evasa) : ZERO;
				str << residuo.string("###.###.##@,@@@");
			}
			append_custom_fields(tipo, rec, str);
		}
	}
	return true;
}

void TDocument_tree::set_cursor(char tipocf, long codcf, int anno, const TString& codnum, const char* filter, bool allow_zero_cf)
{ 
	if (_relation == NULL)
	{
		_relation = new TRelation(LF_DOC);
		_relation->add(LF_RIGHEDOC, "PROVV==PROVV|ANNO==ANNO|CODNUM==CODNUM|NDOC==NDOC");
	}

	TRectype& rec = _relation->curr();
	rec.zero();
	rec.put(DOC_PROVV, "D");
	rec.put(DOC_ANNO, anno);
  rec.put(DOC_CODNUM, codnum);

  int key = 4;
  TString filtro = filter;
  if (allow_zero_cf)
  {
    key = 1;
    filtro << "&&(STR((CODCF=0)||(CODCF=" << codcf << ")))";
  }
  else
  {
    rec.put(DOC_TIPOCF, tipocf);
	  rec.put(DOC_CODCF, codcf);
  }
  
  if (_cursor != NULL)
    delete _cursor;
  _cursor = new TCursor(_relation, filtro, key, &rec, &rec); 
  if (_art_filter.full())
	  _cursor->set_filterfunction(doc_article_filter);
  else
    _cursor->set_filterfunction(NULL);

  const long items = _cursor->items();
	_cursor->freeze(true);
	
	goto_root();
	if (items == 1)
		expand_all();
}

TDocument_tree::TDocument_tree() 
							: _relation(NULL), _cursor(NULL), _multiple_selection(false)
{ }
 
TDocument_tree::~TDocument_tree()
{
	if (_cursor)
		delete _cursor;
	if (_relation)
		delete _relation;
}

///////////////////////////////////////////////////////////
// TElabora_mask
///////////////////////////////////////////////////////////

class TElabora_mask : public TAutomask
{				 
	TDocumento_mask* _main;
	TLista_elaborazioni _elab;
	TDocument_tree _tree;
	int _check_fld;

	TElaborazione* _last_elab;
	
// @access Protected Member
protected:				
	void add_valuta_filter(TString& filter) const;
	
	void docrif_search();
	int update_list();
	void update_ndoc_filter(bool is_tipo_elaborazione = FALSE);

	virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
	
// @access Public Member
public:				
	bool elabora();	
	TElaborazione* curr_elab();

	// @cmember Costruttore (crea la maschera leggendo la descrizione dal file .msk)
	TElabora_mask(TDocumento_mask& main_mask);
	// @cmember Distruttore
	virtual ~TElabora_mask() {} 
};

bool TElabora_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
	switch (o.dlg())
	{								
	case F_CODART:
	case F_CODNUM_ELAB:
		if (e == fe_modify)
			update_ndoc_filter();
		break;
  case F_UMQTA:
    if (e == fe_init || e == fe_modify)
    {
      int dec = 5;
      if (!o.empty())
      {
        const TRectype& um = cache().get("%UMS", o.get());
        if (!um.empty() && um.get_bool("B0")) // Ha dei decimali specificati?
          dec = um.get_int("I0");
      }
      ((TReal_field&)field(F_QTA)).set_decimals(dec);
    }
    break;
	case F_TYPE:
		if (e == fe_init || e == fe_modify)
		{
			int ne = update_list();
			if (e == fe_init && ne == 0)	// Riprova a cambiare flag e ricostruire la lista
			{
				set(F_TYPE, "X");
				ne = update_list();
				if (ne == 0)
					set(F_TYPE, "");
			}
			update_ndoc_filter(true);
			const bool add_to_doc = o.get().full();
  		TElaborazione * e = curr_elab();
			const bool external = e != NULL && e->tipo() == _esterna;
      const bool is_search = o.get().empty() || field(F_CODCF_ELAB).empty() || external || add_to_doc;
			
			o.mask().field(F_NDOC_ELAB).check_type(is_search ? CHECK_SEARCH : CHECK_NORMAL);
			_tree.multiple_selection(add_to_doc);
      
			bool check_tot = false;
			if (add_to_doc)
			{
				if (_check_fld < -1)
				{
					_check_fld = -1;
					const TPointer_array& handlers = _main->doc().tipo().handlers();
          FOR_EACH_ARRAY_ITEM_BACK(handlers, id, hnd)
          {
            if (long(hnd) == 2)  // 2 = totdoc_handler
              _check_fld = id;
          }
				}
				check_tot = _check_fld >= 0;
			}
			if (!add_to_doc)
				o.mask().set(F_TOTSEL, "");
			o.mask().show(-GRP_CHK, check_tot);
			if (check_tot)
				o.mask().set(F_TOTVAL, _main->get(_check_fld));
		}
		break;		
	case F_STATODOC_ELAB:
	case F_TIPODOC_ELAB:
		if (e == fe_modify)
		{
			update_list();
			update_ndoc_filter();
		}
		break;
	case F_ELAB:
		if (e == fe_modify)
			update_ndoc_filter(true);
		break;
	case F_ANNO_ELAB:
		if (e == fe_modify)
			update_ndoc_filter();
		break;
	case F_NUMDOCRIF_ELAB:
		if (e == fe_button) 
			docrif_search();
		break;
  case F_NDOC_ELAB:
      if ((e == fe_modify || e == fe_close) && o.check_type() == CHECK_SEARCH && !o.empty()) 
      {
        TToken_string key; 
        key.add("D"); key.add(get(F_ANNO_ELAB));
        key.add(get(F_CODNUM_ELAB)); key.add(o.get());
        const TRectype& rec = cache().get(LF_DOC, key);
        bool ok = !rec.empty(); // Verifica esistenza documento
       
        if (ok)
        {
          TCursor* c = _tree.get_cursor();
          c->curr() = rec;
          ok = c->test(_isequal) == NOERR; // Verifica compatibilit� documento
        }
        if (!ok)
          return error_box(((TEdit_field&)o).get_warning());
      }
			if (e == fe_init || e == fe_modify)
			{
				const long ndoc = atol(o.get());

				if (ndoc > 0L)
				{
					real val = _tree.select_doc(ndoc);
					if (!val.is_zero())
					{
						val += o.mask().get_real(F_TOTSEL);
						o.mask().set(F_TOTSEL, val);
					}
				}
			}
		break;
	case F_ROWS:
    if (e == fe_modify && is_running()) 
		{								
			TString id;
			_tree.curr_id(id);
			_tree.select(id);
			if (is_running() && !_tree.multiple_selection())
			{
				TCursor* c = _tree.get_cursor();
				if (c != NULL && c->items() > 0)
				{
					const TRectype& head = _tree.testata();
					set(F_DATADOC_ELAB, head.get(DOC_DATADOC)); // Anch'essa nella chiave 2!
					set(F_ANNO_ELAB, head.get(DOC_ANNO));
					set(F_CODNUM_ELAB, head.get(DOC_CODNUM), 2); // Check but not hit
					set(F_NDOC_ELAB, head.get(DOC_NDOC));
				}
			}
		}
		else
			if (e == fe_button)
			{
				if (_tree.multiple_selection())
				{
					const bool on = !_tree.node_selected();
					_tree.select_node(NULL, on);
					if (_check_fld >= 0)
					{
						real val = get_real(F_TOTSEL);
						if (on)
							val += _tree.totale_doc();
						else
						{
							val -= _tree.totale_doc();
							if (_tree.testata().get_long(DOC_NDOC) == o.mask().get_long(F_NDOC_ELAB))
								o.mask().set(F_NDOC_ELAB, "");
						}
						set(F_TOTSEL, val);
					}
				}
			}
		break;
	case DLG_LINK:
		if (e == fe_button)
		{
			_tree.goto_node(_tree.selected());
			const TRectype & rec = _tree.testata();
			
			if (!rec.empty())
			{
				TFilename tempfile;
				tempfile.temp("ve0");
				tempfile.ext("ini");
				{
					TConfig configfile(tempfile);
					configfile.set("Action", "Modify", "Transaction");
					configfile.set("NDOC", rec.get(DOC_NDOC), "33");
					configfile.set(DOC_PROVV, rec.get(DOC_PROVV), "33");
					configfile.set(DOC_ANNO, rec.get(DOC_ANNO), "33");
					configfile.set(DOC_CODNUM, rec.get(DOC_CODNUM), "33");
				}

				TString commandline;

				commandline.format("ve0 -0 /i%s",(const char*)tempfile);

				TExternal_app ve(commandline);
				ve.run();

				remove_file(tempfile);
			}
		}
		break;
  case DLG_SELECT:
    if (e == fe_button)
    {
      TTree_field& tf = tfield(F_ROWS);
      if (tf.active() && _tree.multiple_selection())
      {
        TWait_cursor hourglass;
        const bool sel = _tree.toggle_all_nodes();
        if (_check_fld > DLG_NULL)
        {
           real tot;
           for (bool ok = _tree.goto_root(); ok && sel; ok = _tree.goto_rbrother())
             tot += _tree.totale_doc();
           set(_check_fld, tot.string());
        }
        tf.win().force_update(); 
      }
      return false;
    }
    break;
	default:
		break;
	}
	return true;	
}

int TElabora_mask::update_list()
{
	TString_array elabs;
	const TString& tipo = _main->get(F_TIPODOC);
	const TString& stato = _main->get(F_STATO);
	const TString& tipo_elab = get(F_TIPODOC_ELAB);
	const TString& stato_elab = get(F_STATODOC_ELAB);
	const bool from_elab = !get_bool(F_TYPE);	 
	int items = 0;
	
	if (from_elab)
	{
		items = _elab.select(elabs, tipo, stato, "", "") ;
		field(F_ANNO_ELAB).check_type(CHECK_REQUIRED);
	}
	else
	{
		field(F_ANNO_ELAB).check_type(CHECK_NONE);
		items = _elab.select(elabs, tipo_elab, stato_elab, tipo, stato);
    if (items == 0)
      items = _elab.select(elabs, "", "", tipo, stato);
	}

	TList_field & f = lfield(F_ELAB);
	TToken_string codes;
	TToken_string descrs;
	for (int i = 0; i < items; i++)
	{					 
		const TElaborazione& e = _elab[elabs.row(i)];
		
		if (!from_elab) 
		{
			// AO20123: Impedire contabilizzazione all'indietro!	
			if (e.tipo() == _contabilizzazione || e.tipo() == _generazione_effetti)
				continue;	 
		}
		
		codes.add(e.codice());
		descrs.add(e.descrizione());
	}

	items = codes.items();	// Conta elementi veramente aggiunti
	const bool ok = items > 0;
	enable(DLG_OK, ok);
	enable(F_ELAB, ok);

	if (codes != f.get_codes())
		f.replace_items(codes, descrs);
	const TElaborazione* e = curr_elab();
	if (e != NULL && e->tipo() == _consegna_ordini)
		show(-GRP_ART);
	else
	{
		reset(-GRP_ART);
		hide(-GRP_ART);
	}
	
	return items;
}

bool TElabora_mask::elabora()
{	 
	bool update_mask = false;

	TLista_documenti in;
	TLista_documenti out;																 
	TDocumento& app_doc = ((TDocumento_mask *)_main)->doc();
	const long numdoc = field(F_NDOC_ELAB).active() ? get_long(F_NDOC_ELAB) : app_doc.get_long(DOC_NDOC);
	const bool update_header = get_bool(F_UPDATE_HEADER);
	const bool from_elab = !get_bool(F_TYPE);	 

  TElaborazione* e = curr_elab();
	if (e == NULL)
		return false;
	
	if (e->tipo() == _consegna_ordini)
	{
		TParametri_elaborazione& p = e->params();
		p.set("ARTICOLO", get(F_CODART));
		p.set("UM", get(F_UMQTA));
		p.set("QUANTITA", get(F_QTA));
	}
	if (from_elab)
	{
		const char provv = get(F_PROVV_ELAB)[0];
		const int anno = get_int(F_ANNO_ELAB);
		const TString& codnum = get(F_CODNUM_ELAB);
		const TString& tipo = get(F_TIPODOC_ELAB);
		const TString& stato = get(F_STATODOC_ELAB);

		if (anno <= 0 || codnum.blank() || tipo.blank() || stato.blank())
			return false;

		TDocumento* newdoc = new TDocumento(provv, anno, codnum, numdoc);
		TDocumento& d = *newdoc;

		if (numdoc <= 0)									 
		{						
			TDocumento::copy_data(d.head(), app_doc.head());
			d.put(DOC_TIPODOC, tipo);
			d.put(DOC_STATO, stato);
			
			const TDate datadoc = d.get_date(DOC_DATADOC);
			const TDate datainsc = d.get_date(DOC_DATAINSC);
			const bool equal = !datainsc.ok() || datadoc == datainsc;
			
			d.put(DOC_DATADOC, get(F_DATADOC_ELAB));
			if (equal)
				d.zero(DOC_DATAINSC);
			
			const TTipo_documento & t = d.tipo();
			
			if (t.mov_mag())
				d.put(DOC_CAUSMAG, t.caus_mov());
			else
				d.zero(DOC_CAUSMAG);
		}

		in.add(app_doc);
		out.add(d);
		if (e->elabora(in, out, TDate(TODAY), true))
		{										
			if (out[0] != d)
				out.rewrite();
			if (app_doc != in[0])
			{
				in.rewrite();
				app_doc = in[0];
				update_mask = true;
			}	
		}
		delete newdoc;
	}
	else
	{
		_tree.build_doc_list(in);
		if (in.items() == 0)
			return false ;
		char provv = get(F_PROVV_ELAB)[0];
		int anno = get_int(F_ANNO_ELAB);
		const TString4 codnum = get(F_CODNUM_ELAB);
		long ndoc = get_long(F_NDOC_ELAB);

		if (ndoc > 0L && !in.find(provv, anno, codnum, ndoc))
		{
			TDocumento* d = new TDocumento(provv, anno, codnum, ndoc);
  		in.add(d);
		}
		if (update_header)									 
		{																											
			const TString4 tipo_doc=app_doc.get(DOC_TIPODOC);
			const TString8 caus_mag=app_doc.get(DOC_CAUSMAG);
			const long movmag      = app_doc.get_long(DOC_MOVMAG);
			const TDate datadoc    = app_doc.get_date(DOC_DATADOC);
			const TDate datainsc   = app_doc.get_date(DOC_DATAINSC);
			const TDate datapart   = app_doc.get_date(DOC_DATAPART);
			const TString8 orapart = app_doc.get(DOC_ORAPART);
			const char stato       = app_doc.stato();
			
			TDocumento::copy_data(app_doc.head(), in[0].head());
			
			app_doc.put(DOC_TIPODOC,  tipo_doc);
			app_doc.put(DOC_CAUSMAG,  caus_mag);
			app_doc.put(DOC_MOVMAG,   movmag);
			app_doc.put(DOC_DATADOC,  datadoc);
			app_doc.put(DOC_DATAINSC, datainsc);
			app_doc.put(DOC_DATAPART, datapart);
			app_doc.put(DOC_ORAPART,  orapart);
			app_doc.put(DOC_STATO,    stato);
		}
		out.add(app_doc);
		if (e->elabora(in, out, TDate(TODAY), true))
		{
			if (out[0] != app_doc)
			{
				out.rewrite();
				app_doc.read(out[0].head());
				update_mask = true;
			}
			in.rewrite();

      // Aggiorna eventuale residuo da consegnare
  	  if (e->tipo() == _consegna_ordini)
	    {
		    TParametri_elaborazione& p = e->params();
		    set(F_QTA, p.get("QUANTITA"));
	    }
      // Toglie spunta ai documenti selezionati
      _tree.toggle_all_nodes();
		}
		const TString4 num_in = e->codice_numerazione_iniziale();
		set(F_CODNUM_ELAB, num_in);
		set(F_NDOC_ELAB, "");
		set(F_NUMDOCRIF_ELAB, "");
				((TDocumento_mask *)_main)->set_focus_field(F_SHEET);
	}				 

	// Azzera l'anno in caso di ordini
  if (in.items() > 0 && in[0].is_ordine() && !field(F_ANNO_ELAB).required()) 
	{
		reset(F_ANNO_ELAB);
		update_mask = true;
	}

	if (update_mask)
		update_ndoc_filter();
			
	return update_mask;
}

TElaborazione* TElabora_mask::curr_elab()
{
	const TString& cod_elab = get(F_ELAB);
	return cod_elab.full() ? &_elab[cod_elab] : NULL;
}		 

void TElabora_mask::add_valuta_filter(TString& filter) const
{																						 
	TString4 valuta = get(F_CODVAL_ELAB);
	if (::is_firm_value(valuta))
	{							
		filter << "((CODVAL==\"" << valuta <<	"\")";
		if (valuta.empty())
			valuta = TCurrency::get_firm_val();
		else
			valuta.cut(0);	
		filter << "||(CODVAL==\"" << valuta <<	"\"))";
	}
	else
		filter << "(CODVAL==\"" << valuta <<	"\")";
}

void TElabora_mask::update_ndoc_filter(bool is_tipo_elaborazione)
{
	TString filter;
	add_valuta_filter(filter);
	
	TElaborazione* e = curr_elab();
	const bool elab_changed = e != _last_elab;
	_last_elab = e;

	const bool aggiungi_doc_att = get_bool(F_TYPE); 
	enable(-1, aggiungi_doc_att);
	if (!aggiungi_doc_att && is_tipo_elaborazione )
		reset(-1);

	const bool enable_group_doc = e != NULL && e->tipo() != _generazione_effetti && e->tipo() != _contabilizzazione;
	show(-GRP_DOC, enable_group_doc);

  enable(DLG_SELECT, aggiungi_doc_att && enable_group_doc); // Attiva la selezione multipla se possibile

	if (e != NULL)
	{
		if (aggiungi_doc_att)
		{
      bool agg_test = e->aggiorna_testata_se_vuoto();

			if (agg_test)
			{
				const int nrighe = _main->doc().physical_rows();

				for (int i = 1;agg_test && i <= nrighe; i++)
					if (!_main->doc()[i].is_generata())
						agg_test = false;
			}

			set(F_UPDATE_HEADER, agg_test ? "X" : "");
			const TString4 num_in = e->codice_numerazione_iniziale(); 
			if (elab_changed)
			{ 
				const TString4 tipo_in(e->tipo_iniziale(0));
				const char stato_in = e->stato_iniziale(0);

				set(F_CODNUM_ELAB, num_in, 0x2);
				set(F_TIPODOC_ELAB , tipo_in, 0x2);
				TString4 si; si << stato_in;
				set(F_STATODOC_ELAB, si, 0x2);
	
				// Azzero anno di elaborazione quando ho a che fare con degli ordini				
				const TTipo_documento& tipodocin = cached_tipodoc(tipo_in);
				if (tipodocin.is_ordine() && !field(F_ANNO_ELAB).required())
					reset(F_ANNO_ELAB);
			}

			if (!field(F_TIPODOC_ELAB).empty())																	 
			{ 
				const TString4 tipo(get(F_TIPODOC_ELAB));
				TString80 td; td.format("&&(TIPODOC==\"%s\")", (const char *)tipo);
				filter << td;
				const TString& stato = get(F_STATODOC_ELAB);
				if (stato.not_empty())
				{
					filter << "&&(STATO==\"" << stato << "\")";
				}
				else
				{
					bool almost_one = false;
																					 
					for (int i = 0; i < TElaborazione::_max_tipi_doc_elab; i++)
					{
						const TString4 tipo_in(e->tipo_iniziale(i));
						const char stato_in = e->stato_iniziale(i);
							
						if (tipo == tipo_in && stato_in > '0')
						{											 
							if (almost_one)
								filter << "||";
							else
								filter << "&&(";
							almost_one = TRUE;
							
						 filter << "(STATO==\"" << stato_in << "\")";
						}
					}
					if (almost_one)
						filter << ')';
				}
			}
			else
			{	
				bool almost_one = false;
																				 
				for (int i = 0; i < TElaborazione::_max_tipi_doc_elab; i++)
				{
					const TString4 tipo_in(e->tipo_iniziale(i));
					if (tipo_in.full())
					{											 
						if (almost_one)
							filter << "||";
						else
							filter << "&&(";
						almost_one = true;
						filter << "((TIPODOC==\"" << tipo_in << "\")";
							
						const char stato_in[2] = { e->stato_iniziale(i), '\0' };
						if (stato_in[0] > '0')
							filter << "&&(STATO==\"" << stato_in << "\")";
						filter << ')';
					}
				}
				if (almost_one)
					filter << ')';
			}	 
		}
		else
		{
			const TString4 tipo_fin(e->tipo_finale());
			const TString4 stato_fin(e->stato_finale());

			set(F_UPDATE_HEADER, "");
			filter << "&&";
			if (stato_fin != "0")
				filter << '(';
			filter << "(TIPODOC==\"" << tipo_fin << "\")";
			if (stato_fin != "0")
				filter << "&&(STATO==\"" << stato_fin << "\"))";

			if (is_tipo_elaborazione)
			{					 
				const TString4 num_fin = e->codice_numerazione_finale();
				set(F_CODNUM_ELAB, num_fin, 0x2);
				set(F_TIPODOC_ELAB, tipo_fin, 0x2);
				set(F_STATODOC_ELAB, stato_fin, 0x2);
			}
		}
	}

	if (!field(F_CODNUM_ELAB).empty())
		filter << "&&(CODNUM==\""<< get(F_CODNUM_ELAB) << "\")";

	_art_filter = get(F_CODART);
  if (!aggiungi_doc_att || _art_filter.blank())
    _art_filter.cut(0);


  /* Vedi sotto: copia cursore da albero
	TBrowse& brew = *efield(F_NDOC_ELAB).browse();
	brew.set_filter(filter);
	TCursor* cursor = brew.cursor();
	if (_art_filter.full() && aggiungi_doc_att)
		cursor->set_filterfunction(doc_article_filter);
	else
		cursor->set_filterfunction(NULL);
  */
		
	TTree_field& tf = tfield(F_ROWS); 
	if (e != NULL /*&& !field(F_TIPODOC_ELAB).empty() */ )  // 18-10-2013 tolto test tipo documento vuoto
	{
    const char tipocf = get(F_TIPOCF_ELAB)[0];
    const TString& codnum = get(F_CODNUM_ELAB); 
    const bool allow_zero_cf = tipocf == 'F' && aggiungi_doc_att && codnum.full() && e->tipo() == _consegna_ordini;
  	_tree.set_cursor(tipocf, get_long(F_CODCF_ELAB), get_int(F_ANNO_ELAB), 
                     codnum, filter, allow_zero_cf);
    efield(F_NDOC_ELAB).browse()->replace_cursor(_tree.get_cursor());

		tf.set_tree(&_tree);

    TToken_string header(256, '\n');
		header.add("Anno Num.    N. Data       Cli/For Ragione Sociale");
		header.add("   Codice Articolo      Descrizione Riga                    ");
		if (aggiungi_doc_att && e->tipo() == _consegna_ordini)
			header << "Da Evadere        Residuo";
		else
			header << "  Quantit�";
		tf.set_header(header);

    if (aggiungi_doc_att)	 // GF20059	
		{
			TCursor& cur = *_tree.get_cursor();
			if (cur.items() == 1) // Propone l'unico documento possibile
			{																
				cur = 0L;
				const TRectype& curr = cur.curr();
				set(F_ANNO_ELAB, curr.get(DOC_ANNO));
				set(F_NDOC_ELAB, curr.get(DOC_NDOC));
				set(F_CODNUM_ELAB, curr.get(DOC_CODNUM), 0x2);	// Check but not hit
				set(F_DATADOC_ELAB, curr.get(DOC_DATADOC));
			}
      else
        reset(F_NDOC_ELAB);
		}
	}
	else
		tf.set_tree(NULL);
	tf.win().force_update();
}

void TElabora_mask::docrif_search()
{
	TRectype filtrec(LF_DOC);
	filtrec.put(DOC_TIPOCF, get(F_TIPOCF_ELAB));
	filtrec.put(DOC_CODCF, get(F_CODCF_ELAB));
	filtrec.put(DOC_PROVV, get(F_PROVV_ELAB));
	filtrec.put(DOC_ANNO, get(F_ANNO_ELAB));
		
	TRelation rel(LF_DOC);
	rel.add(LF_CLIFO, "TIPOCF==TIPOCF|CODCF==CODCF");
	TSorted_cursor cur(&rel, "TIPOCF|CODCF|PROVV|ANNO|CODNUM|NUMDOCRIF", "", 2, &filtrec, &filtrec);
	TString flt(256); 
	if (!field(F_CODNUM_ELAB).empty())
		flt << "(CODNUM==\"" << get(F_CODNUM_ELAB) << "\")&&";
	if (!field(F_TIPODOC_ELAB).empty())
		flt << "(TIPODOC==\"" << get(F_TIPODOC_ELAB) << "\")&&";
	if (!field(F_STATODOC_ELAB).empty())
		flt << "(STATO==\"" << get(F_STATODOC_ELAB) << "\")&&";
	add_valuta_filter(flt); flt << "&&";
	TEdit_field& f = efield(F_NUMDOCRIF_ELAB);
	if (!f.empty())
		flt << "(NUMDOCRIF==\"" << f.get() << "\")&&";
	flt.rtrim(2);	// Togli gli ultimi &&
	
	cur.setfilter(flt);
	
	TToken_string fields = "ANNO|CODNUM|TIPODOC|NUMDOCRIF|STATO|DATADOCRIF|DOC1|DOC2|DOC3|NDOC|20->RAGSOC";
	TCursor_sheet sheet(&cur, fields, 
											TR("Documento di riferimento"),
											HR("Anno|Num.|Tipo|Docum.Rif.|Stato|Data@10|Docum.Rif.1|Docum.Rif.2|Docum.Rif.3|Documento|Ragione Sociale@50"),
											0, 1);
	if (sheet.run() == K_ENTER)
	{																		 
		const int nrifpos = fields.get_pos("NUMDOCRIF");
		const TString16 nrif = sheet.row(-1).get(nrifpos);
		f.set(nrif);
		const int ndocpos = fields.get_pos("NDOC");
		const TString16 ndoc = sheet.row(-1).get(ndocpos);
		set(F_NDOC_ELAB, ndoc);
		const int codnumpos = fields.get_pos("CODNUM");
		const TString4 codnum = sheet.row(-1).get(codnumpos);
		set(F_CODNUM_ELAB, codnum, TRUE);
	}
}

TElabora_mask::TElabora_mask(TDocumento_mask& main_mask)
						 : TAutomask("ve0100b"), _main(&main_mask), _last_elab(NULL), _check_fld(-883)
{																						
	const TDate oggi(TODAY);
	set(F_ANNO_ELAB,   oggi.year());	//anno della datadoc proposta (risolve bug 0000331)
	set(F_TIPOCF_ELAB, _main->get(F_TIPOCF));																								 
	set(F_CODCF_ELAB,  _main->get(F_CODCF));
	set(F_CODVAL_ELAB, _main->get(F_CODVAL));
}

bool TDocumento_mask::elabora_handler( TMask_field& f, KEY key )
{
	if (key == K_SPACE)
	{
		TDocumento_mask& m = (TDocumento_mask&)f.mask();
		m.update_progs();
		if (!m.check_fields()) // Check values
      return false;
		
    TElabora_mask* selection = new TElabora_mask(m); 
		bool do_checks = false;
		const char stato_iniziale = m.doc().stato();
		m.update_father_rows();
		while (selection->run() == K_ENTER)   //NON riportare modifiche dalla 3.1!! Gi� sistemato
		{
			m.mask2doc();
			const bool processed = selection->elabora();
			do_checks |= processed;

			if (m.doc().stato() != stato_iniziale)
        break;

			if (processed)
			{	
				m.doc2mask(false);
				TSheet_field& ss = m.sfield(F_SHEET);					
				for (int i = 0; i < ss.items(); i++)
				{
					m.ss_notify(ss,i,K_TAB); 
					m.ss_notify(ss,i,K_SPACE); 
					m.ss_notify(ss,i,K_ENTER); 
				}
			}
  
			if (!selection->get_bool(F_TYPE)) // non aggiunge al documento attuale
				break;
		}
		if (do_checks)      //NON riportare modifiche dalla 3.1!! Gi� sistemato
		{
      m.doc2mask(false);
			// Provoca decodifiche necessarie
			const int tutti = m.fields();
      int i;
			for (i = 0; i < tutti; i++)
			{
				TMask_field& f = m.fld(i);
        if (f.dlg() <= BASE_PIEDE)
					f.check(STARTING_CHECK);
			}
			for (i = tutti-1; i >= 0; i--)
				m.fld(i).set_dirty(FALSE);
		}
		m.update_father_rows(false);
		delete selection;		 
	}
	return true;
}

///////////////////////////////////////////////////////////
// TDocumento_mask
///////////////////////////////////////////////////////////

bool TDocumento_mask::print_handler( TMask_field& f, KEY key )
{
	if (key == K_SPACE)		
  {
		switch (f.dlg())
		{
		case DLG_EMAIL   : app().mailto();  break;
		case DLG_PREVIEW : app().preview();	break;
    default          : app().print();   break;
		}
  }
	return true;
}

void TDocumento_mask::set_field_handler(short fieldid, CONTROL_HANDLER handler)
{
	_handlers.add((TObject *)handler, fieldid);
}

void TDocumento_mask::user_set_handler(short fieldid, int index)
{
	switch (index)
	{
	case  1: set_field_handler(fieldid, ora_hndl);	     break;
	case  2: set_field_handler(fieldid, totdoc_hndl);	   break;
	case  3: set_field_handler(fieldid, numdocrif_hndl); break;
	case  4:
		_smartcard = new TSmart_card();
		if (_smartcard->type() != no_smartcard)
		{
			set_field_handler(fieldid, smart_hndl);
			set_handler(fieldid, universal_handler);
		}
		else
		{
			disable(fieldid);
			delete _smartcard;
			_smartcard = NULL;
		}
		break;
	case  5: set_field_handler(fieldid, dummy_hndl); break;
  case  6: set_field_handler(fieldid, fido_hndl);  break;
	default: break;
	}
}

bool TDocumento_mask::call_handler( TMask_field& f, KEY key)
{
	const short id = f.dlg();
	CONTROL_HANDLER h = (CONTROL_HANDLER) _handlers.objptr(id);
	if (h != NULL)
		return h(f, key);
	return true;
}

bool TDocumento_mask::universal_handler( TMask_field& f, KEY key)
{
	TDocumento_mask& m = (TDocumento_mask&)f.mask();
	bool ok = m.call_handler(f, key);

	if (ok && key == K_TAB && f.focusdirty())
	{
    const TFieldref* fr = f.field(); 
    if (fr != NULL && (fr->file() == 0 || fr->file() == LF_DOC))
      fr->write(f.get(), m.doc());

    const int page = f.page();
		if (m.is_calculated_page(page))
			m.update_progs();
	}
		
	return ok;
}

bool TDocumento_mask::anno_handler( TMask_field& f, KEY key)
{
	if (key == K_TAB && f.to_check(key, TRUE))
		app().update_navigation_bar();
	return true;
}

static TString4 __codnum;

bool tipodoc_ok(const TString & tipodoc)
{
	const TString4 module(main_app().name().left(2));
	const TTipo_documento& tipo = cached_tipodoc(tipodoc);
	const TString & tipomod = tipo.module();

	if (module == "ve" && tipomod.blank())
		return true;
	return tipomod == module;
}

bool tip_filter(const TRelation* r)
{
	if (__codnum.blank())
		return true;
	const TCodice_numerazione & cod_num = cached_numerazione(__codnum);
	const TString4 tipo = r->curr().get("CODTAB");

	int last = cod_num.ntipi_doc();
	for (int i = 0; i < last; i++ )
	{
		const TString & curtipo = cod_num.tipo_doc(i);
		
		if (curtipo == tipo && tipodoc_ok(curtipo))
			return true; 
	}
	return false;
}

bool TDocumento_mask::num_handler( TMask_field& f, KEY key)
{
	if (key == K_TAB && f.to_check(key, true))
	{
		// Ottengo la maschera
		TMask& m = f.mask();
		const TString & codnum = f.get();
		TCursor* cur = m.efield(F_TIPODOC).browse()->cursor();
		TCursor* descur = m.efield(F_DESTIPODOC).browse()->cursor();
	
		__codnum = codnum;
		if (codnum.full())
		{
			const TCodice_numerazione & cod_num = cached_numerazione(codnum);
		
			m.set( F_DESNUM, cod_num.descrizione());
			// Propone il primo tipo di documento come default
			if (m.field(F_TIPODOC).empty() || f.focusdirty())
			{
				m.set( F_TIPODOC, cod_num.tipo_doc(0));
				m.send_key( K_TAB, F_TIPODOC );
			}
			// Se per questa numerazione e' abilitata le numerazione provvisoria
			if (cod_num.num_provv())
			{
				// Setta di default la numerazione provvisoria
				m.set( F_PROVV, "P" );
				// Abilita il campo per la selezione della numerazione
				m.enable( F_PROVV );
			}
			else // Altrimenti ...
			{
				// Setta la numerazione a definitiva
				m.set( F_PROVV, "D" );
				// Disabilita il campo per la selezione della numerazione
				m.disable( F_PROVV );
			}
		}
		else
		{
			m.set( F_DESNUM, "" );
			m.set( F_TIPODOC, "" );
		}
		cur->set_filterfunction(tip_filter);
		descur->set_filterfunction(tip_filter);
		app().update_navigation_bar();
	}
	return TRUE;
}

bool TDocumento_mask::codlist_handler( TMask_field& f, KEY key )
{
	if (key == K_TAB && f.focusdirty())
	{
		TLocalisamfile & list = ((TEdit_field &) f).browse()->cursor()->file();
		const TDate datadoc(f.mask().get(F_DATADOC));
		const TDate datascad(list.get_date("VALFIN"));
		
		if (datascad.ok() && datadoc > datascad)
		{		 
			const TString16 codsucc(list.get("CODLISSUCC"));
			
			if (codsucc.empty())
				return error_box("Listino scaduto il %s", datascad.string());
			else		
			{
				f.set(codsucc);
				f.set_focusdirty();
				((TEdit_field &)f).check();
			}
		}
	}
	return true;
}

bool TDocumento_mask::codcont_handler( TMask_field& f, KEY key )
{
	if (key == K_TAB && f.focusdirty())
	{						
    TDocumento_mask& m = (TDocumento_mask&)f.mask();
		TLocalisamfile & cont = ((TEdit_field &) f).browse()->cursor()->file();
		const TDate datadoc(f.mask().get(F_DATADOC));
		const TDate datascad(cont.get_date(CONDV_VALFIN));
		
		if (datascad.ok() && datadoc > datascad)
			return error_box(FR("Contratto scaduto il %s"), datascad.string());

		static bool __gesconcc = false;
		static long __cntr_firm = -1L;
		const long firm = prefix().get_codditta();
		if (firm != __cntr_firm)
		{
			__gesconcc = ini_get_bool(CONFIG_DITTA, "ve", "GESCONCC");
			__cntr_firm = firm;
		}

		if (m.doc().tipo().load_cont() && f.get().full() && m.get_long(F_CODCF) > 0)
		{
			TSheet_field & s = m.sfield(F_SHEET);

			if (s.items() == 0)
			{
				TString select("TIPO='C' CATVEN=''");

				if(__gesconcc)
					select << " " << RCONDV_TIPOCF<< "='" << m.get(F_TIPOCF) <<"' " << RCONDV_CODCF << "=" << m.get_long(F_CODCF);  
				select << " " << RCONDV_COD << "=" << f.get();  
				TString query("USE RCONDV SELECT ");

				query << RCONDV_TIPORIGA << "=='A'";
				query << "\nFROM " << select;
				query << "\nTO " << select;
				TISAM_recordset recset(query);
				TString last_cod(20);

				for (bool ok = recset.move_first(); ok ; ok = recset.move_next())
				{
					TRiga_documento & r = m.doc().new_row("01");
					const TString & cod = recset.get(RCONDV_CODRIGA).as_string();

					if (cod != last_cod)
					{
						r.put(RDOC_CODART, cod);
					
						const int row = s.insert(-1, false);
						s.row(row);
						r.autoload(s);
						s.check_row(row, 0x2);
						r.autosave(s);
						const TString & um = recset.get(RCONDV_UM).as_string();

						if (um.full())
							r.put(RDOC_UMQTA, um);
						r.put(RDOC_PREZZO, recset.get(RCONDV_PREZZO).as_real());
						r.put(RDOC_SCONTO, recset.get(RCONDV_SCONTO).as_string());
						r.put(RDOC_PERCPROV, recset.get(RCONDV_PERCPROVV).as_real());
						r.autoload(s);
						last_cod = cod;
					}
				}
			}
		}
	}
	return true;
}

bool TDocumento_mask::codcamp_handler( TMask_field& f, KEY key )
{
	if (key == K_TAB && f.focusdirty())
	{
		TLocalisamfile & camp = ((TEdit_field &) f).browse()->cursor()->file();
		const TDate datadoc(f.mask().get(F_DATADOC));
		const TDate datascad(camp.get_date("VALFIN"));
		
		if (datascad.ok() && datadoc > datascad)
			return error_box("Offerta scaduta il %s", datascad.string());
	}
	return TRUE;
}


bool TDocumento_mask::datacambio_handler( TMask_field& f, KEY key )
{
	TMask& m = f.mask();
	if (key == K_TAB && m.field(F_CAMBIO).empty())
	{																																	
		const TString& codval = m.get(F_CODVAL1);
		if (is_true_value(codval))
		{
			const TRectype& rec = cache().get("%VAL", codval);
			m.set(F_CAMBIO, rec.get("S4"));
		}
	}
	return TRUE;
}

bool TDocumento_mask::codval_handler( TMask_field& f, KEY key )
{
	if (key == K_TAB && f.focusdirty() && !f.empty())
	{
		TMask& m = f.mask();		 
		
		// Cerco un cambio per la data specificata, se non lo trovo lo invento
		TDate datacam = m.get_date(F_DATACAMBIO);
		if (!datacam.ok())
		{
			datacam = m.get_date(F_DATADOC);
			m.set(F_DATACAMBIO, datacam);
			m.set(F_DATACAMBIO1, datacam);
		}
		TExchange exc(f.get());
		real cambio = exc.get_change(); // Determino il cambio standard ed il "Contro-Euro"
		TString16 key;
		key.format("%-3s%s", (const char*)f.get(), (const char*)datacam.string(ANSI));
		const real giornaliero(cache().get("CAM", key, "S4"));
		if (!giornaliero.is_zero())
			cambio = giornaliero; // Ho trovato un cambio per il giorno!
		m.set(F_CAMBIO, cambio);
	
		m.sfield(F_SHEET).force_update(); // Aggiorna punti decimali degli importi
	}
	return TRUE;
}


void TDocumento_mask::update_father_rows(bool add)
{
	if (_auto_reopen_nums.empty())
		return;
	const int rows = doc().physical_rows();
	
	for (int i = 1; i <= rows; i++)
	{
		const TRiga_documento & r = doc()[i];
		
		if (r.is_merce() || r.is_omaggio()|| r.is_prestazione())
		{
			const TRectype* original_row = r.find_original_rdoc();

			if (original_row != NULL && _auto_reopen_nums.objptr(original_row->get(RDOC_CODNUM)) != NULL)
			{
			  TToken_string key;
				
				key.add(original_row->get(RDOC_PROVV));
				key.add(original_row->get(RDOC_ANNO));
				key.add(original_row->get(RDOC_CODNUM));
				key.add(original_row->get(RDOC_NDOC));
				key.add(original_row->get(RDOC_IDRIGA));

				real* qta = (real*)_father_rows.objptr(key);
				if (qta == NULL)
				{
					qta = new real;
					_father_rows.add(key, qta);
				}
				
				real value = r.quantita();
				
				if (r.is_articolo())
				{
					TArticolo& art  = cached_article(r.get(RDOC_CODARTMAG));
					value = art.convert_to_um(value, original_row->get(RDOC_UMQTA), r.get(RDOC_UMQTA));
				}
				if(add)
					*qta += value;
				else
					*qta -= value;
        if (qta->is_zero())
					_father_rows.remove(key);
			}
		}
	}
}

TAssoc_array TDocumento_mask::_father_rows;
TAssoc_array TDocumento_mask::_auto_reopen_nums;
TAssoc_array TDocumento_mask::_tipidoc_rels;

void TDocumento_mask::save_father_rows()
{
	if (_auto_reopen_nums.empty())
		return;
	TLocalisamfile rdoc(LF_RIGHEDOC);
	TString_array rows;
	TToken_string last_doc;
	TToken_string curr_doc;
	int nrows = 0;
	
	FOR_EACH_ASSOC_OBJECT(_father_rows, h, k, o)
	{
		rows.add(k);
	}
	rows.sort();
	rows.add("");

	FOR_EACH_ARRAY_ROW(rows, i, r)
	{
		curr_doc = r->get(0);
		curr_doc.add(r->get());
		curr_doc.add(r->get());
		curr_doc.add(r->get());

		if (last_doc != curr_doc && nrows > 0)
		{
			TDocumento d;
			
			d.read(last_doc.get_char(0), last_doc.get_int(1), last_doc.get(2), last_doc.get_long(3), _isequal, _lock);
			for (int j = i - nrows; j < i; j++)
			{
				TToken_string & key = rows.row(j);
				const long idriga = key.get_long(4);
				const int nrows = d.physical_rows();

				for (int k = 1; k <= nrows; k++)
				{
					TRiga_documento & rdoc_row = d[k];

					if (idriga == rdoc_row.get_long(RDOC_IDRIGA))
					{
						const real * qta = (const real *) _father_rows.objptr(key);
						const TString& name = rdoc_row.field_qtaevasa();
						real qtaevasa = rdoc_row.get_real(name) + * qta;
			
						if (qtaevasa < ZERO)
							qtaevasa = ZERO;
						rdoc_row.put(name, qtaevasa);
						if (qtaevasa < rdoc_row.quantita())
							rdoc_row.zero(RDOC_RIGAEVASA);
						else
							rdoc_row.put(RDOC_RIGAEVASA, "X");
						break;
					}
				}
			}
			TToken_string key(d.tipo().codice());

			key.add(doc().tipo().codice());
			
			TStati * stati = (TStati *) _tipidoc_rels.objptr(key);

			if (stati != NULL)
			{
				const int nrows = d.physical_rows();
				bool evaso = true;

				for (int k = 1; evaso && k <= nrows; k++)
					evaso &= d[k].is_evasa();
				d.stato(evaso ? stati->finale() : stati->iniziale());
			}
			d.rewrite();
			nrows = 0;
		}
	 	last_doc = curr_doc;
		nrows++;
	}

}

static bool conf_num_handler(TMask_field& f, KEY key)
{
	if (key == K_TAB && f.to_check(key, true))
	{
		TMask & m  = f.mask();

		__codnum = f.get();

		TCursor * cur = m.efield(F_TIPODOC).browse()->cursor();
		TCursor * descur = m.efield(F_DESTIPODOC).browse()->cursor();

		cur->set_filterfunction(tip_filter);
		descur->set_filterfunction(tip_filter);
	}
	return true;
}

bool TDocumento_mask::confirm_handler( TMask_field& f, KEY key )
{
	bool ok = true;

  if (key == K_SPACE)
  {
		TMask m("ve0100d");
    TDocumento_mask & mask = (TDocumento_mask &) f.mask();
    const TDocumento& src = mask.doc();
		TCodice_numerazione num(src.numerazione());
		TString4 codnum(num.codnumdef());
		TString4 tipodoc(num.tipodocdef());
		if (!num.newnumdef())
		{
			codnum = src.get(DOC_CODNUM);
			tipodoc = src.get(DOC_TIPODOC);
		}
		else
		{
			codnum = num.get("S8");
			tipodoc = num.get("S9");
		}
		bool ok = codnum.full() && tipodoc.full();

		if (!ok)
		{
			TString saved_codnum = __codnum;

			m.set(F_CODNUM, codnum);
			m.enable(F_CODNUM, codnum.blank());
			m.set_handler(F_CODNUM, ::conf_num_handler);
			m.enable(F_DESNUM, codnum.blank());
			m.set(F_TIPODOC, tipodoc);
			m.enable(F_TIPODOC, tipodoc.blank());
			m.enable(F_DESTIPODOC, tipodoc.blank());
			ok = m.run() == K_ENTER;
			if (ok)
			{
				codnum = m.get(F_CODNUM);
				tipodoc = m.get(F_TIPODOC);
			}
			__codnum = saved_codnum;
		}

		ok = codnum.full() && tipodoc.full();
		if (ok)
		{
			TDocumento dest(src);

			dest.put(DOC_CODNUM, codnum);
			dest.put(DOC_TIPODOC, tipodoc);
			dest.put(DOC_PROVV, "D");
  		dest.zero(DOC_NDOC);

			int err = dest.write();
			
			if (err == NOERR)
			{
				err = src.remove();
				if (err == NOERR)
          app().do_elab(dest, 2);
        else
					warning_box("Errore %d nell'eliminazione del documento provvisorio", err);

				mask.stop_run(K_ESC);
				TMask & qmask = app().query_mask();
				qmask.set(F_CODNUM, codnum);
				qmask.set(F_PROVV, dest.get_char(DOC_PROVV));
				qmask.set(F_ANNO, dest.get_int(DOC_ANNO));
				qmask.set(F_NDOC, dest.get_long(DOC_NDOC));
				qmask.field(F_NDOC).update_flags("RP");
			}
			else
				return error_box("Errore %d nella generazione del documento definitivo", err);
		}
  }
  return ok;
}

static int row_compare(const TObject** obj1, const TObject** obj2)
{
	TRiga_documento & row1 = (TRiga_documento & ) **obj1;
	TRiga_documento & row2 = (TRiga_documento & ) **obj2;
	const TDocumento & doc = row1.doc();
	const int r1 = row1.get_int(RDOC_NRIGA);
	const int r2 = row2.get_int(RDOC_NRIGA);
	for (int i = r1 + 1; i < r2; i++)
		if (doc[i].get(RDOC_CODART).blank())
			return -1;
  
	const TString80  c1 = row1.get(RDOC_CODART);
  const TString &  c2 = row2.get(RDOC_CODART);

	if (c1.full() && c2.full())
		return strcmp((const char *) c1, (const char *) c2);
	return r1 - r2;
}

bool TDocumento_mask::sort_row_handler( TMask_field& f, KEY key )
{
  if (key == K_SPACE)
  {
		TSheet_field & sheet = f.mask().sfield(F_SHEET);
		TDocumento_mask & m = (TDocumento_mask &) f.mask();
		TDocumento & doc = m.doc();
		TRecord_array  saved_rows = doc.body();
		TRecord_array & rows = doc.body();
		const int nrows = doc.physical_rows();

		rows.sort(row_compare);
		if (nrows == doc.physical_rows())
		{
			for (int r = 1; r <= nrows; r++)
				doc[r].autoload(sheet);
			sheet.force_update();
		}
		else
		{
			rows = saved_rows;
			return message_box(TR("L'ordinamento non ha avuto un esito positivo"));
		}

  }
  return true;
}

void TDocumento_mask::sel_color()
{
	const TString& mn = doc().tipo().mask_name();
	TSelect_color_mask sel(mn, "0");
	FOR_EACH_ARRAY_ITEM(color_rules(), i, o)
	{
		const TColor_rule& col = *(const TColor_rule*)o;
    COLOR a, b; col.colors(a, b);
    COLOR c, d; col.default_colors(c, d);
  	sel.add_color(col.key(), col.description(), a, b, c, d);
	}

	if (sel.run() != K_ESC)
	{
  	FOR_EACH_ARRAY_ITEM(color_rules(), i, o)
	  {
		  TColor_rule& col = *(TColor_rule*)o;
      COLOR back, fore; sel.get_color(col.key(), back, fore);
		  col.set_colors(back, fore);
    }
		highlight();
	}
}

bool TDocumento_mask::gestione_note_per_articolo() const
{
  return id2pos(F_NAR) > 0;
}

///////////////////////////////////////////////////////////
// Gestione lettore codice a barre
///////////////////////////////////////////////////////////

class TBarcode_mask : public TAutomask
{
  TDocumento_mask& _dm;
  clock_t _last_key;

protected:
  virtual void on_idle();
  virtual bool on_key(KEY k);
  virtual bool on_field_event(TOperable_field& o, TField_event e, long joly);
  virtual bool on_code_entered(const TString& code);
  const TString& barcode2codart(const TString& code) const;

public:
  TBarcode_mask(TDocumento_mask& dm);
};

const TString& TBarcode_mask::barcode2codart(const TString& code) const
{
  TLocalisamfile codcorr(LF_CODCORR);
  codcorr.setkey(2);
  codcorr.put(ANAMAG_CODARTALT, code);
  if (codcorr.read() == NOERR)
    return codcorr.get(ANAMAG_CODART);
  return code;
}

bool TBarcode_mask::on_code_entered(const TString& code)
{
  TCodice_articolo codart;
  real qta = UNO;
  TString16 livello;

  const int codelen = code.len();
  if (codelen >= 16)
  {
    for (int i = 0; i < codelen; )
    {
      const int ctrl = atoi(code.mid(i, 2)); i += 2;
      switch (ctrl)
      {
      case  2: codart = barcode2codart(code.mid(i, 14)); i +=14; break;
      case 10: livello = code.mid(i, 4); i += 4; break;
      case 37: qta = real(code.mid(i, 4)); i += 4; break;
      default: i += 4; break;
      }
    }
    
  }
  else
    codart = barcode2codart(code);

  if (codart.full())
  {
    TSheet_field& s = _dm.sheet();

    TDocumento& doc = _dm.doc();
    FOR_EACH_PHYSICAL_RDOC_BACK(doc, i, rdoc)
    {
      if (rdoc->get(RDOC_CODART) == codart && rdoc->get(RDOC_LIVELLO) == livello)
      {
        rdoc->add(RDOC_QTA, qta);
        s.row(i-1).add(rdoc->get(RDOC_QTA), s.cid2index(FR_QTA));
        s.force_update(i-1);
        return true;
      }
    }

    TRiga_documento& r = doc.new_row(_dm.get(F_LBTIPORIGA));
    r.put(RDOC_CODART, codart);
    r.put(RDOC_LIVELLO, livello);
    r.put(RDOC_QTA, qta);
    r.autoload(s);
    const int i = r.get_int(RDOC_NRIGA)-1; 
    _dm.ss_notify(s, i, K_CTRL+K_INS); // Propone magazzino
	  s.check_row(i, 0x3);
    s.force_update();
  }

  return codart.full();
}

bool TBarcode_mask::on_key(KEY k)
{
  static KEY _barcode_newline = ini_get_int(CONFIG_INSTALL, "Main", "BarcodeNewline");

  if (k == _barcode_newline)
  {
    const TString& code = efield(DLG_USER).get_window_data();
    on_code_entered(code);
    reset(DLG_USER);
  }

  return TAutomask::on_key(k);
}

void TBarcode_mask::on_idle()
{
  if (_last_key > 0 && (clock() - _last_key) > 500)
  {
    _last_key = 0;
    const TString& code = efield(DLG_USER).get_window_data();
    if (code.len() >= 8)
    {
      if (on_code_entered(code))
        reset(DLG_USER);
    }
  }
  return TAutomask::on_idle();
}

bool TBarcode_mask::on_field_event(TOperable_field& o, TField_event e, long joly)
{
  if (e == fe_edit && o.dlg() == DLG_USER)
  {
    _last_key = clock();
  }
  return true;
}

TBarcode_mask::TBarcode_mask(TDocumento_mask& dm) : TAutomask("BAR CODE READER", 1, 40, 3, -1, 4), _dm(dm), _last_key(0)
{
  TButton_tool& bt = add_button_tool(DLG_QUIT, TR("Fine"), TOOL_QUIT);
  add_button_tool(DLG_INFO, TR("Info"), TOOL_INFO);
  add_string(DLG_USER, 0, PR("Codice "), 1, 1, 128, "", 30);
  set_handlers();  
}

bool TDocumento_mask::barcode_handler(TMask_field& f, KEY k)
{
  if (k == K_SPACE)
  {
    TDocumento_mask& mask = (TDocumento_mask&)f.mask();
    TSheet_field& s = mask.sheet();
    if (mask.curr_win() != s.parent())
      s.set_focus();

    TBarcode_mask bcm(mask);
    bcm.run();
  }
  return true;
}