#include #include #include #include #include #include #include #include #include #include #include "ba8201.h" #include "ba8300.h" #include /////////////////////////////////////////////////////////// // TXVT_font /////////////////////////////////////////////////////////// class TXVT_font : public TObject { public: XVT_FNTID _fontid; void create(const TString& name, int size, XVT_FONT_STYLE_MASK style); void destroy(); TXVT_font() : _fontid(NULL) { } virtual ~TXVT_font() { destroy(); } }; void TXVT_font::create(const TString& name, int size, XVT_FONT_STYLE_MASK style) { destroy(); _fontid = xvt_font_create(); xvt_font_set_family(_fontid, (char*)(const char*)name); xvt_font_set_size(_fontid, size); xvt_font_set_style(_fontid, style); } void TXVT_font::destroy() { if (_fontid != NULL) { xvt_font_destroy(_fontid); _fontid = NULL; } } /////////////////////////////////////////////////////////// // TReport_font /////////////////////////////////////////////////////////// class TReport_font : public TObject { enum { DEFAULT_FONT_SIZE = 12 }; TString _name; int _size; bool _bold, _italic, _underline; TArray _physical; public: const TString& name() const { return _name; } int size() const { return _size; } XVT_FNTID get_xvt_font(WINDOW win, int size) const; TReport_font(); virtual ~TReport_font() { } }; XVT_FNTID TReport_font::get_xvt_font(WINDOW win, int charx) const { TXVT_font* font = (TXVT_font*)_physical.objptr(charx); if (font == NULL) { const int quanteM = 8; const int target_width = quanteM * _size * charx / DEFAULT_FONT_SIZE; int mi = 4, me = 0, ma = 4*charx; int best = 0, best_error = 0; TXVT_font f; while (mi < ma) { me = (mi+ma)/2; f.create(XVT_FFN_FIXED, me, XVT_FS_NONE); xvt_dwin_set_font(win, f._fontid); const int width = xvt_dwin_get_text_width(win, "MMMMMMMM", quanteM); const int error = abs(width - target_width); if (best == 0 || error < best_error) { best = me; best_error = error; if (error == 0) break; } if (width > target_width) ma = me-1; else mi = me+1; } XVT_FONT_STYLE_MASK style = 0; if (_bold) style |= XVT_FS_BOLD; if (_italic) style |= XVT_FS_ITALIC; if (_underline) style |= XVT_FS_UNDERLINE; font = new TXVT_font; font->create(_name, best, style); ((TArray&)_physical).add(font, charx); } return font->_fontid; } TReport_font::TReport_font() : _name("Courier New"), _size(DEFAULT_FONT_SIZE), _bold(false), _italic(false), _underline(false) { } /////////////////////////////////////////////////////////// // TReport_section /////////////////////////////////////////////////////////// class TReport_section : public TArray { const TReport_section* _father; TString _str; // Description char _type; // Head,Body,Tail int _level; // 0,1,2,... TReport_font* _font; public: const TString& description() const { return _str; } int image_id() const; const TReport_font& font() const; TReport_section(const TReport_section* f, const char* s, char t, int l); virtual ~TReport_section(); }; int TReport_section::image_id() const { int id = 0; switch (_type) { case 'H': id = 1810; break; case 'B': id = 1811; break; case 'F': id = 1812; break; default : break; } return id; } const TReport_font& TReport_section::font() const { const TReport_font* f = _font; if (f == NULL) { if (_father == NULL) { (TReport_font*)_font = new TReport_font; f = _font; } else f = &_father->font(); } return *f; } TReport_section::TReport_section(const TReport_section* f, const char* s, char t, int l) : _father(f), _str(s), _type(t), _level(l), _font(NULL) { } TReport_section::~TReport_section() { if (_font) delete _font; } /////////////////////////////////////////////////////////// // TReport_window /////////////////////////////////////////////////////////// const int REPORT_SCALE = 100; class TReport_window : public TField_window { int _zoom; // [8,32] int _dragging; TPoint _pt_drag_start; PNT _pt_drag_offset; RCT _rct_drag; protected: virtual void handler(WINDOW win, EVENT* ep); virtual void update(); void draw_grid(); void draw_dragster(); public: virtual PNT log2dev(long x, long y) const; virtual TPoint dev2log(const PNT& pt) const; void log2dev(const RCT& rctlog, RCT& rctdev) const; void dev2log(const RCT& rctdev, RCT& rctlog) const; void scaling(int& k, int& kx, int& ky) const { k = REPORT_SCALE; kx = _zoom; ky = _zoom*2; } TReport_section& curr_section() const; bool get_selection_rect(RCT& rct) const; void draw_fields(); bool pick(const PNT& p) const; void clear_selection(); void select(const RCT& rct); void offset_selection(const TPoint& p); TReport_window(int x, int y, int dx, int dy, WINDOW parent, TWindowed_field* owner); virtual ~TReport_window() { } }; /////////////////////////////////////////////////////////// // TReport_field /////////////////////////////////////////////////////////// class TReport_field : public TObject { TReport_section* _section; char _type; // Text, String, Numeric, Date, Line, Rectangle, Image short _x, _y; // Coordinate in centesimi short _width, _height; // Dimensioni in centesimi TString _picture, _field; TReport_font* _font; bool _selected; protected: const TReport_font& font() const; public: void get_client_rect(const TWindow& win, RCT& r) const; void set_pos(short x, short y); void set_size(short w, short h); void draw(TReport_window& win) const; void get_rect(RCT& rct) const; void select(bool ok = true) { _selected = ok; } bool selected() const { return _selected; } void offset(const TPoint& pt); bool contains(const TPoint& pt) const; TReport_field(TReport_section* sec); }; void TReport_field::set_pos(short x, short y) { _x = x; _y = y; } void TReport_field::set_size(short w, short h) { _width = w; _height = h; } void TReport_field::get_rect(RCT& r) const { r.left = _x; r.top = _y; r.right = _x + _width; r.bottom = _y+_height; } void TReport_field::get_client_rect(const TWindow& win, RCT& r) const { const PNT f = win.log2dev(_x,_y); const PNT t = win.log2dev(_x+_width,_y+_height); r.top = f.v; r.left = f.h; r.bottom = t.v; r.right = t.h; } void TReport_field::draw(TReport_window& win) const { win.set_pen(selected() ? COLOR_RED : COLOR_BLACK); RCT r; get_client_rect(win, r); if (_type != 'L') xvt_dwin_draw_rect(win.win(), &r); switch (_type) { case 'L': { xvt_dwin_draw_set_pos(win.win(), win.log2dev(_x,_y)); xvt_dwin_draw_line(win.win(), win.log2dev(_x+_width,_y+_height)); } break; case 'D': case 'N': case 'S': case 'T': { int k, kx, ky; win.scaling(k, kx, ky); XVT_FNTID fid = font().get_xvt_font(win.win(), kx); xvt_dwin_set_font(win.win(), fid); const int delta = (r.bottom-r.top)/4; xvt_dwin_draw_text(win.win(), r.left, r.bottom-delta, _picture, -1); } break; default: break; } } bool TReport_field::contains(const TPoint& pt) const { return pt.x >= _x && pt.y >= _y && pt.x < _x+_width && pt.y < _y+_height; } void TReport_field::offset(const TPoint& pt) { _x += short(pt.x); _y += short(pt.y); } const TReport_font& TReport_field::font() const { return _font != NULL ? *_font : _section->font(); } TReport_field::TReport_field(TReport_section* sec) : _section(sec), _type('T'), _selected(false), _font(NULL) { set_pos(0,0); set_size(1200,100); } /////////////////////////////////////////////////////////// // TSection_tree /////////////////////////////////////////////////////////// class TSection_tree : public TObject_tree { protected: bool get_description(TString& str) const; TImage* image(bool selected) const; public: TReport_section& curr_section() const { return *(TReport_section*)curr_node(); } void add_node(const char* d, char t = 0, int l = 0) { add_son(new TReport_section(&curr_section(), d, t, l)); } void add_rnode(const char* d, char t = 0, int l = 0) { add_rbrother(new TReport_section(&curr_section(), d, t, l)); } int image_height() const; }; bool TSection_tree::get_description(TString& str) const { const TReport_section* rn = (const TReport_section*)curr_node(); if (rn != NULL) { str = rn->description(); return true; } return false; } TImage* TSection_tree::image(bool selected) const { int id = 0; const TReport_section* rn = (const TReport_section*)curr_node(); if (rn != NULL) { id = rn->image_id(); if (id > 0) return get_res_image(id); } return TObject_tree::image(selected); } int TSection_tree::image_height() const { const TImage* img = image(false); return img != NULL ? img->height() : 0; } /////////////////////////////////////////////////////////// // TReport_mask /////////////////////////////////////////////////////////// class TReport_mask : public TAutomask { TSection_tree _tree; protected: virtual TMask_field* parse_field(TScanner& scanner); virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); protected: bool select_query(); bool select_report(); void on_print(); public: TSection_tree& sections() { return _tree; } TReport_mask(); }; /////////////////////////////////////////////////////////// // TReport_window /////////////////////////////////////////////////////////// TReport_section& TReport_window::curr_section() const { TReport_mask& m = (TReport_mask&)owner().mask(); TTree_field& sections = m.tfield(F_SECTIONS); sections.goto_selected(); return m.sections().curr_section(); } void TReport_window::draw_fields() { TReport_section& rs = curr_section(); FOR_EACH_ARRAY_ITEM(rs, i, o) { const TReport_field& f = *(const TReport_field*)o; f.draw(*this); } } bool TReport_window::pick(const PNT& p) const { TReport_section& rs = curr_section(); RCT rct; FOR_EACH_ARRAY_ITEM(rs, i, o) { TReport_field* f = (TReport_field*)o; f->get_client_rect(*this, rct); rct.left -= 2; rct.top -= 2; rct.right += 2; rct.bottom += 2; if (xvt_rect_has_point(&rct, p)) { f->select(); return true; } } return false; } void TReport_window::clear_selection() { TReport_section& rs = curr_section(); FOR_EACH_ARRAY_ITEM(rs, i, o) { TReport_field* f = (TReport_field*)o; f->select(false); } } bool TReport_window::get_selection_rect(RCT& rct) const { TReport_section& rs = curr_section(); bool full = false; FOR_EACH_ARRAY_ITEM(rs, i, o) { const TReport_field& f = *(const TReport_field*)o; if (f.selected()) { if (!full) { f.get_rect(rct); full = true; } else { RCT r; f.get_rect(r); if (r.left < rct.left) rct.left = r.left; if (r.right > rct.right) rct.right = r.right; if (r.top < rct.top) rct.top = r.top; if (r.bottom > rct.bottom) rct.bottom = r.bottom; } } } return full; } void TReport_window::offset_selection(const TPoint& p) { TReport_section& rs = curr_section(); FOR_EACH_ARRAY_ITEM(rs, i, o) { TReport_field& f = *(TReport_field*)o; if (f.selected()) f.offset(p); } } void TReport_window::select(const RCT& rct) { clear_selection(); TReport_section& rs = curr_section(); FOR_EACH_ARRAY_ITEM(rs, i, o) { TReport_field& f = *(TReport_field*)o; RCT r; f.get_rect(r); if (xvt_rect_intersect(NULL, (RCT*)&rct, &r)) f.select(); } } void TReport_window::draw_dragster() { set_mode(M_XOR); set_pen(COLOR_CYAN); xvt_dwin_draw_rect(win(), &_rct_drag); set_mode(M_COPY); } void TReport_window::handler(WINDOW win, EVENT* ep) { switch (ep->type) { case E_MOUSE_DOWN: { const TPoint pt = dev2log(ep->v.mouse.where); const PNT p = { short(pt.y), short(pt.x) }; RCT rct; bool full = get_selection_rect(rct); if (!full || !xvt_rect_has_point(&rct, p)) { if (full) clear_selection(); pick(ep->v.mouse.where); full = get_selection_rect(rct); } if (full) { log2dev(rct, _rct_drag); _pt_drag_offset.h = ep->v.mouse.where.h - _rct_drag.left; _pt_drag_offset.v = ep->v.mouse.where.v - _rct_drag.top; _dragging = 2; } else { const PNT& pnt = ep->v.mouse.where; xvt_rect_set(&_rct_drag, pnt.h, pnt.v, pnt.h, pnt.v); _dragging = 1; } _pt_drag_start.x = rct.left; _pt_drag_start.y = rct.top; draw_dragster(); xvt_win_trap_pointer(win); } break; case E_MOUSE_MOVE: { int k, kx, ky; scaling(k, kx, ky); TMask& m = owner().mask(); const TPoint p = dev2log(ep->v.mouse.where); m.set(F_X, p.x/k+1); m.set(F_Y, p.y/k+1); if (_dragging != 0) { draw_dragster(); PNT pt = ep->v.mouse.where; switch (_dragging) { case 1: _rct_drag.right = pt.h; _rct_drag.bottom = pt.v; break; case 2: pt.h -= _pt_drag_offset.h; pt.v -= _pt_drag_offset.v; if (!ep->v.mouse.shift) { pt.h = (pt.h / kx) * kx; pt.v = (pt.v / ky) * ky; } xvt_rect_set_pos(&_rct_drag, pt); break; default: break; } draw_dragster(); } } break; case E_MOUSE_UP: if (_dragging != 0) { draw_dragster(); PNT pt = ep->v.mouse.where; switch (_dragging) { case 1: { _rct_drag.right = pt.h; _rct_drag.bottom = pt.v; RCT rct; dev2log(_rct_drag, rct); select(rct); } break; case 2: { pt.h -= _pt_drag_offset.h; pt.v -= _pt_drag_offset.v; int k, kx, ky; scaling(k, kx, ky); if (!ep->v.mouse.shift) { pt.h = (pt.h / kx) * kx; pt.v = (pt.v / ky) * ky; } TPoint offset = dev2log(pt); offset.x -= _pt_drag_start.x; offset.y -= _pt_drag_start.y; offset_selection(offset); } break; default: break; } force_update(); _dragging = 0; xvt_win_release_pointer(); } break; default: break; } TField_window::handler(win, ep); } PNT TReport_window::log2dev(long x, long y) const { int k, kx, ky; scaling(k, kx, ky); x -= k*origin().x; y -= k*origin().y; PNT p; p.h = short(x * kx / k); p.v = short(y * ky / k); return p; } TPoint TReport_window::dev2log(const PNT& pt) const { int k, kx, ky; scaling(k, kx, ky); TPoint p; p.x = pt.h * k / kx + k*origin().x; p.y = pt.v * k / ky + k*origin().y; return p; } void TReport_window::log2dev(const RCT& rctlog, RCT& rctdev) const { const PNT f = log2dev(rctlog.left, rctlog.top); const PNT t = log2dev(rctlog.right, rctlog.bottom); rctdev.left = f.h; rctdev.top = f.v; rctdev.right = t.h; rctdev.bottom = t.v; } void TReport_window::dev2log(const RCT& rctdev, RCT& rctlog) const { const PNT pf = { rctdev.top, rctdev.left }; const PNT pt = { rctdev.bottom, rctdev.right }; const TPoint f = dev2log(pf); const TPoint t = dev2log(pt); rctlog.left = short(f.x); rctlog.top = short(f.y); rctlog.right = short(t.x); rctlog.bottom = short(t.y); } void TReport_window::draw_grid() { int k, kx, ky; scaling(k, kx, ky); // Draw grid clear(COLOR_WHITE); set_pen(MAKE_COLOR(232,232,232)); RCT rct; xvt_vobj_get_client_rect(win(), &rct); const int max = rct.right / kx; const int x = origin().x; const int y = origin().y; for (int i = 1; i < max; i++) { line(x*k, (y+i)*k, (x+max)*k, (y+i)*k); line((x+i)*k, y*k, (x+i)*k, (y+max)*k); } } void TReport_window::update() { draw_grid(); draw_fields(); } TReport_window::TReport_window(int x, int y, int dx, int dy, WINDOW parent, TWindowed_field* owner) : TField_window(x, y, dx, dy, parent, owner), _zoom(10), _dragging(0) { _pixmap = true; set_scroll_max(196,196); } class TReport_drawer : public TWindowed_field { protected: virtual TField_window* create_window(int x, int y, int dx, int dy, WINDOW parent); public: TReport_drawer(TMask* m) : TWindowed_field(m) { } }; TField_window* TReport_drawer::create_window(int x, int y, int dx, int dy, WINDOW parent) { return new TReport_window(x, y, dx, dy, parent, this); } /////////////////////////////////////////////////////////// // TReport_printer /////////////////////////////////////////////////////////// class TReport_printer : public TObject { const TString& _name; const TString& _sql; TSection_tree& _tree; long _pw, _ph, _phr, _pvr; // Printer width, height, horizontal and vertical resolution word _copies; word _pagefrom; word _pageto; bool _aborted; public: bool print_copies(); // caallback do NOT use; bool aborted() const { return _aborted; } bool edit(); bool print(); TReport_printer(const TString& name, const TString& sql, TSection_tree& t); virtual ~TReport_printer(); }; bool TReport_printer::edit() { _tree.goto_root(); TReport_section& rs = _tree.curr_section(); TPrinter& p = printer(); TMask msk("bagn003"); msk.set(F_PRINTER, p.printername()); msk.set(F_FORM, _name); msk.set(F_FONT, rs.font().name()); msk.set(F_SIZE, rs.font().size()); msk.set(F_ISGRAPHICS, p.isgraphics() ? "X" : ""); msk.set(F_FROMPAGE, _pagefrom); msk.set(F_TOPAGE, _pageto); msk.set(F_COPIES, _copies); const bool ok = msk.run() == K_ENTER; if (ok) { _copies = msk.get_int(F_COPIES); _pagefrom = msk.get_int(F_FROMPAGE); _pageto = msk.get_int(F_TOPAGE); if (_pageto < _pagefrom) _pageto = 0; } return ok; } bool TReport_printer::print_copies() { TSQL_query qry(_sql); const TRecnotype items = qry.items(); bool ok = items > 0; for (int copia = 0; ok && copia < _copies; copia++) { xvt_print_open(); xvt_app_escape(XVT_ESC_GET_PRINTER_INFO, printer().get_printrcd(), &_ph, &_pw, &_pvr, &_phr); xvt_print_close(); } return ok; } BOOLEAN print_callback(long jolly) { TReport_printer* rp = (TReport_printer*)jolly; return rp->print_copies(); } bool TReport_printer::print() { _aborted = false; xvt_print_start_thread(print_callback, (long)this); return !aborted(); } TReport_printer::TReport_printer(const TString& n, const TString& sql, TSection_tree& t) : _name(n), _sql(sql), _tree(t), _copies(1), _pagefrom(1), _pageto(0), _aborted(false) { } TReport_printer::~TReport_printer() { } /////////////////////////////////////////////////////////// // TReport_mask /////////////////////////////////////////////////////////// TMask_field* TReport_mask::parse_field(TScanner& scanner) { if (scanner.token().starts_with("RE")) return new TReport_drawer(this); return TAutomask::parse_field(scanner); } bool TReport_mask::select_report() { TFilename path; const bool ok = select_sql_file(path, "rep"); if (ok) { path = path.name(); path.ext(""); set(F_CODICE, path); } return ok; } bool TReport_mask::select_query() { TFilename path; bool ok = select_sql_file(path, "qry"); if (ok) { TXmlItem item; item.Load(path); const TXmlItem* sql = item.FindFirst("sql"); ok = sql != NULL; if (ok) { TString str; sql->GetEnclosedText(str); set(F_SQL, str, true); } } return ok; } static BOOLEAN print_page(long jolly) { return FALSE; } void TReport_mask::on_print() { TReport_printer rp(get(F_CODICE), get(F_SQL), _tree); if (rp.edit()) { xvt_print_start_thread(print_page, long(&rp)); } } bool TReport_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { case F_CODICE: if (e == fe_button) select_report(); break; case F_SECTIONS: if (e == fe_modify) ((TReport_drawer&)field(F_REPORT)).win().force_update(); break; case F_SQL: if (e == fe_init || e == fe_modify) enable(F_SHOW_QRY, !o.empty()); break; case F_NEW_QRY: if (e == fe_button) { TExternal_app q("ba8 -1"); q.run(); } break; case F_IMPORT_QRY: if (e == fe_button) select_query(); break; case F_SHOW_QRY: if (e == fe_button) { TSQL_query qry(get(F_SQL)); if (qry.columns() > 0) { TQuery_sheet sheet(qry); sheet.run(); } } break; case DLG_PRINT: if (e == fe_button) { on_print(); return false; } break; default: break; } return true; } TReport_mask::TReport_mask() { read_mask("ba8300a", 0, -1); set_handlers(); TTree_field& albero = tfield(F_SECTIONS); RCT rct_sec; albero.get_rect(rct_sec); RCT rct_rep; field(F_REPORT).get_rect(rct_rep); rct_rep.left = rct_sec.right+ROWY; rct_rep.right -= ROWY; rct_rep.bottom -= ROWY; field(F_REPORT).set_rect(rct_rep); TString body_id, tail_id; _tree.add_node("Report"); for (int i = 1; i <= 4; i++) { if (body_id.not_empty()) _tree.goto_node(body_id); const char* name[3] = { "Testa", "Corpo", "Coda" }; TString16 bodyn; for (int j = 0; j < 3; j++) { bodyn.format(" %s %d", name[j], i); switch(j) { case 0: _tree.add_node(bodyn, 'H', i); break; case 1: _tree.add_rnode(bodyn, 'B', i); _tree.curr_id(body_id); if (i == 1) { TReport_section& sec = _tree.curr_section(); for (short k = 0; k < 12; k+=1) { TReport_field* rf = new TReport_field(&sec); rf->set_pos(k*100, k*100); sec.add(rf); } } break; case 2: _tree.add_rnode(bodyn, 'F', i); if (tail_id.empty()) _tree.curr_id(tail_id); break; default: break; } } } _tree.goto_node(tail_id); _tree.add_rnode(" Pagina"); _tree.add_node(" Testa", 'H', 0); _tree.add_rnode(" Corpo", 'B', 0); _tree.add_rnode(" Coda", 'F', 0); const int ih = _tree.image_height(); if (ih > CHARY) albero.set_row_height(ih); albero.set_tree(&_tree); _tree.goto_root(); _tree.expand(); } /////////////////////////////////////////////////////////// // TReporter_app /////////////////////////////////////////////////////////// class TReporter_app : public TSkeleton_application { protected: virtual void main_loop(); }; void TReporter_app::main_loop() { TReport_mask* msk = new TReport_mask; msk->run(); delete msk; } int ba8300(int argc, char* argv[]) { TReporter_app app; app.run(argc, argv, TR("Report Generator")); return 0; }