guy 3e25e35ae6 Patch level : 10.0
Files correlati     : ba8
Ricompilazione Demo : [ ]
Commento            :

Riassunto	 0001600: Dopo la stampa di un report in orizz ritorna in visual con il foglio in vert.
Faccio l'anteprima di un report creato con orientamento foglio orrizzontale fisso, dopo aver stampato ritorna in visualizzazione con l'orientamento del foglio impostato sulla stampante (normalmente in verticale)


git-svn-id: svn://10.65.10.50/trunk@20331 c028cbd2-c16b-5b4b-a496-9718f37d4682
2010-04-13 14:30:29 +00:00

2998 lines
75 KiB
C++
Executable File

#include <applicat.h>
#include <automask.h>
#include <colors.h>
#include <config.h>
#include <defmask.h>
#include <diction.h>
#include <dongle.h>
#include <execp.h>
#include <modaut.h>
#include <printer.h>
#include <progind.h>
#include <reprint.h>
#include <spotlite.h>
#include <statbar.h>
#include <urldefid.h>
#include <utility.h>
#include <xvtility.h>
#include <bagn003.h>
static bool _print_aborted = false;
///////////////////////////////////////////////////////////
// Utility
///////////////////////////////////////////////////////////
static void advanced_draw_justified_text_line(WINDOW w, const char* text, short x, short y, short dx)
{
TString256 txt(text); txt.rtrim();
int spaces = 0;
for (int s = 0; txt[s]; s++)
if (isspace(txt[s])) spaces++;
// Il testo e' giustificabile se ha degli spazi ed occupa meno della riga
if (spaces > 0)
{
const int tw = xvt_dwin_get_text_width(w, txt, -1);
if (tw < dx)
{
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(w, parola, -1);
if (last_word) // ultima parola
kx = x+dx-lw;
xvt_dwin_draw_text(w, int(kx+0.5), y, parola, -1);
kx += lw + kspc;
start = i+1;
}
}
else
xvt_dwin_draw_text(w, x, y, txt, -1); // Stringa che deborda dalla riga
}
else
xvt_dwin_draw_text(w, x, y, txt, -1); // Stringa senza spazi
}
void advanced_draw_text_line(WINDOW w, 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(w, text, -1);
switch (halign)
{
case 'C': x += (dx - tw)/2; break;
case 'R': x = r.right-tw-1; break;
default : break;
}
}
// Text Height
int leading, ascent, descent;
xvt_dwin_get_font_metrics(w, &leading, &ascent, &descent);
switch (valign)
{
case 'C': y -= (dy - ascent)/2; break;
case 'T': y = r.top + leading + ascent; break;
default : y -= descent; break;
}
bool can_draw = true;
RCT orig; xvt_dwin_get_clip(w, &orig);
bool restore_clip = !xvt_rect_is_empty(&orig);
if (restore_clip)
{
RCT clipper;
can_draw = xvt_rect_intersect(&clipper, &orig, &r) != 0;
if (can_draw)
xvt_dwin_set_clip(w, &clipper);
else
restore_clip = false;
}
else
xvt_dwin_set_clip(w, &r);
if (can_draw)
{
if (halign == 'J')
advanced_draw_justified_text_line(w, text, x, y, dx);
else
xvt_dwin_draw_text(w, x, y, text, -1);
if (restore_clip)
xvt_dwin_set_clip(w, &orig);
}
}
bool finisce_per_punto(const TString& str)
{
bool yes = false;
const int len = str.len();
if (len > 0)
{
const char last = str[len-1];
yes = strchr(".!?:", last) != NULL;
}
return yes;
}
void advanced_draw_paragraph(WINDOW win, const TString_array& para, const RCT& rct,
char halign, char valign, int default_10row_height)
{
const int rows = para.items();
if (rows > 1) // Devo scrivere piu' righe?
{
int leading, ascent, descent;
xvt_dwin_get_font_metrics(win, &leading, &ascent, &descent);
int ky10 = (leading + ascent + descent) * 10;
// Aggiusta l'altezza di una riga standard, se necessario
if (ky10 < default_10row_height && ky10 > 75*default_10row_height/100)
ky10 = default_10row_height;
const int rct_height = rct.bottom - rct.top;
int ybase = rct.top;
switch (valign)
{
case 'C': ybase += (rct_height - (rows * ky10) / 10) / 2; break;
case 'B': ybase += rct_height - (rows * ky10) / 10; break;
default : break;
}
const int lastop = rct.bottom - ky10/20; // Ultima y valida = base del rettangolo MENO mezza riga
for (int row = 0; row < rows; row++)
{
const int top = ybase + (ky10 * row) / 10;
if (top < lastop)
{
const TString& line = para.row(row);
if (line.full())
{
RCT rctline = rct;
rctline.top = top;
rctline.bottom = ybase + (ky10 * (row+1)) / 10; // top + ky10 / 10;
char ha = halign;
if (ha == 'J' && (row == rows-1 || finisce_per_punto(line)))
ha = 'L'; // Le righe finali non vanno giustificate
advanced_draw_text_line(win, line, rctline, ha, 'T');
}
}
else
break;
}
}
else
{
if (halign == 'J') halign = 'L'; // Le righe isolate non vanno giustificate
advanced_draw_text_line(win, para.row(0), 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;
void draw_page(int pg);
virtual long handler(WINDOW win, EVENT* ep);
virtual void update();
virtual bool on_key(KEY k);
void do_scroll(int kx, int ky);
public:
virtual PNT log2dev(long lx, long ly) const;
void update_scroll_range();
short book2pix(int size) 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);
virtual ~TPrint_preview_window();
};
short TPrint_preview_window::book2pix(int sz) const
{
return short(sz * _zoom / BOOKDPI);
}
PNT TPrint_preview_window::log2dev(long lx, long ly) const
{
PNT pnt = { book2pix(ly), book2pix(lx) };
const TPoint orig = origin();
pnt.h -= short(orig.x);
pnt.v -= short(orig.y);
return pnt;
}
void TPrint_preview_window::update_scroll_range()
{
update_thumb(0, 0); // Azzero origine
const TSize pag = _book->page_size();
const PNT pnt = log2dev(pag.x, pag.y);
RCT rct; xvt_vobj_get_client_rect(win(), &rct);
const PNT siz = { rct.bottom, rct.right };
set_scroll_max(pnt.h, pnt.v);
set_thumb_size(siz.h, siz.v);
}
void TPrint_preview_window::draw_page(int pg)
{
RCT rct; xvt_vobj_get_client_rect(win(), &rct);
const TSize size = _book->page_size();
const PNT pag = log2dev(size.x, size.y);
const PNT ori = log2dev(0, 0);
if (ori.h > 0) rct.left = ori.h;
if (ori.v > 0) rct.top = ori.v;
if (pag.h < rct.right) rct.right = pag.h;
if (pag.v < rct.bottom) rct.bottom = pag.v;
hide_pen(); // Disegna foglio bianco
set_brush(COLOR_WHITE);
xvt_dwin_draw_rect(win(), &rct);
set_pen(COLOR_GRAY); // Disegna ombra grigia
const PNT poly[4] = { {rct.bottom,rct.left+1}, {rct.bottom,rct.right+1}, {rct.top+1,rct.right+1}, {0,0} };
xvt_dwin_draw_polyline(win(), poly, 3); // Disegna ombra
if (_grid)
{
const TSize res = _book->page_res();
const int lpi = _book->lpi();
for (int i = 1; lpi > 0; i++)
{
set_pen(i%lpi ? XVT_MAKE_COLOR(232,232,255) : XVT_MAKE_COLOR(255,192,255));
const short y = short(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 ? XVT_MAKE_COLOR(232,232,255) : XVT_MAKE_COLOR(255,192,255));
const short x = short(j * res.x / cpi);
if (x > size.x)
break;
line(x, 0, x, (short)size.y);
}
}
_book->print_page(*this, pg);
}
void TPrint_preview_window::update()
{
clear(MASK_BACK_COLOR);
draw_page(_page);
size_t last_page = _page;
const size_t pages = _book->pages();
if (_page < pages)
{
const TPoint o = origin();
set_origin(0, 0);
const TSize size = _book->page_size();
const PNT pag = log2dev(size.x, size.y);
RCT rct; xvt_vobj_get_client_rect(win(), &rct);
const int nh = rct.right / (pag.h+2), nv = rct.bottom / (pag.v+2);
if (nh > 1 || nv > 1)
{
for (int v = 0; v < nv; v++)
{
for (int h = 0; h < nh; h++)
{
if ((h > 0 || v > 0) && last_page < pages)
{
set_origin(o.x - h*rct.right/nh, o.y - v*rct.bottom/nv);
draw_page(++last_page);
}
}
}
}
set_origin(o.x, o.y);
}
TString80 str;
if (last_page > _page)
str.format(FR("Pagine da %u a %u di %u"), _page, last_page, pages);
else
str.format(FR("Pagina %u di %u"), _page, pages);
statbar_set_title(TASK_WIN, str);
TMask& m = owner().mask();
m.enable(DLG_FIRSTREC, _page > 1);
m.enable(DLG_PREVREC, _page > 1);
m.enable(DLG_FINDREC, pages > 1);
m.enable(DLG_NEXTREC, _page < pages);
m.enable(DLG_LASTREC, _page < pages);
}
#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 > 35;
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(TR("Ricerca"), 1, 28, 4);
m.add_number(101, 0, PR("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;
}
long TPrint_preview_window::handler(WINDOW win, EVENT* ep)
{
static PNT ptPan;
switch (ep->type)
{
case E_MOUSE_MOVE:
switch (ep->v.mouse.button)
{
case 2:
{
const PNT& ptCur = ep->v.mouse.where;
TPoint orig = origin();
orig.x += ptPan.h - ptCur.h;
orig.y += ptPan.v - ptCur.v;
update_thumb(orig.x, orig.y);
force_update();
ptPan = ptCur;
}
break;
default:
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;
}
break;
case E_MOUSE_DOWN:
switch (ep->v.mouse.button)
{
case 0:
{
const TReport_link* lnk = find_link(ep->v.mouse.where);
if (lnk != NULL && _book != NULL)
_book->on_link(*lnk);
}
break;
case 1:
popup_menu(ep);
break;
case 2:
ptPan = ep->v.mouse.where;
break;
default:
break;
}
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 > 35) { _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:
return TField_window::handler(win, ep);
}
return 0L;
}
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 :
if (k > K_CTRL)
dispatch_e_char(parent(), k); // Gestione acceleratori
else
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(false)
{
_pixmap = true;
_grid = ini_get_bool(CONFIG_GUI, "Preview", "Grid");
}
TPrint_preview_window::~TPrint_preview_window()
{
ini_set_string(CONFIG_GUI, "Preview", "Grid", _grid ? "X" : "");
}
///////////////////////////////////////////////////////////
// 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 long handler(WINDOW win, EVENT* ep);
public:
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' :
if (_pvf != NULL)
return _pvf->win().on_key(k);
break;
default:
break;
}
return TAutomask::on_key(k);
}
long TPreview_mask::handler(WINDOW win, EVENT* ep)
{
// Riflessione eventi di scroll
switch (ep->type)
{
case E_HSCROLL:
case E_VSCROLL:
if (_pvf != NULL)
::dispatch_event(_pvf->win().win(), *ep, false);
break;
case E_SIZE:
if (_pvf != NULL)
{
TPrint_preview_window& ppw = (TPrint_preview_window&)_pvf->win();
xvt_vobj_maximize(ppw.win());
ppw.update_scroll_range();
}
break;
default:
return TAutomask::handler(win, ep);
}
return 0L;
}
bool TPreview_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
if (e == fe_button)
{
short idm = 0;
switch (o.dlg())
{
case DLG_FIRSTREC: idm = POPUP_FIRST; break;
case DLG_PREVREC : idm = POPUP_PREV; break;
case DLG_FINDREC : idm = POPUP_SEARCH; break;
case DLG_NEXTREC : idm = POPUP_NEXT; break;
case DLG_LASTREC : idm = POPUP_LAST; break;
default: break;
}
if (idm > 0 && _pvf != NULL)
dispatch_e_menu(_pvf->win().win(), idm);
}
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), _pvf(NULL)
{
read_mask("bagn008", 0, -1);
set_handlers();
}
///////////////////////////////////////////////////////////
// TWindow_printer
///////////////////////////////////////////////////////////
class TWindow_printer : public TWindow
{
long _pvr, _phr;
long _ph, _pw;
protected:
bool is_ok() const { return win() != NULL_WIN; }
virtual PNT log2dev(long x, long y) const;
public:
bool print_doc(const TFilename& name);
TWindow_printer(PRINT_RCD* rcd, const char* title);
~TWindow_printer();
};
// Converte da coordinate espresse in 1/720 di pollice a coordinate fisiche su carta
PNT TWindow_printer::log2dev(long x, long y) const
{
PNT ptdev;
ptdev.h = short((x * _phr) / BOOKDPI);
ptdev.v = short((y * _pvr) / BOOKDPI);
#ifdef DBG
if(ptdev.h < 0 || ptdev.h >= _pw)
xvtil_statbar_set("Coordinata X errata");
if(ptdev.v < 0 || ptdev.v >= _ph)
xvtil_statbar_set("Coordinata Y errata");
#endif
return ptdev;
}
bool TWindow_printer::print_doc(const TFilename& name)
{
bool ok = name.exist();
if (ok)
{
const bool printing = is_ok();
if (printing)
xvt_print_suspend_thread();
ok = xvt_sys_goto_url(name, "print") != 0;
if (printing)
xvt_print_restart_thread();
}
return ok;
}
TWindow_printer::TWindow_printer(PRINT_RCD* rcd, const char* title)
{
WINDOW prwin = xvt_print_create_win(rcd, title);
set_win(prwin);
_pixmap = true;
xvt_app_escape (XVT_ESC_GET_PRINTER_INFO, rcd, &_ph, &_pw, &_pvr, &_phr);
}
TWindow_printer::~TWindow_printer()
{
if (is_ok())
{
xvt_vobj_destroy(win());
set_win(NULL_WIN);
}
}
///////////////////////////////////////////////////////////
// Writing a page
///////////////////////////////////////////////////////////
// Converte da coordinate logiche (1/100 caratteri) a coordinate di stampa
TPoint TBook::log2dev(const TReport_pnt& ptlog) const
{
TPoint ptdev;
ptdev.x = (ptlog.x * BOOKDPI) / (100 * cpi());
ptdev.y = (ptlog.y * BOOKDPI) / (100 * lpi());
return ptdev;
}
TRectangle TBook::log2dev(const TReport_rct& rctlog) const
{
const TReport_pnt& lp0 = rctlog;
TReport_pnt lp1 = lp0; lp1 += rctlog.size();
const TPoint p0 = log2dev(lp0);
const TPoint p1 = log2dev(lp1);
return TRectangle(p0, p1-p0);
}
PNT TBook::log2pix(const TReport_pnt& ptlog) const
{
const TPoint ptdev = log2dev(ptlog);
return _printwin->log2dev(ptdev.x, ptdev.y);
}
// Converte da coordinate di stampa (1/720 di pollice) in pixel
short TBook::book2pix(int t) const
{
const PNT pnt = _printwin->log2dev(t, 0);
return pnt.h;
}
int TBook::compute_text_frame(const TString& tmp, const TReport_font& font, TReport_rct& rect, TString_array& para) const
{
// Calcola la larghezza massima e l'altezza di 10 righe
// const TReport_rct rect_riga(0,0,rect.width(),1000);
// const PNT size = log2pix(rect_riga.size());
// const int max_row_width = size.h;
// const int def_10row_height = size.v;
const PNT p0 = log2pix(TReport_pnt(0,0));
const PNT p1 = log2pix(TReport_pnt(rect.width(),1000));
const int max_row_width = p1.h-p0.h;
const int def_10row_height = p1.v-p0.v;
if (max_row_width < 100)
return 0; // Con un rettangolo quasi vuoto, si combina poco di buono!
WINDOW w = _printwin->win();
CHECK(w == PRINTER_WIN, "Finestra di stampa non valida");
xvt_dwin_set_font(w, font.get_xvt_font(*_printwin));
int leading, ascent, descent;
xvt_dwin_get_font_metrics(w, &leading, &ascent, &descent);
int ky10 = (leading + ascent + descent) * 10;
// Aggiusta l'altezza di 10 righe standard, se necessario
if (ky10 < def_10row_height && ky10 > 75*def_10row_height/100)
ky10 = def_10row_height;
TToken_string p(tmp, '\n');
FOR_EACH_TOKEN(p, line)
para.add(line);
for (int i = 0; i < para.items(); i++)
{
TString& row = para.row(i);
int pix = xvt_dwin_get_text_width(w, row, -1);
if (pix > max_row_width)
{
int good_len = 0;
const int first_space = row.find(' ');
if (first_space >= 0)
{
// Linea con almeno uno spazio
for (int i = first_space; row[i]; i++) if (row[i] == ' ')
{
pix = xvt_dwin_get_text_width(w, row, i);
if (pix <= max_row_width)
good_len = i;
else
break;
}
}
if (good_len == 0) // Puo' succedere per linee senza spazi o con parole lunghissime
{
for (good_len = row.len() * max_row_width / w + 1; good_len > 0; good_len--)
{
const int pix = xvt_dwin_get_text_width(w, row, good_len);
if (pix < max_row_width)
break;
}
}
TString next_row = row.mid(good_len);
next_row.ltrim();
para.insert(next_row, i+1);
row.cut(good_len);
}
}
int h = para.items() * ky10 * 100 / def_10row_height;
const int resto = h % 100;
if (resto != 0)
h += 100-resto;
rect.set_height(h);
return ky10;
}
TSize TBook::page_size() const
{
if (_page_size.x <= 0 || _page_size.y <= 0) // Valori nulli: mi invento un A4
{
TSize pag = page_res();
pag.x *= 8; pag.y *= 11;
return pag;
}
return _page_size;
}
TSize TBook::page_res() const
{ return TSize(BOOKDPI, BOOKDPI); }
bool TBook::open_page()
{
if (_out == NULL) // Sto per scrivere la prima pagina
{
_out = new ofstream(_file);
_max_frame.x = _max_frame.y = 0;
}
_page++;
_index.add_long((long)_out->tellp(), page()); // Scrive alla posizione 1 l'inizio di pagina 1
*_out << "<page number=" << page() << '>' << endl;
memset(&_tools, 0, sizeof(_tools));
_font.create("", 12, XVT_FA_ALL);
_horizontal_alignment = 'L';
_vertical_alignment = 'T';
_rect.set(-1,-1,0,0);
_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;
// Ignora campi malamente copia/incollati a coordinate negative!
if (_rect.x > 0 && _rect.y > 0)
{
if (_rect.right() > _max_frame.x)
_max_frame.x = _rect.right();
if (_rect.bottom() > _max_frame.y)
_max_frame.y = _rect.bottom();
}
}
}
void TBook::define_frame(const TReport_rct& rr)
{
const TRectangle rb = log2dev(rr); // Converto rr da coordinate logiche a rb a 720 DPI
define_frame(rb); // Salvo le coordinate a 720 DPI
}
void TBook::set_clip(long top, long bottom)
{
if (bottom >= top)
{
const TReport_rct rect(0, top, logical_page_width(), bottom-top);
define_frame(rect);
*_out << "<clip>" << endl;
}
else
*_out << "</clip>" << endl;
}
void TBook::draw_text(const TReport_rct& r, const char* txt, const char* section)
{
if (txt && *txt)
{
const TFixed_string str(txt);
if (str.full())
{
define_frame(r);
*_out << "<text owner=" << section << ">" << endl
<< str << endl << "</text>" << endl;
}
}
}
void TBook::draw_text(const TReport_rct& r, const TString_array& txt, const char* section)
{
if (!txt.empty())
{
define_frame(r);
*_out << "<text owner=" << section << ">" << endl;
for (int i = 0; i < txt.items(); i++)
{
const char* line = txt.row(i);
*_out << line << endl;
}
*_out << "</text>" << endl;
}
}
void TBook::draw_book_pages(const TReport_rct& 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, int shade_angle)
{
if (_tools.brush.color != color || _tools.brush.pat != pattern || shade_angle != _shade_angle)
{
_tools.brush.color = color;
_tools.brush.pat = pattern;
_shade_angle = shade_angle;
*_out << "<brush color=" << color << " pattern=" << pattern;
if (pattern == PAT_SPECIAL)
*_out << " shade_angle=" << shade_angle;
*_out << " />" << 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 TReport_rct& r)
{
define_frame(r);
*_out << "<rectangle/>" << endl;
}
void TBook::draw_round_rectangle(const TReport_rct& r, int radius)
{
define_frame(r);
*_out << "<rounded_rectangle radius=" << radius << " />" << endl;
}
void TBook::draw_ellipse(const TReport_rct& r)
{
define_frame(r);
*_out << "<ellipse/>" << endl;
}
void TBook::draw_line(const TReport_rct& r)
{
define_frame(r);
*_out << "<line/>" << endl;
}
void TBook::draw_link(const TReport_rct& rect, const char* text, const char* link)
{
define_frame(rect);
*_out << "<a href=\"" << link << "\" >" << text << "</a>" << endl;
}
void TBook::draw_image(const TReport_rct& rect, const char* name)
{
define_frame(rect);
*_out << "<image src=\"" << name << "\" />" << endl;
}
void TBook::add_doc(const TString& name)
{
if (name.full())
{
TBook::open_page();
*_out << "<doc url=\"" << name << "\" />"<< endl;
TBook::close_page();
}
}
///////////////////////////////////////////////////////////
// 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;
}
void TBook::print_doc(TWindow& win, const TFilename& name)
{
const bool print = win.win() == PRINTER_WIN;
if (print)
{
TWindow_printer& wp = (TWindow_printer&)win;
wp.print_doc(name);
}
else
{
const TSize ps = page_size();
TRectangle rect(TPoint(0,0), ps);
RCT page; win.log2dev(rect, page);
advanced_draw_text_line(win.win(), name, page, 'C', 'T');
TString8 ext = name.ext(); ext.lower();
if (ext == "bmp" || ext == "gif" || ext == "jpg" || ext == "jpeg" || ext == "png")
{
const TImage* img = _images.image(name);
if (img != NULL)
{
const TSize pr = page_res();
rect.deflate(pr.x/2, pr.y/2);
win.log2dev(rect, page);
const double sx = double(page.right) / double(img->width());
const double sy = double(page.bottom) / double(img->height());
const double s = sx < sy ? sx : sy;
const int w = int(s * img->width());
const int h = int(s * img->height());
RCT rct;
rct.left = (page.right+page.left-w)/2; rct.right = rct.left + w;
rct.top = (page.bottom+page.top-h)/2; rct.bottom = rct.top + h;
img->draw(win.win(), rct);
}
}
}
}
bool TBook::print_page(TWindow& win, size_t page)
{
if (page <= 0 || page > pages())
return false;
WINDOW w = win.win();
const bool preview = w != PRINTER_WIN;
int shade_angle = 0;
RCT visible;
if (preview)
{
xvt_vobj_get_client_rect(w, &visible);
TPrint_preview_window& pw = (TPrint_preview_window&)win;
pw.alinks().destroy();
}
else
xvt_rect_set_null(&visible);
TToken_string str(1024, '=');
TString_array paragrafo; // Testo completo di un campo
// Calcolo altezza riga standard
const TRectangle rect_riga(0,0,BOOKDPI*10/cpi(),BOOKDPI*10/lpi());
RCT rct_riga; win.log2dev(rect_riga, rct_riga);
const int default_10row_height = rct_riga.bottom - rct_riga.top;
const streampos pos = _index.get_long(page);
ifstream ifs(_file);
ifs.seekg(pos);
_rect.set(-1,-1,0,0); // Reset logical frame (1/720 coords)
RCT rct = { 0,0,0,0 }; // Physical frame (pixel coords)
_horizontal_alignment = 'L'; // Reset text alignment
_vertical_alignment = 'T';
bool page_is_open = false; // Stato attuale della pagina della stampante
while (!ifs.eof())
{
ifs.getline(str.get_buffer(), str.size());
if (str.starts_with("</page"))
break;
if (str.starts_with("<page "))
{
// Non apro ora la pagina sulla stampante perche' potrei incontrare un allegato
continue;
}
if (str.starts_with("<doc")) // Stampa il documento allegato senza aprire la pagina su carta
{
TFilename name; get_xml_string(str, "url", name);
print_doc(win, name);
continue;
}
// Per i comandi successivi serve una pagina aperta!
if (!page_is_open && !preview)
{
page_is_open = xvt_print_open_page(_rcd) != 0;
if (!page_is_open)
return false;
}
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.full() && rct.right > rct.left) // Possono esserci campi chiave nascosti
{
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_line(w, stringona, rct, _horizontal_alignment, _vertical_alignment);
win.set_color(dct.fore_color, dct.back_color);
xvt_dwin_set_font(w, oldfont);
xvt_font_destroy(oldfont);
xvt_font_destroy(newfont);
}
}
}
continue;
}
if (str.starts_with("<brush "))
{
// <brush color=%u pattern=%u shade_angle=%d />
const COLOR col = str.get_long(1);
const PAT_STYLE pat = (PAT_STYLE)str.get_long();
if (pat <= PAT_HOLLOW)
win.hide_brush();
else
win.set_brush(col, pat);
shade_angle = (pat == PAT_SPECIAL) ? str.get_int() : 0;
continue;
}
if (str.starts_with("<clip"))
{
xvt_dwin_set_clip(w, &rct);
continue;
} else
if (str.starts_with("</clip"))
{
xvt_dwin_set_clip(w, NULL);
continue;
} else
if (str == "<ellipse/>")
{
xvt_dwin_draw_oval(w, &rct);
continue;
}
if (str.starts_with("<frame "))
{
// <frame x=ld y=%ld dx=%ld dy=%ld />
const long x = str.get_long(1);
const long y = str.get_long();
const long dx= str.get_long();
const long dy= str.get_long();
_rect.set(x, y, dx, dy); // Rettangolo in 1/720 di pollice
win.log2dev(_rect, rct); // Rettangolo in pixel su carta
continue;
}
if (str.starts_with("<font "))
{
TString80 name = DEFAULT_FONT_NAME; 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 (preview)
xvt_dwin_set_font(w, font.get_preview_font(win, page_res()));
else
xvt_dwin_set_font(w, font.get_xvt_font(win));
continue;
}
if (str.starts_with("<image "))
{
TFilename name; get_xml_string(str, "src", name);
TImage* img = _images.image(name);
if (img != NULL)
{
if (is_pdf())
{
name.custom_path();
xvt_dwin_draw_image_on_pdf(w, name, &rct);
}
else
img->draw(w, rct);
}
continue;
}
if (str == "<line/>")
{
const PNT fr = { rct.top, rct.left };
const PNT to = { rct.bottom, rct.right };
xvt_dwin_draw_set_pos(w, fr);
xvt_dwin_draw_line(w, to);
continue;
}
if (str == "<pages/>")
{
TString8 str; str.format("%u", pages());
advanced_draw_text_line(w, str, rct, _horizontal_alignment, _vertical_alignment);
continue;
}
if (str.starts_with("<pen "))
{
// <pen color=%u width=%d style=%u />
COLOR col = str.get_long(1);
int width = str.get_int();
PEN_STYLE style = (PEN_STYLE)str.get_int();
if (width < 0)
win.hide_pen();
else
{
double t = 0;
if (preview)
{
const TPrint_preview_window& pw = (const TPrint_preview_window&)win;
t = pw.book2pix(width ? 100*width : 50)/10.0;
if (t < 1.0) // Sfuma le linee sottili in anteprima
col = blend_colors(col, COLOR_WHITE, t);
}
else
{
t = book2pix(width ? 10*width : 5); // width e' in 1/72 di pollice
}
const int thickness = int(t+0.5); // Arrotonda all'unita' piu' vicina
win.set_pen(col, thickness);
}
continue;
}
if (str == "<rectangle/>")
{
DRAW_CTOOLS ct; xvt_dwin_get_draw_ctools(w, &ct);
if (ct.brush.pat == PAT_SPECIAL)
{
if (shade_angle >= 0)
xvt_dwin_draw_gradient_linear(w, &rct, ct.back_color, ct.brush.color, shade_angle);
else
xvt_dwin_draw_gradient_circular(w, &rct, ct.back_color, ct.brush.color, NULL);
if (ct.pen.style != PAT_HOLLOW)
{
win.hide_brush();
xvt_dwin_draw_rect(w, &rct);
}
}
else
xvt_dwin_draw_rect(w, &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);
const int rad = (re.right-re.left) * lpi() / (cpi() * 2);
xvt_dwin_draw_roundrect(w, &rct, rad, rad);
continue;
}
if (str.starts_with("<text ")) // <text owner=B1>
{
paragrafo.destroy();
while (!ifs.eof())
{
ifs.getline(str.get_buffer(), str.size());
if (str == "</text>")
break;
paragrafo.add(str);
}
advanced_draw_paragraph(win.win(), paragrafo, rct,
_horizontal_alignment, _vertical_alignment, default_10row_height);
continue;
}
if (str.starts_with("<text_align "))
{
// <text_align horizontal=%c vertical=%c />
_horizontal_alignment = str.get_char(1);
_vertical_alignment = str.get_char();
continue;
}
if (str.starts_with("<text_color"))
{
// <text_color fore=%u back=%u opaque=%d />
const COLOR fore = str.get_long(1);
const COLOR back = str.get_long();
const int opaque = str.get_int();
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();
}
}
else
{
if (page_is_open)
xvt_print_close_page(_rcd);
}
return true;
}
bool TBook::export_text(TFilename& fname, bool signature)
{
if (fname.ends_with(".pdf", true))
return export_pdf(fname, signature);
if (fname.ends_with(".xls", true))
return export_excel(fname, signature);
TToken_string str(1024, '=');
ifstream ifs(_file);
ofstream ofs(fname);
TString_array page;
int row, col, wid, hei;
const TSize res = page_res();
while (!ifs.eof())
{
ifs.getline(str.get_buffer(), str.size());
if (str.starts_with("<frame "))
{
// <frame x=%ld y=%ld dx=%ld dy=%ld />
const long x = str.get_long(1);
const long y = str.get_long();
const long dx= str.get_long();
const long dy= str.get_long();
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.starts_with("<text ")) // <text owner=B1>
{
TString stringona;
while (!ifs.eof())
{
ifs.getline(str.get_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 "))
{
// <text_align horizontal=%c vertical=%c />
_horizontal_alignment = str.get_char(1);
_vertical_alignment = str.get_char();
}
}
ofs.close();
if (signature && main_app().has_module(FDAUT))
{
char outfile[_MAX_PATH] = "";
if (xvt_sign_file(fname, outfile))
fname = outfile;
}
return true;
}
static void reformat_excel(TString& str)
{
str.trim();
if (str.not_empty())
{
bool is_number = true;
bool is_mig = false;
bool is_dec = false;
for (int i = 0; str[i]; i++)
{
if (strchr("0123456789.,", str[i]) != NULL)
{
if (str[i] == '.') is_mig = true;
if (str[i] == ',') is_dec = true;
}
else
{
is_number = false;
break;
}
}
if (is_number && (is_dec || is_mig))
{
if (is_mig)
str.strip(".");
if (is_dec)
str.replace(',', '.');
const real n = str;
str = n.stringe();
}
}
}
bool TBook::export_excel(TFilename& fname, bool signature)
{
TTabulator tab;
int row = 0, col = 0, wid = 0;
TToken_string str(1024, '=');
const TSize res = page_res();
if (tab.empty()) // dummy test
{
ifstream ifs(_file);
while (!ifs.eof())
{
ifs.getline(str.get_buffer(), str.size());
if (str.starts_with("<frame "))
{
// <frame x=%ld y=%ld dx=%ld dy=%ld />
const long x = str.get_long(1);
const long y = str.get_long();
const long w = str.get_long();
row = y * lpi() / res.y;
col = x * cpi() / res.x;
wid = w * cpi() / res.x;
} else
if (str.starts_with("<text owner="))
{
// <text owner=B1>
const char* section = str.get(1);
if ((section[0] == 'B'||section[0]=='F') && section[1]>'0')
tab.add_field(col, wid);
// Raggiunge fine del testo
while (str != "</text>" && !ifs.eof())
ifs.getline(str.get_buffer(), str.size());
} else
if (str.starts_with("</page"))
break;
}
tab.sort();
}
if (!tab.empty())
{
TString_array page;
ifstream ifs(_file);
ofstream ofs(fname);
short pageno = 0;
while (!ifs.eof())
{
ifs.getline(str.get_buffer(), str.size());
if (str.starts_with("<frame "))
{
const long x = str.get_long(1);
const long y = str.get_long();
const long w = str.get_long();
row = y * lpi() / res.y;
col = x * cpi() / res.x;
wid = w * cpi() / res.x;
} else
if (str.starts_with("<text "))
{
const char* section = str.get(1);
bool do_export = section[1] > '0';
if (!do_export)
{
switch (section[0])
{
case 'H': do_export = (pageno == 1); break; // Stampa gli header solo sulla prima pagina
default : break;
}
}
while (!ifs.eof())
{
ifs.getline(str.get_buffer(), str.size());
if (str == "</text>")
break;
if (do_export && str.full())
{
const int pos = tab.find_column(col, wid);
if (pos >= 0)
{
TToken_string* line = (TToken_string*)page.objptr(row);
if (line == NULL)
{
line = new TToken_string(256,'\t');
page.add(line, row);
}
reformat_excel(str);
line->add(str, pos);
}
}
}
} else
if (str.starts_with("<page"))
{
pageno = str.get_int(1);
} else
if (str.starts_with("</page"))
{
FOR_EACH_ARRAY_ROW(page, i, line) if (line->full())
{
ofs << *line << endl; // Stampo e...
line->cut(0); // ... svuoto
}
}
}
}
if (signature && main_app().has_module(FDAUT))
{
char outfile[_MAX_PATH] = "";
if (xvt_sign_file(fname, outfile))
fname = outfile;
}
return true;
}
bool TBook::init()
{
if (is_pdf())
{
int size;
_rcd = xvt_print_create_by_name(&size, XVT_PDF_PRINTER_NAME);
}
else
_rcd = printer().get_printrcd();
if (!xvt_print_is_valid(_rcd))
return error_box(TR("Stampante non valida"));
long ph, pw, pvr, phr;
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"));
if (pvr <= 0 || phr <= 0)
return error_box(TR("Risoluzione stampante NULLA"));
if (_page_size.x > 0 && (_page_size.x > _page_size.y) != (pw > ph)) // Orientamento incongruente
{
xvt_app_escape (XVT_ESC_SET_PRINTER_INFO, _rcd, &pw, &ph, NULL, NULL); // Scambio dimensioni
xvt_app_escape (XVT_ESC_GET_PRINTER_INFO, _rcd, &ph, &pw, &pvr, &phr); // Rileggo dimensioni e risoluzione
}
_page_size.y = ph * BOOKDPI / pvr;
_page_size.x = pw * BOOKDPI / phr;
if (_printwin != NULL)
delete _printwin;
_printwin = new TWindow_printer(_rcd, _pdf_file);
return _printwin->win() != NULL_WIN;
}
void TBook::split_file(int colonne)
{
TProgind pi(pages(), TR("Rigenerazione pagine"), true, true);
TFilename temp; temp.temp();
ofstream out(temp);
TPointer_array index;
close_output(); // Chiudo file di stampa eventualmente aperto
ifstream ifs(_file); // Apro file di stampa da splittare
TToken_string str(1024, '=');
for (unsigned int page = 1; page <= pages(); page++)
{
if (!pi.setstatus(page))
break;
const streampos pos = _index.get_long(page);
for (int c = 0; c < colonne; c++)
{
const TRectangle rct_page(c*_page_size.x, 0, _page_size.x, _page_size.y);
ifs.seekg(pos);
while (!ifs.eof())
{
ifs.getline(str.get_buffer(), str.size());
if (str.starts_with("<page "))
{
const int p = (page-1)*colonne+1+c;
index.add_long((long)out.tellp(), p);
str.format("<page number=%d>", p);
} else
if (str.starts_with("<frame "))
{
// <frame x=%ld y=%ld dx=%ld dy=%ld />
const long x = str.get_long(1);
const long y = str.get_long();
const long dx= str.get_long();
const long dy= str.get_long();
str.format("<frame x=%ld y=%ld dx=%ld dy=%ld />", x-rct_page.x, y, dx, dy);
} else
if (str.starts_with("</page "))
{
str.format("</page number=%d>", index.last());
}
out << str << endl;
if (str.starts_with("</page "))
break;
}
}
}
out.close();
// Sostituisce il file di stampa con quello splittato ed aggiorna l'indice delle pagine
fcopy(temp, _file);
xvt_fsys_remove_file(temp);
_index = index;
_pages = _index.last();
}
void TBook::close_output()
{
if (_out != NULL)
{
_out->close();
delete _out;
}
_out = NULL;
}
void TBook::join_file(int pps)
{
TProgind pi(pages(), TR("Rigenerazione pagine"), true, true);
TFilename temp; temp.temp();
ofstream out(temp);
close_output(); // Chiudo file di stampa eventualmente aperto
ifstream ifs(_file); // Apro file di stampa da splittare
_index.destroy(); // Distruggo il vecchio indice delle pagine che poi ricostruisco
_pages = (_pages - 1) / pps + 1; // Ricalcolo in nuovo numero di pagine totali
int in_page = 1;
int out_page = 0;
int off_page = 0;
TToken_string str(1024, '=');
while (!ifs.eof())
{
ifs.getline(str.get_buffer(), str.size());
if (str.starts_with("<page "))
{
// <page number=%d />
in_page = str.get_int(1);
const int sub = ((in_page - 1) % pps);
off_page = sub * logical_page_height() / pps;
if (sub == 0)
{
out_page = (in_page - 1) / pps + 1;
_index.add_long((long)out.tellp(), out_page);
str.format("<page number=%d>", out_page);
}
else
{
// E' utile resettare l'allineamento dei testi :-)
str = "<text_align horizontal=L vertical=T />";
}
} else
if (str.starts_with("<frame ") && off_page > 0)
{
// <frame x=ld y=%ld dx=%ld dy=%ld />
const long x = str.get_long(1);
const long y = str.get_long();
const long dx= str.get_long();
const long dy= str.get_long();
str.format("<frame x=%ld y=%ld dx=%ld dy=%ld />", x, y+off_page, dx, dy);
} else
if (str.starts_with("</page "))
{
if (out_page % pps == 0)
{
str.format("</page number=%d>", out_page);
out_page = 0;
}
else
continue;
}
out << str << endl;
}
if (out_page != 0) // Non ho ancora scritto l'ultimo fine pagina
{
str.format("</page number=%d>", out_page);
out << str << endl;
}
out.close();
// Sostituisce il file di stampa con quello joinato
fcopy(temp, _file);
xvt_fsys_remove_file(temp);
}
bool TBook::can_split(int pages) const
{
return yesno_box(FR("Si desidera suddividere le pagine su %d fogli"), pages);
}
bool TBook::can_merge(int pages) const
{
return yesno_box(FR("Si desidera raggruppare %d pagine per foglio"), pages);
}
bool TBook::split_file_if_needed()
{
if (_max_frame.x > 100 && _max_frame.y > 100) // Evita calcolo splitting se possibile
{
const TSize sheet = page_size();
const int spp = _max_frame.x > sheet.x ? (_max_frame.x+sheet.x-1) / sheet.x : 1;
if (spp > 1 && can_split(spp)) // Sheets per page
{
split_file(spp);
}
else
{
const int pps = (_max_frame.y > 100 && pages() > 1) ? sheet.y / _max_frame.y : 1;
if (pps > 1 && can_merge(pps))
join_file(pps);
}
_max_frame.x = _max_frame.y = 0; // Impedisce ulteriore splitting
}
return true;
}
bool TBook::main_loop()
{
_print_aborted = !init();
if (!_print_aborted)
{
if (_pageto < _pagefrom)
_pageto = pages();
for (word copy = 0; copy < _copies && !_print_aborted; copy++)
{
for (size_t page = _pagefrom; page <= _pageto && !_print_aborted; page++)
_print_aborted = !print_page(*_printwin, page);
}
}
if (is_pdf())
{
xvt_print_destroy(_rcd);
_rcd = NULL;
_pdf_file.cut(0);
}
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, word copies)
{
if (pages() <= 0)
return false;
TPrinter& p = printer();
if (pagefrom == 0)
{
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_LINES, p.get_lines_per_inch());
msk.set(F_ORIENT, p.is_portrait() ? 1 : 2);
msk.set(F_ISGRAPHICS, p.isgraphics());
msk.set(F_FROMPAGE, 1);
msk.set(F_TOPAGE, pages());
msk.set(F_COPIES, 1);
if (msk.run() == K_ENTER)
{
_copies = max(msk.get_int(F_COPIES), 1);
_pagefrom = msk.get_int(F_FROMPAGE);
_pageto = msk.get_int(F_TOPAGE);
}
else
return false;
}
else
{
_pagefrom = pagefrom;
_pageto = pageto;
_copies = max(copies, 1);
}
bool ok = false;
if (p.printtype() == acrobatprinter)
{
TFilename f; f.temp(NULL, "pdf");
_pdf_file = f;
ok = xvt_print_start_thread(main_loop_callback, (long)this) != 0;
if (ok && fsize(f) > 0)
printer().acrobatically_print_pdf(f);
f.fremove();
}
else
{
_pdf_file.cut(0);
ok = xvt_print_start_thread(main_loop_callback, (long)this) != 0;
}
return ok;
}
bool TBook::export_pdf(TFilename& filename, bool signature)
{
bool ok = (pages() > 0) && main_app().has_module(RSAUT); // Controllo paranoico dei permessi
if (ok)
{
// Evita problemi di aggiornamento del pdf: deve sempre rigeneralo!
if (filename.exist() && !filename.fremove())
return error_box(FR("Impossibile riscrivere %s"), (const char*)filename);
_pdf_file = filename;
_pagefrom = 1;
_pageto = 0;
_copies = 1;
ok = xvt_print_start_thread(main_loop_callback, (long)this) != 0;
if (ok)
ok = fsize(filename) > 0;
if (ok && signature && main_app().has_module(FDAUT)) // Controllo paranoico dei permessi
{
char outfile[_MAX_PATH] = "";
if (xvt_sign_file(filename, outfile) && filename != outfile)
{
filename.fremove(); // Sbatto via il documento originale non firmato
filename = outfile;
}
}
}
return ok;
}
bool TBook::esporta()
{
if (pages() <= 0)
return false;
split_file_if_needed();
TFilename fname;
const KEY key = spotlite_ask_name(fname);
bool ok = isalpha(key) != 0;
const bool signature = key >= 'a';
switch (key)
{
case 'A':
case 'a':
ok = archive(NULL, signature);
break;
case 'E':
case 'e':
ok = export_text(fname, signature);
if (ok)
xvt_sys_goto_url(fname, "open");
break;
case 'M':
case 'm':
ok = send_mail(fname, signature);
break;
case 'P':
case 'p':
ok = export_pdf(fname, signature);
if (ok)
xvt_sys_goto_url(fname, "open");
break;
case 'X':
case 'x':
ok = export_excel(fname, signature);
if (ok)
xvt_sys_goto_url(fname, "open");
break;
default:
break;
}
return ok;
}
bool TBook::archive(const char* repname, bool signature)
{
TFilename pdf;
bool ok = spotlite_generate_name(repname, pdf);
if (ok)
{
ok = export_pdf(pdf, signature);
if (ok)
spotlite_notify(pdf);
}
return ok;
}
bool TBook::send_mail(TFilename& file, bool signature)
{
bool ok = export_pdf(file, signature);
if (ok)
ok = spotlite_send_mail(file);
return ok;
}
bool TBook::preview()
{
split_file_if_needed();
TPreview_mask msk(this);
// gestione anteprima di stampa;se si ha l'anteprima,una volta lanciata la maschera di stampa, si torna
// all'anteprima e non alla maschera del programma (decisivo per stampe con elaborazione lunga)
bool go_on = true;
while (go_on)
{
const KEY k = msk.run();
switch (k)
{
case K_QUIT: go_on = false; break;
case K_SAVE: esporta(); break;
default : print(); break;
}
}
return true;
}
bool TBook::print_or_preview()
{
bool ok = true;
switch (printer().printtype())
{
case screenvis: ok = preview(); break;
case exportprinter:
{
TFilename f = printer().get_export_file();
ok = export_text(f, NULL);
if (ok)
xvt_sys_goto_url(f, "open");
}
break;
case acrobatprinter:
{
TFilename f; f.tempdir(); f.add("tmp.pdf");
if (export_pdf(f, false))
printer().acrobatically_print_pdf(f);
}
break;
default: ok = print(); break;
}
return ok;
}
TBook::TBook(const char* name)
: _out(NULL), _is_temporary(false), _max_frame(0,0),
_pages(0), _page(0), _rcd(NULL), _printwin(NULL), _page_is_open(false)
{
_file = name;
if (_file.blank())
{
_file.temp("rep", "rap");
_is_temporary = true;
}
}
TBook::~TBook()
{
close_output();
if (_is_temporary)
xvt_fsys_remove_file(_file);
if (_printwin != NULL)
delete _printwin;
}
///////////////////////////////////////////////////////////
// TPrintind
///////////////////////////////////////////////////////////
class TPrintind : public TProgind
{
TArray _modules;
protected:
virtual void update_bar();
virtual void get_txt_rct(RCT& r) const;
public:
TPrintind(long n, const char* msg);
};
void TPrintind::get_txt_rct(RCT& r) const
{
TProgind::get_txt_rct(r);
r.right -= 48; // Lascia posto all'animazione
}
void TPrintind::update_bar()
{
TProgind::update_bar();
const int m = _modules.items();
if (m > 0) // come dire ADVANCED_GRAPHICS
{
const int n = _status * 100 / _max;
const TImage& img = (const TImage&)_modules[n%m];
RCT r; get_bar_rct(r);
img.draw(win(), r.right - img.width(), r.top - img.height() - 2);
}
}
TPrintind::TPrintind(long n, const char* msg) : TProgind(n, msg, true, true)
{
if (ADVANCED_GRAPHICS)
{
for (int i = 0; i < 4; i++)
{
TImage* img = new TImage(BMP_MODULE1 + i);
img->convert_transparent_color(MASK_BACK_COLOR);
_modules.add(img);
}
}
}
///////////////////////////////////////////////////////////
// TReport_book
///////////////////////////////////////////////////////////
void TReport_book::define_frame(const TReport_rct& rr)
{
TReport_rct ro(rr); ro += _delta; // Applico offset al rettangolo logico
TBook::define_frame(ro); // Salvo le coordinate a 720 DPI
}
long TReport_book::print_section(char type, int level)
{
long h = -3; // Hidden
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)
{
const TReport_pnt& pos = page_background->pos();
_delta.x = pos.x; _delta.y = pos.y;
print_section(*page_background);
_delta.reset();
}
if (_rep_page == 1)
{
const long height = print_section('H', 1);
if (height > 0)
_delta.y += height;
}
TReport_section* page_head = _report->find_section('H', 0);
if (page_head != NULL && (_rep_page > 1 || !page_head->hidden_if_needed()))
{
const TReport_pnt& pos = page_head->pos();
_delta.x += pos.x; _delta.y += pos.y;
const long height = print_section(*page_head);
if (height > 0)
{
_delta.y += height;
_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 TReport_section& rs)
{
int max_group = _report->find_max_level('H');
if (rs.type() == 'H' && rs.level() <= max_group)
max_group = rs.level()-1;
for (int level = 2; level <= max_group; 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;
}
}
}
if (rs.level() > 10) // E' una sottosezione ?
{
TPointer_array headers; // Elenco degli header di sottosezione che devo stampare
for (int level = rs.level(); level > 10; level /= 10)
{
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)
headers.add(rs);
}
}
for (int i = headers.last(); i >= 0; i--) // Stampo in ordine livello
{
TReport_section& rs = (TReport_section&)headers[i];
const long height = rs.compute_size().y;
rs.print(*this);
_delta.y += height;
}
}
}
// Stampa una sezione e ne ritorna l'altezza.
// In caso di problemi particolari torna un'altezza negativa:
// -1 Abort
// -2 Condizione di stampa non verificata
// -3 Nascosta
long TReport_book::print_section(TReport_section& rs)
{
if (_print_aborted)
return -1;
rs.load_fields();
rs.init_dynamic_heights(*this);
// Non sono sicuro se vada prima di load_fields o dopo execute_prescript
if (rs.condition().full())
{
TVariant var;
_report->evaluate(rs.condition(), var, _alfafld);
if (!var.as_bool())
return -2;
}
if (!rs.execute_prescript(*this))
{
_print_aborted = true;
return -1;
}
if (rs.hidden())
{
if (!rs.execute_postscript()) // Faccio ugualmente i post-script
_print_aborted = true;
return -3;
}
const long height = rs.compute_size().y; // Compute size after the initilization script!
if (height > 0) // Has some visible fields
{
long reprint_from = 0; // Posizione di stampa per sezione interrotte a meta'
bool page_break = _page_break_allowed && rs.page_break(); // Salto pagina "forzato"
if (!page_break && rs.level() > 0) // Controlla se il salto pagina e' "necessario"
{
long h = height;
if (rs.keep_with_next()) // Devo mantenermi con la prossima sezione
{
char next_type = 'B'; // Spesso la prossima sezione e' body 1
int next_level = 1;
if (rs.type() == 'H') // Tento di essere piu' preciso con gli headers
{
const int maxlev = rs.report().find_max_level('H');
if (rs.level() < maxlev)
{
next_type = 'H';
next_level = rs.level()+1;
h += 100; // Bonus per il body successivo all'header successivo
}
}
const TReport_section& next_section = rs.report().section(next_type, next_level);
if (next_section.page_break())
h += _page_size.y;
else
h += next_section.compute_size().y;
}
const long space_left = (_logical_foot_pos - _delta.y)/100*100; // Calcola spazio rimasto
page_break = h > space_left; // Controlla se e' sufficiente
// Controllo se la sezione puo' essere stampata su due pagine
if (page_break && space_left > 100 && rs.can_be_broken())
{
reprint_from = space_left;
rs.print_clipped(*this, 0, reprint_from);
}
}
if (page_break)
{
close_page();
open_page();
reprint_group_headers(rs);
}
if (_page_is_open)
{
if (reprint_from > 0)
{
_delta.y -= reprint_from;
rs.print_clipped(*this, reprint_from, height);
}
else
rs.print(*this);
}
if (rs.level() > 0 && (rs.type() != 'H' || rs.level() > 1)) // Ho stampato qualcosa che non fosse lo sfondo!
_page_break_allowed = true;
}
if (!rs.execute_postscript())
{
_print_aborted = true;
return -1;
}
return height;
}
bool TReport_book::init(TReport& rep)
{
TPrinter& pr = printer();
bool save_profile = rep.save_last_printer();
if (save_profile && !pr.manual_setup())
{
const TString profile = rep.filename().name();
const TString& rep_printer = ini_get_string(CONFIG_STAMPE, profile, "Name");
const TString& cur_printer = pr.printername();
if (rep_printer.full() && rep_printer != cur_printer)
{
pr.read_configuration(profile); // Uso la stampante preferita dal report
save_profile = false;
}
}
// Controlla orientamento della carta prima di inizializzare
const int report_orientation = rep.orientation();
if (report_orientation > 0)
{
pr.set_landscape_orientation(report_orientation == 2);
// I parametri verranno riletti dalla TBook::init()
}
if (save_profile)
{
const TString profile = rep.filename().name();
pr.save_configuration(profile);
}
if (!TBook::init())
return false;
_report = &rep;
if (rep.use_printer_font())
rep.load_printer_font();
const TSize siz = page_size();
const TSize res = page_res();
const double pollici_pagina_y = (double)siz.y / (double)res.y;
const double righe_pagina = pollici_pagina_y * 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 * 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;
}
void TReport_book::print_subsections(int father)
{
for (int i = 1; i <= 9 && !_print_aborted; i++)
{
const int level = father*10+i;
TReport_section* rs = _report->find_section('B', level);
if (rs == NULL)
break;
TRecordset* rex = rs->recordset();
if (rex != NULL)
{
rex->requery();
if (rex->items() > 0)
{
long height = print_section('H', level);
if (height > 0)
_delta.y += height;
for (bool ok = rex->move_to(0); ok && !_print_aborted; ok = rex->move_next())
{
height = print_section('B', level);
if (height >= 0)
{
_delta.y += height;
print_subsections(level);
}
}
height = print_section('F', level);
if (height > 0)
_delta.y += height;
}
}
}
}
void TReport_book::add_doc(const TString& name)
{
if (name.ends_with(".rep", true)) // Tratto a parte i report!
{
TReport* eminem = new TReport;
if (eminem->load(name))
{
TReport* rep = _report; // Salvo variabile globale
if (rep->use_mask())
{
TFilename msk = rep->filename().name();
msk.ext("msk");
if (msk.custom_path())
{
TMask m(msk);
rep->report2mask(m);
eminem->mask2report(m);
}
}
add(*eminem, true);
_report = rep; // Ripristino variabile globale
}
delete eminem;
}
else
TBook::add_doc(name);
}
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)
return true;
rex->requery();
const TRecnotype rex_items = rex->items();
if (rex_items <= 0)
return true;
TString msg; msg << TR("Elaborazione report ") << _report->filename();
TProgind* pi = NULL;
if (progind && rex_items > 1)
pi = new TPrintind(rex_items, msg);
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 = rep.last_printed_page(); // Azzera numero di pagina relativo
_is_last_page = false;
bool ok = rex->move_first();
open_page();
for (; 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--)
{
const long height = print_section('F', g);
if (height > 0)
_delta.y += height;
}
}
for (int g = first_changed; g <= max_group; g++)
{
const long height = print_section('H', g);
if (height > 0)
_delta.y += height;
}
}
}
// Stampa di tutti i body
for (int b = 1; b <= max_body; b++)
{
const int dy = print_section('B', b);
if (dy > 0) // Ho stampato fisicamente qualcosa
{
// Cerco di vedere se e' possibile la stampa etichette
int column_delta = 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 (dy >= 0)
{
// Stampa eventuali sottosezioni
print_subsections(b);
}
}
if (pi != NULL)
{
if (!pi->addstatus(1))
_print_aborted = true;
}
}
if (!_print_aborted)
{
// Devo stampare tutte le code degli eventuali raggrupamenti
for (int g = max_group; g >= 2 ; g--)
{
const long height = print_section('F', g);
if (height > 0)
_delta.y += height;
}
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 (!_print_aborted)
{
const TString_array& all = _report->allegates();
for (int a = 0; a < all.items(); a++)
{
TFilename name = all.row(a);
if (name.find('#') >= 0) // Se puo' essere un'espressione
{
TVariant var;
if (_report->evaluate(name, var, _alfafld))
name = var.as_string();
}
add_doc(name);
}
}
}
if (pi != NULL)
delete pi;
return !_print_aborted;
}
int TReport_book::lpi() const
{
if (_report != NULL)
return _report->print_lpi();
return TBook::lpi();
}
int TReport_book::cpi() const
{
if (_report != NULL)
return _report->print_cpi();
return TBook::cpi();
}
bool TReport_book::can_split(int pages) const
{
if (_report != NULL)
return _report->page_split_allowed();
return TBook::can_split(pages);
}
bool TReport_book::can_merge(int pages) const
{
if (_report != NULL)
return _report->page_merge_allowed();
return TBook::can_merge(pages);
}
bool TReport_book::print(size_t pagefrom, size_t pageto, word copies)
{
if (pages() <= 0)
return false;
split_file_if_needed();
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->print_font().name());
msk.set(F_SIZE, _report->print_font().size());
}
else
{
msk.set(F_FONT, p.fontname());
msk.set(F_SIZE, p.get_char_size());
}
msk.set(F_LINES, lpi());
msk.set(F_ORIENT, p.is_portrait() ? 1 : 2);
msk.set(F_ISGRAPHICS, p.isgraphics());
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;
}
return TBook::print(pagefrom, pageto, copies);
}
bool TReport_book::archive(const char* repname, bool signature)
{
TFilename n = repname;
if (n.blank() && _report != NULL)
{
n = _report->filename().name();
n.ext("");
}
return TBook::archive(n, signature);
}
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)
{ }