//#include //#include //#include #include #include #include #include #include const char* const printf_types = "dDiIuUoOxXfeEgGcCnNsSpPrRtTaAvV"; // _FieldTok flags const word LONG_FLAG = 0x0001; const word PICTURE_FLAG = 0x0002; const word PAD_FLAG = 0x0004; const word ALIGN_FLAG = 0x0008; const word TRANS_FLAG = 0x0010; const word DATE_FLAG = 0x0020; const word STRING_FLAG = 0x0040; const word NUMBER_FLAG = 0x0080; const word DEC_FLAG = 0x0100; const word FONT_FLAG = 0x0200; const word JUMP_FLAG = 0x0400; const word RECNO_FLAG = 0x0800; const word BOOLEAN_FLAG = 0x1000; const word IGNORE_FILL = 0x2000; const word VALUTA_FLAG = 0x4000; /////////////////////////////////////////////////////////// // print token containers /////////////////////////////////////////////////////////// class _Transfield : public TObject { friend class TPrint_application; int _lognum; // logical number TString16 _fn; TString _from, _to; public: _Transfield (int l, const char *fn, const char *from, const char *to) : _lognum(l), _fn(fn), _from (from), _to (to) { } virtual ~_Transfield() { } }; class _Token : public TObject { friend class TPrint_application; int _tag; int _row; public: int tag() const { return _tag; } int row() const { return _row; } void tag(int t) { _tag = t; } void row (int r) { _row = r; } virtual ~ _Token () {} }; class _PrintfTok : public _Token // something to be printed (actually already printed on _val) { friend class TPrint_application; TString _val; public: _PrintfTok (int rw, const char *val) : _val(val) { tag(0); row(rw); } virtual ~_PrintfTok () {} }; class _FieldTok : public _Token // something more complex to be printed { friend class TPrint_application; int _size, _dec; char _align; TString80 _fld; // field description word _flags; // all you need to know public: _FieldTok (int rw, const char *fld, word flags, char align = 'l', int size = -1, int dec = -1) { tag(1); row(rw); _fld = fld; _flags = flags; _size = size; _align = align; _dec = dec; } virtual ~_FieldTok () { } }; class _PrintfRef : public _Token // to be printed by reference via format // must pass valid pointer to object { friend class TPrint_application; void *_what; char _type; TString _fmt; public: _PrintfRef (int rw, const char *fmt, char type, void *what):_fmt (1) { tag (2); row (rw); _type = type; _what = what; _fmt = fmt; _fmt[0] = '%'; } virtual ~ _PrintfRef () {} }; class _PrintRowToken : public _Token // printrow direct // must pass valid printrow (duplicated) { friend class TPrint_application; TPrintrow _pr; public: TPrintrow& printrow() { return _pr; } _PrintRowToken (int rw, TPrintrow& pr) : _pr((const TPrintrow&)pr) { tag(3); row(rw); } virtual ~ _PrintRowToken () {} }; void TPrint_application::_reset_tree(link_item * head) { if (head) { if (head->_brother) _reset_tree (head->_brother); if (head->_son) _reset_tree (head->_son); delete head; } } // @doc INTERNAL // @mfunc Cerca per il nodo

