#include #include #include #include #include #include #include #include #include #include #include #define STYLE_NUM 4 HIDDEN TPrinter* _printer = NULL; TPrinter& printer() { if (_printer == NULL) _printer = new TPrinter; return *_printer; } void printer_destroy() { if (_printer != NULL) { delete _printer; _printer = NULL; } } // ---------------------------------------------------------------------- // TPrint_intersector // ---------------------------------------------------------------------- // TPrint_intersector: calcola intersezioni tra elementi grafici e // restituisce, riga per riga, i necessari caratteri di fincatura per // finculare in modo carattere // usata da viswin e printwin class TPrint_intersector : public TString_array { const char* _fink; char check_intersection(int x, int y, char ch); void h_line(int x1, int y1, int len); void v_line(int x1, int y1, int len); // caratteri fincazione: l'ho fatto perche' e' inline char f_topleft() const { return _fink[0]; } char f_topmiddle() const { return _fink[1]; } char f_topright() const { return _fink[2]; } char f_botleft() const { return _fink[3]; } char f_botmiddle() const { return _fink[4]; } char f_botright() const { return _fink[5]; } char f_centerleft() const { return _fink[6]; } char f_centermiddle() const { return _fink[7]; } char f_centerright() const { return _fink[8]; } char f_horizontal() const { return _fink[9]; } char f_vertical() const { return _fink[10]; } public: // aggiunge un elemento grafico void add(TGraphic_shape s, int x1, int y1, int x2, int y2); // aggiunge alla stringa passata i necessari caratteri, leggendo // dalla pagina interna const char* get_chars(int line) const; // sbianca tutto void clear(); TPrint_intersector(const char* fink, int pagesize) : TString_array(pagesize) , _fink(fink) {} virtual ~TPrint_intersector() {} }; char TPrint_intersector::check_intersection(int x, int y, char ch) { char a = ' ', b = ' ', c = ' ', d = ' '; if (y > 0 && objptr(y-1) != NULL) b = row(y-1)[x]; if (objptr(y+1) != NULL) d = row(y+1)[x]; if (x > 0) a = row(y)[x-1]; if (x < row(y).len()-1) c = row(y)[x+1]; if (a == ' ' && b == ' ' && c != ' ' && d != ' ') ch = f_topleft(); else if (a == ' ' && b != ' ' && c != ' ' && d == ' ') ch = f_botleft(); else if (a != ' ' && b != ' ' && c == ' ' && d == ' ') ch = f_botright(); else if (a != ' ' && b == ' ' && c == ' ' && d != ' ') ch = f_topright(); else if (a != ' ' && b != ' ' && c == ' ' && d != ' ') ch = f_centerright(); else if (a == ' ' && b != ' ' && c != ' ' && d != ' ') ch = f_centerleft(); else if (a != ' ' && b != ' ' && c != ' ' && d == ' ') ch = f_botmiddle(); else if (a != ' ' && b == ' ' && c != ' ' && d != ' ') ch = f_topmiddle(); else if ((a != ' ' && b != ' ' && c != ' ' && d != ' ') || ((a != ' ' && b == ' ' && c != ' ' && d == ' ') && ch == f_vertical()) || ((a == ' ' && b != ' ' && c == ' ' && d != ' ') && ch == f_horizontal())) ch = f_centermiddle(); return ch; } void TPrint_intersector::h_line(int x1, int y1, int len) { if (objptr(y1) == NULL) { TString* ss = new TString(256); ss->spaces(); TArray::add(ss, y1); } TString& s = row(y1); for (int i = x1; i < x1+len; i++) s[i] = f_horizontal(); for (i = x1; i < x1+len; i++) s[i] = check_intersection(i, y1, f_horizontal()); } void TPrint_intersector::v_line(int x1, int y1, int len) { for (int i = y1; i < y1+len; i++) { if (objptr(i) == NULL) { TString* ss = new TString(256); ss->spaces(); TArray::add(ss, i); } row(i)[x1] = f_vertical(); } for (i = y1; i < y1+len; i++) row(i)[x1] = check_intersection(x1, i, f_vertical()); } void TPrint_intersector::add(TGraphic_shape s, int x1, int y1, int x2, int y2) { // rows start at 0 y1 --; y2 --; // columns pure, ma e' possibile che siano gia' 0 se la generazione // e' stata automatica (colonna 1. campo - 1) if (x1 > 0) x1 --; if (x2 > 0) x2 --; switch (s) { case line: if (x1 == x2) // vertical v_line(x1, y1, y2-y1+1); else if (y1 == y2) // horizontal h_line(x1,y1, x2-x1+1); else error_box("Linee oblique non supportate in modalita' testo"); break; case box: h_line(x1, y1, x2-x1+1); h_line(x1, y2, x2-x1+1); v_line(x1, y1, y2-y1+1); v_line(x2, y1, y2-y1+1); break; default: break; } } const char* TPrint_intersector::get_chars(int line) const { if (objptr(line) == NULL) return ""; else return row(line); } void TPrint_intersector::clear() { for (int i = 0; i < items(); i++) { TString* s = (TString*)objptr(i); if (s != NULL) s->spaces(); } } /////////////////////////////////////////////////////////// // PrDesc /////////////////////////////////////////////////////////// struct PrDesc { TTextfile *_txt; TPrinter * _p; } PrintWhat; BOOLEAN XVT_CALLCONV1 TPrinter::start_print (long data) { const PrDesc *pd = (PrDesc *) data; TTextfile& txt = *(pd->_txt); const int vofs = pd->_p->get_line_offset(); const int hofs = pd->_p->get_column_offset(); if (pd->_p->is_generic() && (vofs != 0 || hofs != 0)) { TTextfile new_txt; TString s(256); const long last_row = txt.lines(); long out_row = 0; for (long row = (vofs < 0 ? -vofs : 0); row < last_row; row++) { const int pagelen = pd->_p->formlen(); const int page_row = (int) (out_row % pagelen); if (vofs > 0 && page_row == 0) { const int page = (int) (out_row / pagelen); for (int i = vofs; i > 0; i--) { out_row++; if (page > 0) row++; new_txt.append(""); } } if (vofs < 0 && page_row == pagelen + vofs) { for (int i = -vofs; i > 0; i--) { out_row++; row++; new_txt.append(""); } } s = txt.line(row); if (hofs < 0) s.ltrim(-hofs); else if(hofs > 0) s.lpad(s.len() + hofs); new_txt.append(s); out_row++; } TPrintwin pw(new_txt); pw.do_print(); return pw.aborted(); } else { TPrintwin pw(txt); if (pw.win() != NULL_WIN) pw.do_print(); return pw.aborted(); } } // utils del caz HIDDEN int read_int (const char *s, int &n, int &cnt) { char nbuf[16]; while (!isdigit (s[cnt])) cnt++; for (int j = 0; isdigit (s[cnt]); j++) nbuf[j] = s[cnt++]; nbuf[j] = '\0'; return n = atoi (nbuf); } void TPrinter::parse_background(const char* bg_desc, TString_array& background) { TString_array pix; char op, ch; int x1, x2, y1, y2; int id, cnt = 0; TToken_string tt; TFilename bmp; if (!_fink_mode && _finker == NULL) _finker = new TPrint_intersector(_fink, _formlen); else if (_finker) _finker->clear(); while ((ch = bg_desc[cnt++]) != '\0') { op = ch; tt = ""; char bf[2]; bf[1] = '\0'; switch (op) { case ' ': case '\t': case '\n': continue; // ignore whitespace break; case 'i': cnt++; for (x1 = 0; bg_desc[cnt] != ','; x1++) bmp[x1] = bg_desc[cnt++]; bmp[x1] = '\0'; id = _image_names.find(bmp); if (id < 0) id = _image_names.add(bmp); read_int(bg_desc, x1, cnt); if (x1 <= 0) x1 = 1; read_int(bg_desc, y1, cnt); if (y1 <= 0) y1 = 1; read_int(bg_desc, x2, cnt); if (x2 <= 0) x2 = formwidth(); read_int(bg_desc, y2, cnt); if (y2 <= 0) y2 = formlen(); cnt++; if (_isgraphics) { tt << op; tt.add(id); tt.add(x1); tt.add(y1); tt.add(x2); tt.add(y2); } break; case 'l': // line case 'b': // box case 'r': // round box cnt++; read_int (bg_desc, x1, cnt); read_int (bg_desc, y1, cnt); read_int (bg_desc, x2, cnt); read_int (bg_desc, y2, cnt); cnt++; // skip separator if (_isgraphics && _fink_mode) { tt << op; tt.add (x1 - 1); tt.add (y1 - 1); tt.add (x2 - 1); tt.add (y2 - 1); } else { TGraphic_shape s = op == 'b' ? box : line; _finker->add(s, x1, y1, x2, y2); } break; case 't': // text cnt++; read_int (bg_desc, x1, cnt); read_int (bg_desc, y1, cnt); cnt++; tt << op; tt.add (x1-1); tt.add (y1-1); tt << '|'; while ((ch = bg_desc[cnt++]) != '}') tt << ch; break; case 'P': // set pen style case 'B': // set brush case 'W': // set line width case 'C': // set pen color tt << op; bf[0] = bg_desc[cnt++]; tt.add (bf); break; default: yesnofatal_box ("Unknown background opcode: %c", op); break; } pix.add (tt); } // now build row descriptions // colors are listed in printapp: char curcol = 'n'; char curpen = 'n'; char curpat = 'n'; char curwid = '1'; for (int l = 0; l < _formlen; l++) { if (background.objptr(l) == NULL) // Se la riga non esiste creala { TToken_string* r = new TToken_string(15); if (curcol != 'n') *r << 'C' << curcol; // Setta valori se diversi da default if (curpat != 'n') *r << 'B' << curpat; if (curwid != '1') *r << 'W' << curwid; if (curpen != 'n') *r << 'P' << curcol; background.add(r, l); } TString& rwd = background.row(l); for (int j = 0; j < pix.items(); j++) { TToken_string& tt = pix.row(j); // la stringa contiene l'opcode piu' i parametri in binario, // incrementati di 1 per evitare lo 0 switch (tt.get_char(0)) { case 'b': x1 = tt.get_int (1) + 1; y1 = tt.get_int (2) + 1; x2 = tt.get_int (3) + 1; y2 = tt.get_int (4) + 1; if (y1 == l + 1) // at ze biginnin { rwd << 'u' << char (x1); rwd << 'r' << char (x1) << char (x2); rwd << 'u' << char (x2); } else if (y2 == l + 1) // at ze end { rwd << 'o' << char (x1); rwd << 'r' << char (x1) << char (x2); rwd << 'o' << char (x2); } else if (y1 < l + 1 && y2 > l + 1) // in ze middol { rwd << 'v' << char (x1); rwd << 'v' << char (x2); } break; case 'l': x1 = tt.get_int (1) + 1; y1 = tt.get_int (2) + 1; x2 = tt.get_int (3) + 1; y2 = tt.get_int (4) + 1; if (y1 == y2 && y1 == l + 1) // orizzontale { rwd << 'h' << char (x1) << char (x2); } else if (y1 <= l + 1 && y2 >= l + 1) // verticale { rwd << 'v' << char (x1); } break; case 'r': x1 = tt.get_int (1) + 1; y1 = tt.get_int (2) + 1; x2 = tt.get_int (3) + 1; y2 = tt.get_int (4) + 1; if (y1 == y2) // orizzontale { if (y1 == l+1) rwd << 'r' << char (x1) << char (x2); } else { const int l1 = l+1; if (l1 >= y1 && l1 <= y2) // verticale { char code = 'v'; if (y1 == l1) code = 'u'; else if (y2 == l1) code = 'o'; rwd << code << char(x1); } } break; case 't': x1 = tt.get_int (1) + 1; y1 = tt.get_int (2) + 1; // al gh'e' if (y1 == l + 1) {} break; case 'i': id = tt.get_int(); x1 = tt.get_int(); y1 = tt.get_int(); x2 = tt.get_int(); y2 = tt.get_int(); if (l+1 >= y1 && l+1 <= y2) rwd << 'i' << char(id+1) << char(l-y1+2) << char(x1) << char(x2-x1+1) << char(y2-y1+1); break; case 'W': curwid = *(tt.get (1)); rwd << 'W' << curwid; break; case 'P': curpen = *(tt.get (1)); rwd << 'P' << curpen; break; case 'B': curpat = *(tt.get (1)); rwd << 'B' << curpat; break; case 'C': curcol = *(tt.get (1)); rwd << 'C' << curcol; break; default: break; } } } } void TPrinter::setbackground(const char* b, int index) { CHECK(index >= 0 && index <= 3, "Bad background index"); _backgrounds.destroy(index); if (b && *b) { TString_array* bg = new TString_array(formlen()); _backgrounds.add(bg, index); parse_background(b, *bg); } } TString_array& TPrinter::getbgdesc(word page) const { int index = 0; if (page == 0 && _backgrounds.objptr(3)) index = 3; if (page == 1 && _backgrounds.objptr(2)) index = 2; if (index == 0 && (page & 0x1) == 0 && _backgrounds.objptr(1)) index = 1; TString_array* bg = (TString_array*)_backgrounds.objptr(index); if (bg == NULL) { bg = new TString_array(formlen()); ((TPrinter*)this)->_backgrounds.add(bg, index); // keep const } return *bg; } bool printers_on_key(TMask_field & f, KEY key); // fv support structs for config // @doc INTERNAL // @mfunc Legge la descrizione della stampante dal file // // @rdesc Ritorna il risultato dell'operazione: // // @flag TRUE | Se e' riuscito a leggere la descrizione della stampante // @flag FALSE | Se non e' riuscito a leggere la descrizione della stampante bool PrinterDef::read( const char *name, // @parm Nome della stampante di cui cercarne la descrizione FILE * fd) // @parm Puntatore al file contenente la descrizione { _printername = name; _printername.trim (); TToken_string tmp (64, '='); TString l (48); TString r (16); while (TRUE) { const long p = ftell (fd); // Memorizza inizio paragrafo if (fgets (__tmp_string, 256, fd) == NULL) return FALSE; tmp = __tmp_string; tmp.trim (); if (tmp == "[End of File]") return FALSE; if (tmp[0] == '[') { fseek (fd, p, SEEK_SET); // Ritorna ad inizio paragrafo break; } l = tmp.get (); l.trim (); r = tmp.get (); r.trim (); if (l == "Device name") { _devicename = r; } else if (l == "Filter name") { _filtername = r; } else if (l == "Printer type") { _printertype = r; } else if (l == "Normal") { strcpy (_atstr[normalstyle], r); } else if (l == "Bold") { strcpy (_atstr[boldstyle], r); } else if (l == "Italic") { strcpy (_atstr[italicstyle], r); } else if (l == "Underlined") { strcpy (_atstr[underlinedstyle], r); } else if (l == "Code") { TToken_string code (r); _names.add ( code.get() ); _codes.add ( code.get() ); } else if (l == "Form feed") { _ffcode = r; } else if (l == "Newline") { _nlcode = r; } else return error_box ("Riga di configurazione stampante errata:\n%s", (const char *) l); } return TRUE; } bool PrinterDef::isdefault () { return strcmp(_printername, "Default") == 0; } ////////// TPRINTROW ////////// TPrintrow::TPrintrow() { reset(); } TPrintrow::TPrintrow(const TPrintrow& pr) { _row = pr.row (); memcpy (_attr, pr._attr, MAXSTR); memcpy (_cols, pr._cols, MAXSTR); _currentcolor = 'w'; _currentcolor <<= 8; _currentcolor += 'n'; _currentstyle = pr._currentstyle; for (int i = 0; i < MAXSTR; i++) _cols[i] = _currentcolor; _lastpos = pr._lastpos; } TObject *TPrintrow::dup () const { return new TPrintrow (*this); } const char *TPrintrow::class_name () const { return "Printrow"; } word TPrintrow::class_id() const { return CLASS_PRINTROW; } TPrintrow& TPrintrow::reset() { _row.spaces (sizeof(_attr)); // Azzera testo memset(_attr, normalstyle, sizeof (_attr)); // Azzera stile _tab.reset(); // Azzera tabulazioni _currentcolor = 'w'; _currentcolor <<= 8; _currentcolor += 'n'; for (int i = 0; i < MAXSTR; i++) _cols[i] = _currentcolor; // Azzera colori _lastpos = 0; _currentstyle = normalstyle; return *this; } const char* TPrintrow::row_codified() const { char last_attr = -1; int last_color = -1; int last = 0, k = 0, len = -1; for (int i = 0; i < _row.size(); i++) if (_row[i] > ' ') len = i; for (i = 0; i < _row.size(); i++) { if (_tab[i]) { __tmp_string[k++] = '@'; __tmp_string[k++] = 't'; } if (_attr[i] != last_attr) { __tmp_string[k++] = '@'; switch (_attr[i]) { case normalstyle: __tmp_string[k++] = 'r'; break; case boldstyle: __tmp_string[k++] = 'b'; break; case italicstyle: __tmp_string[k++] = 'i'; break; case underlinedstyle: __tmp_string[k++] = 'u'; break; } last_attr = _attr[i]; } if (_cols[i] != last_color && i <= len) { __tmp_string[k++] = '$'; __tmp_string[k++] = '['; __tmp_string[k++] = (char) (_cols[i] & 0x00ff); __tmp_string[k++] = ','; __tmp_string[k++] = (char) (_cols[i] >> 8); __tmp_string[k++] = ']'; last_color = _cols[i]; } __tmp_string[k++] = _row[i]; if (_row[i] > ' ') last = k; } __tmp_string[last] = '\0'; return __tmp_string; } TPrintrow& TPrintrow::put(const char *str, int position, int len) { if (len < 1) len = strlen (str); if (position < 0) position = _lastpos; else _tab.set(position); char bg = 'w', fg = 'n'; for (int i = 0; i < len; i++) { char c = str[i]; if (c == '$' && str[i + 1] == '[') { ++i; fg = str[++i]; c = str[++i]; if (c == ']') bg = _currentcolor >> 8; else if (c == ',') { bg = str[++i]; i++; } else { CHECK (0, "Error in color specification"); } _currentcolor = (bg << 8) + fg; } else if (c == '@') { c = str[++i]; switch (toupper (c)) { case '#': case '<': case '>': // printer MUST handle them { const int n = (c == '#') ? 5 : ((c == '>') ? 10 : 8); _row[position] = '@'; _attr[position++] = _currentstyle; for (int j = 1; j < n; j++) { _row[position] = c; _attr[position++] = _currentstyle; } } break; case 'T': _tab.set(position); break; case 'B': _currentstyle = boldstyle; break; case 'I': _currentstyle = italicstyle; break; case 'U': _currentstyle = underlinedstyle; break; case 'R': _currentstyle = normalstyle; break; default: // should be number followed by skip or jump if (isdigit (c)) { // read number char digbuf[8]; int cnt = 0; digbuf[cnt++] = c; while (isdigit (c = str[++i])) digbuf[cnt++] = c; digbuf[cnt] = '\0'; int pp = atoi (digbuf); if (toupper (c) == 'G') { if (pp >= MAXSTR) fatal_box ("printrow reaches position %d", pp); if (pp > position) for (int k = position; k < pp; k++) { _attr[k] = _currentstyle; _cols[k] = _currentcolor; } position = pp; _tab.set(position); } else if (toupper (c) == 'J') { if (pp + position >= MAXSTR) fatal_box ("printrow reaches position %d", pp + position); for (int k = 0; k < pp; k++) { _attr[k + position] = _currentstyle; _cols[k + position] = _currentcolor; } position += pp; _tab.set(position); } } else { _row[position] = c; _attr[position++] = _currentstyle; _cols[position++] = _currentcolor; } } // switch } else { _row[position] = c; _attr[position] = _currentstyle; _cols[position++] = _currentcolor; } } // for _lastpos = position; return *this; } ////////// TPRINTER ////////// HIDDEN bool printer_handler (TMask_field & f, KEY key) { if (key == K_SPACE) { TToken_string pn1(10), pn2(80); const PrinterDef & def = printer().get_description(atoi(f.get ())); const char *s; int j = 0; while ((s = def.get_codenames (j)) != NULL) { pn1.add (format ("%02d", j)); pn2.add (s); j++; } ((TList_field &) f.mask ().field (MSK_CODES)).replace_items (pn1, pn2); } return TRUE; } void TPrinter::set_printrcd() { if (_print_rcd != NULL) xvt_print_destroy(_print_rcd); _print_rcd = xvt_print_create(&_print_rcd_size); if (!xvt_print_is_valid(_print_rcd)) error_box("Errore di inizializzazione della stampante"); } PRINT_RCD* TPrinter::get_printrcd(int *size) { if (_print_rcd == NULL) set_printrcd(); if (size != NULL) *size = _print_rcd_size; return _print_rcd; } // @doc EXTERNAL // @mfunc Setta le caratteristiche della stampante leggendole da

