// trattasi di -*-c++-*- #ifndef __PRINTAPP_H #define __PRINTAPP_H #ifndef __APPLICATION_H #include <applicat.h> #endif #ifndef __PRINTER_H #include <printer.h> #endif #ifndef __RELATION_H #include <relation.h> #endif // compatibility #define TPrintapp TPrint_application enum print_action { REPEAT_PAGE, NEXT_PAGE }; // user functions to pass field informations to setrow() // no class or nice C++ interface since varargs is nasty // FLD(Num.logico, Nome campo [, da [, a]]) const char* FLD(int lognum, const char* f, int from = -1, int to = -1); // FLD(Num. logico, Nome campo numerico, Picture string) const char* FLD(int lognum, const char* f, const char* picture); // FLD(Nome tabella, Nome campo numerico, Picture string) const char* FLD(const char* tabname, const char* f, const char* picture); // FLD(Num.logico, Nome campo [, da [, a]]) const char* FLD(const char* tabname, const char* f, int from = -1, int to = -1); struct link_item { int _logicnum; link_item* _son; link_item* _brother; int _cnt; link_item(int l) { _logicnum = l; _son = NULL; _brother = NULL; _cnt = 0; } }; class TProgind; class TPrint_application : public TApplication { TArray _rows; // rows descriptor TArray _cursors; // cursor array TCursor* _cur; // current cursor TArray _transtab; // field translation table TArray _header; // header lines TArray _footer; // footer lines int _currow; // current print row TPrintstyle _curstyle; // current print style bool _auto_ff; // automatic form feed after each page const char* _wmess; // wait message for progind bool _wbar; // bar y/n for progind bool _wcancel; // cancel button enabled int _wthr; // minimum # of items to show print progind const char* _confpr; // config filename for printer char _fillchar; // fill character for empty fields link_item* _pr_tree; // functions for autom. printing of relations int _maxrow; // reference to maxrow int _cur_file; bool _print_defined; bool _force_progind; bool _force_setpage; bool _print_zero; TProgind* _prind; const char* _picture; MENU_TAG _last_choice; int _ncopies; bool _repeat_print; bool _cancelled; // set the printer void set_printer() { printer().set(); } // print a single record; does not advance cursor // returns failure or success bool print_one(int file); // to be documented but very fig bool print_tree(link_item* head); static void _pp_header(TPrinter& pr); static void _pp_footer(TPrinter& pr); static void _pp_link(int id, const char* s); link_item* _look_print_node(link_item* head, int logicnum); void _reset_tree(link_item* head); virtual bool create(); virtual bool destroy(); protected: // **************************************************** // ISTRUZIONI PER l'USO // **************************************************** // // La Printapp, saggiamente, consente di operare su uno // o piu' cursori stampando automaticamente anche files // collegati. La sequenza delle operazioni e' la seguente: // // 1) Derivare una classe da TPrint_application // 2) Implementare user_create() e user_destroy(); // Nella user_create() si creino i // necessari cursori, e li si dia in pasto a Printapp // usando add_cursor(). Si puo' fare add_cursor(new TCursor(...)) // dato che il cursore viene distrutto automaticamente. // 3) Per ciascun file del cursore che si desidera porre // nell'albero di stampa, si faccia add_file(logicnum [,from]); // [from] sara' il file a cui e' collegato nella relazione. // add_file VA FATTA anche per il file principale, se no // non stampera' nulla; // ********************************************************* // FUNZIONI VIRTUALI OBBLIGATORIE // ********************************************************* // 4) Si definiscono le necessarie funzioni virtuali: e' // sicuramente necessaria la set_page(file) nella quale // si metteranno (sotto if o switch) le istruzioni // set_row (vedi sotto) corrispondenti alla pagina // logica relativa a ciascun record di ogni file da stampare. // Va definita anche set_print() in cui si presentera' ;a // maschera di scelta se necessaria o una box yes_no; // Ritornando TRUE da set_print la stampa viene eseguita // automaticamente (in genere ritorna FALSE se l'utente // annulla la stampa con ESC.) // // Alla set_page, come alle pre_ e post_ process, viene // passato 0 se il cursore attuale e' nullo (vedi sotto). // ********************************************************* // FUNZIONI VIRTUALI FACOLTATIVE // ********************************************************* // 5) Le varie funzioni pre_ e post_ process _page e _print // vengono chiamate prima e dopo la stampa di ogni record // o gruppo di record relativo alla relazione immessa; // ad esempio, postprocess_print() viene chiamata per il // file principale una volta dopo l'intera stampa; per // un file collegato nella relazione, e' chiamata tante // volte quanti gruppi di almeno un record esistono per // record del file genitore. Qui si possono modificare // righe, calcolare totali etc. A queste funzioni // viene sempre passato il file (logicnum) in corso di stampa e // un contatore che indica quante volte la stampa e' stata // ripetuta. le pre_ ritornano TRUE o FALSE, nell'ultimo // caso interrompono la stampa; le post_ ritornano // NEXT_PAGE (comportamento normale) o REPEAT_PAGE // (indovina cosa fa). // 6) set_print() viene chiamata dalla voce Selezione, // unica del secondo menu. E' il posto dove mettere // una buona maschera di selezione di cosa stampare. // Alla fine, si esegua enable_print_menu() per // abilitare la voce Stampa, inizialmente inattiva. // 7) cancel_hook() permette di intercettare la // cancellazione della stampa; ritornando TRUE // la stampa viene effettivamente cancellata // Tutti i parametri relativi al progress indicator // vengono settati da funzioni apposite (vedi oltre) // **************************************************** // Molte altre minchiatine (form feed automatici, header, // footer etc) sono spiegate nel seguito // **************************************************** virtual bool user_create() pure; virtual bool user_destroy() pure; // set print, bound to menu :Selezione:Stampa // chiamata automaticamente dopo user_create() virtual bool set_print(int i = 1) { return FALSE; } // set_row functions MUST be called here in a switch // for each particular file being printed virtual void set_page(int file, int cnt) {} // called before processing each page // used to set print strings from tables or files // not included in relation // returning FALSE cancels page printing // counter is the current print page number virtual bool preprocess_page(int file, int counter) { return TRUE; } // same before each print request // e.g. to initialize counters // returning FALSE cancels print request or subtree virtual bool preprocess_print(int file, int counter) { return TRUE; } // postprocessing; returning REPEAT_PAGE reprints the // whole page (after all sons are printed) or print // counter is the current page or print number virtual print_action postprocess_page(int file, int counter) { return NEXT_PAGE; } virtual print_action postprocess_print(int file, int counter) { return NEXT_PAGE; } // executed after all print job is completed virtual void postclose_print() {} // called when LINK button is pressed with active selection in // preview window virtual void process_link(int id, const char* text) {} // called when user cancels print; returning TRUE // actually stops printing; not called if no cancel virtual bool cancel_hook() {return TRUE;} // bound to TApplication print menu // redefined ONLY for very special purposes virtual void print(); // bound to <select> menu and automatically called after // user_create() void do_print(int n); public: // -------------------------------------------------------------- // COME SETTARE LE RIGHE DI STAMPA // -------------------------------------------------------------- // setrow() si usa come una printf per settare le righe di stampa // che vengono stampate da print() // I codici per gli argomenti variabili sono di 3 tipi: // @ si usa per stampare campi di database o informazioni di controllo // posizione carrello e font // ACHTUNG: i codici di formato sono diversi da quelli di printf e // sono elencati sotto. Per i campi di database occorre che il codice // sia accoppiato ad una delle funzioni FLD() passata come argomento; // questa provoca la stampa di campi della relazione corrente, // posizionata come e' stato deciso nell'inizializzazione // % si usa esattamente come in una printf con un plus: se il codice di // formato e' maiuscolo (es. S per stringa, D per intero) viene // ignorato il carattere di riempimento eventualmente specificato // con set_fillchar. Cio' vale anche per i codici @ (vedi) // E' possibile usare due codici aggiuntivi: r(R) e t(T). A questi // va fatto seguire un PUNTATORE a real o a TString. Il formato // viene interpretato con le stesse regole di %t in dsprintf per real // (come %d o %f) e di %s per TString. Il puntatore NON // viene memorizzato; per questo occorre il codice # (sotto). // # si usa come % (stessi codici di printf) ma memorizza gli argomenti // per riferimento: ovvero, ogni volta che la riga viene stampata // viene stampato il contenuto in quel momento (che si puo' cambiare // in una delle pre- o post- process). Cio' implica che: // 1) gli argomenti vanno passati per RIFERIMENTO (set_row(1,"#5d",&i)) // 2) i puntatori devono rimanere validi e costanti tra la set_row e // la fine della stampa // Quindi, attenzione a %s con TString ridimensionate; si possono // usare solo se predimensionate alla dimensione massima, ma e' meglio // usare char* o il codice apposito. I codici #r e #t prendono puntatori a // real e a TString, memorizzandoli. Non ci sono problemi con la resize. // Comunque, il modo corretto di adoperare il codice # e' // usarlo solo per stampare MEMBRI della classe derivata da TPrint_application // ---------------------------------------------- // field codes (match one of FLD() functions) // @@ -> @ // @[n[,{l|c|r}]s -> STRING: n = pad, lcr = alignment // @{[n[.d=0]]|[n[,{l|c|r}]]p}n // -> NUMBER: n = digits, d = decimals // p = picture string (first matching arg) // @[l]d -> DATE: l = full year // @f -> BOOL: prints si/no // @[n,{l|c|r}]t -> Translated field (must set translation) // // Tutti questi codici possono essere usati anche maiuscoli, il che inibisce // l'uso del carattere di riempimento (set_fillchar) per uno specifico campo. // --------------------------------------------- // Per tutti i codici che riguardano la stampa di real (@n, %r, #r) // se non vengono date ulteriori specifiche di formato viene usata // una picture che e' "" per default, ma puo' essere modificata con // set_real_picture(). Anche questo e' assai carino. // Normalmente un real uguale a zero viene stampato come stringa vuota // a meno che non si specifichi set_print_zero([TRUE]). // --------------------------------------------- // codici posizionamento e movimento carrello // @<n>g vai a posizione n // @<n>j salta di n posizioni (in orizzontale) // codici stile // @b bold // @i italic // @u underlined // @r reset to normal // --------------------------------------------------- // CODICI COLORE PER VISUALIZZAZIONE E COLLEGAMENTO // --------------------------------------------------- // Se si vuole che in visualizzazione il testo sia colorato // si usa il codice $[]; tra le quadre si scrive il colore // di foreground, opzionalmente seguito da una virgola e dal // colore di background (bianco per default). I colori si // specificano con un singolo carattere come segue: // n nero // g verde // b blu // c cyan // y giallo // v magenta // m colore background maschere (azzurrotto) // d grigio scuro // l grigio chiaro // k grigio normale // ------------------------------------------------------ // Se si fa enable_link(..) con un certo colore, tutto // cio; che e' scritto in quel colore diventa selezionabile // e alla sua selezione (premendo 'Collega') si puo' associare // un'azione in process_link. A quest'ultima viene passata // l'ID ritornata da enable_link() e il testo selezionato alla // pressione di Collega. Vedere ba6 e stampare l'elenco (con // Includi ditte abilitato) per un esempio. // -------------------------------------------------------- void reset_row(int r); // chiamare reset_print() durante la stampa forza la // rilettura di set_page() alla prossima volta void reset_print(); void set_row(int r, const char* fmt, ...); // --------------------------------------------- // set translation values for field // called once for each translation: example // set_translation(12,"STATOCIV","1","Celibe") // provoca la stampa automatica di stringhe al // posto di determinati valori dei campi se e' dato // il codice @t // Il posto giusto per chiamarla: user_create() // --------------------------------------------- void set_translation(int lognum, const char* field, const char* from, const char* to); // -------------------------------------------------------- // hypertext interface for viswin // -------------------------------------------------------- // Quando si vogliono abilitare determinati colori come // indicatori di legame ipertestuale, si faccia enable_link // nella create. L' ID ritornato viene passato a process_link // assieme al testo selezionato int find_link(const char* descr) const; int enable_link (const char* descr, char fg, char bg = 'w'); void disable_link(char fg, char bg = 'w'); void disable_links() { printer().links().destroy(); } // se si setta multiple a TRUE anziche' la descrizione del testo selezionato // viene passata a enable_link una tokenstring con tutti i 'bottoni' dello // stesso colore presenti sulla riga void set_multiple_link(bool on); // BACKGROUND PAINTING! Chefigata! poi vi spiego.... void set_background(const char* bgdesc = NULL); // --------------------------------------------- // set/select cursor // --------------------------------------------- // selects i-th cursor // inutile se c'e' un cursore solo void select_cursor(int i); // return i-th cursor without making it current TCursor* get_cursor(int i); // returns maximum row defined int get_maxrow() { return _maxrow; } // adds cursor to class; return identifier // cursor* can be NULL: no file is used but // print_one is called and iterations are performed // by pre_ and post_ process int add_cursor(TCursor* c); // retrieve current cursor TCursor* current_cursor() { return _cur; } // --------------------------------------------- // set_auto_ff(TRUE) fa si' che dopo ogni pagina logica (relativa ad // un record) si stampi un form feed. (anche se il cursore e' nullo) void set_auto_ff( bool b = TRUE) { _auto_ff = b; } // il carattere specificato con set_fillchar (default ' ') viene // usato per riempire davanti e dietro i campi in cui si e' specificata // una dimensione maggiore della lunghezza effettiva del contenuto, // (a meno che non si sia usato un codice di formato maiuscolo) void set_fillchar(char c) { _fillchar = c; } // riempie di righe vuote la pagina corrente fino alla dimensione // della pagina void fill_page(int from = -1); // di solito basta e avanza quella di default virtual bool menu(MENU_TAG m); virtual word class_id() const { return CLASS_PRINT_APPLICATION; } // print menu is enabled when set_print returns TRUE void enable_print_menu(); void disable_print_menu(); void enable_setprint_menu(); void disable_setprint_menu(); // header/footer (printf, not set_row analogues) // only understand @-codes for setting font attributes, // date and page number // plus every printf %-code // con queste si possono ridefinire header e footer al // verificarsi di condizioni durante la stampa virtual void preprocess_header() {} virtual void preprocess_footer() {} void set_header(int row, const char* fmt, ...); void set_footer(int row, const char* fmt, ...); void reset_header(); void reset_footer(); // vedi sopra per capire void reset_files(); void add_file(int file, int from = 0); void add_file(const char* tab, int from = 0); // set default picture for reals void set_real_picture(const char* p) { _picture = p; } void set_print_zero(bool b = TRUE) { _print_zero = b; } // progress indicator control void set_wait_message(const char* m) { _wmess = m; } void set_wait_bar(bool m) // default yes { _wbar = m; } void set_wait_cancel(bool m) // default yes { _wcancel = m; } void set_wait_threshold(int m) // minimum number of print items to show progress indicator; // default 2 { _wthr = m; } // questa forza la progind anche se si stampa su video void force_progind(bool b = TRUE) { _force_progind = b; } // questa forza la rilettura delle setrow in set_page ad ogni // record stampato, in modo che i dati siano // sempre quelli del record corrente anche se si usano codici % // s'intende che rallenta un po' la stampa void force_setpage(bool b = TRUE) { _force_setpage = b; } void set_config_file(const char* s) { _confpr = s; } word get_page_number() { return printer().getcurrentpage(); } void set_page_number(word n) { printer().setcurrentpage(n); } // dirige la stampa sul file specificato, preservando gli attributi di formato // se header == TRUE si stampano su file anche gli header void set_export_file(const char* name, bool header = TRUE) { printer().set_export_file(name,header); } // infila un file di export fatto da un'altra printer (con formati e tutto, ignora // gli header supponendo che siano gia' presenti nel file) // se header == TRUE gli header stanno nel file e non vengono stampati // se direct == FALSE le rigne vengono aggiunte con set_row da printapp, altrimenti // si usa printer::merge_export_file void merge_export_file(const char* file, bool header = TRUE, bool direct = FALSE); void set_n_copies(int n) { _ncopies = n; } int get_n_copies() const { return _ncopies; } void repeat_print() { _repeat_print = TRUE; } bool is_cancelled() const { return _cancelled; } TPrint_application(); virtual ~TPrint_application(); }; // buon divertimento #endif