campo-sirio/include/reprint.cpp

1782 lines
44 KiB
C++
Raw Normal View History

#include <automask.h>
#include <colors.h>
#include <defmask.h>
#include <diction.h>
#include <printer.h>
#include <progind.h>
#include <reprint.h>
#include <statbar.h>
#include <bagn003.h>
static bool _print_aborted = false;
///////////////////////////////////////////////////////////
// Utility
///////////////////////////////////////////////////////////
bool advanced_set_draw_tools(TWindow& win, PAT_STYLE pat, int border, COLOR fore, COLOR back)
{
const bool has_pen = border > 0;
const bool has_brush = pat > PAT_HOLLOW && back != COLOR_WHITE;
const bool visible = has_pen || has_brush;
if (visible)
{
if (has_pen)
win.set_pen(fore, border, PAT_SOLID);
else
win.hide_pen();
if (has_brush)
win.set_brush(back, pat);
else
win.hide_brush();
}
return visible;
}
void advanced_draw_rect(TWindow& win, const RCT& r, PAT_STYLE pat, int border, COLOR fore, COLOR back, int radius)
{
if (advanced_set_draw_tools(win, pat, border, fore, back))
{
if (radius > 0)
xvt_dwin_draw_roundrect(win.win(), &r, radius, radius);
else
xvt_dwin_draw_rect(win.win(), (RCT*)&r);
}
}
void advanced_draw_justified_text(TWindow& win, const char* text, short x, short y, short dx)
{
TString txt(text); txt.rtrim();
int spaces = 0;
for (int s = 0; txt[s]; s++)
if (isspace(txt[s])) spaces++;
const int tw = xvt_dwin_get_text_width(win.win(), txt, -1);
if (tw < dx && spaces > 0)
{
txt << ' '; // Aggiunge spazio finale
const double kspc = double(dx - tw) / spaces;
int start = 0;
double kx = x;
for (int i = 0; txt[i]; i++)
{
if (isspace(txt[i]))
{
const bool last_word = txt[i+1] == '\0';
const TString& parola = txt.sub(start, i + (last_word ? 0 : 1));
const int lw = xvt_dwin_get_text_width(win.win(), parola, -1);
if (last_word) // ultima parola
kx = x+dx-lw;
xvt_dwin_draw_text(win.win(), int(kx+0.5), y, parola, -1);
kx += lw + kspc;
start = i+1;
}
}
}
else
xvt_dwin_draw_text(win.win(), x, y, text, -1);
}
void advanced_draw_text(TWindow& win, const char* text, const RCT& r,
char halign, char valign)
{
const short dx = r.right-r.left;
const short dy = r.bottom-r.top;
short x = r.left;
short y = r.bottom;
if (halign != 'L')
{
const int tw = xvt_dwin_get_text_width(win.win(), text, -1);
switch (halign)
{
case 'C': x += (dx - tw)/2; break;
case 'R': x = r.right-tw; break;
default : break;
}
}
// Text Height
int leading, ascent, descent;
xvt_dwin_get_font_metrics(win.win(), &leading, &ascent, &descent);
switch (valign)
{
case 'C': y -= (dy - ascent)/2; break;
case 'T': y = r.top + leading + ascent; break;
default : y -= descent; break;
}
if (halign == 'J')
advanced_draw_justified_text(win, text, x, y, dx);
else
xvt_dwin_draw_text(win.win(), x, y, text, -1);
}
void advanced_draw_paragraph(TWindow& win, TString& para, const RCT& rct,
char halign, char valign)
{
const bool acapo = para.find('\n') >= 0;
int leading, ascent, descent;
xvt_dwin_get_font_metrics(win.win(), &leading, &ascent, &descent);
const int ky = leading + ascent + descent;
const int rct_height = rct.bottom - rct.top;
int rows = (rct_height+ky/2) / ky;
if (acapo || rows > 1) // Devo scrivere piu' righe?
{
const int kx = xvt_dwin_get_text_width(win.win(), "ABCDEFGH", 8) / 8;
const unsigned columns = (rct.right - rct.left) / kx;
TParagraph_string str(para, columns);
if (str.items() < rows)
rows = str.items();
int ybase = rct.top;
switch (valign)
{
case 'C': ybase += (rct_height - rows*ky) / 2; break;
case 'B': ybase += rct_height - rows*ky; break;
default : break;
}
for (int row = 0; row < rows; row++)
{
RCT rctline = rct;
rctline.top = ybase + ky*row;
rctline.bottom = rctline.top + ky;
const char* line = str.get();
if (halign == 'J' && (row == rows-1 || strlen(line) < columns/2))
halign = 'L';
advanced_draw_text(win, line, rctline, halign, 'T');
}
}
else
advanced_draw_text(win, para, rct, halign, valign);
}
///////////////////////////////////////////////////////////
// TReport_link
///////////////////////////////////////////////////////////
void TReport_link::set(const char* field, const TString& var)
{
_fields.add(field, var, true);
}
const TString& TReport_link::get(const char* field) const
{
const TString* var = (const TString*)_fields.objptr(field);
return var != NULL ? *var : (const TString&)EMPTY_STRING;
}
void TReport_link::add_rect(const RCT& rct)
{
// Non memorizzo tutti i rettangoli del link, ma la loro unione
if (xvt_rect_is_empty(&_rct))
_rct = rct;
else
{
if (rct.left < _rct.left) _rct.left = rct.left;
if (rct.top < _rct.top) _rct.top = rct.top;
if (rct.right > _rct.right) _rct.right = rct.right;
if (rct.bottom > _rct.bottom) _rct.bottom = rct.bottom;
}
}
int TReport_link::hit_test(const PNT& p) const
{
if (p.v < _rct.top)
return -1;
if (p.v > _rct.bottom)
return +1;
if (p.h < _rct.left)
return -1;
if (p.h > _rct.right)
return +1;
return 0;
}
int TReport_link::compare(const TSortable& s) const
{
const TReport_link& lnk = (const TReport_link&)s;
int cmp = _rct.top - lnk._rct.top;
if (cmp == 0)
cmp = _rct.left - lnk._rct.left;
return cmp;
}
TReport_link::TReport_link(const char* table)
: _table(table)
{
xvt_rect_set_empty(&_rct);
}
///////////////////////////////////////////////////////////
// TPrint_preview_window
///////////////////////////////////////////////////////////
class TPrint_preview_window : public TField_window
{
TBook* _book;
word _page;
int _zoom;
bool _grid;
TAssoc_array _alinks;
TPointer_array _plinks;
protected:
void page_select();
void popup_menu(EVENT* ep);
const TReport_link* find_link(const PNT& pnt) const;
virtual void handler(WINDOW win, EVENT* ep);
virtual void update();
virtual bool on_key(KEY k);
void update_scroll_range();
void do_scroll(int kx, int ky);
public:
virtual PNT log2dev(long lx, long ly) const;
TAssoc_array& alinks() { return _alinks; }
TPointer_array& plinks() { return _plinks; }
TPrint_preview_window(int x, int y, int dx, int dy, WINDOW parent,
TWindowed_field* owner, TBook* book);
};
PNT TPrint_preview_window::log2dev(long lx, long ly) const
{
const TPoint res = _book->page_res();
PNT pnt;
pnt.h = short(lx * _zoom / res.x);
pnt.v = short(ly * _zoom / res.y);
const TPoint orig = origin();
pnt.h -= short(orig.x);
pnt.v -= short(orig.y);
return pnt;
}
void TPrint_preview_window::update_scroll_range()
{
const TPoint size = _book->page_size();
const TPoint res = _book->page_res();
PNT pnt;
pnt.h = short(size.x * _zoom / res.x);
pnt.v = short(size.y * _zoom / res.y);
RCT rct; xvt_vobj_get_client_rect(win(), &rct);
pnt.h -= rct.right; if (pnt.h < 0) pnt.h = 0;
pnt.v -= rct.bottom; if (pnt.v < 0) pnt.v = 0;
update_thumb(0, 0);
set_scroll_max(pnt.h, pnt.v);
}
void TPrint_preview_window::update()
{
clear(MASK_BACK_COLOR);
RCT rct; xvt_vobj_get_client_rect(win(), &rct);
const TPoint size = _book->page_size();
const PNT pag = log2dev(size.x, size.y);
if (pag.h < rct.right) rct.right = pag.h;
if (pag.v < rct.bottom) rct.bottom = pag.v;
hide_pen();
set_brush(COLOR_WHITE);
xvt_dwin_draw_rect(win(), &rct); // Disegna foglio bianco
if (_grid)
{
const TPoint res = _book->page_res();
const int lpi = _book->lpi();
for (int i = 1; lpi > 0; i++)
{
set_pen(i%lpi ? MAKE_COLOR(232,232,255) : MAKE_COLOR(255,192,255));
const short y = i * res.y / lpi;
if (y > size.y)
break;
line(0, y, (short)size.x, y);
}
const int cpi = _book->cpi();
for (int j = 1; cpi > 0; j++)
{
set_pen(j%10 ? MAKE_COLOR(232,232,255) : MAKE_COLOR(255,192,255));
const short x = j * res.x / cpi;
if (x > size.x)
break;
line(x, 0, x, (short)size.y);
}
}
_book->print_page(*this, _page);
TString80 str; str.format(FR("Pagina %u di %u"), _page, _book->pages());
statbar_set_title(TASK_WIN, str);
}
#define POPUP_FIRST 20883
#define POPUP_PREV 20884
#define POPUP_NEXT 20885
#define POPUP_SEARCH 20886
#define POPUP_LAST 20887
#define POPUP_ZOOMIN 20888
#define POPUP_ZOOMOUT 20889
#define POPUP_GRID 20890
void TPrint_preview_window::popup_menu(EVENT* ep)
{
MENU_ITEM menu[16]; // Stiamo larghi
memset(menu, 0, sizeof(menu));
menu[0].tag = POPUP_FIRST; menu[0].text = (char*)TR("Prima"); menu[0].enabled = _page > 1;
menu[1].tag = POPUP_PREV; menu[1].text = (char*)TR("Indietro"); menu[1].enabled = _page > 1;
menu[2].tag = POPUP_NEXT; menu[2].text = (char*)TR("Avanti"); menu[2].enabled = _page < _book->pages();
menu[3].tag = POPUP_LAST; menu[3].text = (char*)TR("Ultima"); menu[3].enabled = _page < _book->pages();
menu[4].tag = -1; menu[4].separator = true;
menu[5].tag = POPUP_ZOOMIN; menu[5].text = (char*)TR("Zoom +"); menu[5].enabled = _zoom < 300;
menu[6].tag = POPUP_ZOOMOUT; menu[6].text = (char*)TR("Zoom -"); menu[6].enabled = _zoom > 50;
menu[7].tag = -1; menu[7].separator = true;
menu[8].tag = POPUP_GRID; menu[8].text = (char*)TR("Griglia"); menu[8].enabled = true;
menu[8].checkable = true; menu[8].checked = _grid;
const PNT& p = ep->v.mouse.where;
xvt_menu_popup(menu, win(), p, XVT_POPUP_CENTER, 0);
}
void TPrint_preview_window::page_select()
{
TMask m("Ricerca", 1, 28, 4);
m.add_number(101, 0, "Pagina ", 1, 1, 4, "U").check_type(CHECK_REQUIRED);
m.add_button(DLG_OK, 0, "", -12, -1, 10, 2);
m.add_button(DLG_CANCEL, 0, "", -22, -1, 10, 2);
if (m.run())
{
_page = m.get_int(101);
if (_page < 1) _page = 1;
if (_page > _book->pages()) _page = _book->pages();
}
}
const TReport_link* TPrint_preview_window::find_link(const PNT& pnt) const
{
int primo = 0, ultimo = _plinks.last();
while (primo <= ultimo)
{
const int in_mezzo = (primo+ultimo)/2;
const TReport_link* lnk = (const TReport_link*)_plinks.objptr(in_mezzo);
const int cmp = lnk->hit_test(pnt);
if (cmp == 0)
return lnk;
if (cmp < 0)
ultimo = in_mezzo-1;
else
primo = in_mezzo+1;
}
return NULL;
}
void TPrint_preview_window::handler(WINDOW win, EVENT* ep)
{
switch (ep->type)
{
case E_MOUSE_MOVE:
if (find_link(ep->v.mouse.where) != NULL)
xvt_win_set_cursor(win, 8004); // Ditino
else
xvt_win_set_cursor(win, CURSOR_ARROW); // Freccia
break;
case E_MOUSE_DOWN:
if (ep->v.mouse.button == 0)
{
const TReport_link* lnk = find_link(ep->v.mouse.where);
if (lnk != NULL && _book != NULL)
_book->on_link(*lnk);
}
else
popup_menu(ep);
break;
case E_COMMAND:
{
bool processed = true;
switch(ep->v.cmd.tag)
{
case POPUP_FIRST :
processed = _page > 1;
if (processed) _page = 1;
break;
case POPUP_PREV :
processed = _page > 1;
if (processed) _page--;
break;
case POPUP_SEARCH : page_select(); break;
case POPUP_NEXT :
processed = _page < _book->pages();
if (processed) _page++;
break;
case POPUP_LAST :
processed = _page < _book->pages();
if (processed) _page = _book->pages();
break;
case POPUP_ZOOMIN : if (_zoom < 300) { _zoom += 10; update_scroll_range(); } break;
case POPUP_ZOOMOUT: if (_zoom > 50) { _zoom -= 10; update_scroll_range(); } break;
case POPUP_GRID : _grid = !_grid; break;
default:processed = false; break;
}
if (processed)
force_update();
}
break;
case E_HSCROLL:
case E_VSCROLL:
{
int kx = 0, ky = 0;
int& k = ep->type == E_HSCROLL ? kx : ky;
switch(ep->v.scroll.what)
{
case SC_PAGE_UP : k = -3; break;
case SC_LINE_UP : k = -1; break;
case SC_PAGE_DOWN: k = +3; break;
case SC_LINE_DOWN: k = +1; break;
default : TField_window::handler(win, ep); break;
}
if (k != 0)
do_scroll(kx, ky); break;
}
break;
default:
TField_window::handler(win, ep);
break;
}
}
void TPrint_preview_window::do_scroll(int kx, int ky)
{
const TPoint& r = range();
TPoint orig = origin();
orig.x += kx * r.x/8;
orig.y += ky * r.y/6;
if (orig.x < 0) orig.x = 0;
if (orig.x > r.x) orig.x = r.x;
if (orig.y < 0) orig.y = 0;
if (orig.y > r.y) orig.y = r.y;
if (orig != origin())
{
update_thumb(orig.x, orig.y);
force_update();
}
}
bool TPrint_preview_window::on_key(KEY k)
{
bool ok = true;
switch (k)
{
case '+' : dispatch_e_menu(win(), POPUP_ZOOMIN); break;
case '-' : dispatch_e_menu(win(), POPUP_ZOOMOUT); break;
case K_HOME :
case K_LHOME : dispatch_e_menu(win(), POPUP_FIRST); break;
case K_PREV : dispatch_e_menu(win(), POPUP_PREV); break;
case K_NEXT : dispatch_e_menu(win(), POPUP_NEXT); break;
case K_END:
case K_LEND : dispatch_e_menu(win(), POPUP_LAST); break;
case K_LEFT : do_scroll(-1, 0); break;
case K_RIGHT : do_scroll(+1, 0); break;
case K_UP : do_scroll(0, -1); break;
case K_DOWN : do_scroll(0, +1); break;
case 'G' :
case 'g' : dispatch_e_menu(win(), POPUP_GRID); break;
default : ok = TField_window::on_key(k); break;
};
return ok;
}
TPrint_preview_window::TPrint_preview_window(int x, int y, int dx, int dy, WINDOW parent,
TWindowed_field* owner, TBook* book)
: TField_window(x, y, dx, dy, parent, owner), _book(book), _page(1), _zoom(100), _grid(true)
{
_pixmap = true;
update_scroll_range();
}
///////////////////////////////////////////////////////////
// TPrint_preview_field
///////////////////////////////////////////////////////////
class TPrint_preview_field : public TWindowed_field
{
TBook* _book;
protected:
virtual TField_window* create_window(int x, int y, int dx, int dy, WINDOW parent);
public:
TPrint_preview_field(TMask* m, TBook* book) : TWindowed_field(m), _book(book) { }
};
TField_window* TPrint_preview_field::create_window(int x, int y, int dx, int dy, WINDOW parent)
{
return new TPrint_preview_window(x, y, dx, dy, parent, this, _book);
}
///////////////////////////////////////////////////////////
// TPreview_mask
///////////////////////////////////////////////////////////
class TPreview_mask : public TAutomask
{
TBook* _book;
TPrint_preview_field* _pvf;
protected:
virtual bool on_key(KEY k);
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
virtual TMask_field* parse_field(TScanner& scanner);
virtual void handler(WINDOW win, EVENT* ep);
public:
void export_text();
TPreview_mask(TBook* book);
};
bool TPreview_mask::on_key(KEY k)
{
switch (k)
{
case '+' :
case '-' :
case K_HOME :
case K_LHOME:
case K_LEFT :
case K_RIGHT:
case K_END :
case K_LEND :
case K_PREV :
case K_NEXT :
case 'G' :
case 'g' :
dispatch_e_char(_pvf->win().win(), k);
return true;
default:
break;
}
return TAutomask::on_key(k);
}
void TPreview_mask::handler(WINDOW win, EVENT* ep)
{
// Riflessione eventi di scroll
if (ep->type == E_HSCROLL || ep->type == E_VSCROLL)
::dispatch_event(_pvf->win().win(), *ep, false);
TAutomask::handler(win, ep);
}
void TPreview_mask::export_text()
{
TFilename n; n.temp(NULL, "txt");
if (_book->export_text(n))
xvt_sys_goto_url(n, "open");
}
bool TPreview_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
if (e == fe_button)
{
switch (o.dlg())
{
case DLG_FIRSTREC: dispatch_e_menu(_pvf->win().win(), POPUP_FIRST); break;
case DLG_PREVREC : dispatch_e_menu(_pvf->win().win(), POPUP_PREV); break;
case DLG_FINDREC : dispatch_e_menu(_pvf->win().win(), POPUP_SEARCH);break;
case DLG_NEXTREC : dispatch_e_menu(_pvf->win().win(), POPUP_NEXT); break;
case DLG_LASTREC : dispatch_e_menu(_pvf->win().win(), POPUP_LAST); break;
case DLG_EDIT : export_text(); break;
default: break;
}
}
return true;
}
TMask_field* TPreview_mask::parse_field(TScanner& scanner)
{
if (scanner.token().starts_with("PR"))
{
_pvf = new TPrint_preview_field(this, _book);
return _pvf;
}
return TAutomask::parse_field(scanner);
}
TPreview_mask::TPreview_mask(TBook* book) : _book(book)
{
read_mask("bagn008", 0, -1);
set_handlers();
int pos = id2pos(DLG_FINDREC);
if (pos >= 0 && id2pos(DLG_FIRSTREC) >= 0) //se e' un bottone pentapartito...
{
TButton_field& f_find = (TButton_field &)fld(pos);
RCT rct_base; f_find.get_rect(rct_base);
const int bwidth = (rct_base.right - rct_base.left);
const int bheight = (rct_base.bottom - rct_base.top);
if (bwidth > 3*bheight/2) // Controllo se ho gia' ridimensionato i bottoni in precedenza
{
int bx = bwidth / 3;
int by = bheight / 2;
RCT r = rct_base; r.left += bx-2; r.right -= bx-2;
f_find.set_rect(r); // Ridimensiona il bottone centrale di ricerca
bx += 5; by += 3; // Aggiusta dimensioni bottoni sussidiari
pos = id2pos(DLG_FIRSTREC);
if (pos >= 0)
{
r = rct_base; r.top = r.bottom - by; r.right = r.left + bx;
fld(pos).set_rect(r);
}
pos = id2pos(DLG_PREVREC);
if (pos >= 0)
{
r = rct_base; r.bottom = r.top + by; r.right = r.left + bx;
fld(pos).set_rect(r);
}
pos = id2pos(DLG_NEXTREC);
if (pos >= 0)
{
r = rct_base; r.bottom = r.top + by; r.left = r.right - bx;
fld(pos).set_rect(r);
}
pos = id2pos(DLG_LASTREC);
if (pos >= 0)
{
r = rct_base; r.top = r.bottom - by; r.left = r.right - bx;
fld(pos).set_rect(r);
}
}
}
}
///////////////////////////////////////////////////////////
// TWindow_printer
///////////////////////////////////////////////////////////
class TWindow_printer : public TWindow
{
public:
TWindow_printer(PRINT_RCD* rcd);
~TWindow_printer();
};
TWindow_printer::TWindow_printer(PRINT_RCD* rcd)
{
WINDOW prwin = xvt_print_create_win(rcd, (char*)(const char*)"Printing");
set_win(prwin);
_pixmap = true;
}
TWindow_printer::~TWindow_printer()
{
if (win() != NULL_WIN)
{
xvt_vobj_destroy(win());
set_win(NULL_WIN);
}
}
///////////////////////////////////////////////////////////
// Writing a page
///////////////////////////////////////////////////////////
TPoint TBook::page_size() const
{
return TPoint(_pw, _ph);
}
TPoint TBook::page_res() const
{
return TPoint(_phr, _pvr);
}
bool TBook::open_page()
{
if (_out == NULL)
_out = new ofstream(_file);
_page++;
_index.add_long(_out->tellp(), page()); // Scrive alla posizione 1 l'inizio di pagina 1
*_out << "<page number=" << page() << '>' << endl;
memset(&_tools, -1, sizeof(_tools));
_font.create("", 12, XVT_FA_ALL);
_horizontal_alignment = 'L';
_vertical_alignment = 'T';
_rect.reset();
_print_aborted = false;
_page_is_open = true;
return _page_is_open;
}
bool TBook::close_page()
{
if (!_page_is_open)
return false;
*_out << "</page number=" << page() << '>' << endl;
_pages++;
_page_is_open = false;
return true;
}
void TBook::set_font(const TReport_font& f)
{
if (f != _font)
{
_font = f;
*_out << "<font"
<< " name=\"" << f.name() << '"'
<< " size=" << f.size()
<< " style=" << f.style()
<< " />" << endl;
}
}
void TBook::define_frame(const TRectangle& rect)
{
if (rect != _rect)
{
_rect = rect;
*_out << "<frame"
<< " x=" << _rect.x << " y=" << _rect.y
<< " dx=" << _rect.width() << " dy=" << _rect.height()
<< " />" << endl;
}
}
void TBook::draw_text(const TRectangle& r, const char* txt)
{
const TFixed_string str(txt);
if (!str.blank())
{
define_frame(r);
*_out << "<text>" << endl << str << endl << "</text>" << endl;
}
}
void TBook::draw_book_pages(const TRectangle& r)
{
define_frame(r);
*_out << "<pages/>" << endl;
}
void TBook::set_pen(COLOR color, int width, PEN_STYLE style)
{
if (_tools.pen.color != color || _tools.pen.width != width || _tools.pen.style != style)
{
_tools.pen.color = color;
_tools.pen.width = width;
_tools.pen.style = style;
*_out << "<pen color=" << color
<< " width=" << width
<< " style=" << style << " />" << endl;
}
}
void TBook::set_brush(COLOR color, PAT_STYLE pattern)
{
if (_tools.brush.color != color || _tools.brush.pat != pattern)
{
_tools.brush.color = color;
_tools.brush.pat = pattern;
*_out << "<brush color=" << color << " pattern=" << pattern << " />" << endl;
}
}
void TBook::set_text_color(COLOR fore, COLOR back, bool opaque)
{
if (_tools.fore_color != fore || _tools.back_color != back || _tools.opaque_text != short(opaque))
{
_tools.fore_color = fore;
_tools.back_color = back;
_tools.opaque_text = opaque;
*_out << "<text_color fore=" << fore
<< " back=" << back
<< " opaque=" << opaque << " />" << endl;
}
}
void TBook::set_text_align(char halign, char valign)
{
if (_horizontal_alignment != halign || _vertical_alignment != valign)
{
_horizontal_alignment = halign;
_vertical_alignment = valign;
*_out << "<text_align horizontal=" << halign << " vertical=" << valign << " />" << endl;
}
}
void TBook::draw_rectangle(const TRectangle& r)
{
define_frame(r);
*_out << "<rectangle/>" << endl;
}
void TBook::draw_round_rectangle(const TRectangle& r, int radius)
{
define_frame(r);
*_out << "<rounded_rectangle radius=" << radius << " />" << endl;
}
void TBook::draw_ellipse(const TRectangle& r)
{
define_frame(r);
*_out << "<ellipse/>" << endl;
}
void TBook::draw_line(const TRectangle& r)
{
define_frame(r);
*_out << "<line/>" << endl;
}
void TBook::draw_link(const TRectangle& rect, const char* text, const char* link)
{
define_frame(rect);
*_out << "<a href=\"" << link << "\" >" << text << "</a>" << endl;
}
void TBook::draw_image(const TRectangle& rect, const char* name)
{
define_frame(rect);
*_out << "<image src=\"" << name << "\" />" << endl;
}
///////////////////////////////////////////////////////////
// Reading a page
///////////////////////////////////////////////////////////
bool get_xml_string(const TString& line, const char* attr, TString& value)
{
TString80 str; str << ' ' << attr << '=';
const int pos = line.find(str);
if (pos >= 0)
{
const int apicia = pos + strlen(attr) + 2;
if (line[apicia] == '"')
{
const int apicic = line.find('"', apicia+1);
if (apicic > apicia)
{
value = line.sub(apicia+1, apicic);
return true;
}
}
else
{
const int space = line.find(' ', apicia);
if (space > 0)
{
value = line.sub(apicia, space);
return true;
}
}
}
return false;
}
int get_xml_int(const TString& line, const char* attr, int def)
{
TString16 str;
if (get_xml_string(line, attr, str))
def = atoi(str);
return def;
}
bool TBook::print_page(TWindow& win, size_t page)
{
if (page <= 0 || page > pages())
return false;
const bool preview = win.win() != 883;
RCT visible;
if (preview)
{
xvt_vobj_get_client_rect(win.win(), &visible);
TPrint_preview_window& pw = (TPrint_preview_window&)win;
pw.alinks().destroy();
}
TString str(1024);
char* buffer = str.get_buffer();
const streampos pos = _index.get_long(page);
ifstream ifs(_file);
ifs.seekg(pos);
_rect.set(-1,-1,0,0); // Reset frame
RCT rct = { 0,0,0,0 };
_horizontal_alignment = 'L'; // Reset text alignment
_vertical_alignment = 'T';
while (!ifs.eof())
{
ifs.getline(buffer, str.size());
if (str.starts_with("</page"))
break;
if (str.starts_with("<a "))
{
if (preview && rct.bottom >= visible.top && rct.top <= visible.bottom)
{
TString link;
if (get_xml_string(str, "href", link))
{
TPrint_preview_window& pw = (TPrint_preview_window&)win;
TAssoc_array& links = pw.alinks();
TToken_string tok(link, '.');
TString80 table, field, key;
tok.get(0, table); tok.get(1, field);
key << table << ',' << _rect.y;
TReport_link* rl = (TReport_link*)links.objptr(key);
if (rl == NULL)
{
rl = new TReport_link(table);
links.add(key, rl);
}
const int inizio = str.find('>')+1;
const int fine = str.rfind('<');
const TString& stringona = str.sub(inizio, fine);
rl->set(field, stringona);
rl->add_rect(rct);
if (!stringona.blank() && rct.right > rct.left) // Possono esserci campi chiave nascosti
{
WINDOW w = win.win();
DRAW_CTOOLS dct;
xvt_dwin_get_draw_ctools(w, &dct);
XVT_FNTID oldfont = xvt_dwin_get_font(w);
XVT_FNTID newfont = xvt_font_create();
xvt_font_copy(newfont, oldfont, XVT_FA_ALL);
xvt_font_set_style(newfont, xvt_font_get_style(oldfont) | XVT_FS_UNDERLINE);
xvt_dwin_set_font(w, newfont);
win.set_color(COLOR_BLUE, dct.back_color);
advanced_draw_text(win, stringona, rct, _horizontal_alignment, _vertical_alignment);
win.set_color(dct.fore_color, dct.back_color);
xvt_dwin_set_font(w, oldfont);
}
}
}
continue;
}
if (str.starts_with("<brush "))
{
COLOR col = COLOR_BLACK;
PAT_STYLE pat = PAT_SOLID;
sscanf(str, "<brush color=%u pattern=%u />", &col, &pat);
if (pat <= PAT_HOLLOW || col == COLOR_WHITE)
win.hide_brush();
else
win.set_brush(col, pat);
continue;
}
if (str == "<ellipse/>")
{
xvt_dwin_draw_oval(win.win(), &rct);
continue;
}
if (str.starts_with("<frame "))
{
long x, y, dx, dy;
sscanf(str, "<frame x=%ld y=%ld dx=%ld dy=%ld />", &x, &y, &dx, &dy);
_rect.set(x, y, dx, dy);
win.log2dev(_rect, rct);
continue;
}
if (str.starts_with("<font "))
{
TString name = XVT_FFN_COURIER; get_xml_string(str, "name", name);
const int size = get_xml_int(str, "size", 12);
const XVT_FONT_STYLE_MASK style = get_xml_int(str, "style", 0);
TReport_font font; font.create(name, size, style);
if (win.win() == 883)
xvt_dwin_set_font(win.win(), font.get_xvt_font(win));
else
xvt_dwin_set_font(win.win(), font.get_preview_font(win, page_res()));
continue;
}
if (str.starts_with("<image "))
{
TString name; get_xml_string(str, "src", name);
TImage* img = _images.image(name);
if (img != NULL)
img->draw(win.win(), rct);
continue;
}
if (str == "<line/>")
{
PNT fr = { rct.top, rct.left };
PNT to = { rct.bottom, rct.right };
xvt_dwin_draw_set_pos(win.win(), fr);
xvt_dwin_draw_line(win.win(), to);
continue;
}
if (str == "<pages/>")
{
TString8 str; str.format("%u", pages());
advanced_draw_text(win, str, rct, _horizontal_alignment, _vertical_alignment);
continue;
}
if (str.starts_with("<pen "))
{
COLOR col = COLOR_BLACK;
int width = 0;
PEN_STYLE style = P_SOLID;
sscanf(str, "<pen color=%u width=%d style=%u />", &col, &width, &style);
if (width < 0)
win.hide_pen();
else
{
if (win.win() == 883)
win.set_pen(col, width * _phr / 72); // Converte width in 72' di pollice
else
win.set_pen(col, width);
}
continue;
}
if (str == "<rectangle/>")
{
xvt_dwin_draw_rect(win.win(), &rct);
continue;
}
if (str.starts_with("<rounded_rectangle"))
{
const int radius = get_xml_int(str, "radius", 0);
const TRectangle rr(0,0,radius,radius);
RCT re; win.log2dev(rr, re);
xvt_dwin_draw_roundrect(win.win(), &rct, re.right-re.left, re.bottom-re.top);
continue;
}
if (str == "<text>")
{
TString stringona;
while (!ifs.eof())
{
ifs.getline(buffer, str.size());
if (str == "</text>")
break;
if (stringona.not_empty())
stringona << '\n';
stringona << str;
}
advanced_draw_paragraph(win, stringona, rct, _horizontal_alignment, _vertical_alignment);
continue;
}
if (str.starts_with("<text_align "))
{
sscanf(str, "<text_align horizontal=%c vertical=%c />",
&_horizontal_alignment, &_vertical_alignment);
continue;
}
if (str.starts_with("<text_color"))
{
COLOR fore, back;
int opaque;
sscanf(str, "<text_color fore=%u back=%u opaque=%d />", &fore, &back, &opaque);
win.set_color(fore, back);
win.set_opaque_text(opaque != 0);
continue;
}
}
if (preview)
{
TPrint_preview_window& pw = (TPrint_preview_window&)win;
TAssoc_array& alinks = pw.alinks();
TPointer_array& plinks = pw.plinks();
plinks.destroy();
if (alinks.items() > 0)
{
FOR_EACH_ASSOC_OBJECT(alinks, h, key, l)
plinks.add((TReport_link*)l);
plinks.sort();
}
}
return true;
}
bool TBook::export_text(const TFilename& fname) const
{
TString str(1024);
char* buffer = str.get_buffer();
ifstream ifs(_file);
ofstream ofs(fname);
TString_array page;
int row, col, wid, hei;
const TPoint res = page_res();
while (!ifs.eof())
{
ifs.getline(buffer, str.size());
if (str.starts_with("<frame "))
{
long x, y, dx, dy;
sscanf(str, "<frame x=%ld y=%ld dx=%ld dy=%ld />", &x, &y, &dx, &dy);
row = y * lpi() / res.y;
col = x * cpi() / res.x;
wid = dx * cpi() / res.x;
hei = dy * lpi() / res.y;
} else
if (str == "<line/>")
{
if (hei == 0 && wid > 0)
{
if (page.objptr(row) == NULL)
page.add("", row);
TString& line = page.row(row);
for (int i = 0; i < wid; i++)
{
const int j = i+col;
if (j >= line.len())
line.overwrite("-", j);
else
{
if (line[j] == '|')
line[j] = '+';
else
{
if (line[j] == ' ')
line[j] = '-';
}
}
}
} else
if (hei > 0 && wid == 0)
{
for (int i = row; i < row+hei; i++)
{
if (page.objptr(i) == NULL)
page.add("", i);
TString& line = page.row(i);
if (line.len() <= col)
line.overwrite("|", col);
else
{
if (line[col] == '-')
line[col] = '+';
else
{
if (line[col] == ' ')
line[col] = '|';
}
}
}
}
}
if (str.starts_with("<page "))
{
page.destroy();
} else
if (str.starts_with("</page "))
{
const int last_row = page.last();
for (int i = 0; i <= last_row; i++)
{
const TString* line = (const TString*)page.objptr(i);
if (line != NULL)
ofs << *line;
ofs << endl;
}
} else
if (str == "<pages/>")
{
TString8 str; str.format("%u", pages());
TString& line = page.row(row);
switch (_horizontal_alignment)
{
case 'C': line.overwrite(str, col+(wid-str.len())/2); break;
case 'R': line.overwrite(str, col+wid-str.len()); break;
default : line.overwrite(str, col); break;
}
} else
if (str == "<text>")
{
TString stringona;
while (!ifs.eof())
{
ifs.getline(buffer, str.size());
if (str == "</text>")
break;
stringona << str << '\n';
}
stringona.rtrim();
TParagraph_string para(stringona, wid);
for (int i = 0; i < hei && i < para.items(); i++)
{
const int j = row+i;
if (page.objptr(j) == NULL)
page.add("", j);
str = para.get();
TString& line = page.row(j);
switch (_horizontal_alignment)
{
case 'C': line.overwrite(str, col+(wid-str.len())/2); break;
case 'R': line.overwrite(str, col+wid-str.len()); break;
default : line.overwrite(str, col); break;
}
}
} else
if (str.starts_with("<text_align "))
{
sscanf(str, "<text_align horizontal=%c vertical=%c />",
&_horizontal_alignment, &_vertical_alignment);
continue;
}
}
return true;
}
bool TBook::init()
{
_rcd = printer().get_printrcd();
if (!xvt_print_is_valid(_rcd))
return error_box(TR("Stampante non valida"));
xvt_app_escape (XVT_ESC_GET_PRINTER_INFO, _rcd, &_ph, &_pw, &_pvr, &_phr);
if (_pw <= 0 || _ph <= 0)
return error_box(TR("Dimensioni pagina NULLE"));
bool ok = true;
if (_pvr < 150 || _phr < 150)
{
ok = yesno_box(TR("Stampante obsoleta o non adeguatamente configurata:\n"
"Risoluzione %ldx%ld. Continuare ugualmente?"), _phr, _pvr);
}
return ok;
}
bool TBook::main_loop()
{
_print_aborted = true;
if (!init())
return false;
TWindow_printer win(_rcd);
if (!win.ok())
return false;
if (_pageto < _pagefrom)
_pageto = pages();
_print_aborted = false;
for (size_t c = 0; c < _copies && !_print_aborted; c++)
{
for (size_t page = _pagefrom; page <= _pageto; page++)
{
if (xvt_print_open_page(_rcd))
{
print_page(win, page);
xvt_print_close_page(_rcd);
}
else
{
_print_aborted = true;
break;
}
}
}
return !_print_aborted;
}
static BOOLEAN main_loop_callback(long jolly)
{
TBook* pp = (TBook*)jolly;
return pp->main_loop();
}
bool TBook::print(size_t pagefrom, size_t pageto, size_t copies)
{
if (pages() <= 0)
return false;
if (pagefrom == 0)
{
TPrinter& p = printer();
TMask msk("bagn003");
msk.set(F_PRINTER, p.printername());
msk.set(F_FORM, p.get_form_name());
msk.set(F_FONT, p.fontname());
msk.set(F_SIZE, p.get_char_size());
msk.set(F_ISGRAPHICS, p.isgraphics() ? "X" : "");
msk.set(F_FROMPAGE, 1);
msk.set(F_TOPAGE, pages());
msk.set(F_COPIES, 1);
if (msk.run() == K_ENTER)
{
_copies = msk.get_int(F_COPIES);
_pagefrom = msk.get_int(F_FROMPAGE);
_pageto = msk.get_int(F_TOPAGE);
}
else
return false;
}
else
{
_pagefrom = pagefrom;
_pageto = pageto;
_copies = copies;
}
xvt_print_start_thread(main_loop_callback, (long)this);
return true;
}
bool TBook::preview()
{
TPreview_mask msk(this);
const KEY k = msk.run();
if (k != K_QUIT)
print();
return true;
}
bool TBook::print_or_preview()
{
bool ok = true;
if (printer().printtype() == screenvis)
ok = preview();
else
ok = print();
return ok;
}
TBook::TBook(const char* name)
: _out(NULL), _is_temporary(false),
_pw(0), _ph(0), _pvr(0), _phr(0),
_pages(0), _page(0)
{
_file = name;
if (_file.blank())
{
_file.temp("rep");
_is_temporary = true;
}
}
TBook::~TBook()
{
if (_out != NULL)
{
_out->close();
delete _out;
if (_is_temporary)
xvt_fsys_removefile(_file);
}
}
///////////////////////////////////////////////////////////
// TReport_book
///////////////////////////////////////////////////////////
// Converte da coordinate logiche (1/100 caratteri) a coordinate fisiche
TPoint TReport_book::log2dev(const TPoint& ptlog) const
{
TPoint ptdev;
ptdev.x = (ptlog.x * _phr) / (100 * _report->cpi());
ptdev.y = (ptlog.y * _pvr) / (100 * _report->lpi());
return ptdev;
}
void TReport_book::define_frame(const TRectangle& r)
{
TPoint ptlog = r; ptlog += _delta;
TPoint szlog = r.size();
const TRectangle rect(log2dev(ptlog), log2dev(szlog));
TBook::define_frame(rect);
}
long TReport_book::print_section(char type, int level)
{
long h = 0;
TReport_section* rs = _report->find_section(type, level);
if (rs != NULL)
h = print_section(*rs);
return h;
}
bool TReport_book::open_page()
{
if (!TBook::open_page())
return false;
_report->set_page(++_rep_page, page());
_page_break_allowed = false;
_delta.reset();
TReport_section* page_background = _report->find_section('B', 0);
if (page_background != NULL)
{
_delta = page_background->pos();
print_section(*page_background);
_delta.reset();
}
if (_rep_page == 1)
_delta.y += print_section('H', 1);
TReport_section* page_head = _report->find_section('H', 0);
if (page_head != NULL && (_rep_page > 1 || !page_head->hidden_if_needed()))
{
_delta += page_head->pos();
_delta.y += print_section(*page_head);
_delta.x = 0;
}
return true;
}
bool TReport_book::close_page()
{
if (_page_is_open)
{
TReport_section* page_foot = _report->find_section('F', 0);
if (page_foot != NULL && (!_is_last_page || !page_foot->hidden_if_needed()))
{
_delta.x = page_foot->pos().x;
_delta.y = _logical_foot_pos;
print_section(*page_foot);
}
}
return TBook::close_page();
}
void TReport_book::reprint_group_headers()
{
const int max_group = _report->find_max_level('H');
for (int level = max_group; level >= 2; level--)
{
TReport_section& rs = _report->section('H', level);
if (rs.repeat_on_page())
{
const long height = rs.compute_size().y; // Compute size after the initilization script!
if (height > 0)
{
rs.print(*this);
_delta.y += height;
}
}
}
}
long TReport_book::print_section(TReport_section& rs)
{
if (_print_aborted)
return 0;
rs.load_fields();
// Non sono sicuro se vada prima di load_fields o dopo execute_prescript
if (rs.condition().not_empty())
{
TVariant var;
_report->evaluate(rs.condition(), var, _nullfld);
if (!var.as_bool())
return 0;
}
if (!rs.execute_prescript())
{
_print_aborted = true;
return 0;
}
const long height = rs.compute_size().y; // Compute size after the initilization script!
if (height > 0) // Has some visible fields
{
bool page_break = _page_break_allowed && rs.page_break();
if (!page_break)
{
long h = height;
if (rs.keep_with_next())
h += rs.report().section('B', 1).compute_size().y;
page_break = (_delta.y + h > _logical_foot_pos);
}
if (page_break && rs.level() > 0) // Avoid recursion
{
close_page();
open_page();
if (rs.type() == 'B')
reprint_group_headers();
}
if (_page_is_open)
rs.print(*this);
if (rs.level() > 0) // Ho stampato qualcosa che non sia lo sfondo!
_page_break_allowed = true;
}
if (!rs.execute_postscript())
_print_aborted = true;
return height;
}
bool TReport_book::init(TReport& rep)
{
if (!TBook::init())
return false;
_report = &rep;
const TPoint siz = page_size();
const TPoint res = page_res();
const double pollici_pagina_y = (double)siz.y / (double)res.y;
const double righe_pagina = pollici_pagina_y * _report->lpi();
_logical_page_height = long(righe_pagina*100.0);
const double pollici_pagina_x = (double)siz.x / (double)res.x;
const double colonne_pagina = pollici_pagina_x * _report->cpi();
_logical_page_width = long(colonne_pagina*100.0);
const TReport_section& footer = _report->section('F',0);
_logical_foot_pos = footer.pos().y;
if (_logical_foot_pos <= 0)
{
const long logical_footer_height = footer.compute_size().y;
_logical_foot_pos = _logical_page_height - logical_footer_height;
}
return true;
}
bool TReport_book::add(TReport& rep, bool progind)
{
if (!init(rep))
return false;
if (!_report->execute_prescript())
return false;
TRecordset* rex = _report->recordset();
if (rex == NULL || rex->items() <= 0)
return true;
TString msg = TR("Elaborazione report");
msg << ' ' << _report->filename();
TProgind* pi = NULL;
if (progind)
pi = new TProgind(rex->items(), msg, true, true);
TString_array oldgroup, newgroup;
const int max_group = _report->find_max_level('H');
if (max_group >= 2)
{
for (int g = 2; g <= max_group; g++)
oldgroup.add(EMPTY_STRING, g);
}
const int max_body = _report->find_max_level('B');
int last_body_height = 0;
_rep_page = 0; // Azzera numero di pagina relativo
_is_last_page = false;
open_page();
for (bool ok = rex->move_to(0); ok && !_print_aborted; ok = rex->move_next())
{
if (max_group >= 2) // Gestione raggruppamenti
{
int first_changed = 0;
TVariant var;
for (int g = 2; g <= max_group; g++)
{
const TString& expr = _report->section('H', g).grouped_by();
_report->evaluate(expr, var, _alfafld);
const TString& grp = var.as_string();
newgroup.add(grp, g);
if (newgroup.row(g) != oldgroup.row(g) || rex->current_row() == 0)
{
if (first_changed == 0)
first_changed = g;
}
}
if (first_changed)
{
oldgroup = newgroup;
if (_delta.x > 0) // Devo tornare a capo!
_delta.y += last_body_height;
_delta.x = 0;
if (rex->current_row() > 0)
{
for (int g = max_group; g >= first_changed ; g--)
_delta.y += print_section('F', g);
}
for (int g = first_changed; g <= max_group; g++)
_delta.y += print_section('H', g);
}
}
// Stampa di tutti i body
for (int b = 1; b <= max_body; b++)
{
const int dy = print_section('B', b);
int column_delta = 0;
// Cerco di vedere se e' possibile la stampa etichette
if (dy > 0)
{
const int dx = _report->section('B', b).size().x;
// Se dx > 0 ho una sezione a dimensione fissa
if (dx > 0 && _delta.x+2*dx <= _logical_page_width)
{
column_delta = dx;
last_body_height = dy;
}
}
if (column_delta > 0)
_delta.x += column_delta;
else
{
_delta.x = 0;
_delta.y += dy;
last_body_height = 0; // Non servirebbe strettamente
}
}
if (pi != NULL)
{
pi->addstatus(1);
if (pi->iscancelled())
_print_aborted = true;
}
}
if (!_print_aborted)
{
// Devo stampare tutte le code degli eventuali raggrupamenti
for (int g = max_group; g >= 2 ; g--)
_delta.y += print_section('F', g);
TReport_section* fl = _report->find_section('F',1);
if (fl != NULL) // Gestione footer last (se esite)
{
const int fy = fl->pos().y;
if (fy > 0) // Ha una coordinata y imposta
{
if (fy < _delta.y) // Sono gia' andato oltre quindi salto pagina
{
close_page();
open_page();
}
_delta.x = 0;
_delta.y = fy;
// Azzero temporaneamente le dimensioni del footer per evitare salti pagina
const int lfp = _logical_foot_pos;
_logical_foot_pos = _logical_page_height;
print_section(*fl);
_logical_foot_pos = lfp;
}
else
print_section(*fl); // Stampa normale
}
_is_last_page = true;
close_page();
_report->execute_postscript();
}
if (pi != NULL)
delete pi;
return !_print_aborted;
}
int TReport_book::lpi() const
{
if (_report != NULL)
return _report->lpi();
return TBook::lpi();
}
int TReport_book::cpi() const
{
if (_report != NULL)
return _report->cpi();
return TBook::cpi();
}
bool TReport_book::print(size_t pagefrom, size_t pageto, size_t copies)
{
if (pages() <= 0)
return false;
if (pagefrom <= 0)
{
TPrinter& p = printer();
TMask msk("bagn003");
msk.set(F_PRINTER, p.printername());
if (_report != NULL)
{
msk.set(F_FORM, _report->filename());
msk.set(F_FONT, _report->font().name());
msk.set(F_SIZE, _report->font().size());
}
msk.set(F_ISGRAPHICS, p.isgraphics() ? "X" : "");
msk.set(F_FROMPAGE, 1);
msk.set(F_TOPAGE, page());
msk.set(F_COPIES, 1);
if (msk.run() == K_ENTER)
{
copies = msk.get_int(F_COPIES);
pagefrom = msk.get_int(F_FROMPAGE);
pageto = msk.get_int(F_TOPAGE);
}
else
return false;
}
return TBook::print(pagefrom, pageto, copies);
}
bool TReport_book::on_link(const TReport_link& lnk)
{
bool ok = false;
if (_report != NULL)
ok = _report->on_link(lnk);
return ok;
}
TReport_book::TReport_book(const char* name)
: TBook(name), _report(NULL)
{
}