dove agganciarsi per rispettare la relazione // // @rdesc Ritorna il nodo a cui agganciarsi link_item *TPrint_application::_look_print_node ( link_item * head, // @parm Nodo per cui effettuare la ricerca int logicnum) // @parm Numero logico del file // @comm E' necessario che non esistano piu' nodi per lo stesso file/alias, altrimenti la // la ricerca termina alla proma occorrenza incontrata { link_item *s; while (head) { if (head->_logicnum == logicnum) return head; else if (head->_son) if ((s = _look_print_node (head->_son, logicnum)) != NULL) return s; head = head->_brother; } return NULL; } // @doc EXTERNAL // @mfunc Setta un segnalibro nell'anteprima di stampa // // @rdesc Ritorna il numero identificatore il segnalibro creato int TPrint_application::set_bookmark( const char* txt, // @parm Testo del segnalibro int father) // @parm Identificatore del segnalibro padre (default -1) // @comm L'aggiunta dei segnalibri causa la comparsa del menu 'Indice' nella viswin, // con la lista dei segnalibri inseriti; questi possono essere legati ad albero n-ario // specificando il bookmark padre, in tal caso il menu sara' gerarchico a sua volta. // Nella prossima release di XVT il menu indice sara' pop-up nella finestra { return printer().set_bookmark(txt, father); } void TPrint_application::add_file (const char *tab, int from) { add_file(TTable::name2log(tab), from); } // @doc EXTERNAL // @mfunc Aggiunge un file del cursore nell'albero di stampa void TPrint_application::add_file ( int file, // @parm Numero logico del file da aggiungere int from) // @parm Posizione nell'albero di stampa nel quale aggiungere il file // @parm const char* | tab | Nome del del file da aggiungere // @syntax add_file(int file, int from = 0); // @syntax add_file(const char* tab, int from = 0); { link_item *nw = new link_item (file); if (_pr_tree == NULL) { _pr_tree = nw; return; } if (from == 0) from = _pr_tree->_logicnum; link_item *fr = _look_print_node (_pr_tree, from); CHECKD (fr, "add_file: nonexistent node: logicnum = ", from); if (fr->_son) { fr = fr->_son; while (fr->_brother) fr = fr->_brother; fr->_brother = nw; } else fr->_son = nw; } // --------------------------------------------------------------- // ------------ user function ------------------------------------ static char tb[120]; // @doc EXTERNAL // @mfunc Permette di trovare un link ipertestuale // // @rdesc Ritorna l'ID del link ipertestuale trovato (-1 se non viene trovato) int TPrint_application::find_link( const char* descr) const // @parm Testo del link da trovare // @xref { const TArray& arr = printer().links(); for (int i = 0; i < arr.items(); i++) { TToken_string& tt = (TToken_string&)arr[i]; const TFixed_string d(tt.get(0)); if (d == descr) return i; } return -1; } // @doc EXTERNAL // @mfunc Permette di abilitare determinati colori come indicatori di legame ipertestuale // // @rdesc Ritorna l'ID del link ipertestuale di cui sono stati abilitati i colori int TPrint_application::enable_link( const char *descr, // @parm Testo del link da abilitare char fg, // @parm Colore del carattere char bg) // @parm Colore dello sfondo (default 'w') // @comm 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 lnk = find_link(descr); if (lnk < 0) { TToken_string *tt = new TToken_string(30); char b[2] = { '\0', '\0' }; tt->add(descr); b[0] = fg; tt->add(b); b[0] = bg; tt->add(b); lnk = printer().links().add(tt); } return lnk; } void TPrint_application::disable_link (char fg, char bg) { for (int i = 0; i < printer().links().items (); i++) { TToken_string & t = (TToken_string&)printer().links()[i]; const char f = *(t.get(1)); const char b = *(t.get()); if (f == fg && b == bg) { printer().links().remove(i, TRUE); break; } } } // @doc EXTERNAL // @mfunc Abilita/disabilita pił link per la void TPrint_application::set_multiple_link ( bool on) // @parm Indica se effettuare il link con tutti gli elementi selezioanti della riga // @comm Se si setta

a TRUE anziche' la descrizione del testo selezionato // viene passata a una tokenstring con tutti i // 'bottoni' dello stesso colore presenti sulla riga. { printer().setmultiplelink (on); } bool TPrint_application::_pp_link (int id, const char *text) { TPrint_application& prapp = (TPrint_application&)main_app(); return prapp.process_link(id, text); } void TPrint_application::_pp_header (TPrinter& p) { TPrint_application& prapp = (TPrint_application&)main_app(); prapp.preprocess_header(); p.resetheader(); const int ii = prapp._header.last(); // reset and add header/footer lines for (int i = 0; i <= ii; i++) { TPrintrow* pr = (TPrintrow*)prapp._header.objptr(i); if (pr) p.setheaderline (i, new TPrintrow(*pr)); } } void TPrint_application::_pp_footer (TPrinter& p) { TPrint_application& prapp = (TPrint_application&)main_app(); prapp.preprocess_footer (); p.resetfooter (); int ii = prapp._footer.last(); for (int i = 0; i <= ii; i++) { TPrintrow* pr = (TPrintrow*)prapp._footer.objptr(i); if (pr) p.setfooterline (i, new TPrintrow(*pr)); } } // @doc EXTERNAL // @mfunc Permette di stampare sullo sfondo e per variarne gli attributi void TPrint_application::set_background ( const char *bgdesc) // @parm Stringa contente i codici per la stampa (vedi descrizione) // @comm Occorre passare una stringa che contiene codici per stampare box, linee, bitmap // sullo sfondo, e per variarne gli attributi: se NULL lo azzera. // Il background e' stampato sia su che su stampante, e riguarda // una PAGINA fisica e non le righe o le "pages" relative al cursore; // viene replicato ad ogni nuova pagina fisica a meno che non venga cancellato // o ridefinito in una qualcosaprocessqualcos'altro(). // CODICI BACKGROUND // Una stringa con n codici, opzionalmente separati da spazi o tab // SETTINGS // @flag Pn | Setta pen style (n = codice XVT) // @flag Bn | Setta brush style (idem) // @flag Wn | Altezza della linea in pixel // @flag Cn | Colore della penna (codice colore solito) // @comm DRAWING COMMANDS // @flag i{string,x1,y1,x2,y2} | Disegna la bitmap

(nome file) alle coordinate indicate // @flag l{x1,y1,x2,y2} | Linea da/a (la resa delle oblique dipende dalla stampante) // @flag b{x1,y1,x2,y2} | Box // @flag r{x1,y1,x2,y2} | Rounded box // @flag t{text,x,y} | Testo text a

