From 8d83316486c8a8b3e2ce2bc29deaa5ee00f758ea Mon Sep 17 00:00:00 2001
From: angelo <angelo@c028cbd2-c16b-5b4b-a496-9718f37d4682>
Date: Thu, 2 Jan 1997 09:01:59 +0000
Subject: [PATCH] Nuova versione programma di stampa documenti, utilizzo piu'
 intensivo di TDocumento e TRiga_documento. Alias: More Cazzuted.

git-svn-id: svn://10.65.10.50/trunk@4034 c028cbd2-c16b-5b4b-a496-9718f37d4682
---
 ve/ve1100.cpp | 1252 +++++++++++++++++++++++++++----------------------
 1 file changed, 702 insertions(+), 550 deletions(-)

diff --git a/ve/ve1100.cpp b/ve/ve1100.cpp
index 0feb673b3..f5ff403fd 100755
--- a/ve/ve1100.cpp
+++ b/ve/ve1100.cpp
@@ -10,65 +10,61 @@
 #include <urldefid.h>
 #include <progind.h>
 
-#include "velib02.h"
+#include <doc.h>
+#include <rdoc.h>
 
 #include "ve1100.h"
 #include "ve0100b.h"
+#include "velib02.h"
 
-//////////////////////////////////////////////////////////////////////////////////////////////
-// classe TStampa_Doc_Vendita customizzata dalla TApplication per l'applicazione principale
-//////////////////////////////////////////////////////////////////////////////////////////////
 
-    
-enum behaviour {
-  skip,
-  go,
-  cancel
-};
+#define Usage "Usage: ve1 -1 [codnum anno {D|P} dalnum alnum {D|P} [ncopie]]"
 
-class TDocVen_Form;
+// Queste classi (TDocisamfile e TRDocisamfile) servono nel costruttore di TDocumento_form
+// in modo da sostituire i file della relazione, ovvero LF_DOC e LF_RIGHEDOC.
+// Facendo in questo modo ogni get() del record, viene reindirizzata alla get() dei
+// TVariable_recfield, in modo da utilizzare nel form le istruzioni FIELD anche per i campi
+// virtuali.
 