void TPrinter::init_formlen( WINDOW prwin) // @parm Finestra effettiva di stampa (default NULL_WIN) // @comm Nel caso

sia NULL_WIN vengono solamente aggiornati i valori { long pw, ph, phr, pvr; // Printer width, height, horizontal and vertical resolution xvt_app_escape (XVT_ESC_GET_PRINTER_INFO, get_printrcd(), &ph, &pw, &pvr, &phr); if (pvr != 0) { _formlen = int(ph * _lines_per_inch / pvr); // Total number of lines per page _dots_per_line = int(pvr / _lines_per_inch); // Number of point per line _vert_offset = (int)(ph - ((long)_formlen * _dots_per_line)) >> 1; if (prwin != NULL_WIN) { const TString spc(256, 'M'); // Compute maximum number of chars per line int w = 0; for (_formwidth = spc.len(); _formwidth >= 80; _formwidth--) { w = xvt_dwin_get_text_width(prwin, (char*)(const char*)spc, _formwidth); if (w < pw) break; } if (isfax()) _horz_offset = 56; else _horz_offset = (_formwidth > 80) ? (int)(pw - w)/2 : 0; } else { _formwidth = 256; _horz_offset = 0; } } else warning_box ("Il driver della stampante non e' valido.\n" "Non stampare prima di averlo reinstallato"); } // Handler della maschera di setup HIDDEN bool set_windows_print_device (TMask_field& f, KEY key) { TMask& m = f.mask(); if (key == K_TAB && (f.focusdirty() || !m.is_running())) { TWait_cursor hourglass; TPrinter& pr = printer(); TToken_string pn; os_get_printer_names(pn); const TString pdev (pn.get(atoi (f.get()))); // Nome stampante corrente os_set_default_printer(pdev); if (m.is_running()) { pr.set_printrcd(); pr.init_formlen(); } const int MAX_FAMILIES = 128; char* family[MAX_FAMILIES]; const int num_families = (int)xvt_fmap_get_families(pr.get_printrcd(), family, MAX_FAMILIES); TToken_string pn1(256), pn2(256); for (int i = 0; i < num_families; i++) { pn1.add(family[i]); pn2.add(family[i]); xvt_mem_free(family[i]); } TList_field& lst = (TList_field&)m.field(MSK_FONT); lst.replace_items(pn1, pn2); m.set(MSK_FONT, printer().fontname(), TRUE); } return TRUE; } HIDDEN bool font_handler(TMask_field& f, KEY key) { TMask& m = f.mask(); if (key == K_TAB && (f.focusdirty() || !m.is_running())) { TWait_cursor hourglass; const char* family = f.get(); const int MAXSIZES = 16; long sizes[MAXSIZES]; BOOLEAN scalable; const int num_sizes = (int)xvt_fmap_get_family_sizes(printer().get_printrcd(), (char*)family, sizes, &scalable, MAXSIZES); TToken_string pn1(80); if (scalable) { for (int i = 4; i <= 32; i++) pn1.add(i); } else { if (num_sizes > 0) { for (int i = 0; i < num_sizes; i++) pn1.add(sizes[i]); } else pn1.add(printer().get_char_size()); } TList_field& lst = (TList_field&)f.mask().field(MSK_SIZE); lst.replace_items(pn1, pn1); lst.set(format("%d", printer().get_char_size())); } return TRUE; } TPrinter::TPrinter() : _date (TODAY), _multiple_link (FALSE), _frozen (FALSE), _isgraphics (TRUE), _lines_per_inch (6), _ch_size (12), _ncopies(1), _export_header(FALSE), _export_header_len(0), _vf(NULL), _l_offset(0), _c_offset(0), _appendfile(FALSE), _print_rcd(NULL) { _footerhandler = _headerhandler = NULL; _linkhandler = NULL; _curprn = 0; // first in list if no default is specified _curcode = 0; // first in list if no default is specified _formlen = 66; _frompage = 0; _topage = 0xffff; _hwformfeed = FALSE; _currentpage = 1; _currentrow = 1; _fp = NULL; _headersize = 0; _footersize = 0; _isopen = FALSE; _multiple_copies = main_app().class_id() == CLASS_PRINT_APPLICATION; // read configuration file read_configuration (); init_formlen (); os_get_default_printer(_defPrinter); TToken_string pn2; os_get_printer_names(pn2); // get printer names CHECK(_curprn >= 0, "Can't find printer "); if (_curprn >= word(pn2.items())) { TString pdev(_defPrinter); // Nome stampante corrente int comma = pdev.find(','); if (comma > 0) pdev.cut(comma); _curprn = pn2.get_pos(pdev); } else { const TString pdev(pn2.get(_curprn)); // Nome stampante corrente // scrivi (e semmai lo si risistema poi) os_set_default_printer(pdev); } set_fincatura("+++++++++-|"); set_fink_mode(TRUE); _finker = _isgraphics && _fink_mode ? NULL : new TPrint_intersector(_fink, _formlen); } bool TPrinter::isfax() const { bool fax = FALSE; if (_printertype == winprinter) { const char* name = (const char*)((TPrinter*)this)->get_printrcd() + 4; fax = strncmp(name, "FaxMan", 6) == 0; } return fax; } // @doc EXTERNAL // @mfunc Legge la configurazione della stampante void TPrinter::read_configuration( const char* parag) // parm Nome del file di configurazione della stampante (default NULL) // @comm Se

e' NULL viene letta la configurazione della stamapnte di default. { TWait_cursor hourglass; _config = parag; // Inizializza nome configurazione if (_config.empty()) // Se non specificata ... _config = "Printer"; // ... usa configurazione standard TConfig* iniptr = NULL; if (_config != "Printer") // Cerca configurazione speciale { iniptr = new TConfig(CONFIG_STAMPE, _config); const int what = iniptr->get_int("Type", NULL, -1, -1); if (what < 0) // Se configurazione annullata ... { delete iniptr; iniptr = NULL; } } if (iniptr == NULL) iniptr = new TConfig(CONFIG_USER, "Printer"); const int what = iniptr->get_int("Type", NULL, -1, 0); // Tipo stampante _curprn = iniptr->get_int("Number", NULL, -1, 0); // Numero stampante corrente _printerfile = iniptr->get("File", NULL, -1, ""); // File di stampa _curcode = iniptr->get_int("Codes", NULL, -1, 0); // Codici di stampa _fontname = iniptr->get("Font", NULL, -1, XVT_FFN_FIXED); // Nome del font _ch_size = iniptr->get_int("Size", NULL, -1, 12); // Dimensione del font _lines_per_inch = iniptr->get_int("Lines", NULL, -1, 6); // Linee per pollice _isgraphics = iniptr->get_bool("Graphic", NULL, -1, FALSE); // Grafica attiva if (iniptr->exist("rcd", 0)) { int size, i = 0; byte* rcd = (byte*)get_printrcd(&size); TToken_string s(256); for (int index = 0; i < size; index++) { s = iniptr->get("rcd", NULL, index); if (*s) { for (const char* n = s.get(0); n && i < size; n = s.get()) rcd[i++] = (byte)atoi(n); } else break; } if (!xvt_print_is_valid(_print_rcd)) { error_box("Attenzione: la stampante corrente non e' valida.\n" "Si prega di selezionare e registrare una nuova stampante."); set_printrcd(); } } delete iniptr; iniptr = NULL; if (_printerfile.empty()) { _printerfile.tempdir(); _printerfile << '/'; } if (_config == "Printer" || _printertype == winprinter) switch (what) { case 0: case 5: _printertype = winprinter; break; case 1: // file _printertype = fileprinter; break; case 4: // video _printertype = screenvis; _curcode = 0; break; case 6: // export _printertype = export; _curcode = 0; break; default: break; } } void TPrinter::save_configuration() { TWait_cursor hourglass; CHECK(_config.not_empty(), "Invalid printer config"); TConfig prini(_config == "Printer" ? CONFIG_USER : CONFIG_STAMPE, _config); prini.set("Type", _printertype); // Tipo stampante prini.set("Number", _curprn); // Numero stampante corrente prini.set("File", _printerfile); // File di stampa prini.set("Codes", _curcode); // Codici di stampa prini.set("Font", _fontname); // Nome del font prini.set("Size", _ch_size); // Dimensione del font prini.set("Lines", _lines_per_inch); // Linee per pollice prini.set("Graphic", _isgraphics ? "X" : ""); // Grafica attiva int n = 0, index = 0; TToken_string val(256); int rcdsize; byte* rcd = (byte*)get_printrcd(&rcdsize); for (int i = 0; i < rcdsize; i++) { val.add((int)rcd[i]); n++; if (n == 24) { prini.set("rcd", val, NULL, TRUE, index++); val.cut(n = 0); } } if (n > 0) prini.set("rcd", val, NULL, TRUE, index); for (index++; prini.remove("rcd", index); index++); } TPrinter::~TPrinter () { if (_print_rcd != NULL) { xvt_print_destroy(_print_rcd); _print_rcd = NULL; } os_set_default_printer(_defPrinter); } const char* TPrinter::class_name() const { return "Printer"; } word TPrinter::class_id() const { return CLASS_PRINTER; } TPrintrow *TPrinter::getheaderline(int linetoget) { return ((TPrintrow *)_header.objptr (linetoget)); } TPrintrow *TPrinter::getfooterline(int linetoget) { return ((TPrintrow *)_footer.objptr(linetoget)); } // @doc EXTERNAL // @mfunc Setta il contenuto di una line dell'header void TPrinter::setheaderline ( int linetoset, // @parm Numero della linea da settare TPrintrow * line) // @parm Contenuto della linea dell'header // @parm const TPrintrow& | line | Indirizzo con il contenuto della // linea dell'header // @syntax void setheaderline (int linetoset, TPrintrow* line); // @syntax void setheaderline (int linetoset, const TPrintrow& line); { _header.add (line, linetoset); if (linetoset >= _headersize) _headersize = linetoset + 1; } void TPrinter::setheaderline (int linetoset, const TPrintrow & line) { TPrintrow *p = new TPrintrow (line); setheaderline (linetoset, p); } // @doc EXTERNAL // @mfunc Setta il contenuto di una line dell'header void TPrinter::setfooterline ( int linetoset, // @parm Numero della linea da settare TPrintrow * line) // @parm Contenuto della linea del footer // @parm const TPrintrow& | line | Indirizzo con il contenuto della // linea del footer // @syntax void setfooterline (int linetoset, TPrintrow* line); // @syntax void setfooterline (int linetoset, const TPrintrow& line); { _footer.add (line, linetoset); } void TPrinter::setfooterline (int linetoset, const TPrintrow& line) { TPrintrow *p = new TPrintrow (line); setfooterline (linetoset, p); } void TPrinter::resetheader () { _header.destroy (); _headersize = 0; } void TPrinter::resetfooter () { _footer.destroy (); // _footersize = 0; } // @doc EXTERNAL // @mfunc Metodo base per la stampa // // @rdesc Ritorna il risulato della stampa: // // @flag TRUE | Se la stampa ha avuto successo // @flag FALSE | Se la stampante non e' attiva bool TPrinter::printrow( TPrintrow* rowtoprint) // @parm Riga da stampare // @comm Se la pagina logica corrente e' precedente alla prima pagina logica o successiva // all'ultima pagina logica viene ritornato TRUE. { if (!isopen ()) return FALSE; if (_currentpage < _frompage || _currentpage > _topage) return TRUE; TString rw (rowtoprint == NULL ? "" : (_printertype == screenvis || _printertype == winprinter || _printertype == export ? rowtoprint->row_codified () : rowtoprint->row ())); rw.rtrim (); int lun = rw.len (); int idx; if (_printertype != export) { for (idx = 0; idx < lun; idx++) { if (rw[idx] == '@') // gestione data e n. di pagina { switch (rw[idx + 1]) { case '#': rw.overwrite (format("%-5u", _currentpage), idx++); break; case '>': rw.overwrite (format("%10s",_date.string (full)), idx++); break; case '<': rw.overwrite (format("%8s",_date.string (brief)), idx++); break; default: break; } } } } if (_printertype == screenvis) { if (!_vf->frozen ()) _vf->add_line(rw); else _frozen = TRUE; return TRUE; } if (_printertype == winprinter || _printertype == export) { // add line to txt if (!_frozen) _txt.append(rw); return TRUE; } if (_printertype == fileprinter) { // add line to txt if (!_frozen) _txt.append (rw); return TRUE; } return TRUE; } word TPrinter::rows_left() const { word left = _formlen - _currentrow - _footersize + 1; if (_currentrow < 2) left -= _headersize; return left; } // @doc EXTERNAL // @mfunc Permette di stampare una riga // // @rdesc Ritorna il risultato della stampa: // // @flag TRUE | Se la stampa ha avuto successo // @flag FALSE | Se non e' riuscito ad effettuare la stampa bool TPrinter::print( TPrintrow& rowtoprint) // @parm Riga da stampare // @comm Nel caso la riga non ci stia nella pagina logica corrente vengono stampanti il footer // della pagina corrente e l'header della successiva prima prima della stampa della riga // vera e propria. { bool ok = TRUE; if (!(_printertype == export && !_export_header)) { if (_currentrow > _formlen - _footersize) ok = printfooter (); if (ok && _currentrow == 1) ok = printheader(); } if (ok) { ok = printrow(&rowtoprint); _currentrow++; } return ok; } bool TPrinter::printheader() { if (_headerhandler) _headerhandler(*this); bool ok = TRUE; for (int i = 0; i < _headersize && ok; i++) ok = printrow(getheaderline(i)); // _currentrow = _headersize + 1; _currentrow = i+1; return ok; } bool TPrinter::printfooter() { if (_footerhandler) _footerhandler (*this); bool ok = TRUE; for (int i = 0; i < _footersize && ok; i++) ok = printrow(getfooterline(i)); _currentrow = 1; _currentpage++; return ok; } // @doc EXTERNAL // @mfunc Permette di settare il tipo di fincatura void TPrinter::set_fink_mode( bool f) // @parm Indica il tipo di fincatura: // // @flag TRUE | Fincatura di tipo grafico // @flag FALSE | Fincatura di tipo testo // @comm Viene prima controllato che la stampante supporti la modalita' grafica, // in tal caso, se viene impostato il flag a TRUE e la stampante e' generica // oppure non ha il flag di stampa elementi grafici attivato, la fincatura sara' // in modo testo. { _fink_mode = f; if (_fink_mode && (is_generic() || !_isgraphics)) _fink_mode = FALSE; } // @doc EXTERNAL // @mfunc Permette di saltare alcune righe dalla posizione corrente // // @rdesc Ritorna il risulato dell'operazione: // // @flag TRUE | Se e' riuscito a saltare le righe // @flag FALSE | Se non e' riuscito a saltare le righe bool TPrinter::skip( int linestoskip) // @parm Vengono accettati solo valori positivi // @xref { CHECK (linestoskip >= 0, "Linestoskip can't be negative"); int jumpline = _currentrow + linestoskip; return jump(jumpline); } // @doc EXTERNAL // @mfunc Permette di saltare alla riga indicata // // @rdesc Ritorna il risultato dell'operazione // // @flag TRUE | Se e' riuscito a saltare alla riga // @flag FALSE | Se non e' riuscito a saltare alla riga o se viene inserito un formfeed bool TPrinter::jump( int jumpline) // @parm Numero della riga a cui saltare nella stampa. Vengono accettai // solo valori positivi // @comm Nel caso si cerchi di saltare ad una riga superiore alla lunghezza della pagina attiva // viene inserito un formfeed. // @xref { int i = 0; bool ok = TRUE; CHECK (jumpline >= 0, "Jumpline can't be negative"); if (jumpline > _formlen - _footersize) ok = formfeed(); else for (i = _currentrow; i < jumpline; i++) if (!printrow()) ok = FALSE; if (jumpline > _formlen - _footersize) ok = FALSE; return ok; } bool TPrinter::formfeed() { const int lastrow = _formlen - _footersize; for (; _currentrow + _export_header_len <= lastrow; _currentrow++) printrow(); return printfooter(); } void TPrinter::reset() { resetheader(); resetfooter(); _currentpage = 1; _currentrow = 1; } bool TPrinter::open() { TToken_string pn2; os_get_printer_names(pn2); // get printer names TString pdev(pn2.get(_curprn)); // Nome stampante corrente os_set_default_printer(pdev); if (_printertype == screenvis) { CHECK(_vf == NULL, "Print preview already open"); _vf = new TViswin (NULL, "Anteprima di stampa", TRUE, TRUE, _linksdescr.items () > 0); _vf->open_modal (); } else { if (_printertype == winprinter || _printertype == export || _printertype == fileprinter) { // prepare text object for new text _txt.destroy(); _txt.interactive(FALSE); if (isfax()) start_fax_server(); } } _currentrow = 1; _currentpage = 1; return _isopen = TRUE; } bool TPrinter::set() { main_app().disable_menu_item (M_FILE_PG_SETUP); TMask mask("bagn001a"); TToken_string pn1(50); int i; mask.set(MSK_FILENAME, _printerfile); mask.set(MSK_NPAGES, _ncopies); const bool can_save = _config == "Printer"; mask.enable(DLG_OK, can_save); // mask.enable(DLG_SAVEREC, can_save); TToken_string pn2; os_get_printer_names(pn2); TString old_default; os_get_default_printer(old_default); const int np = pn2.items(); for (i = 0; i < np; i++) pn1.add(i); TList_field& plst = (TList_field&)mask.field (MSK_PRINTERS); plst.replace_items(pn1, pn2); // Genera printer list mask.set(MSK_PRINTERS, _curprn); // Genera font list set_windows_print_device(mask.field(MSK_PRINTERS), K_TAB); mask.set(MSK_FONT, _fontname); // Genera size list font_handler(mask.field(MSK_FONT),K_TAB); mask.set(MSK_SIZE, _ch_size); mask.set(MSK_LINES, _lines_per_inch); mask.set(MSK_ISGRAPHICS, _isgraphics ? "X" : ""); mask.set_handler (MSK_PRINTERS, set_windows_print_device); mask.set_handler (MSK_FONT, font_handler); if (!_multiple_copies) mask.hide(MSK_NPAGES); if (_printertype == fileprinter) mask.set (MSK_TYPE, "1"); else if (_printertype == screenvis) mask.set (MSK_TYPE, "2"); else mask.set (MSK_TYPE, "0"); const int oldprn = _curprn; s_printrcd * rcd = get_printrcd(); TString oldrcd(_print_rcd_size); memcpy((char *) (const char *) oldrcd, rcd, _print_rcd_size); KEY k; while ((k = mask.run ()) != K_ESC && k != K_ENTER && k != K_INS) { if (k == DLG_SETPRINT) { // l'handler setta default di windows a quella nel listbox e ribecca l'rcd if (xvt_dm_post_page_setup(get_printrcd())) { // Ricarica la lista delle stampanti (L'utente puo' aggiungerne!) os_get_printer_names(pn2); pn1.cut(0); int i = 0; FOR_EACH_TOKEN(pn2, tok) pn1.add(i++); plst.replace_items(pn1, pn2); // Genera printer list // see if user has changed printer // determine index of currently selected printer // ACTHUNG! Deep hacking of XVT internals! NON PORTABLE! const char* name = (const char *)(get_printrcd() + 4); _curprn = pn2.get_pos(name); if (*name == '\0' || _curprn < 0) { NFCHECK("Can't find printer '%s'", name); _curprn = oldprn; } mask.set(MSK_PRINTERS, pn1.get(_curprn)); // set_win_formlen(); // Update dimensions } else beep (); } } if (k == K_ESC) { // riaggiusta stampante default windows come prima // curprn e rcd sono quelle di prima main_app().enable_menu_item(M_FILE_PG_SETUP); os_set_default_printer(old_default); _curprn = oldprn; s_printrcd * rcd = get_printrcd(); memcpy(rcd, (const char *) oldrcd, _print_rcd_size); init_formlen(); return FALSE; } _curprn = atoi(mask.get(MSK_PRINTERS)); _ncopies = atoi (mask.get (MSK_NPAGES)); switch (atoi (mask.get (MSK_TYPE))) { case 0: // stampante _printertype = winprinter; break; case 1: // file _printertype = fileprinter; _printerfile = mask.get (MSK_FILENAME); _curcode = atoi (mask.get (MSK_CODES)); break; case 2: // video _printertype = screenvis; _curcode = 0; break; } _fontname = mask.get(MSK_FONT); const int cs = mask.get_int(MSK_SIZE); if (cs > 4) _ch_size = cs; _lines_per_inch = mask.get_int (MSK_LINES); _isgraphics = mask.get_bool (MSK_ISGRAPHICS); init_formlen (); if (k == K_INS) save_configuration(); main_app().enable_menu_item (M_FILE_PG_SETUP); return TRUE; } // @doc EXTERNAL // @mfunc Inserisce un file di export fatto da un'altra printer void TPrinter::merge_export_file( const char* file, bool header) // @parm Indica se gli header sono presenti nel file: // // @flag TRUE | Gli header sono nel file e quindi non vengono stampanti (default) // @flag FALSE | Gli header non sono nel file e quindi vengono stampanti // @comm Vengono inseriti nel file di export i formati e tutto il resto. Vengono ignorati gli // header supponendo che siano gia' presenti nel file { TTextfile txt(file); for (long i = 0; i < txt.lines(); i++) { TPrintrow* p = new TPrintrow(); p->put(txt.line_formatted(i)); if (header) printrow(p); else print(*p); } } // @doc EXTERNAL // @mfunc Crea un segnalibro // // @rdesc Ritorna l'identificatore del segnalibro creato int TPrinter::set_bookmark( const char* txt, // @parm Nome del segnalibro da creare int father) // @parm Identificatore del segnalibro padre a cui collegare quello // da creare { if (_printertype == screenvis) { BkDef* bkd = new BkDef; bkd->_row = (_currentrow + ((_currentpage - 1)*_formlen)) - 1; bkd->_father_id = father; bkd->_id = _bookmarks.items() + 1; bkd->_txt = txt; _bookmarks.add(bkd); return _bookmarks.items(); } return 0; } void TPrinter::print_txt(TTextfile& txt) { if (txt.lines() > 0) { PrintWhat._txt = &txt; PrintWhat._p = this; xvt_print_open(); xvt_print_start_thread(start_print, (long) (&PrintWhat)); xvt_print_close(); } } void TPrinter::close () { if (isopen() && // la stampante era aperta e _currentrow >1 && // .. ho stampato qualcosa ... _footersize>0 ) // ... c'è footer da stampare formfeed(); if (_fp) { fclose (_fp); _fp = NULL; } if (_printertype == screenvis) { _vf->close_print(); const KEY key = _vf->run (); if (_vf->is_open ()) _vf->close_modal (); _bookmarks.destroy(); if (key == K_CTRL+'S') { _isopen = FALSE; _currentrow = _currentpage = 1; print_txt(_vf->text()); } delete _vf; _vf = NULL; } else if (_printertype == export) { if (_exportfile.not_empty() && _txt.lines() > 0L) { ofstream txt((const char*)_exportfile); for (long i = 0; i < _txt.lines(); i++) txt << _txt.line_formatted(i) << '\n'; txt.close(); } } else if (_printertype == winprinter && _txt.lines() > 0L) { print_txt(_txt); if (is_generic()) os_spool_row("\n"); // Force flushing on Generic printer os_set_default_printer(_defPrinter); } else if (_printertype == fileprinter) { FILE* fp = fopen(_printerfile, _appendfile ? "a" : "w"); if (fp == NULL) { error_box("Impossibile aprire il file %s", (const char*)_printerfile); return; } for (long i = 0; i < _txt.lines(); i++) fprintf(fp,"%s\n", _txt.line(i)); fclose(fp); message_box("Stampa su file terminata. Nome archivio: %s",(const char *)_printerfile); } if (_finker) { delete _finker; _finker = NULL; } // Dealloca sfondi ormai inutili _backgrounds.destroy(); freeze (FALSE); _isopen = FALSE; } // // TFile_printer // #include const long disk_sizes[] = { 360000L, 1200000L, 720000L, 1400000L, 2880000L }; TFile_printer::TFile_printer (const char *ffile, const char *label, int len_rec, int num_rec_inizio, int num_rec_fine, int tipo_disco) { set_printtype (fileprinter); _num_rec_testa_coda = num_rec_inizio + num_rec_fine; _file = ffile; _label = label; _len_rec = len_rec; _volume = 1; _size = disk_sizes[tipo_disco]; _num_rec_volume = int ((_size / len_rec) - _num_rec_testa_coda); _nome_file_fissato = TRUE; _label_fissata = TRUE; } void TFile_printer::open() { } void TFile_printer::close () { } bool TFile_printer::genera_dischetti () { int r; for (int i = 0; i < _tmp_files.items (); i++) { // Avvisa l'utente di inserire un dischetto r = yesno_box ("Inserire il dischetto n. %2d di %2d nel drive %2s", i + 1, _volume, _drive); if (!r) return error_box ("Procedura interrotta!"); // copia il file sul dischetto fcopy ((const char *) &_tmp_files[i], (const char *) _drive); } return TRUE; } TFile_printer::~TFile_printer () { } bool TFile_printer::set () { TMask m ("bagn004"); int f; // // // -------------------------------------------------------------------- // Qui bisogna inserire la lista dei drive disponibili nella maschera // Per ora tale lista e' fissa e contiene solo A: e B: // -------------------------------------------------------------------- // // m.set (F_FILE_DESTINAZIONE, _file); m.set (F_LABEL, _label); if (_nome_file_fissato) m.disable (F_FILE_DESTINAZIONE); if (_label_fissata) m.disable (F_LABEL); const bool ok = m.run () == K_ENTER; if (ok) { f = atoi(m.get(F_FORMATO_DISCO)); _drive = m.get(F_DRIVE); _file = m.get(F_FILE_DESTINAZIONE); _label = m.get(F_LABEL); _size = disk_sizes[f]; _num_rec_volume = int ((_size / _len_rec) - _num_rec_testa_coda); } return ok; } const char* TPrinter::background_chars(int l) const { return _finker == NULL ? "" : _finker->get_chars(l); } /////////////////////////////////////////////////////////// // Calcolo dimensione font /////////////////////////////////////////////////////////// struct font_data { TString _name; int _size; int _columns; }; BOOLEAN XVT_CALLCONV1 calc_font_callback(long data) { font_data& fd = *(font_data*)data; // Create print window WINDOW win = xvt_print_create_win(printer().get_printrcd(), "Calcolo font"); if (win != NULL_WIN) { long pw, ph, phr, pvr; // Printer width, height, horizontal and vertical resolution xvt_app_escape (XVT_ESC_GET_PRINTER_INFO, printer().get_printrcd(), &ph, &pw, &pvr, &phr); TString test(fd._columns); test.fill('M', fd._columns); for (int size = fd._size; size > 0; size--) { // Set print font xvt_set_font(win, fd._name, XVT_FS_NONE, size); const int w = xvt_dwin_get_text_width(win, (char*)(const char*)test, fd._columns); if (w <= pw) break; } if (size > 0) fd._size = size; xvt_vobj_destroy(win); } return win != NULL_WIN; } int TPrinter::calc_font_size(int columns) const { font_data fd; fd._name = fontname(); fd._size = get_char_size(); fd._columns = columns; xvt_print_open(); xvt_print_start_thread(calc_font_callback, (long)&fd); xvt_print_close(); return fd._size; } /////////////////////////////////////////////////////////// // Gestione fax /////////////////////////////////////////////////////////// bool TPrinter::start_fax_server() const { TDDE dde; return dde.execute("EASYFAX", "FAX", "", "bafax"); } void TPrinter::close_fax_server() const { TDDE dde; const bool running = dde.initiate("EASYFAX", "FAX"); if (running) dde.execute("[FileClose]"); } bool TPrinter::send_fax(const char* tipo, const char* codice) { bool ok = isopen() && isfax(); if (ok) { if (tipo && codice) { TString cmd; cmd << "[SetRecipient(" << tipo << ',' << codice << ")]"; TDDE dde; dde.execute("EASYFAX", "FAX", cmd, "bafax"); } close(); // termina la stampa corrente e la spedisce open(); // riapre la stampante } return ok; }