,

{ printer().setbackground (bgdesc); } const char* FLD (int lognum, const char *f, int from, int to) { sprintf (tb, "%c|%d|%s|%d|%d", 'n', lognum, f, from, to); char *p = new char[strlen (tb) + 1]; strcpy (p, tb); return p; } const char* FLD (int lognum, const char *f, const char *picture) { sprintf (tb, "%c|%d|%s|%s", 'p', lognum, f, picture); char *p = new char[strlen (tb) + 1]; strcpy (p, tb); return p; } const char* FLD (const char *tabname, const char *f, int from, int to) { CHECKS (strlen (tabname) < 5, "Invalid table name", tabname); int lognum = TTable ::name2log (tabname); sprintf (tb, "%c|%d|%s|%d|%d", 'n', lognum, f, from, to); char *p = new char[strlen (tb) + 1]; strcpy (p, tb); return p; } const char* FLD (const char *tabname, const char *f, const char *picture) { CHECKS (strlen (tabname) < 5, "Invalid table name", tabname); int lognum = TTable ::name2log (tabname); sprintf (tb, "%c|%d|%s|%s", 'p', lognum, f, picture); char *p = new char[strlen (tb) + 1]; strcpy (p, tb); return p; } TString& fill_str (TString & t, char f) { const int len = t.len(); int kk; for (kk = len - 1; kk >= 0; kk--) if (t[kk] == ' ') t[kk] = f; else break; for (kk = 0; kk < len; kk++) if (t[kk] == ' ') t[kk] = f; else break; return t; } /////////////////////////////////////////////////////////// // Printapp code at last /////////////////////////////////////////////////////////// void TPrint_application::select_cursor (int c) { if (c < 0) _cur = NULL; else _cur = (TCursor *) & _cursors[c]; } TCursor* TPrint_application::get_cursor (int c) { if (c < 0) return NULL; else return (TCursor *) & _cursors[c]; } // @doc EXTERNAL // @mfunc Aggiunge un cursore alla classe // // @rdesc Ritorna l'identificatore del cursore aggiunto int TPrint_application::add_cursor ( TCursor * c) // @parm Cursore da aggiungere all'albero // @comm Nel caso sia passato NULL a

non viene utilizzato nessun file, ma la // viene chaiamta e le iterazione sono valoutate da // pre_ e post_ process. { if (c == NULL) return -1; _cursors.add (c); _cur = c; return _cursors.items() - 1; } void TPrint_application::reset_row (int r) { r--; int tmp = _rows.items (); for (int j = 0; j < tmp; j++) { _Token *t = (_Token *) (_rows.objptr (j)); if (t) { if (t->row () == r) _rows.add (NULL, j); } } _rows.pack (); if (_maxrow == r && _maxrow > 0) _maxrow--; } void TPrint_application::reset_print () { _rows.destroy (); _maxrow = 0; _print_defined = FALSE; } // @doc EXTERNAL // @mfunc Permette di definire l'header della stampa void TPrint_application::set_header ( int r, // @parm Numero della riga nella quale stampare l'header const char *fmt, // @parm Testo dell'header da stampare ...) // @parmvar Uno o piu' parametri corrispondenti ai codici in

{ TString256 tmp; CHECK (r >= 1, "Header rows start at 1"); va_list vl; va_start (vl, fmt); vsprintf (tmp.get_buffer(), fmt, vl); va_end (vl); TPrintrow *pp = (TPrintrow *)_header.objptr(r - 1); if (!pp) { pp = new TPrintrow; _header.add (pp, r - 1); } pp->put (tmp); } // @doc EXTERNAL // @mfunc Permette di definire il footer della stampa void TPrint_application::set_footer ( int r, // @parm Numero della riga nella quale stampare il footer const char *fmt, // @parm Testo del footer da stampare ...) // @parmvar Uno o piu' parametri corrispondenti ai codici in

{ CHECK (r >= 1, "Footer rows start at 1"); TString256 tmp; va_list vl; va_start (vl, fmt); vsprintf (tmp.get_buffer(), fmt, vl); va_end (vl); TPrintrow *pp = (TPrintrow *) _footer.objptr (r - 1); if (pp == NULL) { pp = new TPrintrow; _footer.add (pp, r - 1); } pp->put (tmp); } void TPrint_application::reset_header () { _header.destroy (); printer().resetheader (); } void TPrint_application::reset_footer () { _footer.destroy (); printer().resetfooter (); } void TPrint_application::fill_page (int from) { from--; for (int i = (from == -1 ? _maxrow : from); i <= printer().formlen (); i++) { reset_row (i); set_row (i, ""); } } void TPrint_application::merge_export_file(const char* file, bool header, bool direct) { if (direct) printer().merge_export_file(file, header); else { set_row(_currow+1,""); TTextfile txt(file); for (long i = 0l; i < txt.lines(); i++) set_row(_currow+(int)i+1 + (i == 0l ? 1 : 0), txt.line_formatted(i)); } } void TPrint_application::set_row(int r, TPrintrow& pr) { CHECK (r >= 1, "Print rows start at 1"); _print_defined = TRUE; _currow = --r; if (_currow > _maxrow) _maxrow = _currow; _rows.add(new _PrintRowToken(_currow, pr)); } // @doc EXTERNAL // @mfunc Permette di settare una riga di stampa void TPrint_application::set_row ( int r, // @parm Numero della riga da settare const char *frmt, // @parm Contenuto della riga da stampare ...) // @parmvar Uno o piu' parametri corrispondenti ai codici in