-class TStampa_Doc_Vendita: public TApplication {
-  TString _codnum; // codice di numerazione
-  TString _provv; // stampa provvisioria
-  int _anno; // anno della documentazione
-  int _ncopie, _base_page_no; // numero di copie per ogni documento, numero della pagina base per stampare il numero di pagina
-  long _dalnum, _alnum; // estremi di numerazione dei documenti
-  TDate _dadata, _adata; // estremi di data dei documenti
-  bool _order_by_num; // flag che indica se e' stato selezionato l'ordine principale per numero documento
-  bool _interattivo; // flag che indica se il prog. funziona in interattivo o in batch
-  bool _definitiva; // flag che indica se la stampa � definitiva o no
-  TRelation *_firmrel; // puntatore alla relazione che gestisce i dati della ditta corrente
-  TDocVen_Form *_form; // puntatore al form di stampa
-protected:
-  virtual bool create(void);
-  virtual bool destroy(void);
-  virtual bool menu(MENU_TAG);
-  int select(void);
-  virtual void print(void);
-  virtual void on_firm_change(void);
-  virtual behaviour on_module_change(const TString &, TString &); // funzione chiamata ad ogni cambio modulo durante la stampa
-  virtual bool query_final_print(void); // funzione chiamata all'inizializzazione per sapere se la stampa � definitiva
-  static bool date2num_handler(TMask_field& f, KEY key);
-  static bool range_handler(TMask_field& f, KEY key);
-  static bool filter_rows(const TRelation * r);
+class TDocisamfile : public TLocalisamfile
+{
+  TDocumento *_doc;
 public:
-  int base_no() { return _base_page_no;}
+  virtual TRectype& curr() const { return (TRectype&) *_doc; }
+  TDocisamfile(TDocumento* doc)  : TLocalisamfile(LF_DOC) { _doc = doc;}
+  virtual ~TDocisamfile() {};
 };
 
-
-inline TStampa_Doc_Vendita& app() { return (TStampa_Doc_Vendita&) main_app(); }
+class TRDocisamfile : public TLocalisamfile
+{
+  TDocumento *_doc;
+  int _row;
+protected:
+  TDocumento& doc() const { return *_doc;}  
+public:
+  virtual TRectype& curr() const {return (TRectype&) doc()[_row>0 ? _row : 1];}
+  void set_row(int r) { _row = r;}
+  TRDocisamfile(TDocumento* doc) : TLocalisamfile(LF_RIGHEDOC)  { _doc = doc; _row = 1;}
+  virtual ~TRDocisamfile() {};
+};
 
 ////////////////////////////////////////////////////////////////////////////
-// classe TDocVen_Form customizzata dalla Form per i documenti di vendita
+// classe TDocumento_form customizzata dalla Form per i documenti 
 ////////////////////////////////////////////////////////////////////////////
-class TDocVen_Form: public TForm { 
+class TDocumento_form : public TForm 
+{ 
+
+  static TDocumento_form* _form;
+  TDocisamfile* _docfile;
+  TRDocisamfile* _rdocfile;
+  TLocalisamfile *_tab;
+  TTable *_tip;
   TRelation &_firmrel; // relazione di gestione dei dati della ditta corrente
   TString _module; // codice del modulo di carta associato a questo al form
   TCliFor *_cliente; // oggetto per le informazioni sul cliente
   TString_array _exclude_array; // array di coppie tipo/articolo da escludere dalla stampa
-  TDocumentoEsteso * _doc; // oggetto 
-  bool _cli_loaded; // flag che indica se l'oggetto cliente � gi� stato caricato
+  TDocumentoEsteso * _doc; // Documento da stampare
+  bool _valid, _cli_loaded; // flag che indica se il form e' valido | se l'oggetto cliente � gi� stato caricato
   TString_array _group_decimals; // Array di TToken_string per ogni gruppo definito in GENERAL. 
                                  // Il primo elelemento della token_string conterra' il numero del gruppo
                                  // il secondo il n.ro di decimali per importi in lire ed il terzo il n.ro
@@ -89,24 +85,81 @@ class TDocVen_Form: public TForm {
 protected:
   virtual void extended_parse_general(TScanner &); // gestione dei parametri estesi nella sezione general
   virtual bool validate(TForm_item &, TToken_string &); // gestione dei messaggi estesi nei campi
-  virtual word set_body(word p, bool u); // derivata per la gestione del totalizzatore
   void edit_picture(TForm_item & f, const int dec);
   void modify_pictures();
+  bool print_on_body(int r); // Trascrive la riga 'r' del documento sul body. Ritorna TRUE se va stampata, FALSE se va saltata
+  
+  void print_header(TPrinter& p); // Stampa la testata
+  void print_footer(TPrinter& p); // Stampa la pedata
+
+  static void doc_header_handler(TPrinter& p);
+  static void doc_footer_handler(TPrinter& p);
+
 public:
+  void print_documento();
+  bool valid() { return _valid; }
+  bool doc_arrange();
+  int ncopie() { return _doc->tipo().ncopie(); }
   const TString &get_module_code() { return _module; } // ritorna il codice del modulo di carta
   TString_array & exclude_list()   { return _exclude_array; }
-  TDocumentoEsteso* doc() { return _doc; }
-  TDocVen_Form(const char *, TRelation &, TDocumentoEsteso * );
-  virtual ~TDocVen_Form();
+  TDocumentoEsteso& doc() { return *_doc; }
+  TDocumento_form(TRectype& cur_doc, TRelation& rel, const bool definitiva, const bool interattivo);
+  virtual ~TDocumento_form();
 };
 
+TDocumento_form* TDocumento_form::_form = NULL;
 
+TDocumento_form::TDocumento_form(TRectype& cur_doc, TRelation& rel, const bool definitiva, const bool interattivo): TForm(), _firmrel(rel), _valid(FALSE) 
+{
+  _form = this;
+  
+  _tip = new TTable("%TIP");
+  _tab = new TLocalisamfile(LF_TAB);
+  TString nomeform;
+  TFilename profilo;
+  TString codnum(cur_doc.get(DOC_CODNUM));
+  TString numdoc(cur_doc.get(DOC_NDOC));
+  
+  _tip->put("CODTAB", cur_doc.get(DOC_TIPODOC)); // posiziona la tabella dei tipi di documento
+  int err=_tip->read(); // legge la tabella
+  if (err==NOERR)
+  { // se non ci sono errori procede con la stampa
+    nomeform= _tip->get("S5"); // legge il nome del form di stampa
+    profilo= _tip->get("S4"); // legge il nome del profilo di configurazione
+    profilo.ext("ini"); // aggiunge l'estensione al nome del file del profilo
+    if (profilo.empty() || nomeform.empty()) 
+    {
+      error_box("Nome profilo o form di stampa non valido nella tabella TIP");
+      return;
+    }
+    TConfig config(profilo, "STAMPA"); // apre il file di configurazione del profilo
+    TToken_string stati((const char*)config.get("STATIVALIDI"), ','); // legge gli stati validi di questo tipo di documento
+    if (definitiva && (stati.get_pos(cur_doc.get(DOC_STATO))== -1))
+      // se lo stato del doc. corrente non � valido...
+      if (interattivo)
+      {
+        error_box("Non � possibile stampare il documento %s %s con stato non valido", (const char*) codnum, (const char*) numdoc); // ...viene mostrato un messaggio (solo in modo interattivo)...
+        return;
+      }
+  }
+  else
+  {
+    error_box("Il documento %s %s non � stato trovato nella tabella dei tipi di documento (errore %d)",
+              (const char*) codnum,(const char*) numdoc,err);
+    return;
+  }
+  _valid = TRUE;
 
-TDocVen_Form::TDocVen_Form(const char* name, TRelation &rel, TDocumentoEsteso * doc): TForm(), _firmrel(rel) {
-  read(name);
+  
+  read(nomeform);
   _cliente= new TCliFor;
   _cli_loaded= FALSE;
-  _doc = doc;
+      
+  _doc =  new TDocumentoEsteso(cur_doc); // istanzia TDocumentoEsteso
+  _docfile = new TDocisamfile(_doc);
+  _rdocfile = new TRDocisamfile(_doc);
+  relation()->replace(_docfile,0);
+  relation()->replace(_rdocfile,1);
   modify_pictures();
   dec_parm p;
   const int items = _group_decimals.items();
@@ -128,14 +181,117 @@ TDocVen_Form::TDocVen_Form(const char* name, TRelation &rel, TDocumentoEsteso *
     }
   }
   _doc->set_decimals(p);
+
+  TPrinter& pr = printer();
+  
+  pr.setheaderhandler(doc_header_handler);
+  TPrint_section& head = section('H');
+  pr.headerlen(head.height());
+  
+  pr.setfooterhandler(doc_footer_handler);
+  const TPrint_section& foot = section('F');
+  pr.footerlen(foot.height());
 }
 
-TDocVen_Form::~TDocVen_Form() {
+TDocumento_form::~TDocumento_form()
+{
   delete _cliente;
   if (_doc) delete _doc;
+  if (_tip) delete _tip;
+  if (_tab) delete _tab;
+  if (_docfile) delete _docfile;
+  if (_rdocfile) delete _rdocfile;
 }
 
-void TDocVen_Form::edit_picture(TForm_item & fi, const int dec)
+bool TDocumento_form::doc_arrange()
+{
+  TPrinter& pr = printer();
+  
+  if (char_to_pos() != '\0' || (ipx()+ipy()+fpx()) != 0)
+  {
+    if (offset_x() != 0 || offset_y() != 0)
+    {
+      error_box("Non e' possibile settare contemporaneamente gli offset"
+                " e i parametri di posizionamento del modulo %s.", (const char*)name());
+      return FALSE;
+    }
+    else
+      if (pr.printtype() == winprinter) 
+        _form->arrange_form();
+  }
+  else
+    pr.set_offset(_form->offset_x(),_form->offset_y());
+  return TRUE;
+}
+
+void TDocumento_form::print_documento()
+{
+  // stampa tutte le righe 
+  TPrint_section& body = section('B');
+  TPrint_section& foot = section('F');
+  TPrinter& pr = printer();
+
+  const int righe = _doc->rows();
+  
+  set_last_page(FALSE); // E' importante settare questo flag, per evitare "Falli di Piede" eheh :-)
+  for (int r=1; r<=righe; r++)
+  {
+    _rdocfile->set_row(r);
+    if (pr.rows_left() <= (body.height()+1))   // salto pagina
+      pr.formfeed();
+    
+    if (!print_on_body(r)) continue;
+    
+    const word h = body.height();
+    for (word j = 0; j < h; j++)
+      pr.print(body.row(j));
+  }
+  
+  set_last_page(TRUE); // Cosi' stampera' l'ultima pagina del footer
+  pr.formfeed();      
+  // Rimette ad 1 il numero della pagina
+  pr.setcurrentpage(1);
+}
+
+void TDocumento_form::print_header(TPrinter& pr)
+{
+  TPrint_section& head = section('H');
+  
+  head.update(); 
+
+  const word r = head.height()-1;
+  
+  for (word j = 0; j <= r; j++)
+    pr.setheaderline(j, head.row(j));
+}
+
+
+void TDocumento_form::print_footer(TPrinter& pr)
+{
+  const bool p = _form->page(pr)>0;
+  TPrint_section& foot = section('F',p ? odd_page : last_page);
+
+  foot.update();
+  const word r = foot.height()-1;
+  
+  for (word j = 0; j <= r; j++)
+    pr.setfooterline(j, foot.row(j));
+
+}
+
+void TDocumento_form::doc_header_handler(TPrinter& pr)
+{
+  pr.resetheader();
+  _form->print_header(pr);    
+}
+
+void TDocumento_form::doc_footer_handler(TPrinter& pr)
+{                    
+  pr.resetfooter();
+  _form->print_footer(pr);
+} 
+
+void TDocumento_form::edit_picture(TForm_item & fi, const int dec)
 {
   TString old_picture(20);
   old_picture = fi.picture();
@@ -169,7 +325,7 @@ void TDocVen_Form::edit_picture(TForm_item & fi, const int dec)
   fi.set_picture(new_picture); // setta la nuova picture
 }
 
-void TDocVen_Form::modify_pictures()
+void TDocumento_form::modify_pictures()
 {
   const bool valuta = _doc->in_valuta();
   const char sechar[4] = { 'B', 'F', 'G',  'H' };
@@ -199,17 +355,43 @@ void TDocVen_Form::modify_pictures()
   }
 }
 
-word TDocVen_Form::set_body(word p, bool u) {
-  TPrint_section& body = section('B', p);
-  return TForm::set_body(p, u);
+bool TDocumento_form::print_on_body(int r)
+{
+  TPrint_section& body = section('B');
+  
+  const TRiga_documento& riga = doc()[r];
+
+  TString tiporiga(riga.get(RDOC_TIPORIGA));
+  TString codart(riga.get(RDOC_CODART));
+  const int items = _exclude_array.items();
+  bool ok = TRUE;
+  
+  for (int i = 0; i < items && ok; i++)
+  {
+    TToken_string& s=_exclude_array.row(i);
+    TString tr(s.get(0));
+    TString ar(s.get(1));
+    tr.trim();ar.trim();
+    if (tr.empty() && ar.empty()) continue;
+    if (tr.empty() && ar == codart) ok = FALSE;
+    else if (tr == tiporiga)
+      if (ar.empty() || (ar.not_empty() && ar == codart)) ok = FALSE;
+  }  
+  
+  if (ok)
+    body.update(); // Crea la vera riga di stampa, eventuali allineamenti avverranno nella validate(), come al solito.
+  
+  return ok;
 }
 
-void TDocVen_Form::extended_parse_general(TScanner &scanner) {
+void TDocumento_form::extended_parse_general(TScanner &scanner) 
+{
   // se viene riconosciuto il token per l'impostazione del modulo legge il codice...
   if (scanner.key() == "MO") _module= scanner.string();
 
   // Legge i decimali necessari per gli arrotondamenti (il primo per gli importi in lire, l'altro per quelli in valuta)
-  if (scanner.key() == "PR") {
+  if (scanner.key() == "PR")
+  {
     TToken_string t;
     t.add(29);t.add(scanner.integer());t.add(scanner.integer());
     _group_decimals.add(t);
@@ -224,26 +406,29 @@ void TDocVen_Form::extended_parse_general(TScanner &scanner) {
   } 
   
   // Stessa cosa per gli importi in genere
-  if (scanner.key() == "IM") {
+  if (scanner.key() == "IM")
+  {
     TToken_string t;
     t.add(31);t.add(scanner.integer());t.add(scanner.integer());
     _group_decimals.add(t);
   }
 
-  if (scanner.key() == "NE") {
+  if (scanner.key() == "NE")
+  {
     TToken_string t;
     t.add(scanner.integer());t.add(scanner.integer());t.add(scanner.integer());
     _group_decimals.add(t);
   }
 
   // Esclude certi tipi riga e codici articolo
-  if (scanner.key() == "EX") {
+  if (scanner.key() == "EX")
+  {
     TToken_string s(scanner.string(),',');
     _exclude_array.add(s);
   }
 }
 
-bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) {
+bool TDocumento_form::validate(TForm_item &cf, TToken_string &s) {
   const TString code(s.get(0)); // prende il primo parametro, il codice del messaggio
   TString valore;
 
@@ -292,9 +477,7 @@ bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) {
         } else posrv= poseq+2;
         if (poseq== -1) {
           const TString &dat= file->get(curr); // preleva il nome del campo del file e lo legge dal record
-          cf.set(dat); // setta il campo letto dal file nel campo corrente della form   
           cf.put_paragraph(dat);
-          cf.set(""); // Resetta il campo per la prossima stampa di questo item
         } else {
           TString fld(curr.left(poseq)); // preleva il nome del campo del form alla sinistra dell'uguale
           const TString &dat= file->get(curr.mid(posrv)); // preleva il nome del campo del file alla destra dell'uguale e lo legge dal record
@@ -312,15 +495,11 @@ bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) {
             }
             for (j=0; j<itms; j++) { // per ogni campo della sezione specificata (o sottointesa)...
               TForm_item &fi= section(sec, pt).field(j);
-              fi.set(dat); // ...il contenuto viene settato al valore del file
               fi.put_paragraph(dat);
-              fi.set(""); // Resetta il campo per la prossima stampa di questo item
             }
           } else {
             TForm_item &fi= cf.find_field(fld);
-            fi.set(dat);
             fi.put_paragraph(dat);
-            fi.set(""); // Resetta il campo per la prossima stampa di questo item
           }
         }
       }
@@ -347,12 +526,189 @@ bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) {
     if (tab.read()== NOERR) {
       const TString &fld= s.get(); // prende il nome del campo da leggere...
       valore = tab.get(fld);
-      cf.set(tab.get(fld)); // ...e lo scrive nel campo del form
       cf.put_paragraph(valore);
-      cf.set(""); // Resetta il campo per la prossima stampa di questo item
     }
     return (TRUE);
   } // fine _TABLEREAD
+  
+  if (code== "_DITTA") {
+    // lettura dei dati della ditta
+    // sintassi: _DITTA,{<campo relazione>|<macro>}
+    // dove: <campo relazione> � un riferimento alla relazione di gestione dei dati della ditta (es. 113@->DENCOM � la denominazione del comune di residenza della ditta)
+    //       <macro> � uno delle macro seguenti:
+    //         !RAGSOC  ragione sociale
+    //         !IND     indirizzo (fiscale se c'�, oppure di residenza)
+    //         !NUM     numero civico (fiscale se c'�, oppure di residenza)
+    //         !CAP     CAP (fiscale se c'�, oppure di residenza)
+    //         !COM     comune (fiscale se c'�, oppure di residenza)
+    //         !PROV    provincia (fiscale se c'�, oppure di residenza)
+    //         !IVA     partita iva
+    //         !CF      codice fiscale
+    //         !TEL     numero di telefono (con prefisso)
+    //         !FAX     numero di fax (con prefisso)
+    //         !REGSOC  numero di registrazione presso il Tribunale
+    //         !CCIAA   numero di registrazione presso la camera di commercio
+    // nota: la relazione della ditta � cos� strutturata:
+    //       %NDITTE (9) Dati ditte
+    //       + %ANAGR (6) Anagrafica generale (indirizzo, ecc.)
+    //          + %COMUNI (113@) Comune di residenza
+    //          + %COMUNI (213@) Comune di residenza fiscale
+    TString in(s.get());
+    if (in[0]=='!') {
+      in.ltrim(1);
+      bool _fisc= _firmrel.lfile(6).get("INDRF").not_empty();
+      if (in=="RAGSOC") 
+        valore = _firmrel.lfile().get("RAGSOC");
+      if (in=="IND") {
+        if (_fisc) 
+          valore = _firmrel.lfile(6).get("INDRF");
+        else 
+          valore = _firmrel.lfile(6).get("INDRES");
+      }
+      if (in=="NUM") {
+        if (_fisc)
+          valore = _firmrel.lfile(6).get("CIVRF");
+        else 
+          valore = _firmrel.lfile(6).get("CIVRES");
+      }
+      if (in=="CAP") {
+        if (_fisc) 
+          valore = _firmrel.lfile(6).get("CAPRF");
+        else 
+          valore  = _firmrel.lfile(6).get("CAPRES");
+      }
+      if (in=="COM") {
+        if (_fisc)
+          valore = _firmrel.lfile(-213).get("DENCOM");
+        else 
+          valore = _firmrel.lfile(-113).get("DENCOM");
+      }
+      if (in=="PROV") {
+        if (_fisc)
+          valore = _firmrel.lfile(-213).get("PROVCOM");
+        else 
+          valore = _firmrel.lfile(-113).get("PROVCOM");
+      }
+      if (in=="IVA")
+        valore = _firmrel.lfile(6).get("PAIV");
+      if (in=="CF") 
+        _firmrel.lfile(6).get("COFI");
+      if (in=="TEL") {
+        valore = _firmrel.lfile().get("PTEL");
+        valore << "/" << _firmrel.lfile().get("TEL");
+      }
+      if (in=="FAX") {
+        valore = _firmrel.lfile().get("PFAX");
+        valore << "/" << _firmrel.lfile().get("FAX");
+      }
+      if (in=="REGSOC") {
+        valore = _firmrel[LF_UNLOC].get("REGTRIB");
+        valore << " Vol. " << _firmrel[LF_UNLOC].get("VOLTRIB");
+        valore << " Fasc. " << _firmrel[LF_UNLOC].get("FASCTRIB");
+      }
+      if (in=="CCIAA") {
+        valore = _firmrel[LF_UNLOC].get("NUMCCIAA");
+        valore << " del " << _firmrel[LF_UNLOC].get("DATAICCIAA");
+      }
+    } else {
+      TFieldref fref(s.get(), 0);
+      valore = fref.read(_firmrel);
+    }
+    cf.put_paragraph(valore);
+    return (TRUE);
+  } // fine _DITTA
+
+  if (code== "_CLIENTE") {
+    // lettura dei dati del cliente
+    // sintassi: _CLIENTE,{<campo relazione>|<macro>}
+    // dove: <campo relazione> � un riferimento alla relazione di gestione dei dati del cliente
+    //       <macro> � uno delle macro seguenti:
+    //         !RAGSOC  ragione sociale
+    //         !IND     indirizzo
+    //         !NUM     numero civico
+    //         !INDNUM  indirizzo + numero civico
+    //         !LOC     localit�
+    //         !CAP     CAP
+    //         !COM     comune
+    //         !PROV    provincia
+    //         !IVA     partita iva
+    //         !CF      codice fiscale
+    //         !PERS    <F> se persona fisica, <G> se giuridica
+    //         !DATANAS data di nascita
+    //         !COMNAS  comune di nascita
+    //         !TEL     primo numero di telefono (con prefisso)
+    //         !TEL2    secondo numero di telefono (con prefisso)
+    //         !TEL3    terzo numero di telefono (con prefisso)
+    //         !FAX     numero di fax (con prefisso)
+    // nota: la relazione del cliente � cos� strutturata:
+    //       CLIFO (20) Clienti/fornitori
+    //       + CFVEN (17) Clienti/fornitori per vendite
+    //       + %COMUNI (113@) Comune di residenza
+    //       + %COMUNI (213@) Comune di nascita
+    TLocalisamfile &doc= (cursor())->file(LF_DOC);
+    TString16 tipocf= doc.get("TIPOCF"), codcf= doc.get("CODCF"), ocfpi= doc.get("OCFPI");
+    if (!_cli_loaded ) { // il cliente � sulla testata del documento di vendita, quindi pu� essere caricato una volta sola per tutte
+      _cliente->load(tipocf[0], atol(codcf), ocfpi);
+      _cliente->add(LF_COMUNI, "COM=STATOCF+COMCF", 1, LF_CLIFO, 100+LF_COMUNI);
+      _cliente->add(LF_COMUNI, "COM=STATONASC+COMNASC", 1, LF_CLIFO, 200+LF_COMUNI);
+      _cli_loaded= TRUE;
+    }     
+    TString in(s.get()); // prende la macro o il fieldref
+    if (in[0]=='!') {
+      in.ltrim(1);
+      if (in=="RAGSOC") 
+        valore = _cliente->get(LF_CLIFO, "RAGSOC");
+      if (in=="IND")
+        valore = _cliente->get(LF_CLIFO, "INDCF");
+      if (in=="NUM")
+        valore = _cliente->get(LF_CLIFO, "CIVCF");
+      if (in=="INDNUM") {
+        valore = _cliente->get(LF_CLIFO, "INDCF");
+        valore << " " << _cliente->get(LF_CLIFO,"CIVCF");
+      }
+      if (in=="LOC")
+        valore = _cliente->get(LF_CLIFO, "LOCALITACF");
+      if (in=="CAP")
+        valore = _cliente->get(LF_CLIFO, "CAPCF");
+      if (in=="COM")
+        valore = _cliente->get(-(100+LF_COMUNI), "DENCOM");
+      if (in=="PROV")
+        valore = _cliente->get(-(100+LF_COMUNI), "PROVCOM");
+      if (in=="IVA") 
+        valore = _cliente->get(LF_CLIFO, "PAIV");
+      if (in=="CF")
+        valore = _cliente->get(LF_CLIFO, "COFI");
+      if (in=="PERS")
+        valore = _cliente->get(LF_CLIFO, "TIPOPERS");
+      if (in=="DATANAS")
+        valore = _cliente->get(LF_CLIFO, "DATANASC");
+      if (in=="COMNAS")
+        valore = _cliente->get(-(200+LF_COMUNI), "DENCOM");
+      if (in=="TEL") {
+        valore = _cliente->get(LF_CLIFO, "PTEL");
+        valore << "/" << _cliente->get(LF_CLIFO, "TEL");
+      }
+      if (in=="TEL2") {
+        valore = _cliente->get(LF_CLIFO, "PTEL2");
+        valore << "/" << _cliente->get(LF_CLIFO, "TEL2");
+      }
+      if (in=="TEL3") {
+        valore = _cliente->get(LF_CLIFO, "PTEL3");
+        valore << "/" << _cliente->get(LF_CLIFO, "TEL3");
+      }
+      if (in=="FAX") {
+        valore = _cliente->get(LF_CLIFO, "PFAX");
+        valore << "/" << _cliente->get(LF_CLIFO, "FAX");
+      }
+    } else {
+      TFieldref fref(s.get(), 0);
+      // l'oggetto cliente � figlio della TRelation, quindi lo passo al fieldref semplicemente con un typecast
+      valore = fref.read(*_cliente); 
+    }
+    cf.put_paragraph(valore);
+    return (TRUE);
+  } // fine _CLIENTE
+
   if (code == "_DESCRIGA") {
     // Messaggio per reperire la descrizione estesa sulle righe del documento
     TLocalisamfile &rdoc= (cursor())->file(LF_RIGHEDOC);
@@ -369,12 +725,11 @@ bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) {
           descrizione << " " << linea;
       }
     }
-    cf.set(descrizione);
     cf.put_paragraph(descrizione);
-    cf.set(""); // Resetta il contenuto del TForm_item(R) per la prossima riga
+    // Setta l'altezza effettiva del body, per evitare sprechi di righe
     cf.section().set_height(cf.effective_height() + 1);
   }
-  
+
   if (code== "_ALIGN") {
     // allineamento della posizione di un campo rispetto ad un altro
     // sintassi: _ALIGN,<campo form>[,<allineamento>][,<allineamento>...]
@@ -426,284 +781,13 @@ bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) {
     cf.height() = save_height;
     return (TRUE);
   } // fine _ALIGN
-  
-  if (code== "_DITTA") {
-    // lettura dei dati della ditta
-    // sintassi: _DITTA,{<campo relazione>|<macro>}
-    // dove: <campo relazione> � un riferimento alla relazione di gestione dei dati della ditta (es. 113@->DENCOM � la denominazione del comune di residenza della ditta)
-    //       <macro> � uno delle macro seguenti:
-    //         !RAGSOC  ragione sociale
-    //         !IND     indirizzo (fiscale se c'�, oppure di residenza)
-    //         !NUM     numero civico (fiscale se c'�, oppure di residenza)
-    //         !CAP     CAP (fiscale se c'�, oppure di residenza)
-    //         !COM     comune (fiscale se c'�, oppure di residenza)
-    //         !PROV    provincia (fiscale se c'�, oppure di residenza)
-    //         !IVA     partita iva
-    //         !CF      codice fiscale
-    //         !TEL     numero di telefono (con prefisso)
-    //         !FAX     numero di fax (con prefisso)
-    //         !REGSOC  numero di registrazione presso il Tribunale
-    //         !CCIAA   numero di registrazione presso la camera di commercio
-    // nota: la relazione della ditta � cos� strutturata:
-    //       %NDITTE (9) Dati ditte
-    //       + %ANAGR (6) Anagrafica generale (indirizzo, ecc.)
-    //          + %COMUNI (113@) Comune di residenza
-    //          + %COMUNI (213@) Comune di residenza fiscale
-    TString in(s.get());
-    if (in[0]=='!') {
-      in.ltrim(1);
-      bool _fisc= _firmrel.lfile(6).get("INDRF").not_empty();
-      if (in=="RAGSOC") cf.set(_firmrel.lfile().get("RAGSOC"));
-      if (in=="IND") {
-        if (_fisc) cf.set(_firmrel.lfile(6).get("INDRF"));
-        else cf.set(_firmrel.lfile(6).get("INDRES"));
-      }
-      if (in=="NUM") {
-        if (_fisc) cf.set(_firmrel.lfile(6).get("CIVRF"));
-        else cf.set(_firmrel.lfile(6).get("CIVRES"));
-      }
-      if (in=="CAP") {
-        if (_fisc) cf.set(_firmrel.lfile(6).get("CAPRF"));
-        else cf.set(_firmrel.lfile(6).get("CAPRES"));
-      }
-      if (in=="COM") {
-        if (_fisc) cf.set(_firmrel.lfile(-213).get("DENCOM"));
-        else cf.set(_firmrel.lfile(-113).get("DENCOM"));
-      }
-      if (in=="PROV") {
-        if (_fisc) cf.set(_firmrel.lfile(-213).get("PROVCOM"));
-        else cf.set(_firmrel.lfile(-113).get("PROVCOM"));
-      }
-      if (in=="IVA") cf.set(_firmrel.lfile(6).get("PAIV"));
-      if (in=="CF") cf.set(_firmrel.lfile(6).get("COFI"));
-      if (in=="TEL") {
-        TString tel(_firmrel.lfile().get("PTEL"));
-        tel << "/" << _firmrel.lfile().get("TEL");
-        cf.set(tel);
-      }
-      if (in=="FAX") {
-        TString tel(_firmrel.lfile().get("PFAX"));
-        tel << "/" << _firmrel.lfile().get("FAX");
-        cf.set(tel);
-      }
-      if (in=="REGSOC") {
-        TString reg(_firmrel[LF_UNLOC].get("REGTRIB"));
-        reg << " Vol. " << _firmrel[LF_UNLOC].get("VOLTRIB");
-        reg << " Fasc. " << _firmrel[LF_UNLOC].get("FASCTRIB");
-        cf.set(reg);
-      }
-      if (in=="CCIAA") {
-        TString cod(_firmrel[LF_UNLOC].get("NUMCCIAA"));
-        cod << " del " << _firmrel[LF_UNLOC].get("DATAICCIAA");
-        cf.set(cod);
-      }
-    } else {
-      TFieldref fref(s.get(), 0);
-      cf.set(fref.read(_firmrel));
-    }
-    valore = cf.get();
-    cf.put_paragraph(valore);
-    cf.set(""); // Resetta il campo per la prossima stampa di questo item
-    return (TRUE);
-  } // fine _DITTA
 
-  if (code== "_CIFRELET") {
-    // conversione di un reale da cifre a lettere
-    // sintassi: _CIFRELETTERE[,<campo form>]
-    // dove: <campo form> � il campo della form (preceduto da '#') da cui prendere il valore, se non � specificato � sottointeso il campo corrente
-    // nota: prende il valore del campo specificato e scrive la sua conversione in lettere nel campo corrente
-    TString in;
-    if (s.items()==2) {
-      in= s.get();
-      if (in[0]== '#') in.ltrim(1);
-      TForm_item &fi= cf.find_field(in);
-      in= fi.get();
-    } else in= cf.get();
-    real n(in);
-    valore = n.string("LETTERE");
-    cf.set(valore);
-    cf.put_paragraph(valore);
-    cf.set(""); // Resetta il campo per la prossima stampa di questo item
-    return (TRUE);
-  } // fine _CIFRELET
-  
-  if (code.left(6) == "_TOTAL") {
-    // totalizzatori di testata/coda, riga e progressione
-    // sintassi: _TOTAL_{CODA|RIGA|PROGRES},<totalizzatore>[,<parametri opz>]
-    // dove: <totalizzatore> � il codice del totalizzatore richiesto
-    static real zero("0.0"); // 0 sotto forma di real per i casi in cui il totalizzatore non viene trovato
-    //if (!_doc->summary_compiled() &&_cli_loaded) _doc->set_condv(_cliente);
-    TString tot= s.get(); // prende il codice del totalizzatore richiesto
-    TForm_item *fi; // puntatore al campo della form in cui scrivere il valore del totalizzatore
-    fi= &cf; // prende il puntatore al campo corrente
-    if (code.mid(6) == "_CODA") {
-      TString value;
-      if (tot == "TOTDOC") value = _doc->tot_documento().string();
-      else if (tot == "TIMPNETTI") value = _doc->tot_importi_netti().string();
-      else if (tot == "TIMPOSTE") value = _doc->tot_imposte().string();
-      else if (tot == "TIMPONIBILI")
-      {
-        byte sel = atoi(s.get());
-        value = _doc->tot_imponibili(sel).string();
-      }
-      else
-        value = _doc->get_head_info(tot);
-      if (value.not_empty())
-        fi->set(value); // setta il campo della form
-      else
-        fi->set(zero.string());
-    }
-    if (code.mid(6) == "_RIGA") {
-      TLocalisamfile &rdoc= (cursor())->file(LF_RIGHEDOC);
-      TToken_string totriga(rdoc.get("G1"),'\n'); // prende il campo memo con i totalizzatori sotto forma di token string
-      TString value;
-      const int items = totriga.items();
-      for (int i = 0; i<items; i++)
-      {
-        TToken_string item(totriga.get(),'=');
-        if (tot == item.get())
-        {
-          value = item.get();
-          break;
-        }
-      }
-      if (value.not_empty())
-        fi->set(value); // setta il campo della form
-      else
-        fi->set(zero.string());
-    }
-//    if (code.mid(6) == "_PROGRES") {
-//      TString16 tot16(tot);
-//      fi->set(_total_prog->get(tot16).string());
-//    }
-
-    valore = fi->get();    
-    real x(valore);
-    TString picture(fi->picture());
-    if (x != 0.0)
-      valore = x.string(picture); // Riformatta il valore
-    else 
-      valore = "";
-    fi->put_paragraph(valore);
-    fi->set(""); // Resetta il campo per la prossima stampa di questo item
-    return (TRUE);
-  } // fine _TOTAL_xxx
-  
-  if (code== "_CLIENTE") {
-    // lettura dei dati del cliente
-    // sintassi: _CLIENTE,{<campo relazione>|<macro>}
-    // dove: <campo relazione> � un riferimento alla relazione di gestione dei dati del cliente
-    //       <macro> � uno delle macro seguenti:
-    //         !RAGSOC  ragione sociale
-    //         !IND     indirizzo
-    //         !NUM     numero civico
-    //         !INDNUM  indirizzo + numero civico
-    //         !LOC     localit�
-    //         !CAP     CAP
-    //         !COM     comune
-    //         !PROV    provincia
-    //         !IVA     partita iva
-    //         !CF      codice fiscale
-    //         !PERS    <F> se persona fisica, <G> se giuridica
-    //         !DATANAS data di nascita
-    //         !COMNAS  comune di nascita
-    //         !TEL     primo numero di telefono (con prefisso)
-    //         !TEL2    secondo numero di telefono (con prefisso)
-    //         !TEL3    terzo numero di telefono (con prefisso)
-    //         !FAX     numero di fax (con prefisso)
-    // nota: la relazione del cliente � cos� strutturata:
-    //       CLIFO (20) Clienti/fornitori
-    //       + CFVEN (17) Clienti/fornitori per vendite
-    //       + %COMUNI (113@) Comune di residenza
-    //       + %COMUNI (213@) Comune di nascita
-    TLocalisamfile &doc= (cursor())->file(LF_DOC);
-    TString16 tipocf= doc.get("TIPOCF"), codcf= doc.get("CODCF"), ocfpi= doc.get("OCFPI");
-    if (!_cli_loaded ) { // il cliente � sulla testata del documento di vendita, quindi pu� essere caricato una volta sola per tutte
-      _cliente->load(tipocf[0], atol(codcf), ocfpi);
-      _cliente->add(LF_COMUNI, "COM=STATOCF+COMCF", 1, LF_CLIFO, 100+LF_COMUNI);
-      _cliente->add(LF_COMUNI, "COM=STATONASC+COMNASC", 1, LF_CLIFO, 200+LF_COMUNI);
-      _cli_loaded= TRUE;
-    }     
-    TString in(s.get()); // prende la macro o il fieldref
-    if (in[0]=='!') {
-      in.ltrim(1);
-      if (in=="RAGSOC") cf.set(_cliente->get(LF_CLIFO, "RAGSOC"));
-      if (in=="IND") cf.set(_cliente->get(LF_CLIFO, "INDCF"));
-      if (in=="NUM") cf.set(_cliente->get(LF_CLIFO, "CIVCF"));
-      if (in=="INDNUM") {
-        TString indnum(_cliente->get(LF_CLIFO, "INDCF"));
-        indnum << " " << _cliente->get(LF_CLIFO,"CIVCF");
-        cf.set(indnum);
-      }
-      if (in=="LOC") cf.set(_cliente->get(LF_CLIFO, "LOCALITACF"));
-      if (in=="CAP") cf.set(_cliente->get(LF_CLIFO, "CAPCF"));
-      if (in=="COM") cf.set(_cliente->get(-(100+LF_COMUNI), "DENCOM"));
-      if (in=="PROV") cf.set(_cliente->get(-(100+LF_COMUNI), "PROVCOM"));
-      if (in=="IVA") cf.set(_cliente->get(LF_CLIFO, "PAIV"));
-      if (in=="CF") cf.set(_cliente->get(LF_CLIFO, "COFI"));
-      if (in=="PERS") cf.set(_cliente->get(LF_CLIFO, "TIPOPERS"));
-      if (in=="DATANAS") cf.set(_cliente->get(LF_CLIFO, "DATANASC"));
-      if (in=="COMNAS") cf.set(_cliente->get(-(200+LF_COMUNI), "DENCOM"));
-      if (in=="TEL") {
-        TString tel(_cliente->get(LF_CLIFO, "PTEL"));
-        tel << "/" << _cliente->get(LF_CLIFO, "TEL");
-        cf.set(tel);
-      }
-      if (in=="TEL2") {
-        TString tel2(_cliente->get(LF_CLIFO, "PTEL2"));
-        tel2 << "/" << _cliente->get(LF_CLIFO, "TEL2");
-        cf.set(tel2);
-      }
-      if (in=="TEL3") {
-        TString tel3(_cliente->get(LF_CLIFO, "PTEL3"));
-        tel3 << "/" << _cliente->get(LF_CLIFO, "TEL3");
-        cf.set(tel3);
-      }
-      if (in=="FAX") {
-        TString fax(_cliente->get(LF_CLIFO, "PFAX"));
-        fax << "/" << _cliente->get(LF_CLIFO, "FAX");
-        cf.set(fax);
-      }
-    } else {
-      TFieldref fref(s.get(), 0);
-      cf.set(fref.read(*_cliente)); // l'oggetto cliente � figlio della TRelation, quindi lo passo al fieldref semplicemente con un typecast
-    }
-    valore = cf.get();
-    cf.put_paragraph(valore);
-    cf.set(""); // Resetta il campo per la prossima stampa di questo item
-    return (TRUE);
-  } // fine _CLIENTE
-
-  if (code== "_SCADENZE") {
-    // messaggio per stampare le scadenze
-    // sintassi: _SCADENZE,<macro>,<cambio codice>
-    // dove <macro> e' uno dei seguenti:
-    //      DATA    : stampa la data di scadenza 
-    //      IMPORTO : stampa l'importo in scadenza
-    // dove <cambio codice> vale 0 o 1 se indica di rendere corrente la prossima scadenza
-    if (s.items() == 3)
-    {
-      TString what(s.get());
-      TString value(_doc->scadenze_get(what));
-      cf.set(value);
-        
-      real x(value);
-      if (x.is_real(value))
-      {
-        TString picture(cf.picture());
-        if (x != 0.0)
-          value = x.string(picture); // Riformatta il valore
-        else 
-          value = "";
-      }
-      
-      what = s.get();
-      const bool next = what == "1";
-      if (next) _doc->scadenze_set_next();
-      cf.put_paragraph(value);
-      cf.set(""); // Resetta il campo per la prossima stampa di questo item
-    }
-  }
+  // Messaggio per stampare il numero di pagina corrente
+  if (code== "_PAGENO")
+  {
+    TString16 pg; pg << int(printer().getcurrentpage() );
+    cf.put_paragraph(pg);
+  } 
   
   if (code== "_RIEPILOGOIVA") {
     // tabella riepilogo aliquote iva e relative imposte
@@ -726,7 +810,6 @@ bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) {
     //        0        indica di non leggere il successivo codice IVA nella tabella riepilogativa
     //        1        indica di leggere il successivo codice IVA nella tabella riepilogativa
 
-    //if (!_doc->summary_compiled() &&_cli_loaded) _doc->set_condv(_cliente);
 
     if (s.items() == 4)
     {
@@ -741,7 +824,6 @@ bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) {
         what = s.get();
         const bool next  = what == "1"; // deve cambiare elemento ? 
         if (next) _doc->summary_set_next();
-        cf.set(value);
         
         real x(value);
         if (x.is_real(value))
@@ -753,7 +835,6 @@ bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) {
             value = "";
         }
         cf.put_paragraph(value);
-        cf.set(""); // Resetta il campo per la prossima stampa di questo item
       }
     }
     else
@@ -761,20 +842,246 @@ bool TDocVen_Form::validate(TForm_item &cf, TToken_string &s) {
     return (TRUE);
   } // fine _RIEPILOGOIVA
   
-  // Messaggio per stampare il numero di pagina corrente
-  if (code== "_PAGENO") {
-    TString16 pg; pg << int(printer().getcurrentpage() - app().base_no());
-    cf.set(pg); cf.put_paragraph(pg);
-    cf.set("");
+  if (code == "_TOTIMPONIBILI")
+  {
+    // sintassi: _TOTIMPONIBILI,<selettore>
+    // dove: <selettore> funge da filtro per la somma degli imponibili
+    // vedi _RIEPILOGOIVA per la spiegazione dei filtri selettivi
+    byte sel = atoi(s.get());
+    valore = _doc->tot_imponibili(sel).string();
+
+    real x(valore);
+    TString picture(cf.picture());
+    if (x != 0.0)
+      valore = x.string(picture); // Riformatta il valore
+    else 
+      valore = "";
+    cf.put_paragraph(valore);
+    return (TRUE);
+  } // fine _TOTIMPONIBILI
+
+  if (code== "_SCADENZE") {
+    // messaggio per stampare le scadenze
+    // sintassi: _SCADENZE,<macro>,<cambio codice>
+    // dove <macro> e' uno dei seguenti:
+    //      DATA    : stampa la data di scadenza 
+    //      IMPORTO : stampa l'importo in scadenza
+    // dove <cambio codice> vale 0 o 1 se indica di rendere corrente la prossima scadenza
+    if (s.items() == 3)
+    {
+      TString what(s.get());
+      TString value(_doc->scadenze_get(what));
+        
+      real x(value);
+      if (x.is_real(value))
+      {
+        TString picture(cf.picture());
+        if (x != 0.0)
+          value = x.string(picture); // Riformatta il valore
+        else 
+          value = "";
+      }
+      
+      what = s.get();
+      const bool next = what == "1";
+      if (next) _doc->scadenze_set_next();
+      cf.put_paragraph(value);
+    }
   }
+
   return TForm::validate(cf, s); // se il codice del messaggio non � identificato viene passato alla funzione standard
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////////
-// classe TStampa_Doc_Vendita customizzata dalla TApplication per l'applicazione principale
+// classe TStampaDoc_application customizzata dalla TApplication per l'applicazione principale
 //////////////////////////////////////////////////////////////////////////////////////////////
 
-bool TStampa_Doc_Vendita::date2num_handler(TMask_field& f, KEY key)
+    
+enum behaviour
+{
+  skip,
+  go,
+  cancel
+};
+
+// Chiavi di ordinamento LF_DOC:
+// Chiave 1: ordinamento per Provvisorio + Anno + Codice numerazione + Numero documento
+// Chiave 3: ordinamento per Data documento + Provvisorio + Anno + Codice numerazione + Numero documento
+
+#define BY_NUM_KEY   1
+#define BY_DATE_KEY  3
+
+
+class TStampaDoc_application: public TApplication
+{
+  TString _codnum; // codice di numerazione
+  char _provv; // stampa documenti provvisiori o definitivi (D o P)
+  int _anno; // anno della documentazione
+  int _key;  // chiave per scorrere i documenti (1 o 3, vedi sopra)
+  int _ncopie; // numero di copie per ogni documento
+  long _dalnum, _alnum; // estremi di numerazione dei documenti
+  TDate _dadata, _adata; // estremi di data dei documenti
+  bool _interattivo; // flag che indica se il prog. funziona in interattivo o in batch
+  bool _definitiva; // flag che indica se la stampa � definitiva o no
+  TRelation *_firmrel; // puntatore alla relazione che gestisce i dati della ditta corrente
+  TDocumento_form *_form; // puntatore al form di stampa
+protected:
+  virtual bool create();
+  virtual bool destroy();
+  virtual bool menu(MENU_TAG);
+  bool select(void);
+  virtual void on_firm_change(void);
+  virtual behaviour on_module_change(const TString &, TString &); // funzione chiamata ad ogni cambio modulo durante la stampa
+  virtual bool query_final_print(void); // funzione chiamata all'inizializzazione per sapere se la stampa � definitiva
+  static bool date2num_handler(TMask_field& f, KEY key);
+  static bool range_handler(TMask_field& f, KEY key);
+public:
+  TDocumento_form& form() { return *_form; }
+  void print_documento();
+  void print_selected();   
+  TStampaDoc_application() {};
+  virtual ~TStampaDoc_application() {};
+};
+
+
+void TStampaDoc_application::print_selected()
+{
+  TRelation rel(LF_DOC);
+  rel.add(LF_RIGHEDOC,"CODNUM==CODNUM|ANNO==ANNO|PROVV==PROVV|NDOC==NDOC");
+  TCursor cur(&rel);
+  TLocalisamfile& doc = cur.file();
+  cur.setkey(_key);
+  TRectype darec(LF_DOC),arec(LF_DOC); // Estremi filtro
+  TString modulo_prec;
+  const bool order_by_num = _key == BY_NUM_KEY;
+  
+  doc.put(DOC_CODNUM, _codnum); // compone la chiave per il record di inizio cursore
+  doc.put(DOC_ANNO, _anno);
+  doc.put(DOC_PROVV, _provv);
+  doc.put(DOC_NDOC, _dalnum);
+  if (!order_by_num) doc.put(DOC_DATADOC, _dadata);
+  doc.setkey(_key);
+  doc.read(); // trova il record iniziale
+  darec = doc.curr();
+  doc.put(DOC_NDOC, _alnum);
+  if (!order_by_num) doc.put(DOC_DATADOC, _adata);
+  int err = doc.read(); // trova il record finale
+  if (err == _iseof) doc.last();
+  else if (err == _iskeynotfound) doc.prev();
+  arec = doc.curr();
+  
+  if (arec < darec)
+  {
+    error_box("Non vi sono documenti da stampare nell'intervallo indicato");
+    return;
+  }
+  _definitiva= query_final_print(); // legge il flag di stampa definitiva
+
+  TPrinter& pr =  printer();
+  pr.open();
+
+  TProgind* pi = pr.printtype() != screenvis ? 
+                   new TProgind(cur.items(),"Stampa documenti in corso...",FALSE,TRUE,10) :
+                   NULL;
+
+  cur.setregion(darec, arec);
+  const long items = cur.items();
+  behaviour whattodo = go;
+  bool first_inst = TRUE;
+  for (long i = 0; i < items; i++)
+  {
+    cur = i; // Posiziona il documento
+    _form  = new TDocumento_form(cur.curr(), *_firmrel, _definitiva, _interattivo); // Istanzia il form
+    
+    if (!_form->valid()) break; // interrompe la stampa se il doc corrente non e' tra i tipi validi
+    const TString &modulo= _form->get_module_code(); // legge dal form il codice del modulo di carta per la stampa
+    if (modulo_prec.empty()) modulo_prec = modulo; // se siamo al primo passaggio la variabile di modulo precedente viene riempita
+    else first_inst = FALSE;
+    const bool module_changed = modulo != modulo_prec;
+    if (first_inst || module_changed)
+      if (!_form->doc_arrange())  // Setta l'offset o posiziona manualmente
+        break; // Se vi sono errori interrompe la stampa
+    if (module_changed) whattodo = on_module_change(modulo, modulo_prec); // se il modulo � cambiato dalla stampa precedente interroga la funzione per sapere che comportamento tenere
+    if (whattodo==cancel)   break; // se non si pu� procedere la stampa viene interrotta
+    if (whattodo==skip) continue; // Salta il documento corrente
+    // altrimenti prosegue
+
+    // Carica il numero di copie da stampare per questo form
+    int ncopie  = _ncopie == 0 ? _form->ncopie() : _ncopie; // Numero di copie da stampare per questo documento
+    if (ncopie == 0) ncopie = 1;
+    
+    for (int n=0; n < ncopie; n++)
+    {
+      print_documento();
+      _form->doc().summary_reset();
+      _form->doc().scadenze_reset();
+    }
+    delete _form;
+
+    if (_definitiva && (numerazione_definitiva(doc) != NOERR))
+    { // se la stampa � definitiva viene lanciata la procedura di rinumerazione
+      if (_interattivo) error_box("Non � possibile completare la procedura di numerazione definitiva dei documenti");
+      break;
+    }
+  }
+  
+  if (pi != NULL) delete pi;
+  printer().close();
+}
+
+void TStampaDoc_application::print_documento()
+{
+  CHECK(_form,"Nessun form istanziato!");
+  TDocumento_form& f = form();
+  TLocalisamfile& doc = f.cursor()->file();
+  const bool is_vis = printer().printtype() == screenvis;
+  if (!is_vis)
+  {
+    TString status("Documento: ");
+    status << doc.get(DOC_CODNUM);
+    status << '\\' << doc.get(DOC_NDOC);
+    xvt_statbar_set(status);
+  }
+  f.print_documento();
+  
+  if (!is_vis)
+    xvt_statbar_set(NULL);
+}
+
+behaviour TStampaDoc_application::on_module_change(const TString &modulo, TString &modulo_prec)
+{
+  if (!_interattivo) return skip; // se siamo in interattivo il documento viene saltato...
+  else 
+  { // ...altrimenti viene chiesto all'utente il da farsi
+    int risp= yesnocancel_box("Il modulo di carta � cambiato: inserisci il modulo '%s' e premi 'S�' per continuare, 'No' per saltare il documento o 'Cancel' per interrompere la stampa", modulo);
+    behaviour ret;
+    switch (risp)
+    {
+      case K_YES:
+        modulo_prec= modulo; // aggiorna l'inseguitore dei moduli
+        ret= go; // la stampa pu� continuare
+        break;
+      case K_NO:
+        ret= skip; // il documento viene saltato
+        break;
+      case K_ESC:
+        ret= cancel; // la stampa viene interrotta
+        break;
+    }
+    return ret;
+  }
+}
+
+bool TStampaDoc_application::query_final_print()
+{
+  if (_interattivo) 
+  { // se siamo in interattivo viene richiesto all'utente se la stampa � definitiva o meno
+    if (yesno_box("E' una stampa definitiva?")) return TRUE;
+    else return FALSE;
+  } else return _definitiva; // altrimenti ritorna il valore letto dalla linea di comando
+}
+
+bool TStampaDoc_application::date2num_handler(TMask_field& f, KEY key)
 {
   TMask& m = f.mask();
   if (key == K_TAB && f.focusdirty())
@@ -808,7 +1115,7 @@ bool TStampa_Doc_Vendita::date2num_handler(TMask_field& f, KEY key)
   return TRUE;
 }
 
-bool TStampa_Doc_Vendita::range_handler(TMask_field& f, KEY key)
+bool TStampaDoc_application::range_handler(TMask_field& f, KEY key)
 {
   int rt = TRUE;
   TMask& m = f.mask();
@@ -825,77 +1132,65 @@ bool TStampa_Doc_Vendita::range_handler(TMask_field& f, KEY key)
   return rt;
 }
 
-bool TStampa_Doc_Vendita::filter_rows(const TRelation * r)
+bool TStampaDoc_application::create()
 {
-  TLocalisamfile& righe = r->lfile(LF_RIGHEDOC);
-  bool rt = TRUE;
-  TString tiporiga(righe.get("TIPORIGA"));
-  TString codart(righe.get("CODART"));
-  TString_array& a = app()._form->exclude_list();
-  const int items = a.items();
-  
-  for (int i = 0; i < items && rt; i++)
-  {
-    TToken_string& s=a.row(i);
-    TString tr(s.get(0));
-    TString ar(s.get(1));
-    tr.trim();ar.trim();
-    if (tr.empty() && ar.empty()) continue;
-    if (tr.empty() && ar == codart) rt = FALSE;
-    else if (tr == tiporiga)
-      if (ar.empty() || (ar.not_empty() && ar == codart)) rt = FALSE;
-  }
-  
-  return rt;
-}
-
-bool TStampa_Doc_Vendita::create() {
   TApplication::create();
-  _form = NULL;
   _firmrel= new TRelation(LF_NDITTE); // istanziamento e impostazione della relazione di gestione della ditta corrente
   _firmrel->add(LF_ANAG, "TIPOA=TIPOA|CODANAGR=CODANAGR");
   _firmrel->add(LF_UNLOC,"CODDITTA=CODDITTA"); // si posiziona sulla prima unita' locale della ditta
   _firmrel->add(LF_COMUNI, "COM=STATORES+COMRES", 1, LF_ANAG, 100+LF_COMUNI);
   _firmrel->add(LF_COMUNI, "COM=STATORES+COMRF", 1, LF_ANAG, 200+LF_COMUNI);
-  if (argc()>2) { // lettura dei parametri iniziali dalla linea di comando
+  int argc = TApplication::argc();
+  if (argc>2 && (argc == 8 || argc == 9))
+  { // lettura dei parametri iniziali dalla linea di comando
     _codnum= argv(2); // il primo parametro � il codice di numerazione
     _anno= atoi(argv(3)); // il secondo � l'anno
-    _provv= argv(4); // il terzo � il flag di numerazione provvisoria
+    _provv= argv(4)[0]; // il terzo � il flag di numerazione provvisoria
     _dalnum= atol(argv(5)); // il quarto � il numero di documento di partenza
     _alnum= atol(argv(6)); // il quinto � il numero di documento di fine
     _definitiva= (strcmp(argv(7), "D")==0); // il sesto � se la stampa � definitiva (rinumerazione dei documenti)
-    _ncopie = atoi(argv(8));
+    _ncopie = argc == 9 ? atoi(argv(8)) : 1;
     _interattivo= FALSE;
-    print();
-  } else { // oppure lancio della maschera
+    print_selected();
+  } 
+  else if (argc == 2)
+  { // oppure lancio della maschera
     _interattivo= TRUE;
     dispatch_e_menu(BAR_ITEM(1));
   }
+  else 
+  {
+    error_box(Usage);
+    return FALSE;
+  }
   return TRUE;
 }
 
-bool TStampa_Doc_Vendita::destroy() {
-  if (_form) delete _form;
+bool TStampaDoc_application::destroy()
+{
   delete _firmrel; // distruzione della relazione di gestione della ditta corrente
   return TApplication::destroy();
 }
 
-void TStampa_Doc_Vendita::on_firm_change() {
+void TStampaDoc_application::on_firm_change()
+{
   TLocalisamfile &firmfile= _firmrel->lfile();
   firmfile.put("CODDITTA", get_firm());
   _firmrel->read();
 }
 
-int TStampa_Doc_Vendita::select() {
+bool TStampaDoc_application::select()
+{
   TMask m("ve1100a");
   TString wdate;
   m.set_handler(F_DA_DATADOC, date2num_handler);
   m.set_handler(F_A_DATADOC, date2num_handler);
   m.set_handler(F_A_NDOC, range_handler);
-  if (m.run() == K_ENTER) {
+  if (m.run() == K_ENTER)
+  {
     _codnum= m.get(F_CODNUM); // lettura dei dati dalla maschera
     _anno= m.get_int(F_ANNO);
-    _provv= m.get(F_PROVV);
+    _provv= m.get(F_PROVV)[0];
     _dalnum= m.get_long(F_DA_NDOC);
     _alnum= m.get_long(F_A_NDOC);
     _ncopie = m.get_int(F_NCOPIE);
@@ -906,165 +1201,22 @@ int TStampa_Doc_Vendita::select() {
     wdate = m.get(F_A_DATADOC);
     if (wdate.not_empty()) _adata = wdate;
     else _adata = eotime; 
-    _order_by_num = m.get(F_DATA_O_NUM) == "N";
-    return 1;
-  } else return 0; // 0 indica che non si � usciti con "Conferma" dalla maschera
+    _key = BY_NUM_KEY;
+    if (m.get(F_DATA_O_NUM) != "N") _key = BY_DATE_KEY;
+    return TRUE;
+  } else return FALSE;
 }
 
-bool TStampa_Doc_Vendita::menu(MENU_TAG) { // procedura di dispatch dei menu
-  int s;
-  while ((s= select()) != 0) if (s==1) print(); // se la selezione della maschera ritorna 1 viene lanciata la stampa
+bool TStampaDoc_application::menu(MENU_TAG)
+{
+  while (select()) print_selected(); 
   return FALSE;
 }
 
-void TStampa_Doc_Vendita::print() {
-  TFilename nomeform, profilo; // istanzia le stringhe per il nome del form di stampa e del profilo di configurazione
-  TString modulo_prec;  // istanzia la stringa per l'inseguimento del modulo di carta
-  TTable tip("%TIP"); // istanzia la tabella dei tipi di documento per i profili
-  TRelation rel(LF_DOC); // istanzia la relazione sul file principale
-  TLocalisamfile righe(LF_RIGHEDOC); // cosi' i trecord_array non rompono i coglioni
-  TCursor cur(&rel); // crea il cursore principale dalla relazione
-  if (!_order_by_num) cur.setkey(3); // setta l'ordine per data.
-  TLocalisamfile &doc= cur.file(); // prende il riferimento al file principale
-  doc.zero(); // vuota il record del file 
-  doc.put("CODNUM", _codnum); // compone la chiave per il record di inizio cursore
-  doc.put("ANNO", _anno);
-  doc.put("PROVV", _provv);
-  doc.put("NDOC", _dalnum);
-  if (!_order_by_num) doc.put("DATADOC", _dadata);
-  doc.read(); // posiziona il file sul record
-  TRectype darec= doc.curr(); // copia il record di inizio cursore
-  doc.zero(); // vuota il record del file 
-  doc.put("CODNUM", _codnum); // compone la chiave per il record di fine cursore
-  doc.put("ANNO", _anno);
-  doc.put("PROVV", _provv);
-  doc.put("NDOC", _alnum);
-  if (!_order_by_num) doc.put("DATADOC", _adata);
-  const int err = doc.read(); // posiziona il file sul record
-  if (err == _iseof) doc.last();
-  else if (err == _iskeynotfound) doc.prev();
-  const long num_lim_sup = doc.get_int("NDOC");
-  const TDate date_lim_sup = doc.get_date("DATADOC");
-  if (num_lim_sup > _alnum || (!_order_by_num && date_lim_sup < _adata))
-  {
-    error_box("Non vi sono documenti da stampare nell'intervallo indicato");
-    return;
-  }
-  _definitiva= query_final_print(); // legge il flag di stampa definitiva
-  printer().open(); // apre la stampante
-  TRectype arec= doc.curr(); // copia il record di fine cursore
-  cur.setregion(darec, arec); // imposta il filtro sul cursore di stampa (nell'ordine giusto :-)
-  const bool is_vis = printer().printtype() == screenvis;
-  TProgind* pi;
-  if (!is_vis)
-    pi = new TProgind(cur.items(),"Stampa documenti in corso...",FALSE,TRUE,10);
-  _base_page_no = 0;
-  for (cur= 0; cur.pos()<cur.items(); ++cur) { // ciclo sugli elementi del cursore di stampa
-    if (!is_vis)
-      pi->addstatus(1L);
-    tip.put("CODTAB", doc.get("TIPODOC")); // posiziona la tabella dei tipi di documento
-    int err=tip.read(); // legge la tabella
-    if (err==NOERR) { // se non ci sono errori procede con la stampa
-      nomeform= tip.get("S5"); // legge il nome del form di stampa
-      profilo= tip.get("S4"); // legge il nome del profilo di configurazione
-      profilo.ext("ini"); // aggiunge l'estensione al nome del file del profilo
-      if (profilo.empty() || nomeform.empty()) {
-        error_box("Nome profilo o form di stampa non valido nella tabella TIP");
-        break;
-      }
-      TConfig config(profilo, "STAMPA"); // apre il file di configurazione del profilo
-      TToken_string stati((const char*)config.get("STATIVALIDI"), ','); // legge gli stati validi di questo tipo di documento
-      if (_definitiva && (stati.get_pos(doc.get("STATO"))== -1)) { // se lo stato del doc. corrente non � valido...
-        if (_interattivo) error_box("Non � possibile stampare un documento con stato non valido"); // ...viene mostrato un messaggio (solo in modo interattivo)...
-        break; // ...e la stampa viene interrotta
-      }
-      behaviour whattodo= go; // istanzia la variabile di comportamento
-
-      TDocumentoEsteso * doc_est = new TDocumentoEsteso(cur.curr()); // istanzia TDocumentoEsteso sulla testata attuale
-      // Da implementare quando verra gestito il numero di copie
-      int ncopie  = _ncopie == 0 ? doc_est->tipo().ncopie() : _ncopie; // Numero di copie da stampare per questo documento
-      if (ncopie == 0) ncopie = 1;
-      _form = new TDocVen_Form(nomeform, *_firmrel, doc_est); // istanzia il form, passandogli il documento. (la delete del documento e' nel ditruttore
-      const TString &modulo= _form->get_module_code(); // legge dal form il codice del modulo di carta per la stampa
-      if (modulo_prec.empty()) modulo_prec= modulo; // se siamo al primo passaggio la variabile di modulo precedente viene riempita
-      if (modulo != modulo_prec) whattodo= on_module_change(modulo, modulo_prec); // se il modulo � cambiato dalla stampa precedente interroga la funzione per sapere che comportamento tenere
-      if (whattodo==cancel)   break; // se non si pu� procedere la stampa viene interrotta
-      else if (whattodo==go) { // altrimenti prosegue
-        TCursor &fcur= *(_form->cursor()); // ricava il riferimento al cursore originale del form
-        TLocalisamfile &rdoc= fcur.file(LF_RIGHEDOC); // ricava il riferimento al file principale del cursore del form
-        TRectype darec_r(rdoc.curr());  // istanzia il record di filtro per il cursore
-        darec_r.zero(); // vuota il record
-        darec_r.put("CODNUM", _codnum); // compone la chiave parziale per il filtro sul cursore dal file principale del cursore di selezione dei documenti
-        darec_r.put("ANNO", _anno);
-        darec_r.put("PROVV", _provv);
-        darec_r.put("NDOC", doc.get("NDOC"));
-        TRectype arec_r(darec_r); // istanzia il secondo record per il filtro sul cursore
-        fcur.setregion(darec_r, arec_r); // setta il filtro sul cursore del form
-        fcur.set_filterfunction(filter_rows); // setta il filtro per escludere alcuni tipi riga indicati nel form
-        // Da implementare quando verra gestito il numero di copie
-        for (int j=0; j<ncopie; j++)
-        {
-          _form->print(); // stampa il form corrente
-          _base_page_no = printer().getcurrentpage() -1; // Numero base della pagina
-          _form->doc()->summary_reset();
-          _form->doc()->scadenze_reset();
-        }
-        if (_definitiva && (numerazione_definitiva(doc) != NOERR)) { // se la stampa � definitiva viene lanciata la procedura di rinumerazione
-          if (_interattivo) error_box("Non � possibile completare la procedura di numerazione definitiva dei documenti");
-          break;
-        }
-      }
-      if (_form)
-      {
-        delete _form; 
-        _form = NULL;
-      }
-    } else {
-      error_box("Il documento corrente non � stato trovato nella tabella dei tipi di documento (errore %d)", err);
-      break;
-    }
-  }
-  if (!is_vis) delete pi;
-  if (_form)
-  {
-    delete _form; 
-    _form = NULL;
-  }
-  printer().close(); // chiude la stampante
-}
-
-behaviour TStampa_Doc_Vendita::on_module_change(const TString &modulo, TString &modulo_prec) {
-  if (!_interattivo) return skip; // se siamo in interattivo il documento viene saltato...
-  else { // ...altrimenti viene chiesto all'utente il da farsi
-    int risp= yesnocancel_box("Il modulo di carta � cambiato: inserisci il modulo '%s' e premi 'S�' per continuare, 'No' per saltare il documento o 'Cancel' per interrompere la stampa", modulo);
-    behaviour ret;
-    switch (risp) {
-      case K_YES:
-        modulo_prec= modulo; // aggiorna l'inseguitore dei moduli
-        ret= go; // la stampa pu� continuare
-        break;
-      case K_NO:
-        ret= skip; // il documento viene saltato
-        break;
-      case K_ESC:
-        ret= cancel; // la stampa viene interrotta
-        break;
-    }
-    return ret;
-  }
-}
-
-bool TStampa_Doc_Vendita::query_final_print() {
-  if (_interattivo) { // se siamo in interattivo viene richiesto all'utente se la stampa � definitiva o meno
-    if (yesno_box("E' una stampa definitiva?")) return TRUE;
-    else return FALSE;
-  } else return _definitiva; // altrimenti ritorna il valore letto dalla linea di comando
-}
-
-
-
-int ve1100(int argc, char* argv[]) {
-  TStampa_Doc_Vendita a;
+// Do all the work!
+int ve1100(int argc, char* argv[])
+{
+  TStampaDoc_application a;
   a.run(argc, argv, "Stampa documenti di vendita");
   return (0);
 }