// @comm COME SETTARE LE RIGHE DI STAMPA // Questa funzione si usa come una printf per settare le righe di stampa // che vengono stampate da . // I codici per gli argomenti variabili sono di 3 tipi: // @flag @ | Si usa per stampare campi di database o informazioni di controllo // posizione carrello e font // ATTENZIONE: 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 passata come argomento; // questa provoca la stampa di campi della relazione corrente, // posizionata come e' stato deciso nell'inizializzazione // @flag % | 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 . 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 o a . 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). // @flag # | 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 ridimensionate; si possono // usare solo se predimensionate alla dimensione massima, ma e' meglio // usare char* o il codice apposito. I codici #r, #a e #t prendono puntatori a // real, e a , 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 // // @comm CODICI DI CAMPO (da utilizzare con una delle funzione ): // @flag @@ | Carattere @ // @flag @[n[,{lcr}]s | STRING: n = pad, lcr = alignment // @flag @{[n[.d=0]][n[,{lcr}]]p}n | NUMBER: n = digits, d = decimals // p = picture string (first matching arg) // @flag @[l]d | DATE: l = full year // @flag @f | BOOL: prints si/no // @flag @[n,{lcr}]t | Translated field (must set translation) // // @comm 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 (@n, %r, #r) // se non vengono date ulteriori specifiche di formato viene usata // una picture che e' "" per default, ma puo' essere modificata con // . // Normalmente un real uguale a zero viene stampato come stringa vuota // a meno che non si specifichi TRUE nella . // // CODICI POSIZIONAMENTO E MOVIMENTO CARRELLO // @flag @ng | Vai a posizione n // @flag @nj | Salta di n posizioni (in orizzontale) // @comm CODICI STILE // @flag @b | Grassetto // @flag @i | Corsivo // @flag @u | Sottolineato // @flag @r | Ritorna allo stile normale // // @comm 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: // @flag n | Nero // @flag g | Verde // @flag b | Blu // @flag c | Cyan // @flag y | Giallo // @flag v | Magenta // @flag m | Colore background maschere (azzurrotto) // @flag d | Grigio scuro // @flag l | Grigio chiaro // @flag k | Grigio normale // // @comm Se si fa 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 . 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. { CHECK (r >= 1, "Print rows start at 1"); r--; char digbuf[10]; TString bigbuf(256); char* strbuf = bigbuf.get_buffer(); TString fftt(256); char *fmt = fftt.get_buffer(); char fill = _fillchar; word flags = 0; int size = 0, dec = 0, strind = 0; char ch, align = 'l'; // let the poor programmer use format() at will strcpy (fmt, frmt); _print_defined = TRUE; _currow = r; if (_currow > _maxrow) _maxrow = _currow; va_list params; va_start(params, frmt); // parse format string while ((ch = *fmt++) != '\0') { if (ch == '@') { // check for pending string if (strind) { strbuf[strind] = '\0'; _rows.add (new _PrintfTok (_currow, strbuf)); strind = 0; } ch = *fmt++; if (isdigit (ch)) { int i = 0; digbuf[i++] = ch; while (isdigit (ch = *fmt++)) digbuf[i++] = ch; digbuf[i] = '\0'; size = atoi (digbuf); flags |= PAD_FLAG; if (ch == '.') { // decimal size follows i = 0; digbuf[i++] = ch; while (isdigit (ch = *fmt++)) digbuf[i] = ch; digbuf[i] = '\0'; dec = atoi (digbuf); flags |= DEC_FLAG; } else if (ch == ',') { // aligment spec follows align = (ch = *fmt++); CHECK (ch == 'l' || ch == 'r' || ch == 'c', "TPrint_application::set_row: invalid alignment spec"); flags |= ALIGN_FLAG; ch = *fmt++; } } switch (ch) { // modifiers case 'l': case 'L': flags |= LONG_FLAG; ch = *fmt++; break; case 'p': case 'P': flags |= PICTURE_FLAG; ch = *fmt++; break; } switch (ch) { // codes case '@': _rows.add (new _PrintfTok (_currow, "@")); break; case 'b': case 'i': case 'u': case 'r': { char x[2] = { ch, '\0' }; _rows.add (new _FieldTok (_currow, x, FONT_FLAG)); } break; case 'g': case 'j': { const char* x = format ("%c %d", ch, size); _rows.add (new _FieldTok (_currow, x, JUMP_FLAG)); } break; case 'T': flags |= IGNORE_FILL; // fall down case 't': flags |= TRANS_FLAG; break; case 'D': flags |= IGNORE_FILL; // fall down case 'd': flags |= DATE_FLAG; break; case 'F': flags |= IGNORE_FILL; // fall down case 'f': flags |= BOOLEAN_FLAG; break; case 'S': flags |= IGNORE_FILL; // fall down case 's': flags |= STRING_FLAG; break; case 'C': flags |= IGNORE_FILL; // fall down case 'c': flags |= RECNO_FLAG; break; case 'N': flags |= IGNORE_FILL; // fall down case 'n': if (_magic_currency) { if (size >= 9 && dec == 0 && _picture.find(',') < 0) { flags |= VALUTA_FLAG; flags &= ~PAD_FLAG; } else flags |= NUMBER_FLAG; } else flags |= NUMBER_FLAG; break; case 'V': flags |= IGNORE_FILL; // fall down case 'v': flags |= VALUTA_FLAG; flags &= ~PAD_FLAG; break; default: CHECK (0, "TPrint_application::set_row: invalid @ code"); break; } if (flags & NUMBER_FLAG || flags & DATE_FLAG || flags & TRANS_FLAG || flags & BOOLEAN_FLAG || flags & STRING_FLAG || flags & VALUTA_FLAG) { char* x = va_arg (params, char *); _rows.add (new _FieldTok (_currow, x, flags, align, size, dec)); delete x; // FLD macro has mallocated it! } flags = 0x0000; align = 'l'; } else { switch (ch) { case '#': case '%': { const char ccc = ch; // check for pending string if (strind) { strbuf[strind] = '\0'; _rows.add (new _PrintfTok (_currow, strbuf)); strind = 0; } if ((ch = *fmt++) == ccc) _rows.add (new _PrintfTok (_currow, ccc == '%' ? "%" : "#")); else { // read format TString80 formato; formato << ccc; bool islong = FALSE; while (strchr (printf_types, ch) == NULL) { formato << ch; if (ch == 'l') islong = TRUE; ch = *fmt++; if (ch == '\0') NFCHECK("sorry, zer's samzing vruong uitz ioar format."); } if (isupper (ch)) { ch = tolower (ch); fill = ' '; } if (ch == 't' || ch == 'a') formato << 's'; else if (ch == 'r') #ifdef __LONGDOUBLE__ formato << "Lf"; #else formato << 't'; #endif else formato << ch; if (ccc == '%') { TString256 q; switch (ch) { case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': q.format (formato, islong ? va_arg (params, long) : va_arg (params, int)); break; case 'f': case 'e': case 'E': case 'G': #ifdef WIN32 q.format (formato, islong ? va_arg (params, double) : va_arg (params, float)); #else q.format (formato, va_arg (params, double)); #endif break; case 'c': #ifdef WIN32 q.format (formato, va_arg (params, char)); #else q.format (formato, va_arg (params, int)); #endif break; case 's': q.format (formato, va_arg (params, char *)); break; case 't': // TString q.format(formato,(const char*)(TString)*((va_arg (params, TString*)))); break; case 'a': // TParagraph_string q.format(formato,(const char*)(TParagraph_string)*((va_arg (params, TParagraph_string*)))); break; case 'r': // Real { const real& rrr = * va_arg (params, real *); if (_picture.not_empty() && (formato.len() == 2 || formato == "%Lf")) { // no format specifications // use default picture q.cut(0); if (_magic_currency) { if (_picture == "." || (_picture.len() >= 9 && _picture.find(',') < 0)) real2currency(q, rrr); } if (q.empty()) q = rrr.string(_picture); } else { #ifdef __LONGDOUBLE__ sprintf (q.get_buffer(), formato, (long double)rrr); #else q = rrr.format(formato); #endif } if (rrr.is_zero () && !_print_zero) q.fill (' ', q.len()); } break; case 'v': // Currency { const TCurrency& cur = *va_arg(params, TCurrency*); if (cur.get_num().is_zero() && !_print_zero) q.cut(0); else q = cur.string(_picture.find('.') >= 0); const int width = atoi(formato.mid(1,-1)); if (width > 0) q.right_just(width); } break; default: break; } if (fill != ' ') q = fill_str (q, fill); fill = _fillchar; _rows.add (new _PrintfTok (_currow, q)); } else _rows.add (new _PrintfRef (_currow, formato, ch, va_arg (params, void *))); } } break; case '\n': // ignore break; default: // add to string strbuf[strind++] = ch; if (!ch) fmt--; break; } } } if (strind) { strbuf[strind] = '\0'; _rows.add(new _PrintfTok(_currow, strbuf)); strind = 0; } va_end (params); } // @doc EXTERNAL // @mfunc Setta i valori di traduzione dei campi void TPrint_application::set_translation ( int lognum, // @parm Numero logido del file condenete il campo da tradurre const char *field, // @parm Campo di cui effettuare la straduzione const char *from, // @parm Valore da tradurre const char *to) // @parm Valore che assume il campo // @comm Questa funzione occorre che sia chiamata per ogni traduzione da effettuare. // Esempio: 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 e' nella . { _transtab.add (new _Transfield (lognum, field, from, to)); } void TPrint_application::print() { _cancelled = FALSE; _print_defined = FALSE; // open printer if needed if (!(printer().isopen ())) if (!printer().open ()) return; // only external apps can change it _repeat_print = FALSE; // NULL cursor passed only prints once // pre and post process do everything if (_cur == NULL) { //************************************************ int cnt = 0; bool ok = TRUE; do { if (preprocess_print (0, cnt)) { int cnt2 = 0; do { if (preprocess_page (0, cnt2)) { set_page (0, cnt2); ok = print_one (0); } } while (ok && postprocess_page (0, cnt2++) == REPEAT_PAGE); } } while (ok && postprocess_print (0, cnt++) == REPEAT_PAGE); // ***************************************************** } else { // cursor exists ********************************************* (*_cur) = 0l; _cur->freeze (TRUE); if (_cur->items () >= _wthr && (_force_progind || printer ().printtype () != screenvis)) _prind = new TProgind (_cur->items (), _wmess, _wcancel, _wbar, 35); print_tree (_pr_tree); _cur->freeze (FALSE); if (_prind) { delete _prind; _prind = NULL; } // **************************************************************** } if (!_repeat_print) { if (printer().isopen ()) { printer().close(); printer().resetheader(); printer().resetfooter(); } postclose_print (); } else printer().formfeed(); } bool TPrint_application::print_tree (link_item * head) { bool go = TRUE; while (head) { head->_cnt = 0; if (_cur->is_first_match (head->_logicnum)) { do { if (!preprocess_print (head->_logicnum, head->_cnt)) break; do { // set print rows according to current file if (_force_setpage || _cur_file != head->_logicnum || !_print_defined) { reset_print (); set_page(head->_logicnum, head->_cnt); _cur_file = head->_logicnum; } int cnt2 = 0; do { if (!preprocess_page (head->_logicnum, cnt2)) break; go = print_one (head->_logicnum); if (go && head->_son) go = print_tree (head->_son); } while (go && postprocess_page (head->_logicnum, cnt2++) == REPEAT_PAGE); } while (go && _cur->next_match (head->_logicnum)); } while (go && postprocess_print (head->_logicnum, head->_cnt++) == REPEAT_PAGE); } if (!go) break; go = TRUE; head = head->_brother; } return go; } void TPrint_application::real2currency(TString& s, const real& r, const char* p) const { const TFixed_string pic = (p && *p) ? p : (const char *) _picture; if (!r.is_zero() || _print_zero) { TCurrency c(r); if (_curr_codval.not_empty()) c.change_value(_curr_codval); const bool dotted = pic.empty() || pic.find('.') >= 0; s = c.string(dotted); } else s.cut(0); const int len = pic.len(); if (len >= 9) s.right_just(len); } HIDDEN void raddoppia_chiocciole(TString& toprint) { for (int i = toprint.len()-1; i >= 0; i--) { if (toprint[i] == '@') toprint.insert("@", i); } } // @doc INTERNAL // @mfunc Stampa un singolo record // // @rdesc Ritorna il risultato dell'operazione: // // @flag TRUE | Se e' riuscito a stampare il record // @flag FALSE | Se la stampa non ha avuto successo bool TPrint_application::print_one ( int file) // @parm Numero logico del file di cui stampare il record // @comm Dopo la stampa del record non viene spostato in avanti il cursore { int i = 0; TPrinter& prn = printer(); if ((_prind && _prind->iscancelled()) || prn.frozen()) if (_cancelled = cancel_hook()) return FALSE; if (!_print_defined) return TRUE; if (_prind && file == _pr_tree->_logicnum) _prind->addstatus (1); TArray rw(_maxrow + 1); int *pos = new int[_maxrow + 1]; for (i = 0; i <= _maxrow; i++) { rw.add(new TPrintrow()); pos[i] = -1; } // printing workhorse for (i = 0; i <= _maxrow; i++) for (int j = 0; j < _rows.items (); j++) { _Token* t = (_Token*)&(_rows[j]); if (!t) continue; // should not happen if (t->row() == i) { char pic[36], fn[17]; int ch, ln, from, to; if (t->tag() == 3) { _PrintRowToken* r = (_PrintRowToken*)t; rw.add(r->printrow(), r->row()); } else if (t->tag () == 1) { // it's a _FieldTok _FieldTok *ft = (_FieldTok *) t; TString256 toprint; from = to = -1; if (ft->_flags & FONT_FLAG) { TPrintstyle st = normalstyle; switch (ft->_fld[0]) { case 'u': st = underlinedstyle; break; case 'b': st = boldstyle; break; case 'i': st = italicstyle; break; case 'r': st = normalstyle; break; } ((TPrintrow *)(&rw[ft->row()]))->set_style (st); } else if (ft->_flags & JUMP_FLAG) { char ch; int p; ch = ft->_fld[0]; p = atoi (((const char *) ft->_fld) + 2); if (ch == 'g') // go to pos[ft->row ()] = p; else // jump ahead pos[ft->row ()] = ((TPrintrow *) (&rw[ft->row ()]))->lastpos () + p; } else { if (ft->_fld[0] == 'p') { // picture TToken_string ttt (ft->_fld, '|'); ch = (ttt.get ())[0]; ln = atoi ((const char *) ttt.get ()); strcpy (fn, (const char *) ttt.get ()); strcpy (pic, (const char *) ttt.get ()); } else { TToken_string ttt (ft->_fld, '|'); ch = (ttt.get ())[0]; ln = atoi ((const char *) ttt.get ()); strcpy (fn, (const char *) ttt.get ()); from = atoi ((const char *) ttt.get ()); to = atoi ((const char *) ttt.get ()); } // get field val TLocalisamfile &f = _cur->file(ln); if (ft->_flags & TRANS_FLAG) { _Transfield *tr = NULL; // look up field value in translation table int i; for (i = 0; i < _transtab.items (); i++) { tr = (_Transfield *) & _transtab[i]; if (tr->_fn == fn && tr->_lognum == ln) { // check value if (tr->_from == f.get(fn).sub(from<0 ? 0 : from,to)) break; } } if (i == _transtab.items()) toprint = ""; else toprint = tr->_to; } else if (ft->_flags & DATE_FLAG) { const TDate d(f.get(fn)); toprint = d.string (ft->_flags & LONG_FLAG ? full : brief); if (toprint.empty ()) { toprint = (ft->_flags & LONG_FLAG ? " - - " : " - - "); } } else if (ft->_flags & BOOLEAN_FLAG) { toprint = f.get(fn) == "X" ? "Si" : "No"; } else if (ft->_flags & NUMBER_FLAG) { TString80 pict; real r(f.get (fn)); bool isreal = f.curr ().type (fn) == _realfld; if (ft->_flags & PICTURE_FLAG) pict = pic; else if (!(ft->_flags & DEC_FLAG) && *_picture && isreal) pict = _picture; if (pict.len () > 0) toprint = r.string (pict); else if (ft->_flags & DEC_FLAG) toprint = r.string (ft->_size, ft->_dec); else toprint = r.string (); if (r.is_zero () && !_print_zero) toprint.fill (' ', toprint.len()); } else if (ft->_flags & STRING_FLAG) { toprint = f.curr().get (fn); // perform string extraction if (from != -1) toprint = toprint.sub (from, to); else if (to != -1) toprint = toprint.left (to); if (toprint.find('@') >= 0) raddoppia_chiocciole(toprint); } else if (ft->_flags & VALUTA_FLAG) { const real n(f.get(fn)); real2currency(toprint, n); } } // adjust size and set fill char if (ft->_flags & PAD_FLAG) { if (!(ft->_flags & NUMBER_FLAG)) { if (ft->_size < toprint.len ()) toprint.cut (ft->_size); else toprint.left_just (ft->_size); } if (ft->_flags & ALIGN_FLAG) { if (ft->_align == 'r') toprint.right_just (ft->_size); else if (ft->_align == 'c') toprint.center_just (ft->_size); else if (ft->_align == 'l') toprint.left_just (ft->_size); } } if (_fillchar != ' ' && !(ft->_flags & IGNORE_FILL)) toprint = fill_str (toprint, _fillchar); // add to print row ((TPrintrow *)(&rw[ft->row()]))->put (toprint, pos[ft->row ()]); if (pos[ft->row()] != -1) pos[ft->row ()] += toprint.len (); } else if (t->tag () == 0) { // it's a _PrintfTok _PrintfTok *pt = (_PrintfTok *) t; TString v = pt->_val; ((TPrintrow *) (&rw[pt->row ()]))->put (v, pos[pt->row ()]); if (pos[pt->row ()] != -1) { pos[pt->row ()] += v.len (); const char* s = v; while (*s && strncmp(s, "$[", 2) == 0) { while (*s && *s != ']') { pos[pt->row()]--; s++; } if (*s) pos[pt->row()]--; while (*s && *s != '$') s++; } } } else if (t->tag () == 2) { // printf by reference _PrintfRef *pr = (_PrintfRef *) t; TString ps; TParagraph_string * para_str = NULL; bool islong = (pr->_fmt).find ('l') != -1; switch (pr->_type) { case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': ps.format (pr->_fmt, islong ? *((long *) (pr->_what)) : *((int *) (pr->_what))); break; case 'f': case 'e': ps.format (pr->_fmt, islong ? *((double *) (pr->_what)) : *((float *) (pr->_what))); break; case 'c': ps.format (pr->_fmt, *((char *) (pr->_what))); break; case 's': ps.format (pr->_fmt, (char *) (pr->_what)); break; case 't': ps.format (pr->_fmt, (const char *) (*((TString *) (pr->_what)))); break; case 'a': { para_str = ((TParagraph_string *) (pr->_what)); const char * s = para_str->get(); if (s != NULL) ps.format (pr->_fmt, s); break; } case 'r': { const real& rrr = *(real*)pr->_what; const char* fff = pr->_fmt; if (*_picture && (strlen(fff) == 2 || strcmp(fff, "%Lf") == 0)) { if (_magic_currency && _picture == "." || (_picture.len() >= 9 && _picture.find(',') < 0)) real2currency(ps, rrr); else ps = rrr.string(_picture); } else { #ifdef __LONGDOUBLE__ sprintf(ps.get_buffer(), fff, (long double)rrr); #else ps = rrr.format(fff); #endif } if (rrr.is_zero () && !_print_zero) ps.fill (' ', ps.len()); } break; default: break; } ps = fill_str (ps, _fillchar); ((TPrintrow *) (&rw[pr->row ()]))->put (ps, pos[pr->row ()]); if (para_str != NULL) { const char * s = para_str->get(); int row = pr->row(); TPrintstyle xstyle = ((TPrintrow *)(&rw[row]))->get_style(); while (s != NULL) { ps.format (pr->_fmt, s); ps = fill_str (ps, _fillchar); row++; if (rw.objptr(row) == NULL) rw.add(new TPrintrow ()); ((TPrintrow *) (&rw[row]))->set_style(xstyle); ((TPrintrow *) (&rw[row]))->put(ps, pos[pr->row()]); s = para_str->get(); } ((TPrintrow *) (&rw[row]))->set_style(normalstyle); } if (pos[pr->row ()] != -1) pos[pr->row ()] += ps.len (); } } } // print! const int last = rw.last(); for (i = 0; i <= /*_maxrow*/ last; i++) { TPrintrow *pr = (TPrintrow *) & rw[i]; if (!(prn.print(*pr))) break; } //callback che segnala la fine della stampa fisica di una riga (da lui chiamata "page") on_page_printed(file); if (_auto_ff && prn.rows_left() > 0) printer().formfeed (); delete pos; // TRUE if all rows have been printed // if stopped by preprocess_page returns ok return i == last /*_maxrow */ + 1; } bool TPrint_application::menu(MENU_TAG m) { // funziona da se' fino a 20 voci della menubar if (m >= BAR_ITEM (1) && m <= BAR_ITEM (20)) { _last_choice = m; do_print((m - BAR_ITEM (0)) / 100); } // Se non esistono altre voci di menu termina l'applicazione return xvtil_test_menu_tag (BAR_ITEM (2)); } bool TPrint_application::create() { TApplication::create(); printer().setfooterhandler (_pp_footer); printer().setheaderhandler (_pp_header); printer().setlinkhandler (_pp_link); if (user_create()) { dispatch_e_menu (_last_choice); return TRUE; } else return FALSE; } bool TPrint_application::destroy () { user_destroy(); reset_files(); _cursors.destroy(); return TApplication::destroy (); } void TPrint_application::do_print(int n) { while (set_print(n)) { do { print(); } while(_repeat_print); enable_print_menu(); } } void TPrint_application::enable_print_menu() { enable_menu_item(M_FILE_PRINT, TRUE); } void TPrint_application::disable_print_menu() { enable_menu_item(M_FILE_PRINT, FALSE); } void TPrint_application::enable_setprint_menu() { enable_menu_item(BAR_ITEM (1), TRUE); } void TPrint_application::disable_setprint_menu() { enable_menu_item (BAR_ITEM (1), FALSE); } TPrint_application::TPrint_application ():TApplication (), _rows (100), _cursors (10), _transtab (10), _header (10), _footer (10) { _cur = NULL; _repeat_print = FALSE; _currow = _maxrow = 0; _auto_ff = FALSE; _wbar = _wcancel = TRUE; _wmess = "Stampa in corso\nPrego attendere"; _wthr = 5; _fillchar = ' '; _pr_tree = NULL; _print_defined = FALSE; _force_progind = FALSE; _force_setpage = FALSE; _magic_currency = FALSE; _prind = NULL; _cur_file = 0; _magic_currency = FALSE; _print_zero = FALSE; _last_choice = BAR_ITEM (1); } void TPrint_application::reset_files() { if (_pr_tree != NULL) { _reset_tree(_pr_tree); _pr_tree = NULL; } } TPrint_application::~TPrint_application () {}