diff --git a/include/applicat.cpp b/include/applicat.cpp index 73e5537a5..757b16537 100755 --- a/include/applicat.cpp +++ b/include/applicat.cpp @@ -1,608 +1,601 @@ -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - - -/////////////////////////////////////////////////////////// -// Metodi di accesso globali all'applicazione corrente -/////////////////////////////////////////////////////////// - -HIDDEN TApplication* _application = NULL; -HIDDEN long savefirm = 0; - -TApplication* MainApp() -{ - CHECK(_application, "NULL application!"); - return _application; -} - -TApplication& main_app() -{ - CHECK(_application, "NULL application!"); - return *_application; -} - -bool xvt_running() { return _application != NULL; } - -/////////////////////////////////////////////////////////// -// Gestione dello sfondo della finestra principale -/////////////////////////////////////////////////////////// - -HIDDEN long backdrop_eh( WINDOW win, EVENT* ep) -{ -#if XVTWS == WMWS - clear_window( win, COLOR_BLUE ); -#else - clear_window( win, COLOR_GRAY ); -#endif - - return 0L; -} - -HIDDEN void create_backdrop( void ) -{ -#if XVTWS == WMWS - xvt_escape(XVT_ESC_CH_COLOR, XVT_CH_CLR_MENU, COLOR_BLACK, COLOR_WHITE); - xvt_escape(XVT_ESC_CH_COLOR, XVT_CH_CLR_DIALOG, COLOR_BLUE, COLOR_WHITE); - xvt_escape(XVT_ESC_CH_COLOR, XVT_CH_CLR_WINDOW, COLOR_RED, COLOR_WHITE); - xvt_escape(XVT_ESC_CH_COLOR, XVT_CH_CLR_CONTROL, COLOR_BLACK, COLOR_WHITE); - xvt_escape(XVT_ESC_CH_COLOR, XVT_CH_CLR_DISABLED, COLOR_GRAY, COLOR_WHITE); - xvt_escape(XVT_ESC_CH_COLOR, XVT_CH_CLR_MNEMONIC, COLOR_RED, COLOR_WHITE); - - RCT rct; - get_client_rect( SCREEN_WIN, &rct ); - create_window(W_PLAIN, &rct, (char*) "BACKDROP", 0, TASK_WIN, - WSF_NO_MENUBAR | WSF_CH_BACKDROP , EM_UPDATE, - backdrop_eh, 0L ); -#else - xvt_create_statbar(); - xvt_statbar_set(""); -#endif -} - -/////////////////////////////////////////////////////////// -// Gestione del banner iniziale -/////////////////////////////////////////////////////////// - -class TBanner : public TWindow -{ - enum { FONT_SIZE = 28 }; -protected: - virtual void handler(WINDOW win, EVENT* ep); - -public: - TBanner(); - ~TBanner(); -}; - -TBanner::TBanner() -{ - create(-1, -1, 78, 6, "BANNER", WSF_NONE, W_PLAIN); - hide_brush(); - open_modal(); - do_events(); -} - -TBanner::~TBanner() -{ - close_modal(); -} - -void TBanner::handler(WINDOW win, EVENT* ep) -{ - if (ep->type == E_UPDATE) - { - clear(COLOR_LTGRAY); - RCT r; get_client_rect(win, &r); - - set_color(COLOR_WHITE, COLOR_LTGRAY); - set_font(FF_TIMES, FS_BOLD | FS_ITALIC, FONT_SIZE); - char* t = (char*)(const char*)main_app().title(); - int w = win_get_text_width(win, t, -1); - int x = (r.right-r.left-w)>>1, y = r.bottom - 4*CHARY; - win_draw_text(win, x+2, y+2, t, -1); - set_color(COLOR_BLACK, COLOR_LTGRAY); - win_draw_text(win, x, y, t, -1); - - set_font(FF_TIMES); - t = "PRASSI S.p.A."; - w = win_get_text_width(win, t, -1); - x = (r.right-r.left-w)>>1, y = 2*CHARY; - win_draw_text(win, x, y, t, -1); - - t = "Caricamento in corso"; - w = win_get_text_width(win, t, -1); - x = (r.right-r.left-w)>>1, y = r.bottom - 2*CHARY; - win_draw_text(win, x, y, t, -1); - - r.left += CHARX; r.right -= CHARX; - r.top += CHARX; r.bottom -= CHARX; - set_pen(COLOR_BLACK); win_draw_rect(win, &r); - offset_rect(&r, 1, 1); - set_pen(COLOR_WHITE); win_draw_rect(win, &r); - win_draw_icon(win, CHARX<<1, CHARX<<1, ICON_RSRC); - } - else - TWindow::handler(win, ep); -} - -#if XVT_OS == XVT_OS_WIN - -/////////////////////////////////////////////////////////// -// Gestione dei processi per Windows(R) -/////////////////////////////////////////////////////////// - -#include - -const word WM_WAKEUP = RegisterWindowMessage("WAKEUP"); -DWORD waiting_for = 0; - -HIDDEN BOOLEAN waiting_event_hook(HWND, WORD msg, WORD, - DWORD lparam, long far* ret) -{ - if (msg == WM_WAKEUP) - { - if( lparam == waiting_for || lparam == 0) - { - waiting_for = 0L; - TTemp_window tw(TASK_WIN); - tw.maximize(); - } - *ret = 0; - return TRUE; - } - - return FALSE; -} - - -HIDDEN DWORD name2id(const char* name) -{ - waiting_for = 0L; - for (int i = 0; i < 5 && name[i] > ' '; i++) - { - waiting_for <<= 6; - waiting_for |= toupper(name[i]) - '0'; - } - return waiting_for; -} - - -void TApplication::wait_for(const char* command) -{ - TTemp_window tw(TASK_WIN); - tw.iconize(); - name2id(cmd2name(command)); - set_value(TASK_WIN, ATTR_EVENT_HOOK, (long)waiting_event_hook); - while (waiting_for) do_events(); - - // We need to restore these things - customize_controls(TRUE); - xvt_statbar_refresh(); -} - -void TApplication::wake_up_caller() const -{ - name2id(name()); - SendMessage(-1, WM_WAKEUP, 0, waiting_for); -} - -#endif - - -long TApplication::task_eh(WINDOW win, EVENT *ep) -{ - switch (ep->type) - { - case E_CREATE: - create_backdrop(); -#if defined(DBG) && XVT_OS == XVT_OS_SCOUNIX - message_box("Attach to process %d ...", getpid()); -#endif - do_events(); - break; -#if XVT_OS == XVT_OS_WIN - case E_UPDATE: - backdrop_eh(win, ep); - break; -#endif - default: - break; - } - - return _application->handler(win, ep); -} - -long TApplication::handler(WINDOW, EVENT* ep) -{ - switch (ep->type) - { - case E_CREATE: - { - bool ok = FALSE; - { - TBanner banner; - ok = create(); - } - if (!ok) - stop_run(); - } - break; - case E_CHAR: -{ -#ifdef DBG - KEY k = e_char_to_key(ep); -#endif -} -break; - case E_COMMAND: -{ - MENU_TAG mt = ep->v.cmd.tag; - switch(mt) - { - case M_FILE_QUIT: - if (can_close()) - stop_run(); - break; - case M_FILE_PG_SETUP: - printer().set(); - break; - case M_FILE_PRINT: - print(); - break; - case M_FILE_NEW: - set_firm(); - break; - case M_FILE_REVERT: - config(); - break; - case (M_FILE+11) : - about(); - break; - default: - if (mt >= BAR_ITEM(1)) - { - if(!menu(mt)) - stop_run(); - } - break; - } -} -break; - case E_CLOSE: - if (can_close()) - stop_run(); - break; - case E_QUIT: - if (ep->v.query) -{ - if (can_close()) - quit_OK(); -} -else -stop_run(); -break; -default: -break; -} -return 0L; -} - - -void TApplication::stop_run() -{ - if (savefirm) prefhndl->set_codditta(savefirm); - terminate(); - xvt_terminate(); -} - - -TApplication::TApplication() : _printer(NULL) -{ - init_global_vars(); - _bar = TASK_MENUBAR; -} - - -TApplication::~TApplication() -{} - - -TPrinter* TApplication::set_printer(TPrinter* p) -{ - TPrinter* printer = _printer; - _printer = p; - return printer; -} - - -TPrinter& TApplication::printer() -{ - if (_printer == NULL) - _printer = new TPrinter; - return *_printer; -} - - -bool TApplication::create() -{ - return TRUE; -} - - -bool TApplication::destroy() -{ - return TRUE; -} - - -void TApplication::terminate() -{ -#if XVT_OS == XVT_OS_WIN - wake_up_caller(); // Manda il segnale di risveglio al chiamante -#endif - - close_all_dialogs(); - _application->destroy(); // Distruzione files e maschere - do_events(); - - if (_printer != NULL) // Distruzione dell'eventuale stampante - { - if (printer().isopen()) - printer().close(); - delete _printer; - _printer = NULL; - } - - free_global_vars(); // Distruzione variabili globali - - customize_controls(FALSE); // Rilascio eventuali DLL -} - - -const char* TApplication::get_module_name() const -{ - TScanner scanner("prassi.aut"); - - bool ok = FALSE; - for (int aut = 0; scanner.line() != ""; aut++) - if (strncmp(scanner.token(), _name, 2) == 0) { ok = TRUE; break; } - - const char* module = scanner.token().mid(3); - if (ok) ok = has_module(aut); - - if (!ok) - fatal_box("Il modulo '%s' non e' autorizzato", module); - - return module; -} - -void TApplication::run(int argc, char* argv[], const char* title) -{ - TFilename base(argv[0]); - base.ext(""); base.lower(); - _title = title; - - __argc = argc; - __argv = (const char**)argv; - - int addbar; - if (argc > 1) - { - addbar = atoi(argv[1]+1); - _name = cmd2name(argv[0], argv[1]); - } - else - { - addbar = 0; - _name = cmd2name(argv[0]); - } - - TString80 caption; - caption << "PRASSI S.p.A. - " << get_module_name(); - - static XVT_CONFIG cfg; - cfg.base_appl_name = (char*)base.name(); - cfg.appl_name = (char*)(const char*)_title; - cfg.taskwin_title = (char*)(const char*)caption; - cfg.menu_bar_ID = TASK_MENUBAR+addbar; - cfg.about_box_ID = 0; - - customize_controls(TRUE); - - _application = this; - xvt_system(argc, argv, 0L, task_eh, &cfg); -} - -// About box: risposta alla opzione Informazioni del menu File -void TApplication::about() const -{ -#include - const TFilename n(__argv[0]); - message_box("PRASSI Versione Beta 1.%g\nProgramma %s\nLibreria del %s", - VERSION, (const char*)n.name(), __DATE__); -} - -// Risposta alla selezione Stampa del menu File -void TApplication::print() -{ -#ifdef DBG - error_box("Non saprei bene cosa stampare!"); -#endif -} - -void TApplication::check_menu_item(MENU_TAG item) -{ - win_menu_check(TASK_WIN, item, TRUE); - win_update_menu_bar(TASK_WIN); -} - -void TApplication::uncheck_menu_item(MENU_TAG item) -{ - win_menu_check(TASK_WIN, item, FALSE); - win_update_menu_bar(TASK_WIN); -} - - -void TApplication::enable_menu_item(MENU_TAG item, bool on) -{ - win_menu_enable(TASK_WIN, item, on); - win_update_menu_bar(TASK_WIN); -} - - -void TApplication::dispatch_e_menu(MENU_TAG item) -{ -#if XVT_OS == XVT_OS_WIN - HWND w = (HWND)get_value(TASK_WIN, ATTR_NATIVE_WINDOW); - PostMessage(w, WM_COMMAND, item, 0L); -#else - EVENT e; - e.type = E_COMMAND; - e.v.cmd.tag = item; - e.v.cmd.shift = e.v.cmd.control = 0; - dispatch_event(TASK_WIN, &e); -#endif -} - - -bool TApplication::has_module(int module) const -{ - return (bool)CGetAut(module); -} - - -long TApplication::get_firm() const -{ - return prefhndl->get_codditta(); -} - -const char* TApplication::get_firm_dir() const -{ - return format("%s%s", __ptprf, prefhndl->name()); -} - - -bool TApplication::set_firm(long newfirm) -{ - disable_menu_item(M_FILE_NEW); - const long oldfirm = get_firm(); - - if (newfirm < 1) - { - TMask mask("bagn002"); - - mask.send_key(K_CTRL+K_SHIFT+(extended_firm() ? 's' : 'h'), -2); - const KEY k = mask.run(); - - enable_menu_item(M_FILE_NEW); - if (k == K_ENTER) - { - newfirm = mask.get_long(F_CODDITTA); - const int tipodir = mask.get_int(F_TIPO); - - if (tipodir > 0) - { - if (savefirm == 0) savefirm = oldfirm; - prefhndl->set(tipodir == 1 ? "com" : ""); - return TRUE; - } - } - } - - if (newfirm == oldfirm || newfirm < 1) - return FALSE; - - if (prefhndl->test(newfirm)) - { - prefhndl->set_codditta(newfirm); - savefirm = 0; - } - - return TRUE; -} - -bool TApplication::config() - // gestisce le voci di configurazione - // le si passa il file in cui cercare il proprio - // paragrafo (comunque relativo alla ditta) - // se non c'e', viene creato copiando il default - // la variabile EdMask di quel paragrafo specifica - // la maschera da usare -{ - TConfig cnf(CONFIG_DITTA); - bool ok = FALSE; - - TString80 maskname(cnf.get("EdMask")); - if (!maskname.empty()) - { - TMask m(maskname); - - // carica campi - for (int i = 0; i < m.fields(); i++) - { - TMask_field& f = m.fld(i); - const TFieldref* fref = f.field(); - if (fref != NULL) - { - const char* fname = fref->name(); - if (fname != NULL) - { - TString& oldvl = cnf.get(fname); - if (!oldvl.empty()) - f.set(oldvl); - } - } - } - - - // run mask - disable_menu_item(M_FILE_NEW); - disable_menu_item(M_FILE_REVERT); - - if (m.run() == K_ENTER) - { - // aggiusta campi - for (i = 0; i < m.fields(); i++) - { - TMask_field& f = m.fld(i); - if (f.dirty()) - { - const TFieldref* fref = f.field(); - if (fref != NULL) - { - const char* fname = fref->name(); - const char* value = f.get(); - const char* oldvl = cnf.get(fname); - if (change_config(fname,oldvl,value)) - cnf.set(fname, value, NULL, TRUE); - } - } - } - ok = TRUE; - } - else ok = FALSE; - enable_menu_item(M_FILE_NEW); - enable_menu_item(M_FILE_REVERT); - return ok; - } - return warning_box("Nessun parametro da configurare"); -} - -bool TApplication::change_config(const char* var, const char* oldv, - const char* newv) - -{ return TRUE; } +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +/////////////////////////////////////////////////////////// +// Metodi di accesso globali all'applicazione corrente +/////////////////////////////////////////////////////////// + +HIDDEN TApplication* _application = NULL; +HIDDEN long savefirm = 0; + +TApplication* MainApp() +{ + CHECK(_application, "NULL application!"); + return _application; +} + +TApplication& main_app() +{ + CHECK(_application, "NULL application!"); + return *_application; +} + +bool xvt_running() { return _application != NULL; } + +/////////////////////////////////////////////////////////// +// Gestione dello sfondo della finestra principale +/////////////////////////////////////////////////////////// + +HIDDEN long backdrop_eh( WINDOW win, EVENT* ep) +{ +#if XVTWS == WMWS + clear_window( win, COLOR_BLUE ); +#else + clear_window( win, COLOR_GRAY ); +#endif + + return 0L; +} + +HIDDEN void create_backdrop( void ) +{ +#if XVTWS == WMWS + xvt_escape(XVT_ESC_CH_COLOR, XVT_CH_CLR_MENU, COLOR_BLACK, COLOR_WHITE); + xvt_escape(XVT_ESC_CH_COLOR, XVT_CH_CLR_DIALOG, COLOR_BLUE, COLOR_WHITE); + xvt_escape(XVT_ESC_CH_COLOR, XVT_CH_CLR_WINDOW, COLOR_RED, COLOR_WHITE); + xvt_escape(XVT_ESC_CH_COLOR, XVT_CH_CLR_CONTROL, COLOR_BLACK, COLOR_WHITE); + xvt_escape(XVT_ESC_CH_COLOR, XVT_CH_CLR_DISABLED, COLOR_GRAY, COLOR_WHITE); + xvt_escape(XVT_ESC_CH_COLOR, XVT_CH_CLR_MNEMONIC, COLOR_RED, COLOR_WHITE); + + RCT rct; + get_client_rect( SCREEN_WIN, &rct ); + create_window(W_PLAIN, &rct, (char*) "BACKDROP", 0, TASK_WIN, + WSF_NO_MENUBAR | WSF_CH_BACKDROP , EM_UPDATE, + backdrop_eh, 0L ); +#else + xvt_create_statbar(); + xvt_statbar_set(""); +#endif +} + +/////////////////////////////////////////////////////////// +// Gestione del banner iniziale +/////////////////////////////////////////////////////////// + +class TBanner : public TWindow +{ + enum { FONT_SIZE = 28 }; +protected: + virtual void handler(WINDOW win, EVENT* ep); + +public: + TBanner(); + ~TBanner(); +}; + +TBanner::TBanner() +{ + create(-1, 2, 68, 7, "BANNER", WSF_NONE, W_PLAIN); + hide_brush(); + open_modal(); + do_events(); +} + +TBanner::~TBanner() +{ + close_modal(); +} + +void TBanner::handler(WINDOW win, EVENT* ep) +{ + if (ep->type == E_UPDATE) + { + clear(COLOR_LTGRAY); + RCT r; get_client_rect(win, &r); + + set_color(COLOR_WHITE, COLOR_LTGRAY); + set_font(FF_TIMES, FS_BOLD | FS_ITALIC, FONT_SIZE); + char* t = (char*)(const char*)main_app().title(); + int w = win_get_text_width(win, t, -1); + int x = (r.right-r.left-w)>>1, y = r.bottom - 4*CHARY; + win_draw_text(win, x+2, y+2, t, -1); + set_color(COLOR_BLACK, COLOR_LTGRAY); + win_draw_text(win, x, y, t, -1); + + set_font(FF_TIMES); + t = "PRASSI S.p.A."; + w = win_get_text_width(win, t, -1); + x = (r.right-r.left-w)>>1, y = 2*CHARY; + win_draw_text(win, x, y, t, -1); + + t = "Caricamento in corso"; + w = win_get_text_width(win, t, -1); + x = (r.right-r.left-w)>>1, y = r.bottom - 2*CHARY; + win_draw_text(win, x, y, t, -1); + + r.left += CHARX; r.right -= CHARX; + r.top += CHARX; r.bottom -= CHARX; + set_pen(COLOR_BLACK); win_draw_rect(win, &r); + offset_rect(&r, 1, 1); + set_pen(COLOR_WHITE); win_draw_rect(win, &r); + win_draw_icon(win, CHARX<<1, CHARX<<1, ICON_RSRC); + } + else + TWindow::handler(win, ep); +} + +#if XVT_OS == XVT_OS_WIN + +/////////////////////////////////////////////////////////// +// Gestione dei processi per Windows(R) +/////////////////////////////////////////////////////////// + +#include + +const word WM_WAKEUP = RegisterWindowMessage("WAKEUP"); +DWORD waiting_for = 0; + +HIDDEN BOOLEAN waiting_event_hook(HWND, WORD msg, WORD, + DWORD lparam, long far* ret) +{ + if (msg == WM_WAKEUP) + { + if( lparam == waiting_for || lparam == 0) + { + waiting_for = 0L; + TTemp_window tw(TASK_WIN); + tw.maximize(); + } + *ret = 0; + return TRUE; + } + + return FALSE; +} + + +HIDDEN DWORD name2id(const char* name) +{ + waiting_for = 0L; + for (int i = 0; i < 5 && name[i] > ' '; i++) + { + waiting_for <<= 6; + waiting_for |= toupper(name[i]) - '0'; + } + return waiting_for; +} + + +void TApplication::wait_for(const char* command) +{ + TTemp_window tw(TASK_WIN); + tw.iconize(); + name2id(cmd2name(command)); + set_value(TASK_WIN, ATTR_EVENT_HOOK, (long)waiting_event_hook); + while (waiting_for) do_events(); + + // We need to restore these things + customize_controls(TRUE); + xvt_statbar_refresh(); +} + +void TApplication::wake_up_caller() const +{ + name2id(name()); + SendMessage(-1, WM_WAKEUP, 0, waiting_for); +} + +#endif + + +long TApplication::task_eh(WINDOW win, EVENT *ep) +{ + switch (ep->type) + { + case E_CREATE: + create_backdrop(); +#if defined(DBG) && XVT_OS == XVT_OS_SCOUNIX + message_box("Attach to process %d ...", getpid()); +#endif + do_events(); + break; +#if XVT_OS == XVT_OS_WIN + case E_UPDATE: + backdrop_eh(win, ep); + break; +#endif + default: + break; + } + + return _application->handler(win, ep); +} + +long TApplication::handler(WINDOW, EVENT* ep) +{ + switch (ep->type) + { + case E_CREATE: + { + bool ok = FALSE; + { + TBanner banner; + ok = create(); + } + if (!ok) + stop_run(); + } + break; + case E_COMMAND: + { + const MENU_TAG mt = ep->v.cmd.tag; + switch(mt) + { + case M_FILE_QUIT: + if (can_close()) + stop_run(); + break; + case M_FILE_PG_SETUP: + printer().set(); + break; + case M_FILE_PRINT: + print(); + break; + case M_FILE_NEW: + set_firm(); + break; + case M_FILE_REVERT: + config(); + break; + case (M_FILE+11): + about(); + break; + default: + if (mt >= BAR_ITEM(1)) + { + if(!menu(mt)) + stop_run(); + } + break; + } + } + break; + case E_CLOSE: + if (can_close()) + stop_run(); + break; + case E_QUIT: + if (ep->v.query) + { + if (can_close()) + quit_OK(); + } + else + stop_run(); + break; + default: + break; + } + return 0L; +} + + +void TApplication::stop_run() +{ + if (savefirm) prefhndl->set_codditta(savefirm); + terminate(); + xvt_terminate(); +} + + +TApplication::TApplication() : _printer(NULL) +{ + init_global_vars(); + _bar = TASK_MENUBAR; +} + + +TApplication::~TApplication() +{} + + +TPrinter* TApplication::set_printer(TPrinter* p) +{ + TPrinter* printer = _printer; + _printer = p; + return printer; +} + + +TPrinter& TApplication::printer() +{ + if (_printer == NULL) + _printer = new TPrinter; + return *_printer; +} + + +bool TApplication::create() +{ + return TRUE; +} + + +bool TApplication::destroy() +{ + return TRUE; +} + + +void TApplication::terminate() +{ +#if XVT_OS == XVT_OS_WIN + wake_up_caller(); // Manda il segnale di risveglio al chiamante +#endif + + close_all_dialogs(); + _application->destroy(); // Distruzione files e maschere + do_events(); + + if (_printer != NULL) // Distruzione dell'eventuale stampante + { + if (printer().isopen()) + printer().close(); + delete _printer; + _printer = NULL; + } + + free_global_vars(); // Distruzione variabili globali + + customize_controls(FALSE); // Rilascio eventuali DLL +} + + +const char* TApplication::get_module_name() const +{ + TScanner scanner("prassi.aut"); + + bool ok = FALSE; + for (int aut = 0; scanner.line() != ""; aut++) + if (strncmp(scanner.token(), _name, 2) == 0) { ok = TRUE; break; } + + const char* module = scanner.token().mid(3); + if (ok) ok = has_module(aut); + + if (!ok) + fatal_box("Il modulo '%s' non e' autorizzato", module); + + return module; +} + +void TApplication::run(int argc, char* argv[], const char* title) +{ + TFilename base(argv[0]); + base.ext(""); base.lower(); + _title = title; + + __argc = argc; + __argv = (const char**)argv; + + int addbar; + if (argc > 1) + { + addbar = atoi(argv[1]+1); + _name = cmd2name(argv[0], argv[1]); + } + else + { + addbar = 0; + _name = cmd2name(argv[0]); + } + + TString80 caption; + caption << "PRASSI S.p.A. - " << get_module_name(); + + static XVT_CONFIG cfg; + cfg.base_appl_name = (char*)base.name(); + cfg.appl_name = (char*)(const char*)_title; + cfg.taskwin_title = (char*)(const char*)caption; + cfg.menu_bar_ID = TASK_MENUBAR+addbar; + cfg.about_box_ID = 0; + + customize_controls(TRUE); + + _application = this; + xvt_system(argc, argv, 0L, task_eh, &cfg); +} + +// About box: risposta alla opzione Informazioni del menu File +void TApplication::about() const +{ +#include + const TFilename n(__argv[0]); + message_box("PRASSI Versione SMAU 1.%g\nProgramma %s\nLibreria del %s", + VERSION, (const char*)n.name(), __DATE__); +} + +// Risposta alla selezione Stampa del menu File +void TApplication::print() +{ +#ifdef DBG + error_box("Non saprei bene cosa stampare!"); +#endif +} + +void TApplication::check_menu_item(MENU_TAG item) +{ + win_menu_check(TASK_WIN, item, TRUE); + win_update_menu_bar(TASK_WIN); +} + +void TApplication::uncheck_menu_item(MENU_TAG item) +{ + win_menu_check(TASK_WIN, item, FALSE); + win_update_menu_bar(TASK_WIN); +} + + +void TApplication::enable_menu_item(MENU_TAG item, bool on) +{ + win_menu_enable(TASK_WIN, item, on); + win_update_menu_bar(TASK_WIN); +} + + +void TApplication::dispatch_e_menu(MENU_TAG item) +{ +#if XVT_OS == XVT_OS_WIN + HWND w = (HWND)get_value(TASK_WIN, ATTR_NATIVE_WINDOW); + PostMessage(w, WM_COMMAND, item, 0L); +#else + EVENT e; + e.type = E_COMMAND; + e.v.cmd.tag = item; + e.v.cmd.shift = e.v.cmd.control = 0; + dispatch_event(TASK_WIN, &e); +#endif +} + + +bool TApplication::has_module(int module) const +{ + return (bool)CGetAut(module); +} + + +long TApplication::get_firm() const +{ + return prefhndl->get_codditta(); +} + +const char* TApplication::get_firm_dir() const +{ + return format("%s%s", __ptprf, prefhndl->name()); +} + + +bool TApplication::set_firm(long newfirm) +{ + disable_menu_item(M_FILE_NEW); + const long oldfirm = get_firm(); + + if (newfirm < 1) + { + TMask mask("bagn002"); + + mask.send_key(K_CTRL+K_SHIFT+(extended_firm() ? 's' : 'h'), -2); + const KEY k = mask.run(); + + enable_menu_item(M_FILE_NEW); + if (k == K_ENTER) + { + newfirm = mask.get_long(F_CODDITTA); + const int tipodir = mask.get_int(F_TIPO); + + if (tipodir > 0) + { + if (savefirm == 0) savefirm = oldfirm; + prefhndl->set(tipodir == 1 ? "com" : ""); + return TRUE; + } + } + } + + if (newfirm == oldfirm || newfirm < 1) + return FALSE; + + if (prefhndl->test(newfirm)) + { + prefhndl->set_codditta(newfirm); + savefirm = 0; + } + + return TRUE; +} + +bool TApplication::config() + // gestisce le voci di configurazione + // le si passa il file in cui cercare il proprio + // paragrafo (comunque relativo alla ditta) + // se non c'e', viene creato copiando il default + // la variabile EdMask di quel paragrafo specifica + // la maschera da usare +{ + TConfig cnf(CONFIG_DITTA); + bool ok = FALSE; + + TString80 maskname(cnf.get("EdMask")); + if (!maskname.empty()) + { + TMask m(maskname); + + // carica campi + for (int i = 0; i < m.fields(); i++) + { + TMask_field& f = m.fld(i); + const TFieldref* fref = f.field(); + if (fref != NULL) + { + const char* fname = fref->name(); + if (fname != NULL) + { + TString& oldvl = cnf.get(fname); + if (!oldvl.empty()) + f.set(oldvl); + } + } + } + + + // run mask + disable_menu_item(M_FILE_NEW); + disable_menu_item(M_FILE_REVERT); + + if (m.run() == K_ENTER) + { + // aggiusta campi + for (i = 0; i < m.fields(); i++) + { + TMask_field& f = m.fld(i); + if (f.dirty()) + { + const TFieldref* fref = f.field(); + if (fref != NULL) + { + const char* fname = fref->name(); + const char* value = f.get(); + const char* oldvl = cnf.get(fname); + if (change_config(fname,oldvl,value)) + cnf.set(fname, value, NULL, TRUE); + } + } + } + ok = TRUE; + } + else ok = FALSE; + enable_menu_item(M_FILE_NEW); + enable_menu_item(M_FILE_REVERT); + return ok; + } + return warning_box("Nessun parametro da configurare"); +} + +bool TApplication::change_config(const char* var, const char* oldv, + const char* newv) + +{ return TRUE; } diff --git a/include/execp.cpp b/include/execp.cpp index 95b26ea70..ea64a2a52 100755 --- a/include/execp.cpp +++ b/include/execp.cpp @@ -1,129 +1,129 @@ -// fv 6/10/93 - -#include - -#include - -#if XVT_OS == XVT_OS_SCOUNIX -#include -#include -#endif - -#if XVT_OS == XVT_OS_WIN -#include -#include -#endif - -#if XVT_OS == XVT_OS_DOS -#include -#endif - -#include - - -// char _path[120]; // app name -// int _error; // last error -// int _exitcode; // last exit code -// int _count; // count of calls returning 0 -// int error() { return _error}; -// int exitcode() { return _exitcode}; -// int count() { return _count; }; - -int TExternal_app::run(bool async) -{ - - _error = 0; - _exitcode = 0; - - // save cwd - save_dir(); - - -#if XVT_OS == XVT_OS_DOS - - // ems swap - setems(1); - // *** BLinker support; uncomment as needed - // BLIUNHOOK(); - // ******************* - char* s = getenv("TMPDIR"); - if (s == NULL) - _exitcode = holdev("\\tmp;",0,_path); - else - _exitcode = holdev(s,0,_path); - // *** BLinker support; uncomment as needed - // BLREINIT(); - // ******************* - if (!_exitcode) - _exitcode = childret(); - else - _exitcode = -_exitcode; - xvt_escape(XVT_ESC_CH_REFRESH); - -#elif XVT_OS == XVT_OS_WIN - set_cursor(TASK_WIN, CURSOR_WAIT); - _exitcode = WinExec((char*)_path, SW_SHOW); - if (_exitcode >= 32) - { - if (!async) MainApp()->wait_for(_path); - _exitcode = 0; - } - else - error_box("Impossibile eseguire %s: errore %d", (const char*)_path, _exitcode); - - set_cursor(TASK_WIN, CURSOR_ARROW); -#else - - switch (fork()) - { - case -1: - _error = errno; - _exitcode = -1; - break; - case 0: - const char* s = strdup(_path); - char* p = strchr(s, ' '); - if (p) *p = '\0'; - const char* pathn = strdup(s); - const char* args[21]; - int i = 0; - args[i++] = pathn; - while ((i < 20) && (p)) - { - s = p + 1; - p = strchr(s, ' '); - if (p) *p = '\0'; - args[i++] = strdup(s); - } - args[i] = NULL; - for (i = 3; i < _NFILE; i++) fcntl(i,F_SETFD,1); - // execvp(_path, NULL); - execvp ( pathn , args ); - exit ( -1 ); - default: - if(wait(&_exitcode) == -1) - _exitcode = -1; - else _exitcode = _exitcode >> 8; - break; - } - _error = errno; - xvt_escape(XVT_ESC_CH_REFRESH); - -#endif - - // restore cwd - restore_dir(); - - // update counts - if (_exitcode == 0) - _count++; - return _exitcode; -} - -TExternal_app::TExternal_app(const char* p) -{ - _path = p; - _count = 0; - _error = 0; - _exitcode = 0; -} +// fv 6/10/93 + +#include + +#include + +#if XVT_OS == XVT_OS_SCOUNIX +#include +#include +#endif + +#if XVT_OS == XVT_OS_WIN +#include +#include +#endif + +#if XVT_OS == XVT_OS_DOS +#include +#endif + +#include + + +// char _path[120]; // app name +// int _error; // last error +// int _exitcode; // last exit code +// int _count; // count of calls returning 0 +// int error() { return _error}; +// int exitcode() { return _exitcode}; +// int count() { return _count; }; + +int TExternal_app::run(bool async) +{ + + _error = 0; + _exitcode = 0; + + // save cwd + save_dir(); + + +#if XVT_OS == XVT_OS_DOS + + // ems swap + setems(1); + // *** BLinker support; uncomment as needed + // BLIUNHOOK(); + // ******************* + char* s = getenv("TMPDIR"); + if (s == NULL) + _exitcode = holdev("\\tmp;",0,_path); + else + _exitcode = holdev(s,0,_path); + // *** BLinker support; uncomment as needed + // BLREINIT(); + // ******************* + if (!_exitcode) + _exitcode = childret(); + else + _exitcode = -_exitcode; + xvt_escape(XVT_ESC_CH_REFRESH); + +#elif XVT_OS == XVT_OS_WIN + set_cursor(TASK_WIN, CURSOR_WAIT); + _exitcode = WinExec((char*)_path, SW_SHOW); + if (_exitcode >= 32) + { + if (!async) MainApp()->wait_for(_path); + _exitcode = 0; + } + else + error_box("Impossibile eseguire '%s':\nErrore %d", (const char*)_path, _exitcode); + + set_cursor(TASK_WIN, CURSOR_ARROW); +#else + + switch (fork()) + { + case -1: + _error = errno; + _exitcode = -1; + break; + case 0: + const char* s = strdup(_path); + char* p = strchr(s, ' '); + if (p) *p = '\0'; + const char* pathn = strdup(s); + const char* args[21]; + int i = 0; + args[i++] = pathn; + while ((i < 20) && (p)) + { + s = p + 1; + p = strchr(s, ' '); + if (p) *p = '\0'; + args[i++] = strdup(s); + } + args[i] = NULL; + for (i = 3; i < _NFILE; i++) fcntl(i,F_SETFD,1); + // execvp(_path, NULL); + execvp ( pathn , args ); + exit ( -1 ); + default: + if(wait(&_exitcode) == -1) + _exitcode = -1; + else _exitcode = _exitcode >> 8; + break; + } + _error = errno; + xvt_escape(XVT_ESC_CH_REFRESH); + +#endif + + // restore cwd + restore_dir(); + + // update counts + if (_exitcode == 0) + _count++; + return _exitcode; +} + +TExternal_app::TExternal_app(const char* p) +{ + _path = p; + _count = 0; + _error = 0; + _exitcode = 0; +} diff --git a/include/maskfld.cpp b/include/maskfld.cpp index 4f6ab5b5f..f91b3cf27 100755 --- a/include/maskfld.cpp +++ b/include/maskfld.cpp @@ -1,2885 +1,2885 @@ -// $Id: maskfld.cpp,v 1.20 1994-09-20 12:24:49 guy Exp $ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if XVT_OS == XVT_OS_WIN -#include -#endif - -HIDDEN const int MAXSTR = 128; -HIDDEN char __fpark[MAXSTR]; // Temporary for get/set window data -HIDDEN TFixed_string fpark(__fpark, MAXSTR); - -/////////////////////////////////////////////////////////// -// Field Flags -/////////////////////////////////////////////////////////// - -// Certified 100% -TMask_field::TField_Flags::TField_Flags() -{ - automagic = persistent = FALSE; - enabled = enable_default = TRUE; - showed = show_default = TRUE; - uppercase = rightjust = FALSE; - zerofilled = FALSE; - dirty = focusdirty = FALSE; - roman = exchange = FALSE; - firm = ghost = FALSE; -} - -// Certified 100% -char TMask_field::TField_Flags::update(const char* s) -{ - const char* kk = s; - for (; *s; s++) - switch(toupper(*s)) - { - case 'A': - automagic = persistent = TRUE; break; - case 'D': - enable_default = enabled = FALSE; break; - case 'F': - firm = persistent = TRUE; break; - case 'G': - ghost = TRUE; break; - case 'H': - show_default = showed = FALSE; break; - case 'M': - roman = TRUE; break; - case 'P': - persistent = TRUE; break; - case 'R': - rightjust = TRUE; break; - case 'U': - uppercase = TRUE; break; - case 'V': - exchange = TRUE; break; - case 'Z': - zerofilled = TRUE; break; -#ifdef DBG - default : ::warning_box("FLAG sconosciuto in %s: %c", kk, *s); break; -#endif - } - return *s; -} - - -/////////////////////////////////////////////////////////// -// TMask_field -/////////////////////////////////////////////////////////// - -int TMask_field::_x; // Position of the field -int TMask_field::_y; -int TMask_field::_width; -TFixed_string TMask_field::_prompt(__fpark, MAXSTR); // Prompt of the field - -TMask_field::TMask_field(TMask* m) -: _mask(m), _win(NULL_WIN), _promptwin(NULL_WIN), _dlg(0), - _keys(0), _groups(0), _help(0), _handler(NULL), - _validate_func(-1), _validate_parms(1), _field(NULL) -{} - -// Certified 100% -TMask_field::~TMask_field() -{ - if (_field) delete _field; -} - - -// Certified 100% -bool TMask_field::is_edit() const -{ - const word c = class_id(); - return c == CLASS_EDIT_FIELD || c == CLASS_REAL_FIELD || c == CLASS_DATE_FIELD; -} - - -// Certified 100% -const char* TMask_field::class_name() const -{ return "Field"; } - - -// Certified 100% -word TMask_field::class_id() const -{ return CLASS_FIELD; } - - -// Certified 100% -bool TMask_field::ok() const -{ return win() != NULL_WIN && dlg() >= -1; } - - -// Certified 100% -void TMask_field::parse_head(TScanner&) -{} - - -// Certified 100% -short TMask_field::atodlg(const char* s) const -{ - short d = s ? atoi(s) : 0; - -#ifdef DBG - if (d == 0 || d < -1 || d > 1000) - { - yesnofatal_box("Identificatore non valido nel campo %d: '%s'", dlg(), s); - d = -1; - } -#endif - - return d; -} - -void TMask_field::construct(short id, const char* prompt, int x, int y, - int len, WINDOW parent, const char* flags, int width) -{ - _x = x; _y = y; - _prompt = prompt; - _size = len; - if (class_id() == CLASS_REAL_FIELD) - { - ((TReal_field*)this)->set_decimals(width); - _width = _size; - } - else _width = width < 1 ? _size : width; - _dlg = id; - _flags.update(flags); - - create(parent); -} - - -void TMask_field::construct(TScanner& scanner, WINDOW parent) -{ - _dlg = atodlg(scanner.pop()); - parse_head(scanner); - _prompt.cut(0); - - scanner.popkey(); // BEGIN -#ifdef DBG - if (scanner.key() != "BE") - { - yesnofatal_box("Testata errata o BEGIN mancante nel campo %d", _dlg); - scanner.push(); - } -#endif - - while(scanner.popkey() != "EN") // END of control - parse_item(scanner); - create(parent); -} - -bool TMask_field::parse_item(TScanner& scanner) -{ - if (scanner.key() == "PR") // PROMPT - { - _x = scanner.integer(); - _y = scanner.integer(); - _prompt = scanner.string(); - return TRUE; - } - - if (scanner.key() == "FL") // FLAG - { - const char* f = scanner.string(); - return _flags.update(f) == '\0'; - } - - if (scanner.key() == "FI") // FIELD - { - CHECKD(_field == NULL, "Only one FIELD, please: ", dlg()); - _field = new TFieldref(scanner.line(), 0); - return TRUE; - } - - if (scanner.key() == "HE") // HELP - { - _help = scanner.string(); - return TRUE; - } - - if (scanner.key() == "KE") // KEY - { - _keys.set(scanner.line()); - _keys.set(0L); - return TRUE; - } - - if (scanner.key() == "ME") - { - if (_message.objptr(0) == 0) - _message.add(new TToken_string(64), 0); - TToken_string& ts = (TToken_string&)_message[0]; - ts.add(scanner.line().strip_spaces()); - return TRUE; - } - - if (scanner.key() == "GR") - { - _groups.set(scanner.line()); - return TRUE; - } - - return FALSE; -} - - -long TMask_field::default_flags() const -{ - long f = CTL_FLAG_NATIVE_JUST; - - if (_flags.show_default == FALSE) f |= CTL_FLAG_INVISIBLE; - if (_flags.enable_default == FALSE) f |= CTL_FLAG_DISABLED; - - return f; -} - -// Certified 100% -WINDOW TMask_field::wincreate(WIN_TYPE ct, short dx, short dy, - const char* title, WINDOW parent, - long flags) -{ - _win = xvt_create_control(ct, - _x, _y, dx, dy, - (char*)title, - parent, - flags | default_flags(), - PTR_LONG(this), - _dlg); - - return _win; -} - - -// Certified 100% -WINDOW TMask_field::parent() const -{ return get_parent(win()); } - - -// Certified 90% -int TMask_field::create_prompt(WINDOW parent, int width, int heigth) -{ - const WIN_TYPE wt = (heigth < 3) ? WC_TEXT : WC_GROUPBOX; - if (width < 1) width = strlen(_prompt); - _prompt.rtrim(); // Could save some bytes - - if (width) - { - // Static controls shouldn't be grayed - const long flags = default_flags() & (~CTL_FLAG_DISABLED); -#if XVT_OS == XVT_OS_WIN - char* k = strchr(_prompt, '~'); - if (k != NULL) *k = '&'; -#endif - _promptwin = xvt_create_control - ( - wt, - _x, _y, width, heigth, - _prompt, - parent, - flags, - 0L, - -1 - ); - } - return width; -} - - -// Certified 100% -void TMask_field::destroy() -{ - if (_win) - { close_window(_win); _win = NULL_WIN; } - if (_promptwin) - { close_window(_promptwin); _promptwin = NULL_WIN; } -} - - -// Certified 100% -void TMask_field::create(WINDOW parent) -{ - _width = strlen(_prompt); - if (_width) - wincreate(WC_TEXT, _width, 1, _prompt, parent, CTL_FLAG_LEFT_JUST); -} - - -// Certified 100% -void TMask_field::enable(bool on) -{ - const word c = class_id(); - if (c != CLASS_FIELD) - { - enable_window(_win, on); - _flags.enabled = on; - } -} - - -// Certified 100% -void TMask_field::enable_default() -{ - const bool ed = _flags.enable_default; - enable(ed); -} - - -// Certified 100% -void TMask_field::show(bool on) -{ - show_window(_win, on); - if (_promptwin != NULL_WIN) - show_window(_promptwin, on); - _flags.showed = on; -} - - -// Certified 100% -void TMask_field::show_default() -{ - const bool sd = _flags.show_default; - show(sd); -} - - -// Certified 100% -bool TMask_field::active() const -{ - return enabled() && showed() && class_id() != CLASS_FIELD; -}; - - -// Certified 90% -word TMask_field::last_key() const -{ - long u = _keys.last_one(); - if (u < 0) u = 0; - return (word)u; -} - - -// Certified 99% -const char* TMask_field::get_window_data() const -{ - get_title(win(), __fpark, MAXSTR); - return __fpark; -} - - -// Certified 99% -void TMask_field::set_window_data(const char* data) -{ - if (data != NULL) - set_title(win(), (char*)data); -} - - -// Certified 100% -void TMask_field::set_field_data(const char*) -{} - - -// Certified 100% -const char* TMask_field::get_field_data() const -{ return NULL; } - - -const char* TMask_field::picture_data(const char* data, bool video) -{ - fpark = data; - if (video) - { - fpark.trim(); - if (_flags.uppercase) fpark.upper(); - } - return fpark; -} - - -// Certified 90% -const char* TMask_field::prompt() const -{ - if (_promptwin != NULL_WIN) - _prompt = xvt_get_title(_promptwin); - else - _prompt = ""; - - return _prompt; -} - - -// Certified 100% -void TMask_field::reset() -{ - if (!_flags.persistent && class_id() != CLASS_FIELD) - set(""); -} - - -// Certified 100% -void TMask_field::set_prompt(const char* p) -{ - if (_promptwin != NULL_WIN) - set_title(_promptwin, (char*) p); -} - - -void TMask_field::set(const char* s) -{ - if (mask().is_running()) - { - set_window_data(s); - set_dirty(); - } - else - set_field_data(s); -} - -TString& TMask_field::get() const -{ - static TString80 gpark; - - if (mask().is_running()) - gpark = get_window_data(); - else - gpark = get_field_data(); - - return gpark.trim(); -} - - -void TMask_field::undo() -{ - set_window_data(get_field_data()); -} - - -bool TMask_field::autoload(const TRelation* r) -{ - if (_field) - { - set(_field->read(r)); - return TRUE; - } - return FALSE; -} - - -bool TMask_field::autosave(TRelation* r) const -{ - if (_field) - { - _field->write(get(), r); - return TRUE; - } - return FALSE; -} - - -// Certified 50% -HIDDEN void modify_list(bool add, TMask_field& f, TToken_string& msg) -{ -#ifdef DBG - if (f.class_id() != CLASS_LIST_FIELD) - { - error_box("Can't add/delete items of non list-box field %d", f.dlg()); - return; - } -#endif - TList_field& l = (TList_field&)f; - - TToken_string item(16); - item = msg.get(); - if (add) item.add(msg.get()); - item.strip("\"'"); - if (add) - l.add_item(item); - else - l.delete_item(item); -} - - -// Certified 90% -HIDDEN const char* copy_value(TToken_string& msg, const TString& val) -{ - int from = msg.get_int()-1; - int to = 0; - if (from < 0) from = 0; - else to = msg.get_int(); - return val.sub(from, to); -} - - -// Certified 50% -bool TMask_field::do_message(int num) -{ - const int MAX_CMD = 14; - static const char* commands[MAX_CMD] = - { - "ADD", // 0 - "CLEAR", // 1 - "CO", // 2 - "DEL", // 3 - "DIRTY", // 4 - "DISABLE", // 5 - "ENABLE", // 6 - "ENABLEDEF", // 7 - "EXIT", // 8 - "HIDE", // 9 - "PUSH", // 10 - "RESET", // 11 - "SHOW", // 12 - "UNDO" // 13 - }; - - TToken_string* message = (TToken_string*)_message.objptr(num); - if (message == NULL || message->empty()) return FALSE; - - TToken_string msg(16, ','); - TString value(16); - - for (const char* m = message->get(0); m && *m; m = message->get()) - { - KEY key = 0; - msg = m; - value = msg.get(); - value.trim(); - const char* dlg = msg.get(); - - int cmd = -1; - if (isalpha(value[0])) // binary search - { - int f = 0, l = MAX_CMD-1; - while (TRUE) - { - cmd = (f+l)>>1; - const int cmp = strcmp(value, commands[cmd]); - if (cmp == 0) break; - if (cmp > 0) f = cmd+1; - else l = cmd-1; - if (f > l) - { - cmd = -1; - break; - } - } - } - - if (cmd == 8) - { - mask().stop_run(atoi(dlg)); - continue; - } - - short fld = (dlg && dlg[0] > ' ') ? atodlg(dlg) : 0; - bool broadcast = dlg && strchr(dlg, '@'); - if (value[0] == '"') value = value.strip("\"'"); - else switch (cmd) - { - case 0: - modify_list(TRUE, mask().field(fld), msg); continue; - case 1: - key = 11000+'c'; break; - case 2: - value = copy_value(msg, get()); break; - case 3: - modify_list(FALSE, mask().field(fld), msg); continue; - case 4: - mask().field(fld).set_dirty(); continue; - case 5: - key = 11000+'d'; break; - case 6: - key = 11000+'e'; break; - case 7: - key = 11000+'E'; break; - case 9: - key = 11000+'h'; break; - case 10: - key = K_SPACE; break; - case 11: - key = K_F2; break; - case 12: - key = 11000+'s'; break; - case 13: - key = K_F3; break; - default: - key = atoi(value); - break; - } - - if (key) - { - if (key > 0) - { - if (broadcast) fld = -fld; - mask().send_key(key, fld); - } - } - else - { - // Setta a value il campo fld solo se ha un valore diverso da value - if (broadcast) - { - for (int i = 0; i < mask().fields(); i++) - { - TMask_field& f = mask().fld(i); - if (f.in_group((int)fld)) - { - const char* prev = f.get(); - if (value != prev) - { - f.set(value); - if (f.showed() || f.ghost()) - f.on_hit(); - } - } - } - } - else - { - TMask_field& f = mask().field(fld); - const char* prev = f.get(); - if (value != prev) - { - f.set(value); - if (f.showed() || f.ghost()) - f.on_hit(); - } - } - } - } - - return TRUE; -} - - -// Certified 90% -bool TMask_field::on_hit() -{ - if (_handler) - { - bool ok = _handler(*this, is_edit() ? K_TAB : K_SPACE); - if (!ok) return FALSE; - } - do_message(0); - return TRUE; -} - - -bool TMask_field::to_check(KEY k, bool checkrun) const -{ - bool yes = (k == K_TAB && focusdirty()) || (k == K_ENTER && dirty()); - - if (!yes && checkrun) - yes = k == K_TAB && !mask().is_running(); - - return yes; -} - -// Certified 90% -bool TMask_field::on_key(KEY key) -{ - if (key > 11000) - { - switch(key-11000) - { - case 'E': - enable_default(); break; - case 'c': - reset(); on_hit(); - case 'd': - disable(); break; - case 'e': - enable(); break; - case 'h': - hide(); break; - case 's': - show(); break; -#ifdef DBG - default : - return yesnofatal_box("Invalid key sent to field %d: %d", dlg(), key); -#endif - } - return TRUE; - } - - switch(key) - { - case K_SPACE: - set_dirty(); - break; - case K_PREV: - case K_NEXT: - dispatch_e_char(parent(), key); - break; - case K_F1: - if (_help.not_empty()) - message_box(_help); - else - beep(); - break; - case K_F2: - reset(); - set_dirty(); - break; - case K_F3: - undo(); - set_dirty(); - break; - default: - break; - } - - if (_handler) - return _handler(*this, key); - - return TRUE; -} - - -void TMask_field::set_focus() const -{ - const bool force = mask().is_running(); - mask().set_focus_win(win(), force); -} - -HIDDEN char* const _msg = &__tmp_string[512]; -#define build_msg() va_list argptr;va_start(argptr,fmt);vsprintf(_msg,fmt,argptr);va_end(argptr) - -bool TMask_field::error_box(const char* fmt, ...) const -{ - build_msg(); - if (mask().is_running()) - { - set_focus(); - ::error_box("%s", _msg); - set_focus(); - } - else - { - xvt_statbar_set(_msg); - beep(); - } - return FALSE; -} - -bool TMask_field::message_box(const char* fmt, ...) const -{ - set_focus(); - build_msg(); - ::message_box("%s", _msg); - set_focus(); - return FALSE; -} - -bool TMask_field::warning_box(const char* fmt, ...) const -{ - build_msg(); - - if (mask().is_running()) - { - set_focus(); - ::warning_box("%s", _msg); - set_focus(); - } - else - { - xvt_statbar_set(_msg); - beep(); - } - return FALSE; -} - -bool TMask_field::yesno_box(const char* fmt, ...) const -{ - set_focus(); - build_msg(); - const bool yes = ::yesno_box("%s", _msg); - set_focus(); - return yes; -} - -KEY TMask_field::yesnocancel_box(const char* fmt, ...) const -{ - set_focus(); - build_msg(); - const KEY k = ::yesnocancel_box("%s", _msg); - set_focus(); - return k; -} - -/////////////////////////////////////////////////////////// -// TList_sheet -/////////////////////////////////////////////////////////// - -// Certified 100% -TList_sheet::TList_sheet(TEdit_field* f, const char* caption, const char* head) -: _fld(f), _row(-1) -{ - _sheet = new TArray_sheet(-1, -1, 0, 0, caption, head); -} - -// Certified 100% -TList_sheet::~TList_sheet() -{ - delete _sheet; -} - -// Certified 100% -TMask_field& TList_sheet::field(short id) const -{ return field().mask().field(id); } - - -// Certified 100% -void TList_sheet::read_item(TScanner& scanner) -{ - TToken_string ts(scanner.string()); - _sheet->add(ts); -} - - -// Certified 100% -void TList_sheet::parse_input(TScanner& scanner) -{ - _inp_id.add(scanner.pop()); -} - - -// Certified 100% -void TList_sheet::parse_output(TScanner& scanner) -{ - _out_id.add(scanner.pop()); -} - -// il numero di riga selezionata -int TList_sheet::do_input() -{ - if (_inp_id.empty()) return -2; // List empty! - - _inp_id.restart(); - TToken_string rowsel(80); - - for (const char* fld = _inp_id.get(); fld; fld = _inp_id.get()) - { - if (*fld == '"') - { - rowsel.add(fld+1); - if (rowsel.not_empty()) rowsel.cut(rowsel.len()-1); - } - else - { - const short id = _fld->atodlg(fld); - if (id > 0) rowsel.add(field().mask().get(id)); - else rowsel.add(""); - } - } - - TString80 fd, it; - for (int i = 0 ; i < _sheet->items(); i++) - { - TToken_string& ts =_sheet->row(i); - - ts.restart(); - for ( const char* item = rowsel.get(0); item ; item = rowsel.get()) - { - it = item; it.trim(); - fd = ts.get(); fd.trim(); - if (fd != it) break; - } - if (!item) return i; - } - - return -1; // Value not found! -} - - -// Certified 50% -void TList_sheet::do_output(CheckTime t) -{ - if (_row < 0 || t == FINAL_CHECK) - return; - - _out_id.restart(); - TToken_string& rowsel = _sheet->row(_row); - rowsel.restart(); - for (const char* fld = _out_id.get(); fld; fld = _out_id.get()) - { - const short id = _fld->atodlg(fld); - if (t != STARTING_CHECK || field().field() == NULL) - { - TMask_field& f = field(id); - f.set(rowsel.get()); - if (field().dlg() != id) - f.on_hit(); - } - } -} - - -// Certified 100% -KEY TList_sheet::run() -{ - _row = do_input(); - - _sheet->select(_row); - - const KEY k = _sheet->run(); - - switch (k) - { - case K_ENTER: - _row = (int)_sheet->selected(); - do_output(); - break; - default: - break; - } - - return k; -} - - -// Certified 100% -bool TList_sheet::check(CheckTime t) -{ - const bool passed = (_row = do_input()) != -1; - if (passed) do_output(t); - return passed; -} - - -/////////////////////////////////////////////////////////// -// TBrowse -/////////////////////////////////////////////////////////// - -// Certified 100% -TBrowse::TBrowse(TEdit_field* f, TRelation* r, int key, const char* filter) -: _relation(r), _cursor(new TCursor (r, filter, key)), - _fld(f), _filter(filter), _secondary(FALSE), - _checked(FALSE) -{} - - -// Certified 100% -TBrowse::TBrowse(TEdit_field* f, TCursor* c) -: _relation(NULL), _cursor(c), _fld(f) -{} - - -// Certified 100% -TBrowse::~TBrowse() -{ - if (_relation) - { - delete _relation; - delete _cursor; - } -} - - -// Certified 100% -void TBrowse::parse_display(TScanner& scanner) -{ - const char* s; - s = scanner.string(); - _head.add(s); - s = scanner.line(); - _items.add(s); -} - - -void TBrowse::parse_input(TScanner& scanner) -{ - const char* s = scanner.pop(); - _inp_fn.add(s); - - s = scanner.pop(); - if (*s == '"') // Constant string - { - scanner.push(); - _inp_id.add(scanner.line()); - } - else // Field on the mask - { - TString80 str(s); - if (scanner.popkey() == "SE") str << '@'; // Special FILTERing field - else scanner.push(); - _inp_id.add(str); - } -} - - -void TBrowse::parse_output(TScanner& scanner) -{ - const char* s = scanner.pop(); -#ifdef DBG - field().atodlg(s); -#endif - _out_id.add(s); - s = scanner.pop(); - _out_fn.add(s); -} - - -bool TBrowse::parse_copy(const TString& what, const TBrowse* b) -{ - const bool all = what == "AL"; - if (all || what == "US") - { - set_insert(b->get_insert()); - _filter = b->get_filter(); - if (!all) return TRUE; - } - if (all || what == "IN") - { - _inp_id = b->_inp_id; - _inp_fn = b->_inp_fn; - if (!all) return TRUE; - } - if (all || what == "DI") - { - _head = b->_head; - _items = b->_items; - if (!all) return TRUE; - } - if (all || what == "OU") - { - _out_id = b->_out_id; - _out_fn = b->_out_fn; - _secondary = TRUE; - } - return TRUE; -} - - -void TBrowse::parse_join(TScanner& scanner) -{ - TString80 j(scanner.pop()); // File or table - - CHECKS(_relation, "Can't join to NULL relation ", (const char*)j); - - int to; - if (scanner.popkey() == "TO") // TO keyword - { - const char* t = scanner.pop(); - to = name2log(t); - } - else - { - to = 0; // _relation->lfile()->num(); - scanner.push(); - } - - int key = 1; - if (scanner.popkey() == "KE") - key = scanner.integer(); - else scanner.push(); - - byte alias = 0; - if (scanner.popkey() == "AL") - alias = scanner.integer(); - else scanner.push(); - - TToken_string exp(80); - if (scanner.pop() == "INTO") - { - const char* r = scanner.pop(); - while (strchr(r, '=') != NULL) - { - exp.add(r); - r = scanner.pop(); - } - } - scanner.push(); - -#ifdef DBG - if (exp.empty()) yesnofatal_box("JOIN senza espressioni INTO"); -#endif - - if (isdigit(j[0])) - _relation->add(atoi(j), exp, key, to, alias); // join file - else - { -#ifdef DBG - if (j.len() > 4) - yesnofatal_box("'%s' non e' una tabella valida: %d", (const char*)j); - else -#endif - _relation->add(j, exp, key, to, alias); // join table - } -} - - -void TBrowse::parse_insert(TScanner& scanner) -{ - if (scanner.popkey() == "RU") - { - _insert = "R"; - _insert << scanner.line(); - } - else - { - _insert = "M"; - _insert << scanner.line(); - } - _insert.trim(); -} - - -// Certified 100% -TMask_field& TBrowse::field(short n) const -{ return _fld->mask().field(n); } - -// Ritorna il numero di campi non vuoti e non filtrati -int TBrowse::do_input(bool filter) -{ - int ne = 0; - if (_inp_id.empty()) return ne; - - TRectype& cur = _cursor->curr(); - - cur.zero(); - TRectype filtrec(cur); - - _inp_id.restart(); - _inp_fn.restart(); - - TString80 val; // Value to output - bool tofilter; - - for (const char* fld = _inp_id.get(); fld; fld = _inp_id.get()) - { - if (*fld == '"') - { - val = (fld+1); - if (val.not_empty()) val.rtrim(1); - tofilter = filter; - } - else - { - const short id = _fld->atodlg(fld); - const bool filter_flag = strchr(fld, '@') != NULL; - tofilter = filter && filter_flag; - val = field(id).get(); - if (field(id).is_edit() && val.not_empty() && !filter_flag) - ne++; // Increment not empty fields count - } - - TFieldref fldref(_inp_fn.get(), 0); // Output field - fldref.write(val, _cursor->relation()); - if (tofilter) - { - if (val.empty()) val.fill('~', fldref.len(cur)); - fldref.write(val, filtrec); - } - } - - if (!filter) return ne; - - TString work(_filter.size()); - for (int i = 0; _filter[i]; i++) - { - if (_filter[i] == '"') - { - do - { - work << _filter[i++]; - } while (_filter[i] && _filter[i] != '"'); - work << '"'; - if (!_filter[i]) break; - } - else - if (_filter[i] == '#') - { - work << '"' << field(atoi(&_filter[++i])).get() << '"'; - while (isspace(_filter[i])) i++; - while (isdigit(_filter[i])) i++; - i--; - } - else work << _filter[i]; - } - - _cursor->setfilter(work); - _cursor->setregion(filtrec, filtrec); - - return ne; -} - - -void TBrowse::do_output(CheckTime t) -{ - if (t == FINAL_CHECK) - return; - - TString80 sum; - TToken_string flds(24, '+'); - - _out_fn.restart(); - for (const char* fld = _out_id.get(0); fld && *fld; fld = _out_id.get()) - { - const short id = field().atodlg(fld); - TMask_field& f = field(id); - - flds = _out_fn.get(); - if (t != STARTING_CHECK || f.field() == NULL || f.mask().mode() == MODE_INS) - { - sum.cut(0); - for(const char* fr = flds.get(); fr; fr = flds.get()) - { - TFieldref fld(fr, 0); - const char* val = fld.read(_cursor->relation()); - sum << val; - } - - f.set(sum); - if (field().dlg() != id) - f.on_hit(); - } - } -} - - -void TBrowse::do_clear() -{ - for (TString16 fld = _out_id.get(0); fld.not_empty(); fld = _out_id.get()) - { - TMask_field& f = field(atoi(fld)); - if (f.field() == NULL && _inp_id.get_pos(fld) < 0) - f.reset(); - } -} - - - -bool TBrowse::do_insert() -{ - bool ok = FALSE; - TString80 app; - - if (_insert[0] == 'M') - { - TString80 nm(_insert.mid(1)); - if (strncmp(nm, "BATB", 4) == 0) // Programma gestione tabelle - app = format("ba3 -0 %s", (const char*)nm.mid(4)); - // Obbligatorio usare la format globale - else // Programma generico di browse/edit - app = format("ba3 -3 %s %d", (const char*)nm, _cursor->file()->num()); - // Obbligatorio usare la format globale - } - else - { - app = _insert.mid(1); - } - -#if XVT_OS == XVT_OS_WIN - if (strnicmp(app, MainApp()->name(), 3) == 0) - app.insert("a", 3); -#endif - - TMailbox mail; - TMessage msg(cmd2name(app), MSG_AI, ""); - mail.send(msg); - - TExternal_app a(app); - a.run(); - - if (mail.check()) - { - TMessage* rcv = mail.next_s(MSG_AI); - if (rcv != NULL) _rec = atoi(rcv->body()); - if (_rec > 0) - { - _cursor->file()->readat(_rec); - ok = _cursor->ok(); - if (ok) do_output(); -#ifdef DBG - else error_box("Selezione da programma esterno errata"); -#endif - } - } - return ok; -} - - -TToken_string& TBrowse::create_siblings(TToken_string& siblings) -{ - const TMask& mask = field().mask(); - siblings = ""; // Azzera la lista dei campi associati - - if (!mask.is_running()) - return siblings; // Non saprei come fare - - TBit_array key(4); // Elenco delle chiavi gia' utilizzate - - // Scorre la lista dei campi di output - int n = 0; - for (const char* i = _out_id.get(0); i; i = _out_id.get(), n++) - { - const short id = atoi(i); - const TMask_field& f = mask.field(id); - if (!f.showed() || !f.is_edit()) // Scarta i campi non editabili - continue; - const TEdit_field& e = (const TEdit_field&)f; - const TBrowse* b = e.browse(); - if (b == NULL) - continue; // Scarta i campi senza ricerca (improbabile) - - const TCursor* c = b->cursor(); - - // Considera ricerche sullo stesso file ma con chiave diversa - if (c && c->file()->num() == _cursor->file()->num() && - key[c->key()] == FALSE) - { - const TString16 fn(_out_fn.get(n)); // Legge nome del campo su file - const int pos = _items.get_pos(fn); // Determina header corrispondente - if (pos >= 0) - { - siblings.add(id); - const char* h = _head.get(pos); - siblings.add(h); - const int et = siblings.find('@'); - if (et > 0) siblings.cut(et); - key.set(c->key()); // Marca la chiave come usata - } - } - } - - return siblings; -} - - -KEY TBrowse::run() -{ - do_input(TRUE); - _cursor->read(); - - const char* caption = field().prompt(); - if (!isalnum(*caption)) caption = "Selezione"; - - KEY k = K_ESC; - long selected = 0; - - TToken_string siblings; create_siblings(siblings); - -{ - TToken_string* sib = siblings.empty() ? NULL : &siblings; - const byte buttons = _insert.empty() ? 0 : 1; - TBrowse_sheet s(_cursor, _items, caption, _head, buttons, _fld, sib); - k = s.run(); - selected = s.selected(); -} - -switch (k) -{ - case K_INS: - k = do_insert() ? K_ENTER : K_ESC; - break; - case K_ENTER: - *_cursor = selected; - do_output(); - break; -default: - if (k >= K_CTRL) - { - const short id = siblings.get_int((k - K_CTRL) << 1); - TEdit_field& ef = (TEdit_field&)_fld->mask().field(id); - if (ef.mask().is_running()) ef.set_focus(); - else ef.mask().first_focus(-ef.dlg()); - ef.mask().send_key(k = K_F9, 0); - } - break; -} - -return k; -} - -bool TBrowse::check(CheckTime t) -{ - bool passed = TRUE; - - if (_secondary && t != RUNNING_CHECK) - return TRUE; - // if (_checked && t == FINAL_CHECK) - // return TRUE; - // _checked = TRUE; - if (_fld->check_type() != CHECK_NONE) - { - const TMaskmode mode = (TMaskmode)field().mask().mode(); - - CheckType chk = _fld->check_type(); - const int ne = do_input(TRUE); - if (t == STARTING_CHECK || mode == MODE_QUERY) chk = CHECK_NORMAL; - if (ne || chk == CHECK_REQUIRED) - { - _cursor->setkey(); - _cursor->file()->read(_isequal); - passed = _cursor->ok(); - - if (t != FINAL_CHECK) - { - if (passed) - { - _cursor->repos(); - do_output(t); - } - else - { - do_clear(); - _fld->set_dirty(2); - } - } - } - else - if (t != FINAL_CHECK) do_clear(); - } - // _checked = passed; - return passed; -} - -bool TBrowse::empty_check() -{ - const TMaskmode mode = (TMaskmode)field().mask().mode(); - const bool no_check = mode == MODE_SEARCH || field().mask().query_mode(); - - if ( no_check || _fld->check_type() == CHECK_NONE || - _fld->check_type() == CHECK_NORMAL) - return TRUE; - else - return do_input() > 0; -} - - -/////////////////////////////////////////////////////////// -// TEdit_field -/////////////////////////////////////////////////////////// - -TEdit_field::TEdit_field(TMask* mask) -: TMask_field(mask), _browse(NULL), _sheet(NULL), - _buttonwin(NULL_WIN), _check(CHECK_NONE), _check_enabled(TRUE), - _forced(FALSE) -{} - -TEdit_field::~TEdit_field() -{ - if (_browse) delete _browse; else - if (_sheet) delete _sheet; -} - -word TEdit_field::class_id() const -{ return CLASS_EDIT_FIELD; } - - -void TEdit_field::enable(bool on) -{ - TMask_field::enable(on); - if (_buttonwin != NULL_WIN) - show_window(_buttonwin, on && _check_enabled && showed()); -} - -void TEdit_field::show(bool on) -{ - TMask_field::show(on); - if (_buttonwin != NULL_WIN) - show_window(_buttonwin, on && _check_enabled && enabled()); -} - - -void TEdit_field::parse_head(TScanner& scanner) -{ - _size = scanner.integer(); - if (_size < 1) - { - _size = 8; - error_box("Il campo %d ha dimensione nulla (uso %d)", dlg(), _size); - } - - _width = scanner.integer(); - if (_width == 0) _width = _size; -} - - -const TBrowse* TEdit_field::get_browse(TScanner& scanner) const -{ - const int id = scanner.integer(); - TMask_field& m = mask().field(id); - if (!m.is_edit()) - { - error_box("Il campo %d non puo' fare una COPY del campo %d", - dlg(), id); - return NULL; - } - - TEdit_field& f = (TEdit_field&)m ; - TBrowse* b = (TBrowse*) f.browse(); - if (b == NULL) - error_box("La USE del campo %d non puo' essere copiata da %d", - id, dlg()); - return b; -} - - -bool TEdit_field::parse_item(TScanner& scanner) -{ - if (scanner.key() == "PI") // PICTURE - { - _picture = scanner.string(); - return TRUE; - } - - if (scanner.key() == "CH") - { - scanner.pop(); - if (scanner.key() == "NO") _check = CHECK_NORMAL; - else if (scanner.key() == "RE") _check = CHECK_REQUIRED; - else if (scanner.key() == "FO") {_check = CHECK_REQUIRED; _forced = TRUE;} - else _check = CHECK_NONE; - return TRUE; - } - - if (scanner.key() == "US") // USE - { - if (_browse != NULL) - return error_box("USE duplicata nel campo %d", dlg()); - - int key = 1; - TRelation* r; - - const int logicnum = scanner.integer(); - TString16 tabmaskname; - - if (logicnum > 0) - r = new TRelation(logicnum); - else - { - tabmaskname = scanner.pop(); - if (tabmaskname.len() > 4) - return error_box("'%s' non e' una tabella valida: %d", - (const char*)tabmaskname, dlg()); - r = new TRelation(tabmaskname); - } - - if (scanner.popkey() == "KE") - { - key = scanner.integer(); - if (key < 1) - { - error_box("Chiave %d non valida nella USE del campo %d", key, dlg()); - key = 1; - } - } - else scanner.push(); - - const char* filter = ""; - if (scanner.popkey() == "SE") - filter = (const char*)scanner.line(); - else - scanner.push(); - - _browse = new TBrowse(this, r, key, filter); - - if (tabmaskname.not_empty()) - { - if (strncmp(MainApp()->name(), "ba3", 3) != 0) - { - tabmaskname.insert("MBATB", 0); - _browse->set_insert(tabmaskname); - } - } - - return TRUE; - } - - if (scanner.key() == "CO") // Copyuse - { - const TString16 what(scanner.popkey()); - - const TBrowse* b = get_browse(scanner); -#ifdef DBG - if (b == NULL) - return yesnofatal_box("Impossibile COPYare la browse nel campo %d", dlg()); -#endif - if (what == "US" || what == "AL") - _browse = new TBrowse(this, b->cursor()); - - if (_browse) - return _browse->parse_copy(what, b); - -#ifdef DBG - return yesnofatal_box("Impossibile COPY senza USE nel campo %d", dlg()); -#endif - } - - if (scanner.key() == "JO") - { -#ifdef DBG - if(!_browse) return yesnofatal_box("JOIN senza USE nel campo %d", dlg()); -#endif - _browse->parse_join(scanner); - return TRUE; - } - - if (scanner.key() == "SH") // SHEET - { - if (_sheet) return error_box("SHEET duplicato nel campo %d", dlg()); - _sheet = new TList_sheet(this, _prompt, scanner.string()); - return TRUE; - } - - if (scanner.key() == "IT") // ITEM - { - if (_sheet == NULL) - return error_box("ITEM senza SHEET nel campo %d", dlg()); - _sheet->read_item(scanner); - return TRUE; - } - - if (scanner.key() == "IN") - { - if (_browse) _browse->parse_input(scanner); else - if (_sheet) _sheet->parse_input(scanner); - else error_box("INPUT senza USE o SHEET nel campo %d", dlg()); - return TRUE; - } - - if (scanner.key() == "DI") - { - if(!_browse) - return error_box("DISPLAY senza USE nel campo %d", dlg()); - _browse->parse_display(scanner); - return TRUE; - } - - if (scanner.key() == "OU") - { - if (_browse) _browse->parse_output(scanner); - else if (_sheet) _sheet->parse_output(scanner); - else return error_box("OUTPUT senza USE nel campo %d", dlg()); - return TRUE; - } - - if (scanner.key() == "AD") - { - if(!_browse) return error_box("ADD senza USE nel campo %d", dlg()); - _browse->parse_insert(scanner); - return TRUE; - } - - if (scanner.key() == "VA") - { - const char* n = scanner.pop(); - _validate_func = isdigit(*n) ? atoi(n) : -1; - if (_validate_func < 0) - return yesnofatal_box("Funzione di validazione '%s' errata nel campo %d", n, dlg()); - - const int _nparms = scanner.integer(); - if (_nparms < 0) - return yesnofatal_box("Numero di parametri VALIDATE errato nel campo %d", dlg()); - - for(int i = 0; i < _nparms; i++) - _validate_parms.add(scanner.operand()); - - return TRUE; - } - - if (scanner.key() == "WA") - { - _warning = scanner.string(); - return TRUE; - } - if (scanner.key() == "ME") - { - TFixed_string l(scanner.line().strip_spaces()); - int m = 0; - if (l[0] == '0') - { - l.ltrim(1); - l.ltrim(); - m = 1; - } - if (_message.objptr(m) == 0) - _message.add(new TToken_string(64), m); - TToken_string& ts = (TToken_string&)_message[m]; - ts.add(l); - return TRUE; - } - - return TMask_field::parse_item(scanner); -} - - -void TEdit_field::create(WINDOW parent) -{ - const int len = create_prompt(parent); - - long align = _flags.rightjust ? CTL_FLAG_RIGHT_JUST : CTL_FLAG_LEFT_JUST; - _x += len; - -#if XVTWS == WMWS - const int delta = 2; -#else - const int delta = 1; -#endif - - wincreate(WC_EDIT, _width+delta, 1, _str, parent, align); - -#if XVT_OS == XVT_OS_WIN - HWND hwnd = (HWND)get_value(win(), ATTR_NATIVE_WINDOW); - SendMessage(hwnd, EM_LIMITTEXT, _size, 0L); // Limita il testo - long style = GetWindowLong(hwnd, GWL_STYLE); - if (_flags.uppercase) style != ES_UPPERCASE; // Edit in maiuscolo - SetWindowLong(hwnd, GWL_STYLE, style); -#endif - - if (_browse || _sheet) - { - long flags = default_flags(); - if (flags & CTL_FLAG_DISABLED) - { - flags &= ~CTL_FLAG_DISABLED; - flags |= CTL_FLAG_INVISIBLE; - } - _buttonwin = xvt_create_control(WC_PUSHBUTTON, _x+_width+delta, _y, - 2, 1, "*", parent, flags, PTR_LONG(this), DLG_F9); - } -} - -void TEdit_field::destroy() -{ - if (_buttonwin) - { close_window(_buttonwin); _buttonwin = NULL_WIN; } - TMask_field::destroy(); -} - - -void TEdit_field::set_window_data(const char* data) -{ - TMask_field::set_window_data(format(data)); -} - - -void TEdit_field::set_field_data(const char* data) -{ _str = data; } - -const char* TEdit_field::get_field_data() const -{ return _str; } - - -const char* TEdit_field::format(const char* d) -{ - fpark = d; - fpark.trim(); - - if (fpark.not_empty()) - { - if (fpark.len() > _size) - { -#ifdef DBG - error_box("Campo %d troppo lungo: %d > %d", dlg(), fpark.len(), _size); -#endif - fpark.cut(_size); - } - - if (_flags.uppercase) - fpark.upper(); - - if (_flags.zerofilled) - fpark.right_just(_size, '0'); - else - if (_flags.rightjust) - fpark.right_just(_size); - } - - return fpark; -} - - -const char* TEdit_field::picture_data(const char* data, bool video) -{ - if (video) - { - set_title(win(), (char*)data); - return get_window_data(); - } - - set_window_data(data); - TMask_field::get_window_data(); - fpark.trim(); - return fpark; -} - - -bool TEdit_field::validate(KEY k) -{ - return ::validate(_validate_func, *this, k, _validate_parms); -} - -// Certified 90% -bool TEdit_field::on_hit() -{ - if (_handler) - { - bool ok = _handler(*this, is_edit() ? K_TAB : K_SPACE); - if (!ok) return FALSE; - } - if (_message.objptr(1) && get() == "") do_message(1); - else do_message(0); - return TRUE; -} - -bool TEdit_field::on_key(KEY key) -{ - switch(key) - { - case K_TAB: - if (_validate_func == AUTOEXIT_FUNC || - _validate_func == NUMCALC_FUNC || - _validate_func == STRCALC_FUNC) - set_focusdirty(); // Forza validate - if (to_check(K_TAB, TRUE)) - { - set(get()); - bool ok = validate(key); // Check validation expression - - if (!ok) - { - if (_warning.not_empty()) error_box(_warning); - return FALSE; - } - - TMask& m = mask(); - const bool query = m.query_mode(); - - if (_sheet) ok = query || _sheet->check(); // Check consistency - else - if (check_enabled() && _browse && (!query || forced())) - ok = _browse->check(); // Check consistency - - if (!ok) - { - if (_warning.not_empty()) error_box(_warning); - else error_box("Valore del campo %d non valido: %s", dlg(), (const char*)get()); - return FALSE; - } - - ok = on_hit(); - if (!ok) - return FALSE; - - if (query && required() && in_key(0)) - { - const byte keys = m.num_keys(); - - for (int i = 1; i <= keys; i++) - if (in_key(i) && m.key_valid(i)) - { - for (int fld = m.get_key_field(i, TRUE); fld != -1; fld = m.get_key_field(i, FALSE)) - m.field(fld).set_dirty(FALSE); - dispatch_e_char(get_parent(win()), K_AUTO_ENTER); - break; - } - } - return TRUE; - } - break; - case K_ENTER: - if (field() != NULL || mask().mode() == NO_MODE) - { - if (focusdirty()) set(get()); - - bool ok = validate(K_ENTER); // Check validation expression - if (!ok) - { - if (_warning.not_empty()) error_box(_warning); - return FALSE; - } - - const bool query = mask().query_mode(); - - // check consistency - if (_sheet) ok = query || _sheet->check(FINAL_CHECK); - else if (_browse && check_enabled()) - { - if (!query || forced()) - { - if (dirty()) ok = _browse->check(FINAL_CHECK); // Check consistency - else ok = _browse->empty_check(); - } - } - else - ok = query || !(check_type() == CHECK_REQUIRED && get().empty()); - - if (!ok) - { - if (_warning.not_empty()) error_box(_warning); - else error_box("Valore del campo %d non valido: '%s'", dlg(), (const char*)get()); - return FALSE; - } - } - break; - case K_F9: - if (check_enabled()) - { - if (dirty()) set(get()); - KEY k = K_ESC; - if (_browse) k = _browse->run(); - else if (_sheet) k = _sheet->run(); - else beep(); - if (mask().is_running() && k != K_F9) set_focus(); - if (k == K_ENTER) - { - set_dirty(); - if (mask().is_running()) - mask().send_key(K_TAB, 0); - else - on_hit(); - return TRUE; - } - else - return FALSE; - } - break; - default: - break; - } - - return TMask_field::on_key(key); -} - - -bool TEdit_field::has_check() const -{ - if (_browse) return check_type() != CHECK_NONE; - return _sheet != NULL; -} - -bool TEdit_field::check(CheckTime t) -{ - if (check_enabled() || (t == STARTING_CHECK && showed())) - { - if (_browse) return _browse->check(t); else - if (_sheet) return _sheet->check(t); - } - return TRUE; -} - -void TEdit_field::enable_check(bool on) -{ - _check_enabled = on; - if (_buttonwin != NULL_WIN) - show_window(_buttonwin, on); -} - - -/////////////////////////////////////////////////////////// -// Boolean_field -/////////////////////////////////////////////////////////// - - -TBoolean_field::TBoolean_field(TMask* m) -: TMask_field(m), _on(FALSE) -{} - - -word TBoolean_field::class_id() const -{ return CLASS_BOOLEAN_FIELD; } - - -void TBoolean_field::create(WINDOW parent) -{ - wincreate(WC_CHECKBOX, strlen(_prompt)+4, 1, _prompt, parent, 0); -} - - -const char* TBoolean_field::get_window_data() const -{ - CHECK(win(), "Control window not initialized"); - fpark[0] = xvt_get_checked_state(win()) ? 'X' : ' '; - fpark[1] = '\0'; - return fpark; -} - - -void TBoolean_field::set_window_data(const char* data) -{ - CHECK(win(), "Control window not initialized"); - - if (data == NULL) data = ""; - const bool b = toupper(*data) == 'X'; - xvt_check_box(win(), b); -} - - -void TBoolean_field::set_field_data(const char* data) -{ - if (data == NULL) data = ""; - _on = toupper(*data) == 'X'; -} - -const char* TBoolean_field::get_field_data() const -{ - return _on ? "X" : " "; -} - - -bool TBoolean_field::parse_item(TScanner& scanner) -{ - if (scanner.key() == "ME") - { - const bool tf = scanner.integer() ? TRUE : FALSE; // Message TRUE or FALSE - - if (_message.items() == 0) - { - _message.add(new TToken_string(16)); - _message.add(new TToken_string(16)); - } - TToken_string& ts = (TToken_string&)_message[tf]; - ts.add(scanner.line().strip_spaces()); - - return TRUE; - } - - return TMask_field::parse_item(scanner); -} - -void TBoolean_field::enable(bool on) -{ - _flags.enabled = on; - xvt_enable_control(_win, on); -} - - -bool TBoolean_field::on_hit() -{ - if (_handler) - { - bool ok = _handler(*this, K_SPACE); - if (!ok) return FALSE; - } - const int n = mask().is_running() ? xvt_get_checked_state(win()) : _on; - do_message(n); - return TRUE; -} - -bool TBoolean_field::on_key(KEY key) -{ - if (key == K_SPACE) - { - on_hit(); - set_dirty(); - return TRUE; - } - return TMask_field::on_key(key); -} - -/////////////////////////////////////////////////////////// -// Button_field -/////////////////////////////////////////////////////////// - -TButton_field::TButton_field(TMask* m) -: TMask_field(m) -{ - _flags.persistent = TRUE; -} - - -word TButton_field::class_id() const -{ return CLASS_BUTTON_FIELD; } - -void TButton_field::parse_head(TScanner& scanner) -{ - _width = scanner.integer(); - if (_width < 1) _width = 9; - _size = scanner.integer(); // Height - if (_size < 1) _size = 1; -} - - -bool TButton_field::parse_item(TScanner& scanner) -{ - return TMask_field::parse_item(scanner); -} - - -void TButton_field::create(WINDOW parent) -{ - long flags = CTL_FLAG_CENTER_JUST; - - switch (dlg()) - { - case DLG_OK: - if (_prompt.empty()) - _prompt = "Conferma"; - _virtual_key = _exit_key = K_ENTER; - flags |= CTL_FLAG_DEFAULT; - break; - case DLG_CANCEL: - if (_prompt.empty()) - _prompt = "Annulla"; - _virtual_key = _exit_key = K_ESC; - break; - case DLG_DELREC: - _virtual_key = 'E'; - _exit_key = K_DEL; - break; - case DLG_PRINT: - if (_prompt.empty()) - _prompt = "Stampa"; - _virtual_key = 'S'; - _exit_key = K_ENTER; - break; - case DLG_QUIT: - if (_prompt.empty()) - _prompt = "Fine"; - _virtual_key = K_F4; - _exit_key = K_QUIT; - break; - default: - { - _exit_key = 0; - TToken_string* message = (TToken_string*)_message.objptr(0); - if (message != NULL) - { - TToken_string msg(message->get(0), ','); - const TFixed_string m(msg.get(0)); - if (m == "EXIT") - _exit_key = msg.get_int(); - else - if (msg.get_int() == 0) _exit_key = atoi(m); - } - const int n = _prompt.find('~'); - _virtual_key = (n >= 0) ? toupper(_prompt[n+1]) : _exit_key; - } - break; - } - - -#if XWTWS == WMWS - _prompt.center_just(_width); -#endif - - wincreate(WC_PUSHBUTTON, _width + 2, _size, _prompt, parent, flags); -} - -void TButton_field::enable(bool on) -{ - _flags.enabled = on; - xvt_enable_control(_win, on); -} - -void TButton_field::show(bool on) -{ - TMask_field::show(on); -} - - -bool TButton_field::on_key(KEY key) - -{ - if (key == K_SPACE) - { - on_hit(); - return TRUE; - } - return TMask_field::on_key(key); -} - -/////////////////////////////////////////////////////////// -// Date_field -/////////////////////////////////////////////////////////// - -word TDate_field::class_id() const -{ return CLASS_DATE_FIELD; } - -void TDate_field::create(WINDOW w) -{ - TEdit_field::create(w); - if (automagic()) - { - TDate d(TODAY); - set(d.string()); - } -} - -void TDate_field::parse_head(TScanner&) {} - -TDate_field::TDate_field(TMask* m) : TEdit_field(m) -{ - _size = _width = 10; -} - - -bool TDate_field::on_key(KEY key) -{ - if (to_check(key)) - { - TFixed_string data(get_window_data(), 15); - data.trim(); - if (data.not_empty() || required()) - { - bool changed = FALSE; - if (isdigit(data[0])) - { - if (data.len() == 6) // Fix century (for this millenium only) - { - data.insert("19", 4); - changed = TRUE; - } - for (int meno = 2; meno <= 5; meno += 3) - if (data[meno] != '-') - { - data.insert("-", meno); - changed = TRUE; - } - if (data.len() == 8) // Fix century (for this millenium only) - { - data.insert("19", 6); - changed = TRUE; - } - } - else - { - TDate g(TODAY); - data.upper(); - if (data == "IERI") --g; else - if (data == "DOMANI") ++g; - TString16 gstring(g.string()); - if (data == "PRIMO") { gstring.overwrite("01-01", 0); } else - if (data == "ULTIMO") { gstring.overwrite("31-12", 0); } - data = gstring; - changed = TRUE; - } - - TDate d(data); - if (!d.ok()) - { - // error_box("La data deve essere nel formato gg-mm-aaaa"); - error_box("Data errata o formato non valido"); - return FALSE; - } - else - if (changed) - TMask_field::set_window_data(d.string()); - } - } - - return TEdit_field::on_key(key); -} - - -/////////////////////////////////////////////////////////// -// Real_field -/////////////////////////////////////////////////////////// - -TReal_field::TReal_field(TMask* m) : TEdit_field(m) -{} - -word TReal_field::class_id() const -{ return CLASS_REAL_FIELD; } - -void TReal_field::create(WINDOW w) -{ - TEdit_field::create(w); - - if (_flags.firm) - set(::format("%ld", MainApp()->get_firm())); else - if (automagic()) - { - TDate d(TODAY); - set(::format("%d", d.year())); - } -} - -bool TReal_field::on_key(KEY key) -{ - if (to_check(key)) - { - if (roman()) - { - const int r = atoi(get_window_data()); - if (r < 0) return error_box("Numero romano errato"); - } - else - { - const char* n = get(); - if (*n && !real::is_real(n)) - return error_box("Numero non valido"); - - const int segno = real(n).sign(); - if (required() && segno == 0 && !mask().query_mode()) - return error_box("Manca un valore indispensabile"); - - if (_flags.uppercase && segno < 0) - return error_box("Il numero deve essere positivo"); - } - } - - return TEdit_field::on_key(key); -} - -void TReal_field::parse_head(TScanner& scanner) -{ - _size = scanner.integer(); - -#ifdef DBG - if (_size < 1) - { - _size = 9; - yesnofatal_box("Il campo %d ha dimensione nulla (uso %d)", dlg(), _size); - } -#endif - - _width = _size; - _decimals = scanner.integer(); -} - -void TReal_field::set_window_data(const char* data) -{ - if (data == NULL) data = ""; - - if (roman()) - { - data = itor(atoi(data)); - TMask_field::set_window_data(data); - } - else - { - real n(data); - if (!n.is_zero()) - { - if (_flags.exchange) - { - const real& e = mask().exchange(); - if (e != 1.0) n /= e; - } - if (_picture.empty()) - data = n.stringa(_size, _decimals); - else - data = n.string(_picture); - } else data = ""; - TEdit_field::set_window_data(data); - } -} - -const char* TReal_field::get_window_data() const -{ - TEdit_field::get_window_data(); - if (roman()) - { - int r = atoi(fpark); - if (r == 0) r = rtoi(fpark); - if (r > 0) - { - int s = decimals(); - if (s < 1) s = 4; - if (_flags.zerofilled) - fpark.format("%0*d", s, r); - else - fpark.format("%*d", s, r); - } - else fpark.cut(0); - } - else - { - fpark = real::ita2eng(fpark); - if (_flags.exchange) - { - const real& e = mask().exchange(); - if (e != 1.0) - { - real n(fpark); - n *= e; - if (n.is_zero()) fpark.cut(0); - else fpark = n.string(); - } - } - } - - return fpark; -} - -void TReal_field::set_decimals(int d) -{ - _decimals = d; - if (_picture[0] == '.') - { - if (d > 0) _picture.format(".%d", d); - else _picture = "."; - } -} - - -void TReal_field::exchange(const real& vec, const real& nuo) -{ - const int dec = (nuo != 1.0) ? 2 : 0; - - if (decimals() != dec) - set_decimals(dec); - else - if (dec == 2) - return; - - if (mask().is_running()) - { - const char* n = real::ita2eng(TEdit_field::get_window_data()); - if (*n) - { - real r(n); - r *= vec; - r /= nuo; - r.round(dec); - TEdit_field::set_window_data(r.string(_picture)); - } - } -} - -/////////////////////////////////////////////////////////// -// List_field -/////////////////////////////////////////////////////////// - -TList_field::TList_field(TMask* m) : TMask_field(m) -{} - -word TList_field::class_id() const -{ - return CLASS_LIST_FIELD; -} - - -void TList_field::read_item(TScanner& scanner) -{ - TToken_string ts(scanner.string()); - _codes.add(ts.get()); - _values.add(ts.get()); - - ts = ""; - while (scanner.popkey() == "ME") - ts.add(scanner.line().strip_spaces()); - scanner.push(); - - _message.add(ts); -} - - -void TList_field::parse_head(TScanner& scanner) -{ - _size = scanner.integer(); - _width = scanner.integer(); - if (_width < 1) _width = _size+3; -} - - -bool TList_field::parse_item(TScanner& scanner) -{ - if (scanner.key() == "IT") // ITEM - { - read_item(scanner); - return TRUE; - } - - if (scanner.key() == "LI") // LISTITEM - { - TScanner sc(scanner.pop()); - while (sc.popkey() == "IT") // ITEM - read_item(sc); - return TRUE; - } - - return TMask_field::parse_item(scanner); -} - - -int TList_field::items() const -{ - return _codes.items(); -} - -void TList_field::add_item(const char* s) -{ - TToken_string t(s); - const TString16 item(t.get()); - const int pos = _codes.get_pos(item); - - if (pos < 0 ) - { - _codes.add(item); - win_list_add(win(), -1, (char*)t.get()); - } -} - - -void TList_field::delete_item(const char* s) -{ - TString16 t(s); - const int pos = _codes.get_pos(t); - - if (pos >= 0 ) - { - _codes.destroy(pos); - win_list_delete(win(), pos); - if (mask().is_running()) - { - win_list_set_sel(win(), 0, TRUE); - if (showed()) on_hit(); - } - } -} - - -void TList_field::add_list() -{ - if (roman() && _codes.items() < 12) - { - TString csafe, vsafe; - if (atoi(_codes) > 0) - { - csafe = _codes; _codes = ""; - vsafe = _values; _values = ""; - } - _codes.add("01|02|03|04|05|06|07|08|09|10|11|12"); - _values.add("Gennaio|Febbraio|Marzo|Aprile|Maggio|Giugno"); - _values.add("Luglio|Agosto|Settembre|Ottobre|Novembre|Dicembre"); - if (atoi(csafe) > 0) - { - _codes.add(csafe); - _values.add(vsafe); - if (_message.objptr(0)) - { - _message.add(_message[0], _codes.items()-1); - _message.add(NULL, 0); - } - } - } - - SLIST lst = slist_new(); - for (const char* item = _values.get(0); item; item = _values.get()) - slist_add(lst, (SLIST_ELT)NULL, (char*)item, 0L); - win_list_add(win(), -1, (char*)lst); - slist_dispose(lst); - - const char* init = ""; - if (roman() && automagic()) - init = format("%02d", TDate(TODAY).month()); - set_field_data(init); -} - - -void TList_field::replace_items(const char* codes, const char* values) -{ - _codes = codes; - _values = values; - - if (win() != NULL_WIN) - { - win_list_clear(win()); - add_list(); - current(0); - } -} - - -void TList_field::create(WINDOW parent) -{ - const int len = create_prompt(parent); - _x += len; - - wincreate(WC_LISTBUTTON, _width, 5, "", parent,0); - add_list(); -} - - -int TList_field::str2curr(const char* data) -{ - TString16 str(data); - - if (roman() && str.len() < 2) - str.insert("0",0); - if (_flags.uppercase) - str.upper(); - - int i = str.not_empty() ? _codes.get_pos(str) : 0; - - if (i < 0) // Se non trova il codice ritenta dopo trim - { - for (i = 0; str[i] == '0' || str[i] == ' '; i++); - if (i > 0) - { - str.ltrim(i); - i = _codes.get_pos(str); - } - } - - if (i < 0) - { - if (items() && str.not_empty()) - yesnofatal_box("'%s' non e' un valore valido per il campo %s: %d", - data, prompt(), dlg()); - i = 0; - } - return i; -} - - -void TList_field::set_window_data(const char* data) -{ - CHECKD(win(), "Control window not initialized ", dlg()); - const int i = str2curr(data); - current(i); -} - - -void TList_field::current(int n) -{ - win_list_set_sel(win(), n, TRUE); -} - -int TList_field::current() const -{ - const int sel = win_list_get_sel_index(win()); -#ifdef DBG - if (sel < 0 && items() > 0) - error_box("Lista senza selezione nel campo %d", dlg()); -#endif - return sel; -} - -const char* TList_field::get_window_data() const -{ - const int c = current(); - const char* v = ((TList_field*)this)->_codes.get(c); - return v; -} - -void TList_field::set_field_data(const char* data) -{ - if (data == NULL || *data == '\0') data = _codes.get(0); - _str = data; -} - -bool TList_field::on_hit() -{ - if (_handler) - { - bool ok = _handler(*this, K_SPACE); - if (!ok) return FALSE; - } - const int n = mask().is_running() ? current() : str2curr(_str); - do_message(n); - return TRUE; -} - -const char* TList_field::get_field_data() const -{ - return _str; -} - -bool TList_field::on_key(KEY key) -{ - if (key >= '0' && key <= 'z') - { - const int index = win_list_get_sel_index(win()); - CHECK(index >= 0, "List with no selection!"); - int newindex = -1; - -#if XVTWS == WMWS - if (key >= 'A' && key <= 'z') - { - for (int i = index+1; i != index; i++) - { - char item[16]; - bool flag; - - do - { - flag = win_list_get_elt(win(), i, item, 16); - if (!flag) - { - CHECK(i, "La lista e' vuota!"); - i = -1; - break; - } - } while (!flag); - if (flag && toupper(*item) == toupper(key)) - { - newindex = i; - break; - } - } // for - } // alphabetic -#endif - - if (key >= '0' && key <= '9') - { - newindex = (key == '0') ? 10 : key - '1'; - if (newindex > items()) - { - newindex = -1; - beep(); - } - } - - if (newindex >= 0) - { - win_list_suspend(win()); - win_list_set_sel(win(), index, FALSE); - win_list_set_sel(win(), newindex, TRUE); - win_list_resume(win()); - } - } // alphanumeric - -#if XVTWS == VMWS - if (key == K_TAB && class_id() == CLASS_LIST_FIELD) - dispacth_e_char(win(), K_F9); -#endif - - if (key == K_SPACE) on_hit(); - - return TMask_field::on_key(key); -} - - -/////////////////////////////////////////////////////////// -// TRadio_field -/////////////////////////////////////////////////////////// - -TRadio_field::TRadio_field(TMask* mask) -: TList_field(mask), _nitems(0), _active_item(0) -{} - - -word TRadio_field::class_id() const -{ - return CLASS_RADIO_FIELD; -} - - -void TRadio_field::create(WINDOW parent) -{ - const short id = dlg(); // Salva il control id - - if (_prompt.not_empty()) - { - const int dy = _codes.items()+2; - create_prompt(parent, _width, dy); - } - _x++; _y++; - _values.restart(); - - const char* s; - for(_nitems = 0; (s = _values.get()) != NULL; _nitems++, _y++) - { - CHECKD(_nitems < MAX_RADIO, "Too many items in radio button ", id); - - wincreate(WC_RADIOBUTTON, _width-2, 1, s, parent,0); - _radio_ctl_win[_nitems] = _win; - _dlg += 1000; - } - _radio_ctl_win[_nitems] = NULL_WIN; // Comodo per debug - - _dlg = id; // Ripristina control id - - set_field_data(""); -} - -void TRadio_field::destroy() -{ - if (_promptwin) - { close_window(_promptwin); _promptwin = NULL_WIN; } - - for(int i = 0; i < _nitems; i++) - { - close_window(_radio_ctl_win[i]); - _radio_ctl_win[i] = NULL_WIN; - } -} - - -int TRadio_field::current() const -{ - const int c = xvt_get_checked_radio(_radio_ctl_win, _nitems); - return c; -} - - -void TRadio_field::current(int n) -{ - _active_item = n; - xvt_check_radio_button(win(), _radio_ctl_win, _nitems); -} - - -void TRadio_field::check_radiobutton(WINDOW checked) -{ - for(int i = 0; i < _nitems && checked != _radio_ctl_win[i]; i++); - CHECK(i < _nitems, "Trying to check an invalid radio button"); - current(i); -} - - -void TRadio_field::enable(bool on) -{ - _flags.enabled = on; - for(int i = 0; i < _nitems; i++) - xvt_enable_control(_radio_ctl_win[i], on); -} - - -void TRadio_field::show(bool on) -{ - if (_promptwin) - show_window(_promptwin, on); - - for(int i = 0; i < _nitems; i++) - show_window(_radio_ctl_win[i], on); - _flags.showed = on; -} - -// Return TRUE if focus has left the radio -bool TRadio_field::move_focus(int d) -{ - const int act = _active_item + d; - if (act >= _nitems || act < 0) - { - _active_item = current(); - return TRUE; - } - xvt_set_front_control(_radio_ctl_win[_active_item = act]); - return FALSE; -} - - -/////////////////////////////////////////////////////////// -// TGroup_field -/////////////////////////////////////////////////////////// - -TGroup_field::TGroup_field(TMask* mask) : TMask_field(mask) -{ - _flags.persistent = TRUE; -} - -// _size means _heigth -void TGroup_field::parse_head(TScanner& scanner) -{ - _width = scanner.integer(); - _size = scanner.integer(); -} - - -void TGroup_field::create(WINDOW parent) -{ - const long f = _flags.rightjust ? CTL_FLAG_MULTIPLE : 0; - wincreate(WC_GROUPBOX, _width, _size, _prompt, parent, f); -} - +// $Id: maskfld.cpp,v 1.21 1994-09-21 11:16:20 guy Exp $ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if XVT_OS == XVT_OS_WIN +#include +#endif + +HIDDEN const int MAXSTR = 128; +HIDDEN char __fpark[MAXSTR]; // Temporary for get/set window data +HIDDEN TFixed_string fpark(__fpark, MAXSTR); + +/////////////////////////////////////////////////////////// +// Field Flags +/////////////////////////////////////////////////////////// + +// Certified 100% +TMask_field::TField_Flags::TField_Flags() +{ + automagic = persistent = FALSE; + enabled = enable_default = TRUE; + showed = show_default = TRUE; + uppercase = rightjust = FALSE; + zerofilled = FALSE; + dirty = focusdirty = FALSE; + roman = exchange = FALSE; + firm = ghost = FALSE; +} + +// Certified 100% +char TMask_field::TField_Flags::update(const char* s) +{ + const char* kk = s; + for (; *s; s++) + switch(toupper(*s)) + { + case 'A': + automagic = persistent = TRUE; break; + case 'D': + enable_default = enabled = FALSE; break; + case 'F': + firm = persistent = TRUE; break; + case 'G': + ghost = TRUE; break; + case 'H': + show_default = showed = FALSE; break; + case 'M': + roman = TRUE; break; + case 'P': + persistent = TRUE; break; + case 'R': + rightjust = TRUE; break; + case 'U': + uppercase = TRUE; break; + case 'V': + exchange = TRUE; break; + case 'Z': + zerofilled = TRUE; break; +#ifdef DBG + default : ::warning_box("FLAG sconosciuto in %s: %c", kk, *s); break; +#endif + } + return *s; +} + + +/////////////////////////////////////////////////////////// +// TMask_field +/////////////////////////////////////////////////////////// + +int TMask_field::_x; // Position of the field +int TMask_field::_y; +int TMask_field::_width; +TFixed_string TMask_field::_prompt(__fpark, MAXSTR); // Prompt of the field + +TMask_field::TMask_field(TMask* m) +: _mask(m), _win(NULL_WIN), _promptwin(NULL_WIN), _dlg(0), + _keys(0), _groups(0), _help(0), _handler(NULL), + _validate_func(-1), _validate_parms(1), _field(NULL) +{} + +// Certified 100% +TMask_field::~TMask_field() +{ + if (_field) delete _field; +} + + +// Certified 100% +bool TMask_field::is_edit() const +{ + const word c = class_id(); + return c == CLASS_EDIT_FIELD || c == CLASS_REAL_FIELD || c == CLASS_DATE_FIELD; +} + + +// Certified 100% +const char* TMask_field::class_name() const +{ return "Field"; } + + +// Certified 100% +word TMask_field::class_id() const +{ return CLASS_FIELD; } + + +// Certified 100% +bool TMask_field::ok() const +{ return win() != NULL_WIN && dlg() >= -1; } + + +// Certified 100% +void TMask_field::parse_head(TScanner&) +{} + + +// Certified 100% +short TMask_field::atodlg(const char* s) const +{ + short d = s ? atoi(s) : 0; + +#ifdef DBG + if (d == 0 || d < -1 || d > 1000) + { + yesnofatal_box("Identificatore non valido nel campo %d: '%s'", dlg(), s); + d = -1; + } +#endif + + return d; +} + +void TMask_field::construct(short id, const char* prompt, int x, int y, + int len, WINDOW parent, const char* flags, int width) +{ + _x = x; _y = y; + _prompt = prompt; + _size = len; + if (class_id() == CLASS_REAL_FIELD) + { + ((TReal_field*)this)->set_decimals(width); + _width = _size; + } + else _width = width < 1 ? _size : width; + _dlg = id; + _flags.update(flags); + + create(parent); +} + + +void TMask_field::construct(TScanner& scanner, WINDOW parent) +{ + _dlg = atodlg(scanner.pop()); + parse_head(scanner); + _prompt.cut(0); + + scanner.popkey(); // BEGIN +#ifdef DBG + if (scanner.key() != "BE") + { + yesnofatal_box("Testata errata o BEGIN mancante nel campo %d", _dlg); + scanner.push(); + } +#endif + + while(scanner.popkey() != "EN") // END of control + parse_item(scanner); + create(parent); +} + +bool TMask_field::parse_item(TScanner& scanner) +{ + if (scanner.key() == "PR") // PROMPT + { + _x = scanner.integer(); + _y = scanner.integer(); + _prompt = scanner.string(); + return TRUE; + } + + if (scanner.key() == "FL") // FLAG + { + const char* f = scanner.string(); + return _flags.update(f) == '\0'; + } + + if (scanner.key() == "FI") // FIELD + { + CHECKD(_field == NULL, "Only one FIELD, please: ", dlg()); + _field = new TFieldref(scanner.line(), 0); + return TRUE; + } + + if (scanner.key() == "HE") // HELP + { + _help = scanner.string(); + return TRUE; + } + + if (scanner.key() == "KE") // KEY + { + _keys.set(scanner.line()); + _keys.set(0L); + return TRUE; + } + + if (scanner.key() == "ME") + { + if (_message.objptr(0) == 0) + _message.add(new TToken_string(64), 0); + TToken_string& ts = (TToken_string&)_message[0]; + ts.add(scanner.line().strip_spaces()); + return TRUE; + } + + if (scanner.key() == "GR") + { + _groups.set(scanner.line()); + return TRUE; + } + + return FALSE; +} + + +long TMask_field::default_flags() const +{ + long f = CTL_FLAG_NATIVE_JUST; + + if (_flags.show_default == FALSE) f |= CTL_FLAG_INVISIBLE; + if (_flags.enable_default == FALSE) f |= CTL_FLAG_DISABLED; + + return f; +} + +// Certified 100% +WINDOW TMask_field::wincreate(WIN_TYPE ct, short dx, short dy, + const char* title, WINDOW parent, + long flags) +{ + _win = xvt_create_control(ct, + _x, _y, dx, dy, + (char*)title, + parent, + flags | default_flags(), + PTR_LONG(this), + _dlg); + + return _win; +} + + +// Certified 100% +WINDOW TMask_field::parent() const +{ return get_parent(win()); } + + +// Certified 90% +int TMask_field::create_prompt(WINDOW parent, int width, int heigth) +{ + const WIN_TYPE wt = (heigth < 3) ? WC_TEXT : WC_GROUPBOX; + if (width < 1) width = strlen(_prompt); + _prompt.rtrim(); // Could save some bytes + + if (width) + { + // Static controls shouldn't be grayed + const long flags = default_flags() & (~CTL_FLAG_DISABLED); +#if XVT_OS == XVT_OS_WIN + char* k = strchr(_prompt, '~'); + if (k != NULL) *k = '&'; +#endif + _promptwin = xvt_create_control + ( + wt, + _x, _y, width, heigth, + _prompt, + parent, + flags, + 0L, + -1 + ); + } + return width; +} + + +// Certified 100% +void TMask_field::destroy() +{ + if (_win) + { close_window(_win); _win = NULL_WIN; } + if (_promptwin) + { close_window(_promptwin); _promptwin = NULL_WIN; } +} + + +// Certified 100% +void TMask_field::create(WINDOW parent) +{ + _width = strlen(_prompt); + if (_width) + wincreate(WC_TEXT, _width, 1, _prompt, parent, CTL_FLAG_LEFT_JUST); +} + + +// Certified 100% +void TMask_field::enable(bool on) +{ + const word c = class_id(); + if (c != CLASS_FIELD) + { + enable_window(_win, on); + _flags.enabled = on; + } +} + + +// Certified 100% +void TMask_field::enable_default() +{ + const bool ed = _flags.enable_default; + enable(ed); +} + + +// Certified 100% +void TMask_field::show(bool on) +{ + show_window(_win, on); + if (_promptwin != NULL_WIN) + show_window(_promptwin, on); + _flags.showed = on; +} + + +// Certified 100% +void TMask_field::show_default() +{ + const bool sd = _flags.show_default; + show(sd); +} + + +// Certified 100% +bool TMask_field::active() const +{ + return enabled() && showed() && class_id() != CLASS_FIELD; +}; + + +// Certified 90% +word TMask_field::last_key() const +{ + long u = _keys.last_one(); + if (u < 0) u = 0; + return (word)u; +} + + +// Certified 99% +const char* TMask_field::get_window_data() const +{ + get_title(win(), __fpark, MAXSTR); + return __fpark; +} + + +// Certified 99% +void TMask_field::set_window_data(const char* data) +{ + if (data != NULL) + set_title(win(), (char*)data); +} + + +// Certified 100% +void TMask_field::set_field_data(const char*) +{} + + +// Certified 100% +const char* TMask_field::get_field_data() const +{ return NULL; } + + +const char* TMask_field::picture_data(const char* data, bool video) +{ + fpark = data; + if (video) + { + fpark.trim(); + if (_flags.uppercase) fpark.upper(); + } + return fpark; +} + + +// Certified 90% +const char* TMask_field::prompt() const +{ + if (_promptwin != NULL_WIN) + _prompt = xvt_get_title(_promptwin); + else + _prompt = ""; + + return _prompt; +} + + +// Certified 100% +void TMask_field::reset() +{ + if (!_flags.persistent && class_id() != CLASS_FIELD) + set(""); +} + + +// Certified 100% +void TMask_field::set_prompt(const char* p) +{ + if (_promptwin != NULL_WIN) + set_title(_promptwin, (char*) p); +} + + +void TMask_field::set(const char* s) +{ + if (mask().is_running()) + { + set_window_data(s); + set_dirty(); + } + else + set_field_data(s); +} + +TString& TMask_field::get() const +{ + static TString80 gpark; + + if (mask().is_running()) + gpark = get_window_data(); + else + gpark = get_field_data(); + + return gpark.trim(); +} + + +void TMask_field::undo() +{ + set_window_data(get_field_data()); +} + + +bool TMask_field::autoload(const TRelation* r) +{ + if (_field) + { + set(_field->read(r)); + return TRUE; + } + return FALSE; +} + + +bool TMask_field::autosave(TRelation* r) const +{ + if (_field) + { + _field->write(get(), r); + return TRUE; + } + return FALSE; +} + + +// Certified 50% +HIDDEN void modify_list(bool add, TMask_field& f, TToken_string& msg) +{ +#ifdef DBG + if (f.class_id() != CLASS_LIST_FIELD) + { + error_box("Can't add/delete items of non list-box field %d", f.dlg()); + return; + } +#endif + TList_field& l = (TList_field&)f; + + TToken_string item(16); + item = msg.get(); + if (add) item.add(msg.get()); + item.strip("\"'"); + if (add) + l.add_item(item); + else + l.delete_item(item); +} + + +// Certified 90% +HIDDEN const char* copy_value(TToken_string& msg, const TString& val) +{ + int from = msg.get_int()-1; + int to = 0; + if (from < 0) from = 0; + else to = msg.get_int(); + return val.sub(from, to); +} + + +// Certified 50% +bool TMask_field::do_message(int num) +{ + const int MAX_CMD = 14; + static const char* commands[MAX_CMD] = + { + "ADD", // 0 + "CLEAR", // 1 + "CO", // 2 + "DEL", // 3 + "DIRTY", // 4 + "DISABLE", // 5 + "ENABLE", // 6 + "ENABLEDEF", // 7 + "EXIT", // 8 + "HIDE", // 9 + "PUSH", // 10 + "RESET", // 11 + "SHOW", // 12 + "UNDO" // 13 + }; + + TToken_string* message = (TToken_string*)_message.objptr(num); + if (message == NULL || message->empty()) return FALSE; + + TToken_string msg(16, ','); + TString value(16); + + for (const char* m = message->get(0); m && *m; m = message->get()) + { + KEY key = 0; + msg = m; + value = msg.get(); + value.trim(); + const char* dlg = msg.get(); + + int cmd = -1; + if (isalpha(value[0])) // binary search + { + int f = 0, l = MAX_CMD-1; + while (TRUE) + { + cmd = (f+l)>>1; + const int cmp = strcmp(value, commands[cmd]); + if (cmp == 0) break; + if (cmp > 0) f = cmd+1; + else l = cmd-1; + if (f > l) + { + cmd = -1; + break; + } + } + } + + if (cmd == 8) + { + mask().stop_run(atoi(dlg)); + continue; + } + + short fld = (dlg && dlg[0] > ' ') ? atodlg(dlg) : 0; + bool broadcast = dlg && strchr(dlg, '@'); + if (value[0] == '"') value = value.strip("\"'"); + else switch (cmd) + { + case 0: + modify_list(TRUE, mask().field(fld), msg); continue; + case 1: + key = 11000+'c'; break; + case 2: + value = copy_value(msg, get()); break; + case 3: + modify_list(FALSE, mask().field(fld), msg); continue; + case 4: + mask().field(fld).set_dirty(); continue; + case 5: + key = 11000+'d'; break; + case 6: + key = 11000+'e'; break; + case 7: + key = 11000+'E'; break; + case 9: + key = 11000+'h'; break; + case 10: + key = K_SPACE; break; + case 11: + key = K_F2; break; + case 12: + key = 11000+'s'; break; + case 13: + key = K_F3; break; + default: + key = atoi(value); + break; + } + + if (key) + { + if (key > 0) + { + if (broadcast) fld = -fld; + mask().send_key(key, fld); + } + } + else + { + // Setta a value il campo fld solo se ha un valore diverso da value + if (broadcast) + { + for (int i = 0; i < mask().fields(); i++) + { + TMask_field& f = mask().fld(i); + if (f.in_group((int)fld)) + { + const char* prev = f.get(); + if (value != prev) + { + f.set(value); + if (f.showed() || f.ghost()) + f.on_hit(); + } + } + } + } + else + { + TMask_field& f = mask().field(fld); + const char* prev = f.get(); + if (value != prev) + { + f.set(value); + if (f.showed() || f.ghost()) + f.on_hit(); + } + } + } + } + + return TRUE; +} + + +// Certified 90% +bool TMask_field::on_hit() +{ + if (_handler) + { + bool ok = _handler(*this, is_edit() ? K_TAB : K_SPACE); + if (!ok) return FALSE; + } + do_message(0); + return TRUE; +} + + +bool TMask_field::to_check(KEY k, bool checkrun) const +{ + bool yes = (k == K_TAB && focusdirty()) || (k == K_ENTER && dirty()); + + if (!yes && checkrun) + yes = k == K_TAB && !mask().is_running(); + + return yes; +} + +// Certified 90% +bool TMask_field::on_key(KEY key) +{ + if (key > 11000) + { + switch(key-11000) + { + case 'E': + enable_default(); break; + case 'c': + reset(); on_hit(); + case 'd': + disable(); break; + case 'e': + enable(); break; + case 'h': + hide(); break; + case 's': + show(); break; +#ifdef DBG + default : + return yesnofatal_box("Invalid key sent to field %d: %d", dlg(), key); +#endif + } + return TRUE; + } + + switch(key) + { + case K_SPACE: + set_dirty(); + break; + case K_PREV: + case K_NEXT: + dispatch_e_char(parent(), key); + break; + case K_F1: + if (_help.not_empty()) + message_box(_help); + else + beep(); + break; + case K_F2: + reset(); + set_dirty(); + break; + case K_F3: + undo(); + set_dirty(); + break; + default: + break; + } + + if (_handler) + return _handler(*this, key); + + return TRUE; +} + + +void TMask_field::set_focus() const +{ + const bool force = mask().is_running(); + mask().set_focus_win(win(), force); +} + +HIDDEN char* const _msg = &__tmp_string[512]; +#define build_msg() va_list argptr;va_start(argptr,fmt);vsprintf(_msg,fmt,argptr);va_end(argptr) + +bool TMask_field::error_box(const char* fmt, ...) const +{ + build_msg(); + if (mask().is_running()) + { + set_focus(); + ::error_box("%s", _msg); + set_focus(); + } + else + { + xvt_statbar_set(_msg); + beep(); + } + return FALSE; +} + +bool TMask_field::message_box(const char* fmt, ...) const +{ + set_focus(); + build_msg(); + ::message_box("%s", _msg); + set_focus(); + return FALSE; +} + +bool TMask_field::warning_box(const char* fmt, ...) const +{ + build_msg(); + + if (mask().is_running()) + { + set_focus(); + ::warning_box("%s", _msg); + set_focus(); + } + else + { + xvt_statbar_set(_msg); + beep(); + } + return FALSE; +} + +bool TMask_field::yesno_box(const char* fmt, ...) const +{ + set_focus(); + build_msg(); + const bool yes = ::yesno_box("%s", _msg); + set_focus(); + return yes; +} + +KEY TMask_field::yesnocancel_box(const char* fmt, ...) const +{ + set_focus(); + build_msg(); + const KEY k = ::yesnocancel_box("%s", _msg); + set_focus(); + return k; +} + +/////////////////////////////////////////////////////////// +// TList_sheet +/////////////////////////////////////////////////////////// + +// Certified 100% +TList_sheet::TList_sheet(TEdit_field* f, const char* caption, const char* head) +: _fld(f), _row(-1) +{ + _sheet = new TArray_sheet(-1, -1, 0, 0, caption, head); +} + +// Certified 100% +TList_sheet::~TList_sheet() +{ + delete _sheet; +} + +// Certified 100% +TMask_field& TList_sheet::field(short id) const +{ return field().mask().field(id); } + + +// Certified 100% +void TList_sheet::read_item(TScanner& scanner) +{ + TToken_string ts(scanner.string()); + _sheet->add(ts); +} + + +// Certified 100% +void TList_sheet::parse_input(TScanner& scanner) +{ + _inp_id.add(scanner.pop()); +} + + +// Certified 100% +void TList_sheet::parse_output(TScanner& scanner) +{ + _out_id.add(scanner.pop()); +} + +// il numero di riga selezionata +int TList_sheet::do_input() +{ + if (_inp_id.empty()) return -2; // List empty! + + _inp_id.restart(); + TToken_string rowsel(80); + + for (const char* fld = _inp_id.get(); fld; fld = _inp_id.get()) + { + if (*fld == '"') + { + rowsel.add(fld+1); + if (rowsel.not_empty()) rowsel.cut(rowsel.len()-1); + } + else + { + const short id = _fld->atodlg(fld); + if (id > 0) rowsel.add(field().mask().get(id)); + else rowsel.add(""); + } + } + + TString80 fd, it; + for (int i = 0 ; i < _sheet->items(); i++) + { + TToken_string& ts =_sheet->row(i); + + ts.restart(); + for ( const char* item = rowsel.get(0); item ; item = rowsel.get()) + { + it = item; it.trim(); + fd = ts.get(); fd.trim(); + if (fd != it) break; + } + if (!item) return i; + } + + return -1; // Value not found! +} + + +// Certified 50% +void TList_sheet::do_output(CheckTime t) +{ + if (_row < 0 || t == FINAL_CHECK) + return; + + _out_id.restart(); + TToken_string& rowsel = _sheet->row(_row); + rowsel.restart(); + for (const char* fld = _out_id.get(); fld; fld = _out_id.get()) + { + const short id = _fld->atodlg(fld); + if (t != STARTING_CHECK || field().field() == NULL) + { + TMask_field& f = field(id); + f.set(rowsel.get()); + if (field().dlg() != id) + f.on_hit(); + } + } +} + + +// Certified 100% +KEY TList_sheet::run() +{ + _row = do_input(); + + _sheet->select(_row); + + const KEY k = _sheet->run(); + + switch (k) + { + case K_ENTER: + _row = (int)_sheet->selected(); + do_output(); + break; + default: + break; + } + + return k; +} + + +// Certified 100% +bool TList_sheet::check(CheckTime t) +{ + const bool passed = (_row = do_input()) != -1; + if (passed) do_output(t); + return passed; +} + + +/////////////////////////////////////////////////////////// +// TBrowse +/////////////////////////////////////////////////////////// + +// Certified 100% +TBrowse::TBrowse(TEdit_field* f, TRelation* r, int key, const char* filter) +: _relation(r), _cursor(new TCursor (r, filter, key)), + _fld(f), _filter(filter), _secondary(FALSE), + _checked(FALSE) +{} + + +// Certified 100% +TBrowse::TBrowse(TEdit_field* f, TCursor* c) +: _relation(NULL), _cursor(c), _fld(f) +{} + + +// Certified 100% +TBrowse::~TBrowse() +{ + if (_relation) + { + delete _relation; + delete _cursor; + } +} + + +// Certified 100% +void TBrowse::parse_display(TScanner& scanner) +{ + const char* s; + s = scanner.string(); + _head.add(s); + s = scanner.line(); + _items.add(s); +} + + +void TBrowse::parse_input(TScanner& scanner) +{ + const char* s = scanner.pop(); + _inp_fn.add(s); + + s = scanner.pop(); + if (*s == '"') // Constant string + { + scanner.push(); + _inp_id.add(scanner.line()); + } + else // Field on the mask + { + TString80 str(s); + if (scanner.popkey() == "SE") str << '@'; // Special FILTERing field + else scanner.push(); + _inp_id.add(str); + } +} + + +void TBrowse::parse_output(TScanner& scanner) +{ + const char* s = scanner.pop(); +#ifdef DBG + field().atodlg(s); +#endif + _out_id.add(s); + s = scanner.pop(); + _out_fn.add(s); +} + + +bool TBrowse::parse_copy(const TString& what, const TBrowse* b) +{ + const bool all = what == "AL"; + if (all || what == "US") + { + set_insert(b->get_insert()); + _filter = b->get_filter(); + if (!all) return TRUE; + } + if (all || what == "IN") + { + _inp_id = b->_inp_id; + _inp_fn = b->_inp_fn; + if (!all) return TRUE; + } + if (all || what == "DI") + { + _head = b->_head; + _items = b->_items; + if (!all) return TRUE; + } + if (all || what == "OU") + { + _out_id = b->_out_id; + _out_fn = b->_out_fn; + _secondary = TRUE; + } + return TRUE; +} + + +void TBrowse::parse_join(TScanner& scanner) +{ + TString80 j(scanner.pop()); // File or table + + CHECKS(_relation, "Can't join to NULL relation ", (const char*)j); + + int to; + if (scanner.popkey() == "TO") // TO keyword + { + const char* t = scanner.pop(); + to = name2log(t); + } + else + { + to = 0; // _relation->lfile()->num(); + scanner.push(); + } + + int key = 1; + if (scanner.popkey() == "KE") + key = scanner.integer(); + else scanner.push(); + + byte alias = 0; + if (scanner.popkey() == "AL") + alias = scanner.integer(); + else scanner.push(); + + TToken_string exp(80); + if (scanner.pop() == "INTO") + { + const char* r = scanner.pop(); + while (strchr(r, '=') != NULL) + { + exp.add(r); + r = scanner.pop(); + } + } + scanner.push(); + +#ifdef DBG + if (exp.empty()) yesnofatal_box("JOIN senza espressioni INTO"); +#endif + + if (isdigit(j[0])) + _relation->add(atoi(j), exp, key, to, alias); // join file + else + { +#ifdef DBG + if (j.len() > 4) + yesnofatal_box("'%s' non e' una tabella valida: %d", (const char*)j); + else +#endif + _relation->add(j, exp, key, to, alias); // join table + } +} + + +void TBrowse::parse_insert(TScanner& scanner) +{ + if (scanner.popkey() == "RU") + { + _insert = "R"; + _insert << scanner.line(); + } + else + { + _insert = "M"; + _insert << scanner.line(); + } + _insert.trim(); +} + + +// Certified 100% +TMask_field& TBrowse::field(short n) const +{ return _fld->mask().field(n); } + +// Ritorna il numero di campi non vuoti e non filtrati +int TBrowse::do_input(bool filter) +{ + int ne = 0; + if (_inp_id.empty()) return ne; + + TRectype& cur = _cursor->curr(); + + cur.zero(); + TRectype filtrec(cur); + + _inp_id.restart(); + _inp_fn.restart(); + + TString80 val; // Value to output + bool tofilter; + + for (const char* fld = _inp_id.get(); fld; fld = _inp_id.get()) + { + if (*fld == '"') + { + val = (fld+1); + if (val.not_empty()) val.rtrim(1); + tofilter = filter; + } + else + { + const short id = _fld->atodlg(fld); + const bool filter_flag = strchr(fld, '@') != NULL; + tofilter = filter && filter_flag; + val = field(id).get(); + if (field(id).is_edit() && val.not_empty() && !filter_flag) + ne++; // Increment not empty fields count + } + + TFieldref fldref(_inp_fn.get(), 0); // Output field + fldref.write(val, _cursor->relation()); + if (tofilter) + { + if (val.empty()) val.fill('~', fldref.len(cur)); + fldref.write(val, filtrec); + } + } + + if (!filter) return ne; + + TString work(_filter.size()); + for (int i = 0; _filter[i]; i++) + { + if (_filter[i] == '"') + { + do + { + work << _filter[i++]; + } while (_filter[i] && _filter[i] != '"'); + work << '"'; + if (!_filter[i]) break; + } + else + if (_filter[i] == '#') + { + work << '"' << field(atoi(&_filter[++i])).get() << '"'; + while (isspace(_filter[i])) i++; + while (isdigit(_filter[i])) i++; + i--; + } + else work << _filter[i]; + } + + _cursor->setfilter(work); + _cursor->setregion(filtrec, filtrec); + + return ne; +} + + +void TBrowse::do_output(CheckTime t) +{ + if (t == FINAL_CHECK) + return; + + TString80 sum; + TToken_string flds(24, '+'); + + _out_fn.restart(); + for (const char* fld = _out_id.get(0); fld && *fld; fld = _out_id.get()) + { + const short id = field().atodlg(fld); + TMask_field& f = field(id); + + flds = _out_fn.get(); + if (t != STARTING_CHECK || f.field() == NULL || f.mask().mode() == MODE_INS) + { + sum.cut(0); + for(const char* fr = flds.get(); fr; fr = flds.get()) + { + TFieldref fld(fr, 0); + const char* val = fld.read(_cursor->relation()); + sum << val; + } + + f.set(sum); + if (field().dlg() != id) + f.on_hit(); + } + } +} + + +void TBrowse::do_clear() +{ + for (TString16 fld = _out_id.get(0); fld.not_empty(); fld = _out_id.get()) + { + TMask_field& f = field(atoi(fld)); + if (f.field() == NULL && _inp_id.get_pos(fld) < 0) + f.reset(); + } +} + + + +bool TBrowse::do_insert() +{ + bool ok = FALSE; + TString80 app; + + if (_insert[0] == 'M') + { + TString80 nm(_insert.mid(1)); + if (strncmp(nm, "BATB", 4) == 0) // Programma gestione tabelle + app = format("ba3 -0 %s", (const char*)nm.mid(4)); + // Obbligatorio usare la format globale + else // Programma generico di browse/edit + app = format("ba3 -3 %s %d", (const char*)nm, _cursor->file().num()); + // Obbligatorio usare la format globale + } + else + { + app = _insert.mid(1); + } + +#if XVT_OS == XVT_OS_WIN + if (strnicmp(app, MainApp()->name(), 3) == 0) + app.insert("a", 3); +#endif + + TMailbox mail; + TMessage msg(cmd2name(app), MSG_AI, ""); + mail.send(msg); + + TExternal_app a(app); + a.run(); + + if (mail.check()) + { + TMessage* rcv = mail.next_s(MSG_AI); + if (rcv != NULL) _rec = atoi(rcv->body()); + if (_rec > 0) + { + _cursor->file().readat(_rec); + ok = _cursor->ok(); + if (ok) do_output(); +#ifdef DBG + else error_box("Selezione da programma esterno errata"); +#endif + } + } + return ok; +} + + +TToken_string& TBrowse::create_siblings(TToken_string& siblings) +{ + const TMask& mask = field().mask(); + siblings = ""; // Azzera la lista dei campi associati + + if (!mask.is_running()) + return siblings; // Non saprei come fare + + TBit_array key(4); // Elenco delle chiavi gia' utilizzate + + // Scorre la lista dei campi di output + int n = 0; + for (const char* i = _out_id.get(0); i; i = _out_id.get(), n++) + { + const short id = atoi(i); + const TMask_field& f = mask.field(id); + if (!f.showed() || !f.is_edit()) // Scarta i campi non editabili + continue; + const TEdit_field& e = (const TEdit_field&)f; + const TBrowse* b = e.browse(); + if (b == NULL) + continue; // Scarta i campi senza ricerca (improbabile) + + const TCursor* c = b->cursor(); + + // Considera ricerche sullo stesso file ma con chiave diversa + if (c && c->file().num() == _cursor->file().num() && + key[c->key()] == FALSE) + { + const TString16 fn(_out_fn.get(n)); // Legge nome del campo su file + const int pos = _items.get_pos(fn); // Determina header corrispondente + if (pos >= 0) + { + siblings.add(id); + const char* h = _head.get(pos); + siblings.add(h); + const int et = siblings.find('@'); + if (et > 0) siblings.cut(et); + key.set(c->key()); // Marca la chiave come usata + } + } + } + + return siblings; +} + + +KEY TBrowse::run() +{ + do_input(TRUE); + _cursor->read(); + + const char* caption = field().prompt(); + if (!isalnum(*caption)) caption = "Selezione"; + + KEY k = K_ESC; + long selected = 0; + + TToken_string siblings; create_siblings(siblings); + +{ + TToken_string* sib = siblings.empty() ? NULL : &siblings; + const byte buttons = _insert.empty() ? 0 : 1; + TBrowse_sheet s(_cursor, _items, caption, _head, buttons, _fld, sib); + k = s.run(); + selected = s.selected(); +} + +switch (k) +{ + case K_INS: + k = do_insert() ? K_ENTER : K_ESC; + break; + case K_ENTER: + *_cursor = selected; + do_output(); + break; +default: + if (k >= K_CTRL) + { + const short id = siblings.get_int((k - K_CTRL) << 1); + TEdit_field& ef = (TEdit_field&)_fld->mask().field(id); + if (ef.mask().is_running()) ef.set_focus(); + else ef.mask().first_focus(-ef.dlg()); + ef.mask().send_key(k = K_F9, 0); + } + break; +} + +return k; +} + +bool TBrowse::check(CheckTime t) +{ + bool passed = TRUE; + + if (_secondary && t != RUNNING_CHECK) + return TRUE; + // if (_checked && t == FINAL_CHECK) + // return TRUE; + // _checked = TRUE; + if (_fld->check_type() != CHECK_NONE) + { + const TMaskmode mode = (TMaskmode)field().mask().mode(); + + CheckType chk = _fld->check_type(); + const int ne = do_input(TRUE); + if (t == STARTING_CHECK || mode == MODE_QUERY) chk = CHECK_NORMAL; + if (ne || chk == CHECK_REQUIRED) + { + _cursor->setkey(); + _cursor->file().read(_isequal); + passed = _cursor->ok(); + + if (t != FINAL_CHECK) + { + if (passed) + { + _cursor->repos(); + do_output(t); + } + else + { + do_clear(); + _fld->set_dirty(2); + } + } + } + else + if (t != FINAL_CHECK) do_clear(); + } + // _checked = passed; + return passed; +} + +bool TBrowse::empty_check() +{ + const TMaskmode mode = (TMaskmode)field().mask().mode(); + const bool no_check = mode == MODE_SEARCH || field().mask().query_mode(); + + if ( no_check || _fld->check_type() == CHECK_NONE || + _fld->check_type() == CHECK_NORMAL) + return TRUE; + else + return do_input() > 0; +} + + +/////////////////////////////////////////////////////////// +// TEdit_field +/////////////////////////////////////////////////////////// + +TEdit_field::TEdit_field(TMask* mask) +: TMask_field(mask), _browse(NULL), _sheet(NULL), + _buttonwin(NULL_WIN), _check(CHECK_NONE), _check_enabled(TRUE), + _forced(FALSE) +{} + +TEdit_field::~TEdit_field() +{ + if (_browse) delete _browse; else + if (_sheet) delete _sheet; +} + +word TEdit_field::class_id() const +{ return CLASS_EDIT_FIELD; } + + +void TEdit_field::enable(bool on) +{ + TMask_field::enable(on); + if (_buttonwin != NULL_WIN) + show_window(_buttonwin, on && _check_enabled && showed()); +} + +void TEdit_field::show(bool on) +{ + TMask_field::show(on); + if (_buttonwin != NULL_WIN) + show_window(_buttonwin, on && _check_enabled && enabled()); +} + + +void TEdit_field::parse_head(TScanner& scanner) +{ + _size = scanner.integer(); + if (_size < 1) + { + _size = 8; + error_box("Il campo %d ha dimensione nulla (uso %d)", dlg(), _size); + } + + _width = scanner.integer(); + if (_width == 0) _width = _size; +} + + +const TBrowse* TEdit_field::get_browse(TScanner& scanner) const +{ + const int id = scanner.integer(); + TMask_field& m = mask().field(id); + if (!m.is_edit()) + { + error_box("Il campo %d non puo' fare una COPY del campo %d", + dlg(), id); + return NULL; + } + + TEdit_field& f = (TEdit_field&)m ; + TBrowse* b = (TBrowse*) f.browse(); + if (b == NULL) + error_box("La USE del campo %d non puo' essere copiata da %d", + id, dlg()); + return b; +} + + +bool TEdit_field::parse_item(TScanner& scanner) +{ + if (scanner.key() == "PI") // PICTURE + { + _picture = scanner.string(); + return TRUE; + } + + if (scanner.key() == "CH") + { + scanner.pop(); + if (scanner.key() == "NO") _check = CHECK_NORMAL; + else if (scanner.key() == "RE") _check = CHECK_REQUIRED; + else if (scanner.key() == "FO") {_check = CHECK_REQUIRED; _forced = TRUE;} + else _check = CHECK_NONE; + return TRUE; + } + + if (scanner.key() == "US") // USE + { + if (_browse != NULL) + return error_box("USE duplicata nel campo %d", dlg()); + + int key = 1; + TRelation* r; + + const int logicnum = scanner.integer(); + TString16 tabmaskname; + + if (logicnum > 0) + r = new TRelation(logicnum); + else + { + tabmaskname = scanner.pop(); + if (tabmaskname.len() > 4) + return error_box("'%s' non e' una tabella valida: %d", + (const char*)tabmaskname, dlg()); + r = new TRelation(tabmaskname); + } + + if (scanner.popkey() == "KE") + { + key = scanner.integer(); + if (key < 1) + { + error_box("Chiave %d non valida nella USE del campo %d", key, dlg()); + key = 1; + } + } + else scanner.push(); + + const char* filter = ""; + if (scanner.popkey() == "SE") + filter = (const char*)scanner.line(); + else + scanner.push(); + + _browse = new TBrowse(this, r, key, filter); + + if (tabmaskname.not_empty()) + { + if (strncmp(MainApp()->name(), "ba3", 3) != 0) + { + tabmaskname.insert("MBATB", 0); + _browse->set_insert(tabmaskname); + } + } + + return TRUE; + } + + if (scanner.key() == "CO") // Copyuse + { + const TString16 what(scanner.popkey()); + + const TBrowse* b = get_browse(scanner); +#ifdef DBG + if (b == NULL) + return yesnofatal_box("Impossibile COPYare la browse nel campo %d", dlg()); +#endif + if (what == "US" || what == "AL") + _browse = new TBrowse(this, b->cursor()); + + if (_browse) + return _browse->parse_copy(what, b); + +#ifdef DBG + return yesnofatal_box("Impossibile COPY senza USE nel campo %d", dlg()); +#endif + } + + if (scanner.key() == "JO") + { +#ifdef DBG + if(!_browse) return yesnofatal_box("JOIN senza USE nel campo %d", dlg()); +#endif + _browse->parse_join(scanner); + return TRUE; + } + + if (scanner.key() == "SH") // SHEET + { + if (_sheet) return error_box("SHEET duplicato nel campo %d", dlg()); + _sheet = new TList_sheet(this, _prompt, scanner.string()); + return TRUE; + } + + if (scanner.key() == "IT") // ITEM + { + if (_sheet == NULL) + return error_box("ITEM senza SHEET nel campo %d", dlg()); + _sheet->read_item(scanner); + return TRUE; + } + + if (scanner.key() == "IN") + { + if (_browse) _browse->parse_input(scanner); else + if (_sheet) _sheet->parse_input(scanner); + else error_box("INPUT senza USE o SHEET nel campo %d", dlg()); + return TRUE; + } + + if (scanner.key() == "DI") + { + if(!_browse) + return error_box("DISPLAY senza USE nel campo %d", dlg()); + _browse->parse_display(scanner); + return TRUE; + } + + if (scanner.key() == "OU") + { + if (_browse) _browse->parse_output(scanner); + else if (_sheet) _sheet->parse_output(scanner); + else return error_box("OUTPUT senza USE nel campo %d", dlg()); + return TRUE; + } + + if (scanner.key() == "AD") + { + if(!_browse) return error_box("ADD senza USE nel campo %d", dlg()); + _browse->parse_insert(scanner); + return TRUE; + } + + if (scanner.key() == "VA") + { + const char* n = scanner.pop(); + _validate_func = isdigit(*n) ? atoi(n) : -1; + if (_validate_func < 0) + return yesnofatal_box("Funzione di validazione '%s' errata nel campo %d", n, dlg()); + + const int _nparms = scanner.integer(); + if (_nparms < 0) + return yesnofatal_box("Numero di parametri VALIDATE errato nel campo %d", dlg()); + + for(int i = 0; i < _nparms; i++) + _validate_parms.add(scanner.operand()); + + return TRUE; + } + + if (scanner.key() == "WA") + { + _warning = scanner.string(); + return TRUE; + } + if (scanner.key() == "ME") + { + TFixed_string l(scanner.line().strip_spaces()); + int m = 0; + if (l[0] == '0') + { + l.ltrim(1); + l.ltrim(); + m = 1; + } + if (_message.objptr(m) == 0) + _message.add(new TToken_string(64), m); + TToken_string& ts = (TToken_string&)_message[m]; + ts.add(l); + return TRUE; + } + + return TMask_field::parse_item(scanner); +} + + +void TEdit_field::create(WINDOW parent) +{ + const int len = create_prompt(parent); + + long align = _flags.rightjust ? CTL_FLAG_RIGHT_JUST : CTL_FLAG_LEFT_JUST; + _x += len; + +#if XVTWS == WMWS + const int delta = 2; +#else + const int delta = 1; +#endif + + wincreate(WC_EDIT, _width+delta, 1, _str, parent, align); + +#if XVT_OS == XVT_OS_WIN + HWND hwnd = (HWND)get_value(win(), ATTR_NATIVE_WINDOW); + SendMessage(hwnd, EM_LIMITTEXT, _size, 0L); // Limita il testo + long style = GetWindowLong(hwnd, GWL_STYLE); + if (_flags.uppercase) style != ES_UPPERCASE; // Edit in maiuscolo + SetWindowLong(hwnd, GWL_STYLE, style); +#endif + + if (_browse || _sheet) + { + long flags = default_flags(); + if (flags & CTL_FLAG_DISABLED) + { + flags &= ~CTL_FLAG_DISABLED; + flags |= CTL_FLAG_INVISIBLE; + } + _buttonwin = xvt_create_control(WC_PUSHBUTTON, _x+_width+delta, _y, + 2, 1, "*", parent, flags, PTR_LONG(this), DLG_F9); + } +} + +void TEdit_field::destroy() +{ + if (_buttonwin) + { close_window(_buttonwin); _buttonwin = NULL_WIN; } + TMask_field::destroy(); +} + + +void TEdit_field::set_window_data(const char* data) +{ + TMask_field::set_window_data(format(data)); +} + + +void TEdit_field::set_field_data(const char* data) +{ _str = data; } + +const char* TEdit_field::get_field_data() const +{ return _str; } + + +const char* TEdit_field::format(const char* d) +{ + fpark = d; + fpark.trim(); + + if (fpark.not_empty()) + { + if (fpark.len() > _size) + { +#ifdef DBG + error_box("Campo %d troppo lungo: %d > %d", dlg(), fpark.len(), _size); +#endif + fpark.cut(_size); + } + + if (_flags.uppercase) + fpark.upper(); + + if (_flags.zerofilled) + fpark.right_just(_size, '0'); + else + if (_flags.rightjust) + fpark.right_just(_size); + } + + return fpark; +} + + +const char* TEdit_field::picture_data(const char* data, bool video) +{ + if (video) + { + set_title(win(), (char*)data); + return get_window_data(); + } + + set_window_data(data); + TMask_field::get_window_data(); + fpark.trim(); + return fpark; +} + + +bool TEdit_field::validate(KEY k) +{ + return ::validate(_validate_func, *this, k, _validate_parms); +} + +// Certified 90% +bool TEdit_field::on_hit() +{ + if (_handler) + { + bool ok = _handler(*this, is_edit() ? K_TAB : K_SPACE); + if (!ok) return FALSE; + } + if (_message.objptr(1) && get() == "") do_message(1); + else do_message(0); + return TRUE; +} + +bool TEdit_field::on_key(KEY key) +{ + switch(key) + { + case K_TAB: + if (_validate_func == AUTOEXIT_FUNC || + _validate_func == NUMCALC_FUNC || + _validate_func == STRCALC_FUNC) + set_focusdirty(); // Forza validate + if (to_check(K_TAB, TRUE)) + { + set(get()); + bool ok = validate(key); // Check validation expression + + if (!ok) + { + if (_warning.not_empty()) error_box(_warning); + return FALSE; + } + + TMask& m = mask(); + const bool query = m.query_mode(); + + if (_sheet) ok = query || _sheet->check(); // Check consistency + else + if (check_enabled() && _browse && (!query || forced())) + ok = _browse->check(); // Check consistency + + if (!ok) + { + if (_warning.not_empty()) error_box(_warning); + else error_box("Valore del campo %d non valido: %s", dlg(), (const char*)get()); + return FALSE; + } + + ok = on_hit(); + if (!ok) + return FALSE; + + if (query && required() && in_key(0)) + { + const byte keys = m.num_keys(); + + for (int i = 1; i <= keys; i++) + if (in_key(i) && m.key_valid(i)) + { + for (int fld = m.get_key_field(i, TRUE); fld != -1; fld = m.get_key_field(i, FALSE)) + m.field(fld).set_dirty(FALSE); + dispatch_e_char(get_parent(win()), K_AUTO_ENTER); + break; + } + } + return TRUE; + } + break; + case K_ENTER: + if (field() != NULL || mask().mode() == NO_MODE) + { + if (focusdirty()) set(get()); + + bool ok = validate(K_ENTER); // Check validation expression + if (!ok) + { + if (_warning.not_empty()) error_box(_warning); + return FALSE; + } + + const bool query = mask().query_mode(); + + // check consistency + if (_sheet) ok = query || _sheet->check(FINAL_CHECK); + else if (_browse && check_enabled()) + { + if (!query || forced()) + { + if (dirty()) ok = _browse->check(FINAL_CHECK); // Check consistency + else ok = _browse->empty_check(); + } + } + else + ok = query || !(check_type() == CHECK_REQUIRED && get().empty()); + + if (!ok) + { + if (_warning.not_empty()) error_box(_warning); + else error_box("Valore del campo %d non valido: '%s'", dlg(), (const char*)get()); + return FALSE; + } + } + break; + case K_F9: + if (check_enabled()) + { + if (dirty()) set(get()); + KEY k = K_ESC; + if (_browse) k = _browse->run(); + else if (_sheet) k = _sheet->run(); + else beep(); + if (mask().is_running() && k != K_F9) set_focus(); + if (k == K_ENTER) + { + set_dirty(); + if (mask().is_running()) + mask().send_key(K_TAB, 0); + else + on_hit(); + return TRUE; + } + else + return FALSE; + } + break; + default: + break; + } + + return TMask_field::on_key(key); +} + + +bool TEdit_field::has_check() const +{ + if (_browse) return check_type() != CHECK_NONE; + return _sheet != NULL; +} + +bool TEdit_field::check(CheckTime t) +{ + if (check_enabled() || (t == STARTING_CHECK && showed())) + { + if (_browse) return _browse->check(t); else + if (_sheet) return _sheet->check(t); + } + return TRUE; +} + +void TEdit_field::enable_check(bool on) +{ + _check_enabled = on; + if (_buttonwin != NULL_WIN) + show_window(_buttonwin, on); +} + + +/////////////////////////////////////////////////////////// +// Boolean_field +/////////////////////////////////////////////////////////// + + +TBoolean_field::TBoolean_field(TMask* m) +: TMask_field(m), _on(FALSE) +{} + + +word TBoolean_field::class_id() const +{ return CLASS_BOOLEAN_FIELD; } + + +void TBoolean_field::create(WINDOW parent) +{ + wincreate(WC_CHECKBOX, strlen(_prompt)+4, 1, _prompt, parent, 0); +} + + +const char* TBoolean_field::get_window_data() const +{ + CHECK(win(), "Control window not initialized"); + fpark[0] = xvt_get_checked_state(win()) ? 'X' : ' '; + fpark[1] = '\0'; + return fpark; +} + + +void TBoolean_field::set_window_data(const char* data) +{ + CHECK(win(), "Control window not initialized"); + + if (data == NULL) data = ""; + const bool b = toupper(*data) == 'X'; + xvt_check_box(win(), b); +} + + +void TBoolean_field::set_field_data(const char* data) +{ + if (data == NULL) data = ""; + _on = toupper(*data) == 'X'; +} + +const char* TBoolean_field::get_field_data() const +{ + return _on ? "X" : " "; +} + + +bool TBoolean_field::parse_item(TScanner& scanner) +{ + if (scanner.key() == "ME") + { + const bool tf = scanner.integer() ? TRUE : FALSE; // Message TRUE or FALSE + + if (_message.items() == 0) + { + _message.add(new TToken_string(16)); + _message.add(new TToken_string(16)); + } + TToken_string& ts = (TToken_string&)_message[tf]; + ts.add(scanner.line().strip_spaces()); + + return TRUE; + } + + return TMask_field::parse_item(scanner); +} + +void TBoolean_field::enable(bool on) +{ + _flags.enabled = on; + xvt_enable_control(_win, on); +} + + +bool TBoolean_field::on_hit() +{ + if (_handler) + { + bool ok = _handler(*this, K_SPACE); + if (!ok) return FALSE; + } + const int n = mask().is_running() ? xvt_get_checked_state(win()) : _on; + do_message(n); + return TRUE; +} + +bool TBoolean_field::on_key(KEY key) +{ + if (key == K_SPACE) + { + on_hit(); + set_dirty(); + return TRUE; + } + return TMask_field::on_key(key); +} + +/////////////////////////////////////////////////////////// +// Button_field +/////////////////////////////////////////////////////////// + +TButton_field::TButton_field(TMask* m) +: TMask_field(m) +{ + _flags.persistent = TRUE; +} + + +word TButton_field::class_id() const +{ return CLASS_BUTTON_FIELD; } + +void TButton_field::parse_head(TScanner& scanner) +{ + _width = scanner.integer(); + if (_width < 1) _width = 9; + _size = scanner.integer(); // Height + if (_size < 1) _size = 1; +} + + +bool TButton_field::parse_item(TScanner& scanner) +{ + return TMask_field::parse_item(scanner); +} + + +void TButton_field::create(WINDOW parent) +{ + long flags = CTL_FLAG_CENTER_JUST; + + switch (dlg()) + { + case DLG_OK: + if (_prompt.empty()) + _prompt = "Conferma"; + _virtual_key = _exit_key = K_ENTER; + flags |= CTL_FLAG_DEFAULT; + break; + case DLG_CANCEL: + if (_prompt.empty()) + _prompt = "Annulla"; + _virtual_key = _exit_key = K_ESC; + break; + case DLG_DELREC: + _virtual_key = 'E'; + _exit_key = K_DEL; + break; + case DLG_PRINT: + if (_prompt.empty()) + _prompt = "Stampa"; + _virtual_key = 'S'; + _exit_key = K_ENTER; + break; + case DLG_QUIT: + if (_prompt.empty()) + _prompt = "Fine"; + _virtual_key = K_F4; + _exit_key = K_QUIT; + break; + default: + { + _exit_key = 0; + TToken_string* message = (TToken_string*)_message.objptr(0); + if (message != NULL) + { + TToken_string msg(message->get(0), ','); + const TFixed_string m(msg.get(0)); + if (m == "EXIT") + _exit_key = msg.get_int(); + else + if (msg.get_int() == 0) _exit_key = atoi(m); + } + const int n = _prompt.find('~'); + _virtual_key = (n >= 0) ? toupper(_prompt[n+1]) : _exit_key; + } + break; + } + + +#if XWTWS == WMWS + _prompt.center_just(_width); +#endif + + wincreate(WC_PUSHBUTTON, _width + 2, _size, _prompt, parent, flags); +} + +void TButton_field::enable(bool on) +{ + _flags.enabled = on; + xvt_enable_control(_win, on); +} + +void TButton_field::show(bool on) +{ + TMask_field::show(on); +} + + +bool TButton_field::on_key(KEY key) + +{ + if (key == K_SPACE) + { + on_hit(); + return TRUE; + } + return TMask_field::on_key(key); +} + +/////////////////////////////////////////////////////////// +// Date_field +/////////////////////////////////////////////////////////// + +word TDate_field::class_id() const +{ return CLASS_DATE_FIELD; } + +void TDate_field::create(WINDOW w) +{ + TEdit_field::create(w); + if (automagic()) + { + TDate d(TODAY); + set(d.string()); + } +} + +void TDate_field::parse_head(TScanner&) {} + +TDate_field::TDate_field(TMask* m) : TEdit_field(m) +{ + _size = _width = 10; +} + + +bool TDate_field::on_key(KEY key) +{ + if (to_check(key)) + { + TFixed_string data(get_window_data(), 15); + data.trim(); + if (data.not_empty() || required()) + { + bool changed = FALSE; + if (isdigit(data[0])) + { + if (data.len() == 6) // Fix century (for this millenium only) + { + data.insert("19", 4); + changed = TRUE; + } + for (int meno = 2; meno <= 5; meno += 3) + if (data[meno] != '-') + { + data.insert("-", meno); + changed = TRUE; + } + if (data.len() == 8) // Fix century (for this millenium only) + { + data.insert("19", 6); + changed = TRUE; + } + } + else + { + TDate g(TODAY); + data.upper(); + if (data == "IERI") --g; else + if (data == "DOMANI") ++g; + TString16 gstring(g.string()); + if (data == "PRIMO") { gstring.overwrite("01-01", 0); } else + if (data == "ULTIMO") { gstring.overwrite("31-12", 0); } + data = gstring; + changed = TRUE; + } + + TDate d(data); + if (!d.ok()) + { + // error_box("La data deve essere nel formato gg-mm-aaaa"); + error_box("Data errata o formato non valido"); + return FALSE; + } + else + if (changed) + TMask_field::set_window_data(d.string()); + } + } + + return TEdit_field::on_key(key); +} + + +/////////////////////////////////////////////////////////// +// Real_field +/////////////////////////////////////////////////////////// + +TReal_field::TReal_field(TMask* m) : TEdit_field(m) +{} + +word TReal_field::class_id() const +{ return CLASS_REAL_FIELD; } + +void TReal_field::create(WINDOW w) +{ + TEdit_field::create(w); + + if (_flags.firm) + set(::format("%ld", MainApp()->get_firm())); else + if (automagic()) + { + TDate d(TODAY); + set(::format("%d", d.year())); + } +} + +bool TReal_field::on_key(KEY key) +{ + if (to_check(key)) + { + if (roman()) + { + const int r = atoi(get_window_data()); + if (r < 0) return error_box("Numero romano errato"); + } + else + { + const char* n = get(); + if (*n && !real::is_real(n)) + return error_box("Numero non valido"); + + const int segno = real(n).sign(); + if (required() && segno == 0 && !mask().query_mode()) + return error_box("Manca un valore indispensabile"); + + if (_flags.uppercase && segno < 0) + return error_box("Il numero deve essere positivo"); + } + } + + return TEdit_field::on_key(key); +} + +void TReal_field::parse_head(TScanner& scanner) +{ + _size = scanner.integer(); + +#ifdef DBG + if (_size < 1) + { + _size = 9; + yesnofatal_box("Il campo %d ha dimensione nulla (uso %d)", dlg(), _size); + } +#endif + + _width = _size; + _decimals = scanner.integer(); +} + +void TReal_field::set_window_data(const char* data) +{ + if (data == NULL) data = ""; + + if (roman()) + { + data = itor(atoi(data)); + TMask_field::set_window_data(data); + } + else + { + real n(data); + if (!n.is_zero()) + { + if (_flags.exchange) + { + const real& e = mask().exchange(); + if (e != 1.0) n /= e; + } + if (_picture.empty()) + data = n.stringa(_size, _decimals); + else + data = n.string(_picture); + } else data = ""; + TEdit_field::set_window_data(data); + } +} + +const char* TReal_field::get_window_data() const +{ + TEdit_field::get_window_data(); + if (roman()) + { + int r = atoi(fpark); + if (r == 0) r = rtoi(fpark); + if (r > 0) + { + int s = decimals(); + if (s < 1) s = 4; + if (_flags.zerofilled) + fpark.format("%0*d", s, r); + else + fpark.format("%*d", s, r); + } + else fpark.cut(0); + } + else + { + fpark = real::ita2eng(fpark); + if (_flags.exchange) + { + const real& e = mask().exchange(); + if (e != 1.0) + { + real n(fpark); + n *= e; + if (n.is_zero()) fpark.cut(0); + else fpark = n.string(); + } + } + } + + return fpark; +} + +void TReal_field::set_decimals(int d) +{ + _decimals = d; + if (_picture[0] == '.') + { + if (d > 0) _picture.format(".%d", d); + else _picture = "."; + } +} + + +void TReal_field::exchange(const real& vec, const real& nuo) +{ + const int dec = (nuo != 1.0) ? 2 : 0; + + if (decimals() != dec) + set_decimals(dec); + else + if (dec == 2) + return; + + if (mask().is_running()) + { + const char* n = real::ita2eng(TEdit_field::get_window_data()); + if (*n) + { + real r(n); + r *= vec; + r /= nuo; + r.round(dec); + TEdit_field::set_window_data(r.string(_picture)); + } + } +} + +/////////////////////////////////////////////////////////// +// List_field +/////////////////////////////////////////////////////////// + +TList_field::TList_field(TMask* m) : TMask_field(m) +{} + +word TList_field::class_id() const +{ + return CLASS_LIST_FIELD; +} + + +void TList_field::read_item(TScanner& scanner) +{ + TToken_string ts(scanner.string()); + _codes.add(ts.get()); + _values.add(ts.get()); + + ts = ""; + while (scanner.popkey() == "ME") + ts.add(scanner.line().strip_spaces()); + scanner.push(); + + _message.add(ts); +} + + +void TList_field::parse_head(TScanner& scanner) +{ + _size = scanner.integer(); + _width = scanner.integer(); + if (_width < 1) _width = _size+3; +} + + +bool TList_field::parse_item(TScanner& scanner) +{ + if (scanner.key() == "IT") // ITEM + { + read_item(scanner); + return TRUE; + } + + if (scanner.key() == "LI") // LISTITEM + { + TScanner sc(scanner.pop()); + while (sc.popkey() == "IT") // ITEM + read_item(sc); + return TRUE; + } + + return TMask_field::parse_item(scanner); +} + + +int TList_field::items() const +{ + return _codes.items(); +} + +void TList_field::add_item(const char* s) +{ + TToken_string t(s); + const TString16 item(t.get()); + const int pos = _codes.get_pos(item); + + if (pos < 0 ) + { + _codes.add(item); + win_list_add(win(), -1, (char*)t.get()); + } +} + + +void TList_field::delete_item(const char* s) +{ + TString16 t(s); + const int pos = _codes.get_pos(t); + + if (pos >= 0 ) + { + _codes.destroy(pos); + win_list_delete(win(), pos); + if (mask().is_running()) + { + win_list_set_sel(win(), 0, TRUE); + if (showed()) on_hit(); + } + } +} + + +void TList_field::add_list() +{ + if (roman() && _codes.items() < 12) + { + TString csafe, vsafe; + if (atoi(_codes) > 0) + { + csafe = _codes; _codes = ""; + vsafe = _values; _values = ""; + } + _codes.add("01|02|03|04|05|06|07|08|09|10|11|12"); + _values.add("Gennaio|Febbraio|Marzo|Aprile|Maggio|Giugno"); + _values.add("Luglio|Agosto|Settembre|Ottobre|Novembre|Dicembre"); + if (atoi(csafe) > 0) + { + _codes.add(csafe); + _values.add(vsafe); + if (_message.objptr(0)) + { + _message.add(_message[0], _codes.items()-1); + _message.add(NULL, 0); + } + } + } + + SLIST lst = slist_new(); + for (const char* item = _values.get(0); item; item = _values.get()) + slist_add(lst, (SLIST_ELT)NULL, (char*)item, 0L); + win_list_add(win(), -1, (char*)lst); + slist_dispose(lst); + + const char* init = ""; + if (roman() && automagic()) + init = format("%02d", TDate(TODAY).month()); + set_field_data(init); +} + + +void TList_field::replace_items(const char* codes, const char* values) +{ + _codes = codes; + _values = values; + + if (win() != NULL_WIN) + { + win_list_clear(win()); + add_list(); + current(0); + } +} + + +void TList_field::create(WINDOW parent) +{ + const int len = create_prompt(parent); + _x += len; + + wincreate(WC_LISTBUTTON, _width, 5, "", parent,0); + add_list(); +} + + +int TList_field::str2curr(const char* data) +{ + TString16 str(data); + + if (roman() && str.len() < 2) + str.insert("0",0); + if (_flags.uppercase) + str.upper(); + + int i = str.not_empty() ? _codes.get_pos(str) : 0; + + if (i < 0) // Se non trova il codice ritenta dopo trim + { + for (i = 0; str[i] == '0' || str[i] == ' '; i++); + if (i > 0) + { + str.ltrim(i); + i = _codes.get_pos(str); + } + } + + if (i < 0) + { + if (items() && str.not_empty()) + yesnofatal_box("'%s' non e' un valore valido per il campo %s: %d", + data, prompt(), dlg()); + i = 0; + } + return i; +} + + +void TList_field::set_window_data(const char* data) +{ + CHECKD(win(), "Control window not initialized ", dlg()); + const int i = str2curr(data); + current(i); +} + + +void TList_field::current(int n) +{ + win_list_set_sel(win(), n, TRUE); +} + +int TList_field::current() const +{ + const int sel = win_list_get_sel_index(win()); +#ifdef DBG + if (sel < 0 && items() > 0) + error_box("Lista senza selezione nel campo %d", dlg()); +#endif + return sel; +} + +const char* TList_field::get_window_data() const +{ + const int c = current(); + const char* v = ((TList_field*)this)->_codes.get(c); + return v; +} + +void TList_field::set_field_data(const char* data) +{ + if (data == NULL || *data == '\0') data = _codes.get(0); + _str = data; +} + +bool TList_field::on_hit() +{ + if (_handler) + { + bool ok = _handler(*this, K_SPACE); + if (!ok) return FALSE; + } + const int n = mask().is_running() ? current() : str2curr(_str); + do_message(n); + return TRUE; +} + +const char* TList_field::get_field_data() const +{ + return _str; +} + +bool TList_field::on_key(KEY key) +{ + if (key >= '0' && key <= 'z') + { + const int index = win_list_get_sel_index(win()); + CHECK(index >= 0, "List with no selection!"); + int newindex = -1; + +#if XVTWS == WMWS + if (key >= 'A' && key <= 'z') + { + for (int i = index+1; i != index; i++) + { + char item[16]; + bool flag; + + do + { + flag = win_list_get_elt(win(), i, item, 16); + if (!flag) + { + CHECK(i, "La lista e' vuota!"); + i = -1; + break; + } + } while (!flag); + if (flag && toupper(*item) == toupper(key)) + { + newindex = i; + break; + } + } // for + } // alphabetic +#endif + + if (key >= '0' && key <= '9') + { + newindex = (key == '0') ? 10 : key - '1'; + if (newindex > items()) + { + newindex = -1; + beep(); + } + } + + if (newindex >= 0) + { + win_list_suspend(win()); + win_list_set_sel(win(), index, FALSE); + win_list_set_sel(win(), newindex, TRUE); + win_list_resume(win()); + } + } // alphanumeric + +#if XVTWS == VMWS + if (key == K_TAB && class_id() == CLASS_LIST_FIELD) + dispacth_e_char(win(), K_F9); +#endif + + if (key == K_SPACE) on_hit(); + + return TMask_field::on_key(key); +} + + +/////////////////////////////////////////////////////////// +// TRadio_field +/////////////////////////////////////////////////////////// + +TRadio_field::TRadio_field(TMask* mask) +: TList_field(mask), _nitems(0), _active_item(0) +{} + + +word TRadio_field::class_id() const +{ + return CLASS_RADIO_FIELD; +} + + +void TRadio_field::create(WINDOW parent) +{ + const short id = dlg(); // Salva il control id + + if (_prompt.not_empty()) + { + const int dy = _codes.items()+2; + create_prompt(parent, _width, dy); + } + _x++; _y++; + _values.restart(); + + const char* s; + for(_nitems = 0; (s = _values.get()) != NULL; _nitems++, _y++) + { + CHECKD(_nitems < MAX_RADIO, "Too many items in radio button ", id); + + wincreate(WC_RADIOBUTTON, _width-2, 1, s, parent,0); + _radio_ctl_win[_nitems] = _win; + _dlg += 1000; + } + _radio_ctl_win[_nitems] = NULL_WIN; // Comodo per debug + + _dlg = id; // Ripristina control id + + set_field_data(""); +} + +void TRadio_field::destroy() +{ + if (_promptwin) + { close_window(_promptwin); _promptwin = NULL_WIN; } + + for(int i = 0; i < _nitems; i++) + { + close_window(_radio_ctl_win[i]); + _radio_ctl_win[i] = NULL_WIN; + } +} + + +int TRadio_field::current() const +{ + const int c = xvt_get_checked_radio(_radio_ctl_win, _nitems); + return c; +} + + +void TRadio_field::current(int n) +{ + _active_item = n; + xvt_check_radio_button(win(), _radio_ctl_win, _nitems); +} + + +void TRadio_field::check_radiobutton(WINDOW checked) +{ + for(int i = 0; i < _nitems && checked != _radio_ctl_win[i]; i++); + CHECK(i < _nitems, "Trying to check an invalid radio button"); + current(i); +} + + +void TRadio_field::enable(bool on) +{ + _flags.enabled = on; + for(int i = 0; i < _nitems; i++) + xvt_enable_control(_radio_ctl_win[i], on); +} + + +void TRadio_field::show(bool on) +{ + if (_promptwin) + show_window(_promptwin, on); + + for(int i = 0; i < _nitems; i++) + show_window(_radio_ctl_win[i], on); + _flags.showed = on; +} + +// Return TRUE if focus has left the radio +bool TRadio_field::move_focus(int d) +{ + const int act = _active_item + d; + if (act >= _nitems || act < 0) + { + _active_item = current(); + return TRUE; + } + xvt_set_front_control(_radio_ctl_win[_active_item = act]); + return FALSE; +} + + +/////////////////////////////////////////////////////////// +// TGroup_field +/////////////////////////////////////////////////////////// + +TGroup_field::TGroup_field(TMask* mask) : TMask_field(mask) +{ + _flags.persistent = TRUE; +} + +// _size means _heigth +void TGroup_field::parse_head(TScanner& scanner) +{ + _width = scanner.integer(); + _size = scanner.integer(); +} + + +void TGroup_field::create(WINDOW parent) +{ + const long f = _flags.rightjust ? CTL_FLAG_MULTIPLE : 0; + wincreate(WC_GROUPBOX, _width, _size, _prompt, parent, f); +} + diff --git a/include/prassi.ver b/include/prassi.ver index a7057f176..694198ddb 100755 --- a/include/prassi.ver +++ b/include/prassi.ver @@ -1 +1 @@ -#define VERSION 1.3 +#define VERSION 1.4 diff --git a/include/printapp.cpp b/include/printapp.cpp index ca66fc4e4..a3579a213 100755 --- a/include/printapp.cpp +++ b/include/printapp.cpp @@ -1,1267 +1,1280 @@ -// $Id: printapp.cpp,v 1.10 1994-09-16 09:36:17 alex Exp $ -#include -#include - -#include - -#include -#include -#include -#include -#include - -TLocalisamfile *fff; - -const char *printf_types = "dDiIuUoOxXfeEgGcCnNsSpPrRtT"; - -// _FieldTok flags - -const word LONG_FLAG = 0x0001; -const word PICTURE_FLAG = 0x0002; -const word PAD_FLAG = 0x0004; -const word ALIGN_FLAG = 0x0008; -const word TRANS_FLAG = 0x0010; -const word DATE_FLAG = 0x0020; -const word STRING_FLAG = 0x0040; -const word NUMBER_FLAG = 0x0080; -const word DEC_FLAG = 0x0100; -const word FONT_FLAG = 0x0200; -const word JUMP_FLAG = 0x0400; -const word RECNO_FLAG = 0x0800; -const word BOOLEAN_FLAG = 0x1000; -const word IGNORE_FILL = 0x2000; - -// ============================================================= -// print token containers -// ============================================================= - -class _Transfield:public TObject -{ - friend class TPrint_application; - TString _from, // "from" value - _to, // "to" value - _fn; // field name - - int _lognum; // logical number - - public: - _Transfield (int l, const char *fn, const char *from, const char *to): - _from (3), _to (20), _fn (10) - { - _lognum = l; - _from = from; - _to = to; - _fn = fn; - } -}; - -class _Token:public TObject -{ - friend class TPrint_application; - int _tag; - int _row; -public: - int tag () - { - return _tag; - } - int row () - { - return _row; - } - void tag (int t) - { - _tag = t; - } - void row (int r) - { - _row = r; - } - virtual ~ _Token () {} -}; - -class _PrintfTok : public _Token -// something to be printed (actually already printed on _val) -{ - friend class TPrint_application; - TString _val; - public: - _PrintfTok (int rw, const char *val):_val (0) - { - tag (0); - row (rw); - _val = val; - } - virtual ~ _PrintfTok () {} -}; - -class _FieldTok : public _Token -// something more complex to be printed -{ - friend class TPrint_application; - int _size, _dec; - char _align; - TString _fld; // field description - - word _flags; // all you need to know - - public: - _FieldTok (int rw, char *fld, word flags, char align = 'l', - int size = -1, int dec = -1): - _fld (20) - { - tag (1); - row (rw); - _fld = (const char *) fld; - _flags = flags; - _size = size, _align = align; - _dec = dec; - delete fld; - } - virtual ~ _FieldTok () - { - } -}; - -class _PrintfRef : public _Token -// to be printed by reference via format -// must pass valid pointer to object -{ - friend class TPrint_application; - void *_what; - char _type; - TString _fmt; - public: - _PrintfRef (int rw, const char *fmt, char type, void *what):_fmt (1) - { - tag (2); - row (rw); - _type = type; - _what = what; - _fmt = fmt; - _fmt[0] = '%'; - } - virtual ~ _PrintfRef () - { - } -}; - -void TPrint_application::_reset_tree (link_item * head) -{ - if (head) - { - if (head->_brother) - _reset_tree (head->_brother); - if (head->_son) - _reset_tree (head->_son); - delete head; - } -} - -link_item *TPrint_application::_look_print_node (link_item * head, int logicnum) -{ - // look for node to attach to - // since it reflects a relation, it won't have more than - // one node for the same file/alias, so it stops at first match - link_item *s; - while (head) - { - if (head->_logicnum == logicnum) - return head; - else if (head->_son) - if ((s = _look_print_node (head->_son, logicnum)) != NULL) - return s; - head = head->_brother; - } - return NULL; -} - -void TPrint_application::add_file (const char *tab, int from) -{ - add_file (TTable ::name2log (tab), from); -} - -void TPrint_application::add_file (int file, int from) -{ - link_item *nw = new link_item (file); - if (_pr_tree == NULL) - { - _pr_tree = nw; - return; - } - - if (from == 0) - from = _pr_tree->_logicnum; - - link_item *fr = _look_print_node (_pr_tree, from); - - CHECKD (fr, "add_file: nonexistent node: logicnum = ", from); - - if (fr->_son) - { - fr = fr->_son; - while (fr->_brother) - fr = fr->_brother; - fr->_brother = nw; - } - else - fr->_son = nw; -} - -// --------------------------------------------------------------- -// ------------ user function ------------------------------------ - -static char tb[120]; - -int TPrint_application::enable_link (const char *descr, char fg, char bg) -{ - TToken_string *tt = new TToken_string (30); - char b[2]; - b[1] = '\0'; - tt->add (descr); - b[0] = fg; - tt->add (b); - b[0] = bg; - tt->add (b); - printer().links ().add (tt); - return printer().links ().items () - 1; -} - -void TPrint_application::disable_link (char fg, char bg) -{ - for (int i = 0; i < printer().links ().items (); i++) - { - TToken_string & t = (TToken_string &) printer().links ()[i]; - char f = *(t.get (1)); - char b = *(t.get (2)); - if (f == fg && b == bg) - { - printer().links ().add (NULL, i); - printer().links ().pack (); - break; - } - } -} - -void TPrint_application::set_multiple_link (bool on) -{ - printer().setmultiplelink (on); -} - -void TPrint_application::_pp_link (int id, const char *text) -{ - TPrint_application *prapp = (TPrint_application *) MainApp (); - prapp->process_link (id, text); -} - -void TPrint_application::_pp_header (TPrinter &) -{ - TPrint_application *prapp = (TPrint_application *) MainApp (); - - prapp->preprocess_header (); - - prapp->printer().resetheader (); - int ii = (prapp->_header).last (); - // reset and add header/footer lines - for (int i = 0; i <= ii; i++) - if ((prapp->_header).objptr (i) != NULL) - prapp->printer().setheaderline (i, - new TPrintrow ((TPrintrow &) (prapp->_header)[i])); -} - -void TPrint_application::_pp_footer (TPrinter &) -{ - TPrint_application *prapp = (TPrint_application *) MainApp (); - - prapp->preprocess_footer (); - prapp->printer().resetfooter (); - int ii = (prapp->_footer).last (); - for (int i = 0; i <= ii; i++) - if ((prapp->_footer).objptr (i) != NULL) - prapp->printer().setfooterline (i, - new TPrintrow ((TPrintrow &) (prapp->_footer)[i])); -} - -void TPrint_application::set_background (const char *bgdesc) -{ - printer().setbackground (bgdesc); -} - -const char* FLD (int lognum, const char *f, int from, int to) -{ - sprintf (tb, "%c|%d|%s|%d|%d", 'n', lognum, f, from, to); - char *p = new char[strlen (tb) + 1]; - strcpy (p, tb); - return p; -} - -const char* FLD (int lognum, const char *f, const char *picture) -{ - sprintf (tb, "%c|%d|%s|%s", 'p', lognum, f, picture); - char *p = new char[strlen (tb) + 1]; - strcpy (p, tb); - return p; -} - -const char* FLD (const char *tabname, const char *f, int from, int to) -{ - CHECKS (strlen (tabname) < 5, "Invalid table name", tabname); - int lognum = TTable ::name2log (tabname); - sprintf (tb, "%c|%d|%s|%d|%d", 'n', lognum, f, from, to); - char *p = new char[strlen (tb) + 1]; - strcpy (p, tb); - return p; -} - -const char* FLD (const char *tabname, const char *f, const char *picture) -{ - CHECKS (strlen (tabname) < 5, "Invalid table name", tabname); - int lognum = TTable ::name2log (tabname); - sprintf (tb, "%c|%d|%s|%s", 'p', lognum, f, picture); - char *p = new char[strlen (tb) + 1]; - strcpy (p, tb); - return p; -} - -TString& fill_str (TString & t, char f) -{ - for (int kk = t.len () - 1; kk >= 0; kk--) - { - if (t[kk] == ' ') - t[kk] = f; - else - break; - } - for (kk = 0; kk < t.len (); kk++) - { - if (t[kk] == ' ') - t[kk] = f; - else - break; - } - return t; -} - -// ======================================================== -// Printapp code at last -// ======================================================== - -//void TPrint_application::enable_link(const char* descr, char fg, char bg) -// { -// printer().setlinkdescr(descr); -// } - -void TPrint_application::select_cursor (int c) -{ - if (c == -1) - _cur = NULL; - else - _cur = (TCursor *) & _cursors[c]; -} - -TCursor* TPrint_application::get_cursor (int c) -{ - if (c == -1) - return NULL; - else - return (TCursor *) & _cursors[c]; -} - -int TPrint_application::add_cursor (TCursor * c) -{ - if (c == NULL) - return -1; - _cursors.add (c); - _cur = c; - return _cursors.items () - 1; -} - -void TPrint_application::reset_row (int r) -{ - r--; - int tmp = _rows.items (); - for (int j = 0; j < tmp; j++) - { - _Token *t = (_Token *) (_rows.objptr (j)); - if (t) - { - if (t->row () == r) - _rows.add (NULL, j); - } - } - _rows.pack (); - if (_maxrow == r && _maxrow > 0) - _maxrow--; -} - -void TPrint_application::reset_print () -{ - _rows.destroy (); - _maxrow = 0; - _print_defined = FALSE; -} - -void TPrint_application::set_header (int r, const char *fmt,...) -{ - CHECK (r >= 1, "Header rows start at 1"); - va_list vl; - va_start (vl, fmt); - vsprintf (__tmp_string, fmt, vl); - va_end (vl); - - TPrintrow *pp = (TPrintrow *) _header.objptr (r - 1); - if (!pp) - { - pp = new TPrintrow; - _header.add (pp, r - 1); - } - pp->put (__tmp_string); -} - -void TPrint_application::set_footer (int r, const char *fmt,...) -{ - CHECK (r >= 1, "Footer rows start at 1"); - va_list vl; - va_start (vl, fmt); - vsprintf (__tmp_string, fmt, vl); - va_end (vl); - TPrintrow *pp = (TPrintrow *) _footer.objptr (r - 1); - if (pp == NULL) - { - pp = new TPrintrow; - _footer.add (pp, r - 1); - } - pp->put (__tmp_string); -} - -void TPrint_application::reset_header () -{ - _header.destroy (); - printer().resetheader (); -} - -void TPrint_application::reset_footer () -{ - _footer.destroy (); - printer().resetfooter (); -} - -void TPrint_application::fill_page (int from) -{ - from--; - for (int i = (from == -1 ? _maxrow : from); i <= printer().formlen (); i++) - { - reset_row (i); - set_row (i, ""); - } -} - -void TPrint_application::set_row (int r, const char *frmt,...) -{ - CHECK (r >= 1, "Print rows start at 1"); - - r--; - - char digbuf[10]; - char strbuf[120]; - char fftt[120]; - char *fmt = fftt; - char fill = _fillchar; - - word flags = 0; - int size = 0, dec = 0, strind = 0; - char ch, align = 'l'; - - // let the poor programmer use format() at will - strcpy (fmt, frmt); - _print_defined = TRUE; - - _currow = r; - if (_currow > _maxrow) - _maxrow = _currow; - - va_list params; - va_start (params, frmt); - - // parse format string - while ((ch = *fmt++) != '\0') - { - if (ch == '@') - { - // check for pending string - if (strind) - { - strbuf[strind] = '\0'; - _rows.add (new _PrintfTok (_currow, strbuf)); - strind = 0; - } - ch = *fmt++; - if (isdigit (ch)) - { - int i = 0; - digbuf[i++] = ch; - while (isdigit (ch = *fmt++)) - digbuf[i++] = ch; - digbuf[i] = '\0'; - size = atoi (digbuf); - flags |= PAD_FLAG; - if (ch == '.') - { - // decimal size follows - i = 0; - digbuf[i++] = ch; - while (isdigit (ch = *fmt++)) - digbuf[i] = ch; - digbuf[i] = '\0'; - dec = atoi (digbuf); - flags |= DEC_FLAG; - // ch = *fmt++; - } - else if (ch == ',') - { - // aligment spec follows - align = (ch = *fmt++); - CHECK (ch == 'l' || ch == 'r' || ch == 'c', - "TPrint_application::set_row: invalid alignment spec"); - flags |= ALIGN_FLAG; - ch = *fmt++; - } - } - switch (ch) - { - // modifiers - case 'l': - case 'L': - flags |= LONG_FLAG; - ch = *fmt++; - break; - case 'p': - case 'P': - flags |= PICTURE_FLAG; - ch = *fmt++; - break; - } - switch (ch) - { - // codes - case '@': - _rows.add (new _PrintfTok (_currow, "@")); - break; - case 'b': - case 'i': - case 'u': - case 'r': - { - char *xxxx = new char[2]; - xxxx[0] = ch; - xxxx[1] = '\0'; - _rows.add (new _FieldTok (_currow, xxxx, FONT_FLAG)); - } - break; - case 'g': - case 'j': - { - const char *xxx = format ("%c %d", ch, size); - char *xxxx = new char[strlen (xxx) + 1]; - strcpy (xxxx, xxx); - _rows.add (new _FieldTok (_currow, xxxx, JUMP_FLAG)); - } - break; - case 'T': - flags |= IGNORE_FILL; - case 't': - flags |= TRANS_FLAG; - break; - case 'D': - flags |= IGNORE_FILL; - case 'd': - flags |= DATE_FLAG; - break; - case 'F': - flags |= IGNORE_FILL; - case 'f': - flags |= BOOLEAN_FLAG; - break; - case 'S': - flags |= IGNORE_FILL; - case 's': - flags |= STRING_FLAG; - break; - case 'C': - flags |= IGNORE_FILL; - case 'c': - flags |= RECNO_FLAG; - break; - case 'N': - flags |= IGNORE_FILL; - case 'n': - flags |= NUMBER_FLAG; - break; - default: - CHECK (0, "TPrint_application::set_row: invalid @ code"); - break; - } - if (flags & NUMBER_FLAG || - flags & DATE_FLAG || - flags & TRANS_FLAG || - flags & BOOLEAN_FLAG || - flags & STRING_FLAG) - { - char *xxx = va_arg (params, char *); - _rows.add (new _FieldTok (_currow, xxx, - flags, align, size, dec)); - } - flags = 0x0000; - align = 'l'; - } - else - { - TString t; - switch (ch) - { - case '#': - case '%': - { - char ccc = ch; - // check for pending string - if (strind) - { - strbuf[strind] = '\0'; - _rows.add (new _PrintfTok (_currow, strbuf)); - strind = 0; - } - if ((ch = *fmt++) == ccc) - _rows.add (new _PrintfTok (_currow, ccc == '%' ? "%" : "#")); - else - { - // read format - t << ccc; - bool islong = FALSE; - while (strchr (printf_types, ch) == NULL) - { - t << ch; - if (ch == 'l') - islong = TRUE; - ch = *fmt++; - if (ch == '\0') - fatal_box ("sorry, zer's samzing vruong" - " uitz ioar format."); - } - if (isupper (ch)) - { - ch = tolower (ch); - fill = ' '; - } - if (ch == 't') - t << 's'; - else if (ch == 'r') - t << 't'; - else - t << ch; - if (ccc == '%') - { - TString q (60); - switch (ch) - { - case 'd': - case 'i': - case 'u': - case 'o': - case 'x': - case 'X': - q.format (t, islong ? va_arg (params, long) : - va_arg (params, int)); - break; - case 'f': - case 'e': - case 'E': - case 'G': - q.format (t, islong ? va_arg (params, double) : - va_arg (params, float)); - break; - case 'c': - q.format (t, va_arg (params, char)); - break; - case 's': - q.format (t, va_arg (params, char *)); - break; - case 't': // TString - - q.format (t, (const char *) - (TString) * ((va_arg (params, TString *)))); - break; - case 'r': // Real - - { - real *rrr = va_arg (params, real *); - if (t.len () == 2 && *_picture) - { - // no format specifications - // use default picture - q = rrr->string (_picture); - } - else - { - char *fff = (char *) ((const char *) t); - // dsprintf(__tmp_string, fff, - // (DEC*)(*rrr)); - dsprintf (__tmp_string, fff, rrr->ptr ()); - q = __tmp_string; - } - if (rrr->is_zero () && !_print_zero) - q.fill (' '); - } - break; - default: - break; - } - if (fill != ' ') - q = fill_str (q, fill); - fill = _fillchar; - _rows.add (new _PrintfTok (_currow, q)); - } - else - _rows.add (new _PrintfRef (_currow, t, ch, - va_arg (params, void *))); - } - } - break; - case '\n': // ignore - - break; - default: - // add to string - strbuf[strind++] = ch; - if (!ch) - fmt--; - break; - } - } - } - if (strind) - { - strbuf[strind] = '\0'; - _rows.add (new _PrintfTok (_currow, strbuf)); - strind = 0; - } - va_end (params); -} - -void TPrint_application::set_translation (int lognum, const char *field, - const char *from, const char *to) -{ - _transtab.add (new _Transfield (lognum, field, from, to)); -} - -void TPrint_application::print() -{ - // open printer if needed - if (!(printer().isopen ())) - if (!printer().open ()) - return; - - // only external apps can change it - _repeat_print = FALSE; - int ncopies = printer().n_copies(); - - // never print multiple copies if printer is viswin - // only application may repeat printing by setting _repeat_print - int nc = printer().printtype() == screenvis ? 1 : ncopies; - - // NULL cursor passed only prints once - // pre and post process do everything - - if (_cur == NULL) - { - //************************************************ - while (nc--) - { - - int cnt = 0; - bool ok = TRUE; - do - { - if (preprocess_print (0, cnt)) - { - int cnt2 = 0; - do - { - if (preprocess_page (0, cnt2)) - { - set_page (0, cnt2); - ok = print_one (0); - } - } - while (ok && postprocess_page (0, cnt2++) == REPEAT_PAGE); - } - } - while (ok && postprocess_print (0, cnt++) == REPEAT_PAGE); - // ***************************************************** - } - } - else - { - // cursor exists ********************************************* - while (nc--) - { - (*_cur) = 0l; - _cur->freeze (TRUE); - - if (_cur->items () >= _wthr && - (_force_progind || printer ().printtype () != screenvis)) - _prind = new TProgind (_cur->items (), - (char *) (const char *) _wmess, - _wcancel, _wbar, 35); - print_tree (_pr_tree); - _cur->freeze (FALSE); - - if (_prind) - { - delete _prind;; - _prind = NULL; - } - } - // **************************************************************** - } - if (printer().isopen ()) - { - printer().close(); - printer().resetheader(); - printer().resetfooter(); - } - postclose_print (); -} - -bool TPrint_application::print_tree (link_item * head) -{ - bool go = TRUE; - while (head) - { - head->_cnt = 0; - if (_cur->is_first_match (head->_logicnum)) - { - do - { - if (!preprocess_print (head->_logicnum, head->_cnt)) - break; - do - { - // set print rows according to current file - if (_force_setpage || _cur_file != head->_logicnum - || !_print_defined) - { - reset_print (); - set_page(head->_logicnum, head->_cnt); - _cur_file = head->_logicnum; - } - int cnt2 = 0; - do - { - if (!preprocess_page (head->_logicnum, cnt2)) - break; - go = print_one (head->_logicnum); - if (go && head->_son) - go = print_tree (head->_son); - } - while (go && postprocess_page (head->_logicnum, cnt2++) == - REPEAT_PAGE); - } - while (go && _cur->next_match (head->_logicnum)); - } - while (go && postprocess_print (head->_logicnum, head->_cnt++) - == REPEAT_PAGE); - } - if (!go) - break; - go = TRUE; - head = head->_brother; - } - return go; -} - -bool TPrint_application::print_one (int file) -{ - int i = 0; - - if ((_prind && _prind->iscancelled ()) || printer ().frozen ()) - return FALSE; - - if (!_print_defined) - return TRUE; - - if (_prind && file == _pr_tree->_logicnum) - _prind->addstatus (1); - - TArray rw (_maxrow + 1); - int *pos = new int[_maxrow + 1]; - - for (i = 0; i <= _maxrow; i++) - { - rw.add (new TPrintrow ()); - pos[i] = -1; - } - - // printing workhorse - for (i = 0; i <= _maxrow; i++) - for (int j = 0; j < _rows.items (); j++) - { - _Token *t = (_Token *) & (_rows[j]); - if (!t) - continue; // should not happen - - if (t->row () == i) - { - char pic[36], fn[17]; - int ch, ln, from, to; - - if (t->tag () == 1) - { - // it's a _FieldTok - _FieldTok *ft = (_FieldTok *) t; - TString toprint; - from = to = -1; - - if (ft->_flags & FONT_FLAG) - { - TPrintstyle st = normalstyle; - switch (((const char *) (ft->_fld))[0]) - { - case 'u': - st = underlinedstyle; - break; - case 'b': - st = boldstyle; - break; - case 'i': - st = italicstyle; - break; - case 'r': - st = normalstyle; - break; - } - ((TPrintrow *) (&rw[ft->row ()]))->set_style (st); - } - else if (ft->_flags & JUMP_FLAG) - { - char ch; - int p; - - ch = ft->_fld[0]; - p = atoi (((const char *) ft->_fld) + 2); - if (ch == 'g') - // go to - pos[ft->row ()] = p; - else - // jump ahead - pos[ft->row ()] = - ((TPrintrow *) (&rw[ft->row ()]))-> - lastpos () + p; - } - else - { - if ((*(const char *) (ft->_fld)) == 'p') - { - // picture - TToken_string ttt (ft->_fld, '|'); - ch = (ttt.get ())[0]; - ln = atoi ((const char *) ttt.get ()); - strcpy (fn, (const char *) ttt.get ()); - strcpy (pic, (const char *) ttt.get ()); - } - else - { - TToken_string ttt (ft->_fld, '|'); - ch = (ttt.get ())[0]; - ln = atoi ((const char *) ttt.get ()); - strcpy (fn, (const char *) ttt.get ()); - from = atoi ((const char *) ttt.get ()); - to = atoi ((const char *) ttt.get ()); - } - // get field val - TLocalisamfile *f = _cur->file (ln); - if (ft->_flags & TRANS_FLAG) - { - _Transfield *tr = NULL; - // look up field value in translation table - for (int i = 0; i < _transtab.items (); i++) - { - tr = (_Transfield *) & _transtab[i]; - if (tr->_fn == fn && tr->_lognum == ln) - { - // check value - if (tr->_from == f->get (fn)) - break; - } - } - if (i == _transtab.items ()) - toprint = ""; - else - toprint = tr->_to; - } - else if (ft->_flags & DATE_FLAG) - { - TDate d = (f->curr ()).get_date (fn); - toprint = d.string (ft->_flags & LONG_FLAG ? 4 : 2); - if (toprint.empty ()) - { - toprint = (ft->_flags & LONG_FLAG ? - " - - " : - " - - "); - } - } - else if (ft->_flags & BOOLEAN_FLAG) - { - toprint = (f->curr ()).get (fn) == "X" ? "Si" : "No"; - } - else if (ft->_flags & NUMBER_FLAG) - { - TString pict (0); - real r = f->curr ().get (fn); - - bool isreal = f->curr ().type (fn) == _realfld; - - if (ft->_flags & PICTURE_FLAG) - pict = pic; - else if (!(ft->_flags & DEC_FLAG) && *_picture - && isreal) - pict = _picture; - - if (pict.len () > 0) - toprint = r.string (pict); - else if (ft->_flags & DEC_FLAG) - toprint = r.string (ft->_size, ft->_dec); - else - toprint = r.string (); - - if (r.is_zero () && !_print_zero) - toprint.fill (' '); - } - else if (ft->_flags & STRING_FLAG) - { - toprint = f->curr ().get (fn); - // perform string extraction - if (from != -1) - toprint = toprint.sub (from, to); - else if (to != -1) - toprint = toprint.left (to); - } - } - // adjust size and set fill char - if (ft->_flags & PAD_FLAG) - { - if (!(ft->_flags & NUMBER_FLAG)) - { - if (ft->_size < toprint.len ()) - toprint.cut (ft->_size); - else - toprint.left_just (ft->_size); - } - if (ft->_flags & ALIGN_FLAG) - { - if (ft->_align == 'r') - toprint.right_just (toprint.len ()); - else if (ft->_align == 'c') - toprint.center_just (toprint.len ()); - else if (ft->_align == 'l') - toprint.left_just (toprint.len ()); - } - } - if (_fillchar != ' ' && !(ft->_flags & IGNORE_FILL)) - toprint = fill_str (toprint, _fillchar); - // add to print row - ((TPrintrow *) (&rw[ft->row ()]))->put (toprint, - pos[ft->row ()]); - if (pos[ft->row ()] != -1) - pos[ft->row ()] += toprint.len (); - } - - else if (t->tag () == 0) - { - // it's a _PrintfTok - _PrintfTok *pt = (_PrintfTok *) t; - TString v = pt->_val; - ((TPrintrow *) (&rw[pt->row ()]))->put (v, pos[pt->row ()]); - if (pos[pt->row ()] != -1) - { - pos[pt->row ()] += v.len (); - const char * s = v; - while (*s && strncmp(s, "$[", 2) == 0) - { - while (*s && *s != ']') - { - pos[pt->row()]--; - s++; - } - if (*s) - pos[pt->row()]--; - while (*s && *s != '$') s++; - } - } - } - else - if (t->tag () == 2) - { - // printf by reference - _PrintfRef *pr = (_PrintfRef *) t; - TString ps; - bool islong = (pr->_fmt).find ('l') != -1; - switch (pr->_type) - { - case 'd': - case 'i': - case 'u': - case 'o': - case 'x': - case 'X': - ps.format (pr->_fmt, islong ? *((long *) (pr->_what)) : - *((int *) (pr->_what))); - break; - case 'f': - case 'e': - ps.format (pr->_fmt, islong ? *((double *) (pr->_what)) : - *((float *) (pr->_what))); - break; - case 'c': - ps.format (pr->_fmt, *((char *) (pr->_what))); - break; - case 's': - ps.format (pr->_fmt, (char *) (pr->_what)); - break; - case 't': - ps.format (pr->_fmt, (const char *) - (*((TString *) (pr->_what)))); - break; - case 'r': - { - real *rrr = (real *) pr->_what; - if (pr->_fmt.len () == 2 && *_picture) - { - strcpy (__tmp_string, rrr->string (_picture)); - } - else - { - char *fff = (char *) ((const char *) pr->_fmt); - dsprintf (__tmp_string, fff, - // (DEC*)*((real*)(pr->_what))); - ((real *) pr->_what)->ptr ()); - } - ps = __tmp_string; - if (rrr->is_zero () && !_print_zero) - ps.fill (' '); - break; - } - } - - ps = fill_str (ps, _fillchar); - ((TPrintrow *) (&rw[pr->row ()]))-> - put (ps, pos[pr->row ()]); - if (pos[pr->row ()] != -1) - pos[pr->row ()] += ps.len (); - } - } - } - - // print! - for (i = 0; i <= _maxrow; i++) - { - TPrintrow *pr = (TPrintrow *) & rw[i]; - if (!(printer().print (*pr))) - break; - } - if (_auto_ff && _maxrow < printer().formlen ()) - printer().formfeed (); - delete pos; - - // TRUE if all rows have been printed - // if stopped by preprocess_page returns ok - return i == _maxrow + 1; -} - -bool TPrint_application::menu(MENU_TAG m) -{ - // funziona da se' fino a 20 voci della menubar - if (m >= BAR_ITEM (1) && m <= BAR_ITEM (20)) - { - _last_choice = m; - do_print((m - BAR_ITEM (0)) / 100); - } - - // Se non esistono altre voci di menu termina l'applicazione - return xvt_test_menu_tag (BAR_ITEM (2)); -} - -bool TPrint_application::create () -{ - TApplication ::create (); - printer().setfooterhandler (_pp_footer); - printer().setheaderhandler (_pp_header); - printer().setlinkhandler (_pp_link); - user_create (); - dispatch_e_menu (_last_choice); - return TRUE; -} - -bool TPrint_application::destroy () -{ - user_destroy (); - TApplication::destroy (); - return TRUE; -} - -void TPrint_application::do_print (int n) -{ - while (set_print (n)) - { - do { print(); } while (_repeat_print); - enable_print_menu (); - } -} - -void TPrint_application::enable_print_menu () -{ - enable_menu_item (M_FILE_PRINT, TRUE); -} - -void TPrint_application::disable_print_menu () -{ - enable_menu_item (M_FILE_PRINT, FALSE); -} - -void TPrint_application::enable_setprint_menu () -{ - enable_menu_item (BAR_ITEM (1), TRUE); -} - -void TPrint_application::disable_setprint_menu () -{ - enable_menu_item (BAR_ITEM (1), FALSE); -} - -TPrint_application::TPrint_application ():TApplication (), _transtab (10), - _cursors (10), _header (10), - _footer (10), _rows (100) -{ - _cur = NULL; - _repeat_print = FALSE; - _currow = _maxrow = 0; - _auto_ff = FALSE; - _wbar = _wcancel = TRUE; - _wmess = "Stampa in corso\nPrego attendere"; - _wthr = 5; - _confpr = "printer.ini"; - _fillchar = ' '; - _pr_tree = NULL; - _print_defined = FALSE; - _force_progind = FALSE; - _force_setpage = FALSE; - _prind = NULL; - _cur_file = 0; - _picture = ""; - _print_zero = FALSE; - _last_choice = BAR_ITEM (1); -} - -TPrint_application::~TPrint_application () -{ - reset_files (); -} +// $Id: printapp.cpp,v 1.11 1994-09-21 11:16:25 guy Exp $ +#include +#include + +#include + +#include +#include +#include +#include +#include + +TLocalisamfile *fff; + +const char *printf_types = "dDiIuUoOxXfeEgGcCnNsSpPrRtT"; + +// _FieldTok flags + +const word LONG_FLAG = 0x0001; +const word PICTURE_FLAG = 0x0002; +const word PAD_FLAG = 0x0004; +const word ALIGN_FLAG = 0x0008; +const word TRANS_FLAG = 0x0010; +const word DATE_FLAG = 0x0020; +const word STRING_FLAG = 0x0040; +const word NUMBER_FLAG = 0x0080; +const word DEC_FLAG = 0x0100; +const word FONT_FLAG = 0x0200; +const word JUMP_FLAG = 0x0400; +const word RECNO_FLAG = 0x0800; +const word BOOLEAN_FLAG = 0x1000; +const word IGNORE_FILL = 0x2000; + +// ============================================================= +// print token containers +// ============================================================= + +class _Transfield:public TObject +{ + friend class TPrint_application; + TString _from, // "from" value + _to, // "to" value + _fn; // field name + + int _lognum; // logical number + + public: + _Transfield (int l, const char *fn, const char *from, const char *to): + _from (3), _to (20), _fn (10) + { + _lognum = l; + _from = from; + _to = to; + _fn = fn; + } +}; + +class _Token:public TObject +{ + friend class TPrint_application; + int _tag; + int _row; +public: + int tag () + { + return _tag; + } + int row () + { + return _row; + } + void tag (int t) + { + _tag = t; + } + void row (int r) + { + _row = r; + } + virtual ~ _Token () {} +}; + +class _PrintfTok : public _Token +// something to be printed (actually already printed on _val) +{ + friend class TPrint_application; + TString _val; + public: + _PrintfTok (int rw, const char *val):_val (0) + { + tag (0); + row (rw); + _val = val; + } + virtual ~ _PrintfTok () {} +}; + +class _FieldTok : public _Token +// something more complex to be printed +{ + friend class TPrint_application; + int _size, _dec; + char _align; + TString _fld; // field description + + word _flags; // all you need to know + + public: + _FieldTok (int rw, char *fld, word flags, char align = 'l', + int size = -1, int dec = -1): + _fld (20) + { + tag (1); + row (rw); + _fld = (const char *) fld; + _flags = flags; + _size = size, _align = align; + _dec = dec; + delete fld; + } + virtual ~ _FieldTok () + { + } +}; + +class _PrintfRef : public _Token +// to be printed by reference via format +// must pass valid pointer to object +{ + friend class TPrint_application; + void *_what; + char _type; + TString _fmt; + public: + _PrintfRef (int rw, const char *fmt, char type, void *what):_fmt (1) + { + tag (2); + row (rw); + _type = type; + _what = what; + _fmt = fmt; + _fmt[0] = '%'; + } + virtual ~ _PrintfRef () + { + } +}; + +void TPrint_application::_reset_tree(link_item * head) +{ + if (head) + { + if (head->_brother) + _reset_tree (head->_brother); + if (head->_son) + _reset_tree (head->_son); + delete head; + } +} + +link_item *TPrint_application::_look_print_node (link_item * head, int logicnum) +{ + // look for node to attach to + // since it reflects a relation, it won't have more than + // one node for the same file/alias, so it stops at first match + link_item *s; + while (head) + { + if (head->_logicnum == logicnum) + return head; + else if (head->_son) + if ((s = _look_print_node (head->_son, logicnum)) != NULL) + return s; + head = head->_brother; + } + return NULL; +} + +void TPrint_application::add_file (const char *tab, int from) +{ + add_file (TTable ::name2log (tab), from); +} + +void TPrint_application::add_file (int file, int from) +{ + link_item *nw = new link_item (file); + if (_pr_tree == NULL) + { + _pr_tree = nw; + return; + } + + if (from == 0) + from = _pr_tree->_logicnum; + + link_item *fr = _look_print_node (_pr_tree, from); + + CHECKD (fr, "add_file: nonexistent node: logicnum = ", from); + + if (fr->_son) + { + fr = fr->_son; + while (fr->_brother) + fr = fr->_brother; + fr->_brother = nw; + } + else + fr->_son = nw; +} + +// --------------------------------------------------------------- +// ------------ user function ------------------------------------ + +static char tb[120]; + +int TPrint_application::find_link(const char* descr) const +{ + const TArray& arr = main_app().printer().links(); + for (int i = 0; i < arr.items(); i++) + { + TToken_string& tt = (TToken_string&)arr[i]; + const TFixed_string d(tt.get(0)); + if (d == descr) + return i; + } + return -1; +} + +int TPrint_application::enable_link(const char *descr, char fg, char bg) +{ + int lnk = find_link(descr); + if (lnk < 0) + { + TToken_string *tt = new TToken_string(30); + char b[2] = { '\0', '\0' }; + tt->add(descr); + b[0] = fg; + tt->add(b); + b[0] = bg; + tt->add(b); + lnk = printer().links().add(tt); + } + + return lnk; +} + +void TPrint_application::disable_link (char fg, char bg) +{ + for (int i = 0; i < printer().links().items (); i++) + { + TToken_string & t = (TToken_string&)printer().links()[i]; + const char f = *(t.get(1)); + const char b = *(t.get()); + if (f == fg && b == bg) + { + printer().links().remove(i, TRUE); + break; + } + } +} + +void TPrint_application::set_multiple_link (bool on) +{ + printer().setmultiplelink (on); +} + +void TPrint_application::_pp_link (int id, const char *text) +{ + TPrint_application& prapp = (TPrint_application&)main_app(); + prapp.process_link(id, text); +} + +void TPrint_application::_pp_header (TPrinter &) +{ + TPrint_application& prapp = (TPrint_application&)main_app(); + prapp.preprocess_header(); + prapp.printer().resetheader(); + const int ii = prapp._header.last(); + // reset and add header/footer lines + for (int i = 0; i <= ii; i++) + if (prapp._header.objptr(i) != NULL) + prapp.printer().setheaderline (i, new TPrintrow((TPrintrow &)prapp._header[i])); +} + +void TPrint_application::_pp_footer (TPrinter &) +{ + TPrint_application& prapp = (TPrint_application&)main_app(); + + prapp.preprocess_footer (); + prapp.printer().resetfooter (); + int ii = prapp._footer.last(); + for (int i = 0; i <= ii; i++) + if (prapp._footer.objptr(i) != NULL) + prapp.printer().setfooterline (i, + new TPrintrow ((TPrintrow &) (prapp._footer)[i])); +} + +void TPrint_application::set_background (const char *bgdesc) +{ + printer().setbackground (bgdesc); +} + +const char* FLD (int lognum, const char *f, int from, int to) +{ + sprintf (tb, "%c|%d|%s|%d|%d", 'n', lognum, f, from, to); + char *p = new char[strlen (tb) + 1]; + strcpy (p, tb); + return p; +} + +const char* FLD (int lognum, const char *f, const char *picture) +{ + sprintf (tb, "%c|%d|%s|%s", 'p', lognum, f, picture); + char *p = new char[strlen (tb) + 1]; + strcpy (p, tb); + return p; +} + +const char* FLD (const char *tabname, const char *f, int from, int to) +{ + CHECKS (strlen (tabname) < 5, "Invalid table name", tabname); + int lognum = TTable ::name2log (tabname); + sprintf (tb, "%c|%d|%s|%d|%d", 'n', lognum, f, from, to); + char *p = new char[strlen (tb) + 1]; + strcpy (p, tb); + return p; +} + +const char* FLD (const char *tabname, const char *f, const char *picture) +{ + CHECKS (strlen (tabname) < 5, "Invalid table name", tabname); + int lognum = TTable ::name2log (tabname); + sprintf (tb, "%c|%d|%s|%s", 'p', lognum, f, picture); + char *p = new char[strlen (tb) + 1]; + strcpy (p, tb); + return p; +} + +TString& fill_str (TString & t, char f) +{ + for (int kk = t.len () - 1; kk >= 0; kk--) + { + if (t[kk] == ' ') + t[kk] = f; + else + break; + } + for (kk = 0; kk < t.len (); kk++) + { + if (t[kk] == ' ') + t[kk] = f; + else + break; + } + return t; +} + +// ======================================================== +// Printapp code at last +// ======================================================== + +//void TPrint_application::enable_link(const char* descr, char fg, char bg) +// { +// printer().setlinkdescr(descr); +// } + +void TPrint_application::select_cursor (int c) +{ + if (c == -1) + _cur = NULL; + else + _cur = (TCursor *) & _cursors[c]; +} + +TCursor* TPrint_application::get_cursor (int c) +{ + if (c == -1) + return NULL; + else + return (TCursor *) & _cursors[c]; +} + +int TPrint_application::add_cursor (TCursor * c) +{ + if (c == NULL) + return -1; + _cursors.add (c); + _cur = c; + return _cursors.items () - 1; +} + +void TPrint_application::reset_row (int r) +{ + r--; + int tmp = _rows.items (); + for (int j = 0; j < tmp; j++) + { + _Token *t = (_Token *) (_rows.objptr (j)); + if (t) + { + if (t->row () == r) + _rows.add (NULL, j); + } + } + _rows.pack (); + if (_maxrow == r && _maxrow > 0) + _maxrow--; +} + +void TPrint_application::reset_print () +{ + _rows.destroy (); + _maxrow = 0; + _print_defined = FALSE; +} + +void TPrint_application::set_header (int r, const char *fmt,...) +{ + CHECK (r >= 1, "Header rows start at 1"); + va_list vl; + va_start (vl, fmt); + vsprintf (__tmp_string, fmt, vl); + va_end (vl); + + TPrintrow *pp = (TPrintrow *) _header.objptr (r - 1); + if (!pp) + { + pp = new TPrintrow; + _header.add (pp, r - 1); + } + pp->put (__tmp_string); +} + +void TPrint_application::set_footer (int r, const char *fmt,...) +{ + CHECK (r >= 1, "Footer rows start at 1"); + va_list vl; + va_start (vl, fmt); + vsprintf (__tmp_string, fmt, vl); + va_end (vl); + TPrintrow *pp = (TPrintrow *) _footer.objptr (r - 1); + if (pp == NULL) + { + pp = new TPrintrow; + _footer.add (pp, r - 1); + } + pp->put (__tmp_string); +} + +void TPrint_application::reset_header () +{ + _header.destroy (); + printer().resetheader (); +} + +void TPrint_application::reset_footer () +{ + _footer.destroy (); + printer().resetfooter (); +} + +void TPrint_application::fill_page (int from) +{ + from--; + for (int i = (from == -1 ? _maxrow : from); i <= printer().formlen (); i++) + { + reset_row (i); + set_row (i, ""); + } +} + +void TPrint_application::set_row (int r, const char *frmt,...) +{ + CHECK (r >= 1, "Print rows start at 1"); + + r--; + + char digbuf[10]; + char strbuf[120]; + char fftt[120]; + char *fmt = fftt; + char fill = _fillchar; + + word flags = 0; + int size = 0, dec = 0, strind = 0; + char ch, align = 'l'; + + // let the poor programmer use format() at will + strcpy (fmt, frmt); + _print_defined = TRUE; + + _currow = r; + if (_currow > _maxrow) + _maxrow = _currow; + + va_list params; + va_start (params, frmt); + + // parse format string + while ((ch = *fmt++) != '\0') + { + if (ch == '@') + { + // check for pending string + if (strind) + { + strbuf[strind] = '\0'; + _rows.add (new _PrintfTok (_currow, strbuf)); + strind = 0; + } + ch = *fmt++; + if (isdigit (ch)) + { + int i = 0; + digbuf[i++] = ch; + while (isdigit (ch = *fmt++)) + digbuf[i++] = ch; + digbuf[i] = '\0'; + size = atoi (digbuf); + flags |= PAD_FLAG; + if (ch == '.') + { + // decimal size follows + i = 0; + digbuf[i++] = ch; + while (isdigit (ch = *fmt++)) + digbuf[i] = ch; + digbuf[i] = '\0'; + dec = atoi (digbuf); + flags |= DEC_FLAG; + // ch = *fmt++; + } + else if (ch == ',') + { + // aligment spec follows + align = (ch = *fmt++); + CHECK (ch == 'l' || ch == 'r' || ch == 'c', + "TPrint_application::set_row: invalid alignment spec"); + flags |= ALIGN_FLAG; + ch = *fmt++; + } + } + switch (ch) + { + // modifiers + case 'l': + case 'L': + flags |= LONG_FLAG; + ch = *fmt++; + break; + case 'p': + case 'P': + flags |= PICTURE_FLAG; + ch = *fmt++; + break; + } + switch (ch) + { + // codes + case '@': + _rows.add (new _PrintfTok (_currow, "@")); + break; + case 'b': + case 'i': + case 'u': + case 'r': + { + char *xxxx = new char[2]; + xxxx[0] = ch; + xxxx[1] = '\0'; + _rows.add (new _FieldTok (_currow, xxxx, FONT_FLAG)); + } + break; + case 'g': + case 'j': + { + const char *xxx = format ("%c %d", ch, size); + char *xxxx = new char[strlen (xxx) + 1]; + strcpy (xxxx, xxx); + _rows.add (new _FieldTok (_currow, xxxx, JUMP_FLAG)); + } + break; + case 'T': + flags |= IGNORE_FILL; + case 't': + flags |= TRANS_FLAG; + break; + case 'D': + flags |= IGNORE_FILL; + case 'd': + flags |= DATE_FLAG; + break; + case 'F': + flags |= IGNORE_FILL; + case 'f': + flags |= BOOLEAN_FLAG; + break; + case 'S': + flags |= IGNORE_FILL; + case 's': + flags |= STRING_FLAG; + break; + case 'C': + flags |= IGNORE_FILL; + case 'c': + flags |= RECNO_FLAG; + break; + case 'N': + flags |= IGNORE_FILL; + case 'n': + flags |= NUMBER_FLAG; + break; + default: + CHECK (0, "TPrint_application::set_row: invalid @ code"); + break; + } + if (flags & NUMBER_FLAG || + flags & DATE_FLAG || + flags & TRANS_FLAG || + flags & BOOLEAN_FLAG || + flags & STRING_FLAG) + { + char *xxx = va_arg (params, char *); + _rows.add (new _FieldTok (_currow, xxx, + flags, align, size, dec)); + } + flags = 0x0000; + align = 'l'; + } + else + { + TString t; + switch (ch) + { + case '#': + case '%': + { + char ccc = ch; + // check for pending string + if (strind) + { + strbuf[strind] = '\0'; + _rows.add (new _PrintfTok (_currow, strbuf)); + strind = 0; + } + if ((ch = *fmt++) == ccc) + _rows.add (new _PrintfTok (_currow, ccc == '%' ? "%" : "#")); + else + { + // read format + t << ccc; + bool islong = FALSE; + while (strchr (printf_types, ch) == NULL) + { + t << ch; + if (ch == 'l') + islong = TRUE; + ch = *fmt++; + if (ch == '\0') + fatal_box ("sorry, zer's samzing vruong" + " uitz ioar format."); + } + if (isupper (ch)) + { + ch = tolower (ch); + fill = ' '; + } + if (ch == 't') + t << 's'; + else if (ch == 'r') + t << 't'; + else + t << ch; + if (ccc == '%') + { + TString q (60); + switch (ch) + { + case 'd': + case 'i': + case 'u': + case 'o': + case 'x': + case 'X': + q.format (t, islong ? va_arg (params, long) : + va_arg (params, int)); + break; + case 'f': + case 'e': + case 'E': + case 'G': + q.format (t, islong ? va_arg (params, double) : + va_arg (params, float)); + break; + case 'c': + q.format (t, va_arg (params, char)); + break; + case 's': + q.format (t, va_arg (params, char *)); + break; + case 't': // TString + + q.format (t, (const char *) + (TString) * ((va_arg (params, TString *)))); + break; + case 'r': // Real + + { + real *rrr = va_arg (params, real *); + if (t.len () == 2 && *_picture) + { + // no format specifications + // use default picture + q = rrr->string (_picture); + } + else + { + char *fff = (char *) ((const char *) t); + // dsprintf(__tmp_string, fff, + // (DEC*)(*rrr)); + dsprintf (__tmp_string, fff, rrr->ptr ()); + q = __tmp_string; + } + if (rrr->is_zero () && !_print_zero) + q.fill (' '); + } + break; + default: + break; + } + if (fill != ' ') + q = fill_str (q, fill); + fill = _fillchar; + _rows.add (new _PrintfTok (_currow, q)); + } + else + _rows.add (new _PrintfRef (_currow, t, ch, + va_arg (params, void *))); + } + } + break; + case '\n': // ignore + + break; + default: + // add to string + strbuf[strind++] = ch; + if (!ch) + fmt--; + break; + } + } + } + if (strind) + { + strbuf[strind] = '\0'; + _rows.add (new _PrintfTok (_currow, strbuf)); + strind = 0; + } + va_end (params); +} + +void TPrint_application::set_translation (int lognum, const char *field, + const char *from, const char *to) +{ + _transtab.add (new _Transfield (lognum, field, from, to)); +} + +void TPrint_application::print() +{ + // open printer if needed + if (!(printer().isopen ())) + if (!printer().open ()) + return; + + // only external apps can change it + _repeat_print = FALSE; + int ncopies = printer().n_copies(); + + // never print multiple copies if printer is viswin + // only application may repeat printing by setting _repeat_print + int nc = printer().printtype() == screenvis ? 1 : ncopies; + + // NULL cursor passed only prints once + // pre and post process do everything + + if (_cur == NULL) + { + //************************************************ + while (nc--) + { + + int cnt = 0; + bool ok = TRUE; + do + { + if (preprocess_print (0, cnt)) + { + int cnt2 = 0; + do + { + if (preprocess_page (0, cnt2)) + { + set_page (0, cnt2); + ok = print_one (0); + } + } + while (ok && postprocess_page (0, cnt2++) == REPEAT_PAGE); + } + } + while (ok && postprocess_print (0, cnt++) == REPEAT_PAGE); + // ***************************************************** + } + } + else + { + // cursor exists ********************************************* + while (nc--) + { + (*_cur) = 0l; + _cur->freeze (TRUE); + + if (_cur->items () >= _wthr && + (_force_progind || printer ().printtype () != screenvis)) + _prind = new TProgind (_cur->items (), + (char *) (const char *) _wmess, + _wcancel, _wbar, 35); + print_tree (_pr_tree); + _cur->freeze (FALSE); + + if (_prind) + { + delete _prind;; + _prind = NULL; + } + } + // **************************************************************** + } + if (printer().isopen ()) + { + printer().close(); + printer().resetheader(); + printer().resetfooter(); + } + postclose_print (); +} + +bool TPrint_application::print_tree (link_item * head) +{ + bool go = TRUE; + while (head) + { + head->_cnt = 0; + if (_cur->is_first_match (head->_logicnum)) + { + do + { + if (!preprocess_print (head->_logicnum, head->_cnt)) + break; + do + { + // set print rows according to current file + if (_force_setpage || _cur_file != head->_logicnum + || !_print_defined) + { + reset_print (); + set_page(head->_logicnum, head->_cnt); + _cur_file = head->_logicnum; + } + int cnt2 = 0; + do + { + if (!preprocess_page (head->_logicnum, cnt2)) + break; + go = print_one (head->_logicnum); + if (go && head->_son) + go = print_tree (head->_son); + } + while (go && postprocess_page (head->_logicnum, cnt2++) == + REPEAT_PAGE); + } + while (go && _cur->next_match (head->_logicnum)); + } + while (go && postprocess_print (head->_logicnum, head->_cnt++) + == REPEAT_PAGE); + } + if (!go) + break; + go = TRUE; + head = head->_brother; + } + return go; +} + +bool TPrint_application::print_one (int file) +{ + int i = 0; + + if ((_prind && _prind->iscancelled ()) || printer ().frozen ()) + return FALSE; + + if (!_print_defined) + return TRUE; + + if (_prind && file == _pr_tree->_logicnum) + _prind->addstatus (1); + + TArray rw (_maxrow + 1); + int *pos = new int[_maxrow + 1]; + + for (i = 0; i <= _maxrow; i++) + { + rw.add (new TPrintrow ()); + pos[i] = -1; + } + + // printing workhorse + for (i = 0; i <= _maxrow; i++) + for (int j = 0; j < _rows.items (); j++) + { + _Token *t = (_Token *) & (_rows[j]); + if (!t) + continue; // should not happen + + if (t->row () == i) + { + char pic[36], fn[17]; + int ch, ln, from, to; + + if (t->tag () == 1) + { + // it's a _FieldTok + _FieldTok *ft = (_FieldTok *) t; + TString toprint; + from = to = -1; + + if (ft->_flags & FONT_FLAG) + { + TPrintstyle st = normalstyle; + switch (((const char *) (ft->_fld))[0]) + { + case 'u': + st = underlinedstyle; + break; + case 'b': + st = boldstyle; + break; + case 'i': + st = italicstyle; + break; + case 'r': + st = normalstyle; + break; + } + ((TPrintrow *) (&rw[ft->row ()]))->set_style (st); + } + else if (ft->_flags & JUMP_FLAG) + { + char ch; + int p; + + ch = ft->_fld[0]; + p = atoi (((const char *) ft->_fld) + 2); + if (ch == 'g') + // go to + pos[ft->row ()] = p; + else + // jump ahead + pos[ft->row ()] = + ((TPrintrow *) (&rw[ft->row ()]))-> + lastpos () + p; + } + else + { + if ((*(const char *) (ft->_fld)) == 'p') + { + // picture + TToken_string ttt (ft->_fld, '|'); + ch = (ttt.get ())[0]; + ln = atoi ((const char *) ttt.get ()); + strcpy (fn, (const char *) ttt.get ()); + strcpy (pic, (const char *) ttt.get ()); + } + else + { + TToken_string ttt (ft->_fld, '|'); + ch = (ttt.get ())[0]; + ln = atoi ((const char *) ttt.get ()); + strcpy (fn, (const char *) ttt.get ()); + from = atoi ((const char *) ttt.get ()); + to = atoi ((const char *) ttt.get ()); + } + // get field val + TLocalisamfile &f = _cur->file(ln); + if (ft->_flags & TRANS_FLAG) + { + _Transfield *tr = NULL; + // look up field value in translation table + for (int i = 0; i < _transtab.items (); i++) + { + tr = (_Transfield *) & _transtab[i]; + if (tr->_fn == fn && tr->_lognum == ln) + { + // check value + if (tr->_from == f.get (fn)) + break; + } + } + if (i == _transtab.items ()) + toprint = ""; + else + toprint = tr->_to; + } + else if (ft->_flags & DATE_FLAG) + { + const TDate d(f.get(fn)); + toprint = d.string (ft->_flags & LONG_FLAG ? 4 : 2); + if (toprint.empty ()) + { + toprint = (ft->_flags & LONG_FLAG ? + " - - " : + " - - "); + } + } + else if (ft->_flags & BOOLEAN_FLAG) + { + toprint = f.get(fn) == "X" ? "Si" : "No"; + } + else if (ft->_flags & NUMBER_FLAG) + { + TString pict (0); + real r(f.get (fn)); + + bool isreal = f.curr ().type (fn) == _realfld; + + if (ft->_flags & PICTURE_FLAG) + pict = pic; + else if (!(ft->_flags & DEC_FLAG) && *_picture + && isreal) + pict = _picture; + + if (pict.len () > 0) + toprint = r.string (pict); + else if (ft->_flags & DEC_FLAG) + toprint = r.string (ft->_size, ft->_dec); + else + toprint = r.string (); + + if (r.is_zero () && !_print_zero) + toprint.fill (' '); + } + else if (ft->_flags & STRING_FLAG) + { + toprint = f.curr().get (fn); + // perform string extraction + if (from != -1) + toprint = toprint.sub (from, to); + else if (to != -1) + toprint = toprint.left (to); + } + } + // adjust size and set fill char + if (ft->_flags & PAD_FLAG) + { + if (!(ft->_flags & NUMBER_FLAG)) + { + if (ft->_size < toprint.len ()) + toprint.cut (ft->_size); + else + toprint.left_just (ft->_size); + } + if (ft->_flags & ALIGN_FLAG) + { + if (ft->_align == 'r') + toprint.right_just (toprint.len ()); + else if (ft->_align == 'c') + toprint.center_just (toprint.len ()); + else if (ft->_align == 'l') + toprint.left_just (toprint.len ()); + } + } + if (_fillchar != ' ' && !(ft->_flags & IGNORE_FILL)) + toprint = fill_str (toprint, _fillchar); + // add to print row + ((TPrintrow *) (&rw[ft->row ()]))->put (toprint, + pos[ft->row ()]); + if (pos[ft->row ()] != -1) + pos[ft->row ()] += toprint.len (); + } + + else if (t->tag () == 0) + { + // it's a _PrintfTok + _PrintfTok *pt = (_PrintfTok *) t; + TString v = pt->_val; + ((TPrintrow *) (&rw[pt->row ()]))->put (v, pos[pt->row ()]); + if (pos[pt->row ()] != -1) + { + pos[pt->row ()] += v.len (); + const char * s = v; + while (*s && strncmp(s, "$[", 2) == 0) + { + while (*s && *s != ']') + { + pos[pt->row()]--; + s++; + } + if (*s) + pos[pt->row()]--; + while (*s && *s != '$') s++; + } + } + } + else + if (t->tag () == 2) + { + // printf by reference + _PrintfRef *pr = (_PrintfRef *) t; + TString ps; + bool islong = (pr->_fmt).find ('l') != -1; + switch (pr->_type) + { + case 'd': + case 'i': + case 'u': + case 'o': + case 'x': + case 'X': + ps.format (pr->_fmt, islong ? *((long *) (pr->_what)) : + *((int *) (pr->_what))); + break; + case 'f': + case 'e': + ps.format (pr->_fmt, islong ? *((double *) (pr->_what)) : + *((float *) (pr->_what))); + break; + case 'c': + ps.format (pr->_fmt, *((char *) (pr->_what))); + break; + case 's': + ps.format (pr->_fmt, (char *) (pr->_what)); + break; + case 't': + ps.format (pr->_fmt, (const char *) + (*((TString *) (pr->_what)))); + break; + case 'r': + { + real *rrr = (real *) pr->_what; + if (pr->_fmt.len () == 2 && *_picture) + { + strcpy (__tmp_string, rrr->string (_picture)); + } + else + { + char *fff = (char *) ((const char *) pr->_fmt); + dsprintf (__tmp_string, fff, + // (DEC*)*((real*)(pr->_what))); + ((real *) pr->_what)->ptr ()); + } + ps = __tmp_string; + if (rrr->is_zero () && !_print_zero) + ps.fill (' '); + break; + } + } + + ps = fill_str (ps, _fillchar); + ((TPrintrow *) (&rw[pr->row ()]))-> + put (ps, pos[pr->row ()]); + if (pos[pr->row ()] != -1) + pos[pr->row ()] += ps.len (); + } + } + } + + // print! + for (i = 0; i <= _maxrow; i++) + { + TPrintrow *pr = (TPrintrow *) & rw[i]; + if (!(printer().print (*pr))) + break; + } + if (_auto_ff && _maxrow < printer().formlen ()) + printer().formfeed (); + delete pos; + + // TRUE if all rows have been printed + // if stopped by preprocess_page returns ok + return i == _maxrow + 1; +} + +bool TPrint_application::menu(MENU_TAG m) +{ + // funziona da se' fino a 20 voci della menubar + if (m >= BAR_ITEM (1) && m <= BAR_ITEM (20)) + { + _last_choice = m; + do_print((m - BAR_ITEM (0)) / 100); + } + + // Se non esistono altre voci di menu termina l'applicazione + return xvt_test_menu_tag (BAR_ITEM (2)); +} + +bool TPrint_application::create () +{ + TApplication ::create (); + printer().setfooterhandler (_pp_footer); + printer().setheaderhandler (_pp_header); + printer().setlinkhandler (_pp_link); + user_create (); + dispatch_e_menu (_last_choice); + return TRUE; +} + +bool TPrint_application::destroy () +{ + user_destroy (); + TApplication::destroy (); + return TRUE; +} + +void TPrint_application::do_print (int n) +{ + while (set_print (n)) + { + do { print(); } while (_repeat_print); + enable_print_menu (); + } +} + +void TPrint_application::enable_print_menu () +{ + enable_menu_item (M_FILE_PRINT, TRUE); +} + +void TPrint_application::disable_print_menu () +{ + enable_menu_item (M_FILE_PRINT, FALSE); +} + +void TPrint_application::enable_setprint_menu () +{ + enable_menu_item (BAR_ITEM (1), TRUE); +} + +void TPrint_application::disable_setprint_menu () +{ + enable_menu_item (BAR_ITEM (1), FALSE); +} + +TPrint_application::TPrint_application ():TApplication (), _transtab (10), + _cursors (10), _header (10), + _footer (10), _rows (100) +{ + _cur = NULL; + _repeat_print = FALSE; + _currow = _maxrow = 0; + _auto_ff = FALSE; + _wbar = _wcancel = TRUE; + _wmess = "Stampa in corso\nPrego attendere"; + _wthr = 5; + _confpr = "printer.ini"; + _fillchar = ' '; + _pr_tree = NULL; + _print_defined = FALSE; + _force_progind = FALSE; + _force_setpage = FALSE; + _prind = NULL; + _cur_file = 0; + _picture = ""; + _print_zero = FALSE; + _last_choice = BAR_ITEM (1); +} + +TPrint_application::~TPrint_application () +{ + reset_files (); +} diff --git a/include/printapp.h b/include/printapp.h index d0233c2d9..f7a5c2b02 100755 --- a/include/printapp.h +++ b/include/printapp.h @@ -1,471 +1,471 @@ -// trattasi di -*-c++-*- -#ifndef __PRINTAPP_H -#define __PRINTAPP_H - -#ifndef __APPLICATION_H -#include -#endif - -#ifndef __PRINTER_H -#include -#endif - -#ifndef __RELATION_H -#include -#endif - -// compatibility -#define TPrintapp TPrint_application - - -enum print_action { REPEAT_PAGE, NEXT_PAGE }; - -// user functions to pass field informations to setrow() -// no class or nice C++ interface since varargs is nasty - -// FLD(Num.logico, Nome campo [, da [, a]]) -const char* FLD(int lognum, const char* f, int from = -1, int to = -1); -// FLD(Num. logico, Nome campo numerico, Picture string) -const char* FLD(int lognum, const char* f, const char* picture); -// FLD(Nome tabella, Nome campo numerico, Picture string) -const char* FLD(const char* tabname, const char* f, const char* picture); -// FLD(Num.logico, Nome campo [, da [, a]]) -const char* FLD(const char* tabname, const char* f, int from = -1, int to = -1); - -struct link_item { - int _logicnum; - link_item* _son; - link_item* _brother; - int _cnt; - - link_item(int l) - { _logicnum = l; _son = NULL; _brother = NULL; _cnt = 0; } -}; - -class TProgind; - - -class TPrint_application : public TApplication -{ - TArray _rows; // rows descriptor - TArray _cursors; // cursor array - TCursor* _cur; // current cursor - TArray _transtab; // field translation table - TArray _header; // header lines - TArray _footer; // footer lines - int _currow; // current print row - TPrintstyle _curstyle; // current print style - bool _auto_ff; // automatic form feed after each page - const char* _wmess; // wait message for progind - bool _wbar; // bar y/n for progind - bool _wcancel; // cancel button enabled - int _wthr; // minimum # of items to show print progind - const char* _confpr; // config filename for printer - char _fillchar; // fill character for empty fields - link_item* _pr_tree; // functions for autom. printing of relations - int _maxrow; // reference to maxrow - int _cur_file; - bool _print_defined; - bool _force_progind; - bool _force_setpage; - bool _print_zero; - TProgind* _prind; - const char* _picture; - MENU_TAG _last_choice; - int _ncopies; - bool _repeat_print; - - // set the printer - void set_printer() { printer().set(); } - // print a single record; does not advance cursor - // returns failure or success - bool print_one(int file); - // to be documented but very fig - bool print_tree(link_item* head); - - static void _pp_header(TPrinter& pr); - static void _pp_footer(TPrinter& pr); - static void _pp_link(int id, const char* s); - - link_item* _look_print_node(link_item* head, int logicnum); - void _reset_tree(link_item* head); - virtual bool create(); - virtual bool destroy(); - - -protected: - - // **************************************************** - // ISTRUZIONI PER l'USO - // **************************************************** - // - // La Printapp, saggiamente, consente di operare su uno - // o piu' cursori stampando automaticamente anche files - // collegati. La sequenza delle operazioni e' la seguente: - // - // 1) Derivare una classe da TPrint_application - // 2) Implementare user_create() e user_destroy(); - // Nella user_create() si creino i - // necessari cursori, e li si dia in pasto a Printapp - // usando add_cursor(). Si puo' fare add_cursor(new TCursor(...)) - // dato che il cursore viene distrutto automaticamente. - // 3) Per ciascun file del cursore che si desidera porre - // nell'albero di stampa, si faccia add_file(logicnum [,from]); - // [from] sara' il file a cui e' collegato nella relazione. - // add_file VA FATTA anche per il file principale, se no - // non stampera' nulla; - // ********************************************************* - // FUNZIONI VIRTUALI OBBLIGATORIE - // ********************************************************* - // 4) Si definiscono le necessarie funzioni virtuali: e' - // sicuramente necessaria la set_page(file) nella quale - // si metteranno (sotto if o switch) le istruzioni - // set_row (vedi sotto) corrispondenti alla pagina - // logica relativa a ciascun record di ogni file da stampare. - // Va definita anche set_print() in cui si presentera' ;a - // maschera di scelta se necessaria o una box yes_no; - // Ritornando TRUE da set_print la stampa viene eseguita - // automaticamente (in genere ritorna FALSE se l'utente - // annulla la stampa con ESC.) - // - // Alla set_page, come alle pre_ e post_ process, viene - // passato 0 se il cursore attuale e' nullo (vedi sotto). - // ********************************************************* - // FUNZIONI VIRTUALI FACOLTATIVE - // ********************************************************* - // 5) Le varie funzioni pre_ e post_ process _page e _print - // vengono chiamate prima e dopo la stampa di ogni record - // o gruppo di record relativo alla relazione immessa; - // ad esempio, postprocess_print() viene chiamata per il - // file principale una volta dopo l'intera stampa; per - // un file collegato nella relazione, e' chiamata tante - // volte quanti gruppi di almeno un record esistono per - // record del file genitore. Qui si possono modificare - // righe, calcolare totali etc. A queste funzioni - // viene sempre passato il file (logicnum) in corso di stampa e - // un contatore che indica quante volte la stampa e' stata - // ripetuta. le pre_ ritornano TRUE o FALSE, nell'ultimo - // caso interrompono la stampa; le post_ ritornano - // NEXT_PAGE (comportamento normale) o REPEAT_PAGE - // (indovina cosa fa). - // 6) set_print() viene chiamata dalla voce Selezione, - // unica del secondo menu. E' il posto dove mettere - // una buona maschera di selezione di cosa stampare. - // Alla fine, si esegua enable_print_menu() per - // abilitare la voce Stampa, inizialmente inattiva. - // 7) cancel_hook() permette di intercettare la - // cancellazione della stampa; ritornando TRUE - // la stampa viene effettivamente cancellata - // Tutti i parametri relativi al progress indicator - // vengono settati da funzioni apposite (vedi oltre) - // **************************************************** - // Molte altre minchiatine (form feed automatici, header, - // footer etc) sono spiegate nel seguito - // **************************************************** - - virtual void user_create() {} - virtual void user_destroy() {} - - // set print, bound to menu :Selezione:Stampa - // chiamata automaticamente dopo user_create() - virtual bool set_print(int i = 1) { return FALSE; } - - // set_row functions MUST be called here in a switch - // for each particular file being printed - virtual void set_page(int file, int cnt) {} - - // called before processing each page - // used to set print strings from tables or files - // not included in relation - // returning FALSE cancels page printing - // counter is the current print page number - virtual bool preprocess_page(int file, int counter) - { return TRUE; } - - // same before each print request - // e.g. to initialize counters - // returning FALSE cancels print request or subtree - virtual bool preprocess_print(int file, int counter) - { return TRUE; } - - // postprocessing; returning REPEAT_PAGE reprints the - // whole page (after all sons are printed) or print - // counter is the current page or print number - virtual print_action postprocess_page(int file, int counter) - { return NEXT_PAGE; } - virtual print_action postprocess_print(int file, int counter) - { return NEXT_PAGE; } - // executed after all print job is completed - virtual void postclose_print() {} - - // called when LINK button is pressed with active selection in - // preview window - virtual void process_link(int id, const char* text) {} - - - // called when user cancels print; returning TRUE - // actually stops printing; not called if no cancel - virtual bool cancel_hook() {return TRUE;} - - // bound to TApplication print menu - // redefined ONLY for very special purposes - virtual void print(); - - // bound to menu and automatically called after + // user_create() + void do_print(int n); + +public: + + // -------------------------------------------------------------- + // COME SETTARE LE RIGHE DI STAMPA + // -------------------------------------------------------------- + // setrow() si usa come una printf per settare le righe di stampa + // che vengono stampate da print() + // I codici per gli argomenti variabili sono di 3 tipi: + // @ si usa per stampare campi di database o informazioni di controllo + // posizione carrello e font + // ACHTUNG: i codici di formato sono diversi da quelli di printf e + // sono elencati sotto. Per i campi di database occorre che il codice + // sia accoppiato ad una delle funzioni FLD() passata come argomento; + // questa provoca la stampa di campi della relazione corrente, + // posizionata come e' stato deciso nell'inizializzazione + // % si usa esattamente come in una printf con un plus: se il codice di + // formato e' maiuscolo (es. S per stringa, D per intero) viene + // ignorato il carattere di riempimento eventualmente specificato + // con set_fillchar. Cio' vale anche per i codici @ (vedi) + // E' possibile usare due codici aggiuntivi: r(R) e t(T). A questi + // va fatto seguire un PUNTATORE a real o a TString. Il formato + // viene interpretato con le stesse regole di %t in dsprintf per real + // (come %d o %f) e di %s per TString. Il puntatore NON + // viene memorizzato; per questo occorre il codice # (sotto). + // # si usa come % (stessi codici di printf) ma memorizza gli argomenti + // per riferimento: ovvero, ogni volta che la riga viene stampata + // viene stampato il contenuto in quel momento (che si puo' cambiare + // in una delle pre- o post- process). Cio' implica che: + // 1) gli argomenti vanno passati per RIFERIMENTO (set_row(1,"#5d",&i)) + // 2) i puntatori devono rimanere validi e costanti tra la set_row e + // la fine della stampa + // Quindi, attenzione a %s con TString ridimensionate; si possono + // usare solo se predimensionate alla dimensione massima, ma e' meglio + // usare char* o il codice apposito. I codici #r e #t prendono puntatori a + // real e a TString, memorizzandoli. Non ci sono problemi con la resize. + // Comunque, il modo corretto di adoperare il codice # e' + // usarlo solo per stampare MEMBRI della classe derivata da TPrint_application + // ---------------------------------------------- + // field codes (match one of FLD() functions) + // @@ -> @ + // @[n[,{l|c|r}]s -> STRING: n = pad, lcr = alignment + // @{[n[.d=0]]|[n[,{l|c|r}]]p}n + // -> NUMBER: n = digits, d = decimals + // p = picture string (first matching arg) + // @[l]d -> DATE: l = full year + // @f -> BOOL: prints si/no + // @[n,{l|c|r}]t -> Translated field (must set translation) + // + // Tutti questi codici possono essere usati anche maiuscoli, il che inibisce + // l'uso del carattere di riempimento (set_fillchar) per uno specifico campo. + // --------------------------------------------- + // Per tutti i codici che riguardano la stampa di real (@n, %r, #r) + // se non vengono date ulteriori specifiche di formato viene usata + // una picture che e' "" per default, ma puo' essere modificata con + // set_real_picture(). Anche questo e' assai carino. + // Normalmente un real uguale a zero viene stampato come stringa vuota + // a meno che non si specifichi set_print_zero([TRUE]). + // --------------------------------------------- + // codici posizionamento e movimento carrello + // @g vai a posizione n + // @j salta di n posizioni (in orizzontale) + // codici stile + // @b bold + // @i italic + // @u underlined + // @r reset to normal + // --------------------------------------------------- + // CODICI COLORE PER VISUALIZZAZIONE E COLLEGAMENTO + // --------------------------------------------------- + // Se si vuole che in visualizzazione il testo sia colorato + // si usa il codice $[]; tra le quadre si scrive il colore + // di foreground, opzionalmente seguito da una virgola e dal + // colore di background (bianco per default). I colori si + // specificano con un singolo carattere come segue: + // n nero + // g verde + // b blu + // c cyan + // y giallo + // v magenta + // m colore background maschere (azzurrotto) + // d grigio scuro + // l grigio chiaro + // k grigio normale + // ------------------------------------------------------ + // Se si fa enable_link(..) con un certo colore, tutto + // cio; che e' scritto in quel colore diventa selezionabile + // e alla sua selezione (premendo 'Collega') si puo' associare + // un'azione in process_link. A quest'ultima viene passata + // l'ID ritornata da enable_link() e il testo selezionato alla + // pressione di Collega. Vedere ba6 e stampare l'elenco (con + // Includi ditte abilitato) per un esempio. + // -------------------------------------------------------- + + void reset_row(int r); + + // chiamare reset_print() durante la stampa forza la + // rilettura di set_page() alla prossima volta + void reset_print(); + + void set_row(int r, const char* fmt, ...); + + // --------------------------------------------- + // set translation values for field + // called once for each translation: example + // set_translation(12,"STATOCIV","1","Celibe") + // provoca la stampa automatica di stringhe al + // posto di determinati valori dei campi se e' dato + // il codice @t + // Il posto giusto per chiamarla: user_create() + // --------------------------------------------- + void set_translation(int lognum, const char* field, + const char* from, const char* to); + + + // -------------------------------------------------------- + // hypertext interface for viswin + // -------------------------------------------------------- + // Quando si vogliono abilitare determinati colori come + // indicatori di legame ipertestuale, si faccia enable_link + // nella create. L' ID ritornato viene passato a process_link + // assieme al testo selezionato + int find_link(const char* descr) const; + int enable_link (const char* descr, char fg, char bg = 'w'); + void disable_link(char fg, char bg = 'w'); + void disable_links() { printer().links().destroy(); } + // se si setta multiple a TRUE anziche' la descrizione del testo selezionato + // viene passata a enable_link una tokenstring con tutti i 'bottoni' dello + // stesso colore presenti sulla riga + void set_multiple_link(bool on); + + // BACKGROUND PAINTING! Chefigata! poi vi spiego.... + void set_background(const char* bgdesc = NULL); + + + // --------------------------------------------- + // set/select cursor + // --------------------------------------------- + // selects i-th cursor + // inutile se c'e' un cursore solo + void select_cursor(int i); + + // return i-th cursor without making it current + TCursor* get_cursor(int i); + // returns maximum row defined + int get_maxrow() { return _maxrow; } + + // adds cursor to class; return identifier + // cursor* can be NULL: no file is used but + // print_one is called and iterations are performed + // by pre_ and post_ process + int add_cursor(TCursor* c); + + // retrieve current cursor + TCursor* current_cursor() { return _cur; } + + // --------------------------------------------- + // set_auto_ff(TRUE) fa si' che dopo ogni pagina logica (relativa ad + // un record) si stampi un form feed. (anche se il cursore e' nullo) + void set_auto_ff( bool b = TRUE) + { _auto_ff = b; } + + // il carattere specificato con set_fillchar (default ' ') viene + // usato per riempire davanti e dietro i campi in cui si e' specificata + // una dimensione maggiore della lunghezza effettiva del contenuto, + // (a meno che non si sia usato un codice di formato maiuscolo) + void set_fillchar(char c) + { _fillchar = c; } + + // riempie di righe vuote la pagina corrente fino alla dimensione + // della pagina + void fill_page(int from = -1); + + // di solito basta e avanza quella di default + virtual bool menu(MENU_TAG m); + + virtual word class_id() const { return CLASS_PRINT_APPLICATION; } + + // print menu is enabled when set_print returns TRUE + void enable_print_menu(); + void disable_print_menu(); + void enable_setprint_menu(); + void disable_setprint_menu(); + + // header/footer (printf, not set_row analogues) + // only understand @-codes for setting font attributes, + // date and page number + // plus every printf %-code + + // con queste si possono ridefinire header e footer al + // verificarsi di condizioni durante la stampa + virtual void preprocess_header() {} + virtual void preprocess_footer() {} + + void set_header(int row, const char* fmt, ...); + void set_footer(int row, const char* fmt, ...); + void reset_header(); + void reset_footer(); + + // vedi sopra per capire + void reset_files() { _reset_tree(_pr_tree); _pr_tree = NULL; } + void add_file(int file, int from = 0); + void add_file(const char* tab, int from = 0); + + // set default picture for reals + void set_real_picture(const char* p) { _picture = p; } + void set_print_zero(bool b = TRUE) { _print_zero = b; } + + // progress indicator control + void set_wait_message(const char* m) + { _wmess = m; } + void set_wait_bar(bool m) + // default yes + { _wbar = m; } + void set_wait_cancel(bool m) + // default yes + { _wcancel = m; } + void set_wait_threshold(int m) + // minimum number of print items to show progress indicator; + // default 2 + { _wthr = m; } + + // questa forza la progind anche se si stampa su video + void force_progind(bool b = TRUE) + { _force_progind = b; } + + // questa forza la rilettura delle setrow in set_page ad ogni + // record stampato, in modo che i dati siano + // sempre quelli del record corrente anche se si usano codici % + // s'intende che rallenta un po' la stampa + void force_setpage(bool b = TRUE) + { _force_setpage = b; } + + void set_config_file(const char* s) + { _confpr = s; } + word get_page_number() + { return printer().getcurrentpage(); } + void set_page_number(word n) + { printer().setcurrentpage(n); } + + + void set_n_copies(int n) { _ncopies = n; } + int get_n_copies() { return _ncopies; } + void repeat_print() { _repeat_print = TRUE; } + + TPrint_application(); + virtual ~TPrint_application(); +}; + +// buon divertimento + + +#endif + diff --git a/include/relapp.cpp b/include/relapp.cpp index 4b97929ae..aa7c41996 100755 --- a/include/relapp.cpp +++ b/include/relapp.cpp @@ -1,869 +1,869 @@ -// $Id: relapp.cpp,v 1.9 1994-09-15 16:45:33 guy Exp $ -#include -#include -#include -#include -#include -#include - -#if XVT_OS == XVT_OS_WIN -extern "C" { -#include -} -#endif - -/////////////////////////////////////////////////////////// -// Array delle chiavi della maschera di ricerca -/////////////////////////////////////////////////////////// - -class TChiave : public TObject -{ - enum { MAX = 16 }; - int _pos[MAX]; - byte _num; - -public: - void add(int p); - int pos(byte n) const { return (n >= _num) ? -1 : _pos[n]; } - byte items() const { return _num; } - TChiave() : _num(0) {} - virtual ~TChiave() {} -}; - -void TChiave::add(int p) -{ - CHECKD(_num < MAX, "Too many fields in key : field n.", p); - _pos[_num++] = p; -} - -class TKey_array : public TArray -{ - const TMask* _mask; - -public: - TKey_array(const TMask* m); - virtual ~TKey_array() {} - - TChiave& key(byte k); -}; - -TChiave& TKey_array::key(byte k) -{ - k--; - TChiave* chiave = (TChiave*)objptr(k); - if (chiave == NULL) - { - chiave = new TChiave; - add(chiave, k); - } - return *chiave; -} - -TKey_array::TKey_array(const TMask* m) : _mask(m) -{ - const byte keys = m->num_keys(); - for (int f = 0; f < m->fields(); f++) - { - TMask_field& c = m->fld(f); - if (c.in_key(0)) - for (byte k = 1; k <= keys; k++) - if (c.in_key(k)) - key(k).add(f); - } -} - -/////////////////////////////////////////////////////////// -// TRelation_application -/////////////////////////////////////////////////////////// - -TRelation_application::TRelation_application() -: _mask(NULL), _maskeys(NULL), _search_id(-1), _lnflag(FALSE) -{} - -TRelation_application::~TRelation_application() -{ - if (_maskeys) delete _maskeys; -} - -void TRelation_application::setkey() -{ - if (has_filtered_cursor()) - { - TEdit_field* f = (TEdit_field*) get_search_field(); - TCursor* cur = f->browse()->cursor(); - cur->setkey(); - return; - } - file().setkey(1); -} - - -// what - meaning -// 0 - nop -// 1 - first -// 2 - last -// 3 - both -void TRelation_application::set_limits(byte what) -{ - if (has_filtered_cursor()) - { - TEdit_field* f = (TEdit_field*) get_search_field(); - - CHECK(f, "Manca il campo di ricerca"); - TCursor* cur = f->browse()->cursor(); - if (cur) - { - cur->setkey(); - f->browse()->do_input(TRUE); - if (cur->items() == 0) _first = _last = -1; - else - { - if (what & 0x1) - { - *cur = 0; - _first = cur->file()->recno(); - } - if (what & 0x2) - { - *cur = cur->items() - 1; - _last = cur->file()->recno(); - } - } - return; - } - } - file().setkey(1); - if (what & 0x1) - { - if (file().empty()) _first = 1; - else - { - file().first(); - _first = file().recno(); - } - } - - if (what & 0x2) - { - if (file().empty()) _last = 1; - else - { - file().last(); - _last = file().recno(); - } - } -} - -bool TRelation_application::create() -{ - TApplication::create(); - const bool ok = user_create(); - if (ok) - { - write_enable(); - _mask = get_mask(MODE_QUERY); - filter(); - _maskeys = new TKey_array(_mask); - set_limits(); - dispatch_e_menu(BAR_ITEM(1)); - } - return ok; -} - - -bool TRelation_application::menu(MENU_TAG m) -{ - if (m == BAR_ITEM(1)) - return main_loop(); - return TRUE; -} - - -bool TRelation_application::destroy() -{ - user_destroy(); - return TApplication::destroy(); -} - - -void TRelation_application::set_fixed() -{ - TString s(16); - for (const char* f = _fixed.get(0); f && *f; f = _fixed.get()) - { - s = f; - const int u = s.find('='); - const int id = atoi(s.left(u)); - _mask->disable(id); - const char* val = s.mid(u+1); - if (*val) - _mask->set(id, val); - } -} - - -void TRelation_application::enable_query() -{ - const bool query = _mask->mode() == MODE_QUERY; - const byte numkeys = _maskeys->items(); - - for (byte k = 1; k <= numkeys; k++) - { - const TChiave& chiave = _maskeys->key(k); - for (int i = 0; i < chiave.items(); i++) - { - const int num = chiave.pos(i); - TMask_field& c = _mask->fld(num); - const bool has_query = c.has_query(); - if (k == 1) - { - // THIS should have been fixed - // if (!query && has_query) c.check(STARTING_CHECK); - c.enable(query); - } - if (has_query) - ((TEdit_field&)c).enable_check(query); - } - } - - set_fixed(); -} - - -void TRelation_application::set_toolbar(bool all) -{ - const int mode = _mask->mode(); - int pos; - - if (all) - { - pos = _mask->id2pos(DLG_SAVEREC); - if (pos >= 0) _mask->fld(pos).enable(mode != MODE_QUERY); - pos = _mask->id2pos(DLG_DELREC); - if (pos >= 0) - { - bool enabdel = mode == MODE_MOD; - if (enabdel) - { - TRelation& r = *get_relation(); - const TRecnotype oldpos = r.lfile()->recno(); - enabdel = !protected_record(r.curr()); - if (r.lfile()->recno() != oldpos) - r.lfile()->readat(oldpos); - } - _mask->fld(pos).enable(enabdel); - } - /* - const bool full = !file().empty() && _first != -1; - pos = _mask->id2pos(DLG_FIRSTREC); - if (pos >= 0) _mask->fld(pos).enable(full); - pos = _mask->id2pos(DLG_LASTREC); - if (pos >= 0) _mask->fld(pos).enable(full); - pos = _mask->id2pos(DLG_STOPREC); - if (pos >= 0) _mask->fld(pos).enable(full); - */ - } - - enable_query(); - - /* - const TRecnotype rpos = file().recno(); - pos = _mask->id2pos(DLG_PREVREC); - if (pos >= 0) _mask->fld(pos).enable(mod && rpos != _first); - pos = _mask->id2pos(DLG_NEXTREC); - if (pos >= 0) _mask->fld(pos).enable(mod && rpos != _last); - */ -} - - -int TRelation_application::set_mode(int mode) -{ - static int _mode = NO_MODE; - if (mode < NO_MODE) mode = _mode; - - const int m = ((TMaskmode)mode == NO_MODE) ? (int) MODE_QUERY : mode; - _mask->set_mode(m); - - if (mode == _mode) - { - set_toolbar(FALSE); // Fast buttons update - } - else - { - set_toolbar(TRUE); // Full buttons update - _mode = mode; - } - - const char* t = ""; - switch(mode) - { - case MODE_QUERY : t = "Ricerca"; break; - case MODE_MOD : t = "Modifica"; break; - case NO_MODE : t = "Ricerca/Inserimento"; break; - case MODE_INS : t = "Inserimento"; break; - default : break; - } - - xvt_statbar_set(t); - - return _mode; -} - - -bool TRelation_application::autonum(TMask* m, bool rec) -{ - TToken_string k(get_next_key()); - - for (const char* n = k.get(0); n && *n; n = k.get()) - { - const short id = atoi(n); - if (id < 1) break; - const char* val = k.get(); - TMask_field& f = m->field(id); - if (rec || f.get().empty()) f.set(val); - if (rec) f.autosave(get_relation()); - } - return k.not_empty(); -} - - -void TRelation_application::query_mode(bool pre_ins) -{ - TMask* old = _mask; - const bool changing = changing_mask(MODE_QUERY) || old == NULL; - - if (changing && old) - old->close_modal(); - - _mask = get_mask(MODE_QUERY); - if (changing) - { - if (old) _mask->open_modal(); - if (_maskeys) delete _maskeys; - _maskeys = new TKey_array(_mask); - set_limits(); - } - - _mask->reset(); - - if (pre_ins) - { - set_mode(NO_MODE); - autonum(_mask, FALSE); - init_query_insert_mode(*_mask); - } - else - { - set_mode(MODE_QUERY); - init_query_mode(*_mask); - } -} - - -void TRelation_application::insert_mode() -{ - if (test_key(1, FALSE) == FALSE) - { - if (!autonum(_mask, FALSE)) - { - query_insert_mode(); - return; - } - } - - const bool changing = changing_mask(MODE_INS); - - TFilename workname; workname.temp("rim.$$"); - - if (changing) - { - _mask->set_workfile(workname); - _mask->save(); - _mask->close_modal(); - } - _mask = get_mask(MODE_INS); - if (changing) - { - _mask->reset(); - _mask->set_workfile(workname); - _mask->load(); - ::remove(workname); - _mask->open_modal(); - delete _maskeys; - _maskeys = new TKey_array(_mask); - } - - set_mode(MODE_INS); - init_insert_mode(*_mask); -} - -bool TRelation_application::modify_mode() -{ - int err = get_relation()->read(_isequal, _testandlock); - if (err != NOERR) - { - if (err == _islocked) - message_box("I dati sono gia' in uso ad un altro utente"); - else - error_box("Impossibile leggere i dati: errore %d", err); - query_mode(); - return FALSE; - } - - const bool changing = changing_mask(MODE_MOD); - - if (changing) - { - _mask->close_modal(); - } - - _mask = get_mask(MODE_MOD); - set_mode(MODE_MOD); - - err = read(*_mask); - - if (changing) - _mask->open_modal(); - - if (err != NOERR) - { - error_box("Errore di caricamento dati nella maschera %d", err); - query_mode(); - return FALSE; - } - - get_relation()->save_status(); - init_modify_mode(*_mask); - return TRUE; -} - - -TMask_field* TRelation_application::get_search_field() const -{ - if (_search_id > 0) return &_mask->field(_search_id); - const TChiave& k = _maskeys->key(1); - for (int i = 0; i < k.items(); i++) - { - TMask_field* f = &_mask->fld(k.pos(i)); - if (f->required()) return f; - } - return NULL; -} - -bool TRelation_application::search_mode() -{ - if (_mask->mode() != MODE_QUERY) - query_mode(); - - TMask_field* f = get_search_field(); - if (f) - if (f->on_key(K_F9)) - if (find(1)) - return modify_mode(); - - return FALSE; -} - - -bool TRelation_application::test_key(byte k, bool err) -{ - const TChiave& chiave = _maskeys->key(k); - bool onereq = FALSE, onefill = FALSE; - - for (int i = 0; i < chiave.items(); i++) - { - const int num = chiave.pos(i); - TMask_field& c = _mask->fld(num); - if (c.required()) - { - onereq = TRUE; - if (c.get().empty()) - { - if (err) - { - _mask->first_focus(-c.dlg()); - error_box("Manca un valore indispensabile per la ricerca"); - } - return FALSE; - } - } - else - if (k == 1 && !onereq && !onefill && c.get().not_empty()) - onefill = TRUE; - } - if (k == 1 && !onereq && !onefill) - { - if (err) - error_box("Manca un valore indispensabile per la ricerca"); - return FALSE; - } - return TRUE; -} - -// Guy: doesn't change fields -bool TRelation_application::find(byte k) -{ - const byte numkeys = _maskeys->items(); - - if (k == 0) - { - for (k = 1; k <= numkeys && !test_key(k, FALSE); k++); - if (k > numkeys) - return test_key(1, TRUE); - } - - file().setkey(k); - file().zero(); - const TChiave& chiave = _maskeys->key(k); - for (int i = 0; i < chiave.items(); i++) - { - const TMask_field& c = _mask->fld(chiave.pos(i)); - c.autosave(get_relation()); - } - - const int err = file().read(_isequal); - return err == NOERR; -} - - -bool TRelation_application::save(bool check_dirty) -{ - static bool was_dirty = FALSE; - - int err = NOERR; - const int mode = _mask->mode(); - - if (check_dirty) - { - const int dirty = _mask->dirty(); - if (mode == MODE_QUERY) - { - const bool cont = !dirty || yesno_box("Annullare i dati inseriti?"); - return cont; - } - - if (!dirty && !was_dirty) - { - if (mode == MODE_MOD) - { - get_relation()->restore_status(); - get_relation()->lfile()->reread(_unlock); // Unlock main file - } - return TRUE; - } - - const KEY k = yesnocancel_box(mode == MODE_MOD ? "Registrare le modifiche?" - : "Registrare i dati inseriti?"); - if (k == K_ESC) - { - was_dirty = TRUE; - return FALSE; - } - if (k == K_NO) - { - get_relation()->restore_status(); - get_relation()->lfile()->reread(_unlock); // Unlock main file - was_dirty = FALSE; - return TRUE; - } - if (_mask->last_key() == K_ESC || _mask->last_key() == K_QUIT) - { - _mask->get_mask_fields(); - if (!_mask->check_fields()) // Exit with ESC didn't check values - { - _mask->first_focus(-_mask->fld(_mask->focus_field()).dlg()); - was_dirty = TRUE; - return FALSE; - } - } - } - was_dirty = FALSE; - - if (mode == MODE_INS) - { - bool changed = TRUE; - while (changed) - { - err = write(*_mask); - if (err == _isreinsert) - changed = autonum(_mask, TRUE); - else - changed = FALSE; - } - if (err == NOERR) - { - get_relation()->save_status(); - set_limits(); - get_relation()->restore_status(); - } - } - else - err = rewrite(*_mask); - - switch(err) - { - case NOERR: - break; - case _isreinsert: - warning_box("Esiste gia' un documento con la stessa chiave"); - break; - default: - error_box("Impossibile registrare i dati: errore %d", err); - break; - } - return err == NOERR; -} - - -int TRelation_application::read(TMask& m) -{ - const TRelation *r = get_relation(); - m.autoload(r); - return NOERR; -} - - -int TRelation_application::write(const TMask& m) -{ - TRelation *r = get_relation(); - r->zero(); - m.autosave(r); - r->write(); - return r->status(); -} - - -int TRelation_application::rewrite(const TMask& m) -{ - TRelation *r = get_relation(); - r->zero(); - m.autosave(r); - r->rewrite(); - return r->status(); -} - - -bool TRelation_application::remove() -{ - CHECK(_mask->mode() == MODE_MOD, "You can call remove in MODE_MOD only"); - TRelation *r = get_relation(); - - r->restore_status(); - - if (protected_record(r->curr())) - return message_box("Registrazione non eliminabile"); - - if (yesno_box("Confermare l'eliminazione")) - { - r->restore_status(); - const int err = r->remove(); - if (err == NOERR) - set_limits(); - else - return error_box("Errore di cancellazione"); - } - return TRUE; -} - - -bool TRelation_application::main_loop() -{ - long recins = -1; - - query_mode(); - _mask->open_modal(); - - KEY k; - - // Provoca l'autopremimento per il messaggio di LINK - if (_lnflag) _mask->send_key(K_AUTO_ENTER, 0); - - do - { - // Seleziona il cursore a freccia - set_cursor(TASK_WIN, CURSOR_ARROW); - - // Dis/abilita cambio ditta - enable_menu_item(M_FILE_NEW, (_mask->mode() == MODE_QUERY)); - - - k = _mask->run(); - - // Seleziona il cursore a clessidra se necessario - if (k != K_QUIT && k != K_F9) set_cursor(TASK_WIN, CURSOR_WAIT); - - switch (k) - { - case K_ESC: - if (save(TRUE)) - query_mode(); - if (_lnflag) - k = K_QUIT; - break; - case K_QUIT: - if (save(TRUE)) - { - if (_mask->mode() == MODE_MOD && - (_autoins_caller.not_empty() || _lnflag)) - recins = file().recno(); - } - else k = K_ENTER; - break; - case K_ENTER: - if (find(0)) modify_mode(); - else insert_mode(); - break; - case K_SAVE: - if (save(FALSE)) - { - if (_autoins_caller.not_empty() || _lnflag) - { - recins = file().recno(); - k = K_QUIT; - } - else - modify_mode(); - } - break; - case K_INS: - if (_mask->mode() == MODE_QUERY) - insert_mode(); - else - if (save(TRUE)) - query_mode(TRUE); - break; - case K_DEL: - { - if (remove()) - query_mode(); - } - break; - case K_F9: - if (save(TRUE)); - search_mode(); - break; - default: - if (save(TRUE)) - { - setkey(); - int err = ~NOERR; - switch (k) - { - case K_HOME: - err = file().readat(_first, _testandlock); - break; - case K_NEXT: - err = file().reread(); - err = file().next(_testandlock); - break; - case K_PREV: - err = file().reread(); - err = file().prev(_testandlock); - break; - case K_END: - err = file().readat(_last, _testandlock); - break; - default: - break; - } - if (err == NOERR || err == _islocked) modify_mode(); - else query_mode(); - } - break; - } - } while (k != K_QUIT); - - if (_mask->is_open()) - _mask->close_modal(); - - _mask->set_mode(NO_MODE); - - if (recins > 0 && _autoins_caller.not_empty()) - { - TMessage msg(_autoins_caller, MSG_AI, format("%ld", recins)); - msg.send(); - } - if (recins > 0 && _lnflag) - { - TMessage msg(_autoins_caller, MSG_LN, format("%ld", recins)); - msg.send(); - } - - return k != K_QUIT; -} - - -bool TRelation_application::filter() -{ - TMailbox mail; - TMessage* msg = mail.next_s(MSG_FS); - - if (msg) - { - _mask = get_mask(MODE_MOD); - TToken_string body(msg->body()); - - short id = body.get_int(); - while (id > 0) - { - _search_id = id; - TEdit_field& f = (TEdit_field&)_mask->field(id); - TCursor* cur = f.browse()->cursor(); - TRectype& rec = cur->curr(); - rec.zero(); - - TString80 t; - const char* s; - while((s = body.get()) != NULL) - { - t = s; - const int u = t.find('='); - if (u < 0) - { - id = atoi(t); - break; - } - _fixed.add(t); - const short fid = atoi(t.left(u)); - const TFieldref* campo = _mask->field(fid).field(); - if (campo != NULL) - campo->write(t.mid(u+1), rec); - } - cur->setfilter(""); - cur->setregion(rec, rec); - if (s == NULL) id = 0; - } - } - - mail.restart(); - msg = mail.next_s(MSG_AI); - if (msg) _autoins_caller = msg->from(); - - mail.restart(); - msg = mail.next_s(MSG_LN); - if (msg) - { - TToken_string body(msg->body()); - const int key = body.get_int(); - const int max = _mask->fields(); - - _autoins_caller = msg->from(); - _lnflag = TRUE; - - const char* v = body.get(); - - for (int i = 0; i < max && v != NULL; i++) - { - TMask_field& f = _mask->fld(i); - - if (f.active() && f.dlg() > 0 && f.in_key(key)) - { - const TString s(v); - _fixed.add(format("%d=%s", f.dlg(), (const char*) s)); - v = body.get(); - } - } - } - - return TRUE; -} +// $Id: relapp.cpp,v 1.10 1994-09-21 11:16:28 guy Exp $ +#include +#include +#include +#include +#include +#include + +#if XVT_OS == XVT_OS_WIN +extern "C" { +#include +} +#endif + +/////////////////////////////////////////////////////////// +// Array delle chiavi della maschera di ricerca +/////////////////////////////////////////////////////////// + +class TChiave : public TObject +{ + enum { MAX = 16 }; + int _pos[MAX]; + byte _num; + +public: + void add(int p); + int pos(byte n) const { return (n >= _num) ? -1 : _pos[n]; } + byte items() const { return _num; } + TChiave() : _num(0) {} + virtual ~TChiave() {} +}; + +void TChiave::add(int p) +{ + CHECKD(_num < MAX, "Too many fields in key : field n.", p); + _pos[_num++] = p; +} + +class TKey_array : public TArray +{ + const TMask* _mask; + +public: + TKey_array(const TMask* m); + virtual ~TKey_array() {} + + TChiave& key(byte k); +}; + +TChiave& TKey_array::key(byte k) +{ + k--; + TChiave* chiave = (TChiave*)objptr(k); + if (chiave == NULL) + { + chiave = new TChiave; + add(chiave, k); + } + return *chiave; +} + +TKey_array::TKey_array(const TMask* m) : _mask(m) +{ + const byte keys = m->num_keys(); + for (int f = 0; f < m->fields(); f++) + { + TMask_field& c = m->fld(f); + if (c.in_key(0)) + for (byte k = 1; k <= keys; k++) + if (c.in_key(k)) + key(k).add(f); + } +} + +/////////////////////////////////////////////////////////// +// TRelation_application +/////////////////////////////////////////////////////////// + +TRelation_application::TRelation_application() +: _mask(NULL), _maskeys(NULL), _search_id(-1), _lnflag(FALSE) +{} + +TRelation_application::~TRelation_application() +{ + if (_maskeys) delete _maskeys; +} + +void TRelation_application::setkey() +{ + if (has_filtered_cursor()) + { + TEdit_field* f = (TEdit_field*) get_search_field(); + TCursor* cur = f->browse()->cursor(); + cur->setkey(); + return; + } + file().setkey(1); +} + + +// what - meaning +// 0 - nop +// 1 - first +// 2 - last +// 3 - both +void TRelation_application::set_limits(byte what) +{ + if (has_filtered_cursor()) + { + TEdit_field* f = (TEdit_field*) get_search_field(); + + CHECK(f, "Manca il campo di ricerca"); + TCursor* cur = f->browse()->cursor(); + if (cur) + { + cur->setkey(); + f->browse()->do_input(TRUE); + if (cur->items() == 0) _first = _last = -1; + else + { + if (what & 0x1) + { + *cur = 0; + _first = cur->file().recno(); + } + if (what & 0x2) + { + *cur = cur->items() - 1; + _last = cur->file().recno(); + } + } + return; + } + } + file().setkey(1); + if (what & 0x1) + { + if (file().empty()) _first = 1; + else + { + file().first(); + _first = file().recno(); + } + } + + if (what & 0x2) + { + if (file().empty()) _last = 1; + else + { + file().last(); + _last = file().recno(); + } + } +} + +bool TRelation_application::create() +{ + TApplication::create(); + const bool ok = user_create(); + if (ok) + { + write_enable(); + _mask = get_mask(MODE_QUERY); + filter(); + _maskeys = new TKey_array(_mask); + set_limits(); + dispatch_e_menu(BAR_ITEM(1)); + } + return ok; +} + + +bool TRelation_application::menu(MENU_TAG m) +{ + if (m == BAR_ITEM(1)) + return main_loop(); + return TRUE; +} + + +bool TRelation_application::destroy() +{ + user_destroy(); + return TApplication::destroy(); +} + + +void TRelation_application::set_fixed() +{ + TString s(16); + for (const char* f = _fixed.get(0); f && *f; f = _fixed.get()) + { + s = f; + const int u = s.find('='); + const int id = atoi(s.left(u)); + _mask->disable(id); + const char* val = s.mid(u+1); + if (*val) + _mask->set(id, val); + } +} + + +void TRelation_application::enable_query() +{ + const bool query = _mask->mode() == MODE_QUERY; + const byte numkeys = _maskeys->items(); + + for (byte k = 1; k <= numkeys; k++) + { + const TChiave& chiave = _maskeys->key(k); + for (int i = 0; i < chiave.items(); i++) + { + const int num = chiave.pos(i); + TMask_field& c = _mask->fld(num); + const bool has_query = c.has_query(); + if (k == 1) + { + // THIS should have been fixed + // if (!query && has_query) c.check(STARTING_CHECK); + c.enable(query); + } + if (has_query) + ((TEdit_field&)c).enable_check(query); + } + } + + set_fixed(); +} + + +void TRelation_application::set_toolbar(bool all) +{ + const int mode = _mask->mode(); + int pos; + + if (all) + { + pos = _mask->id2pos(DLG_SAVEREC); + if (pos >= 0) _mask->fld(pos).enable(mode != MODE_QUERY); + pos = _mask->id2pos(DLG_DELREC); + if (pos >= 0) + { + bool enabdel = mode == MODE_MOD; + if (enabdel) + { + TRelation& r = *get_relation(); + const TRecnotype oldpos = r.lfile().recno(); + enabdel = !protected_record(r.curr()); + if (r.lfile().recno() != oldpos) + r.lfile().readat(oldpos); + } + _mask->fld(pos).enable(enabdel); + } + /* + const bool full = !file().empty() && _first != -1; + pos = _mask->id2pos(DLG_FIRSTREC); + if (pos >= 0) _mask->fld(pos).enable(full); + pos = _mask->id2pos(DLG_LASTREC); + if (pos >= 0) _mask->fld(pos).enable(full); + pos = _mask->id2pos(DLG_STOPREC); + if (pos >= 0) _mask->fld(pos).enable(full); + */ + } + + enable_query(); + + /* + const TRecnotype rpos = file().recno(); + pos = _mask->id2pos(DLG_PREVREC); + if (pos >= 0) _mask->fld(pos).enable(mod && rpos != _first); + pos = _mask->id2pos(DLG_NEXTREC); + if (pos >= 0) _mask->fld(pos).enable(mod && rpos != _last); + */ +} + + +int TRelation_application::set_mode(int mode) +{ + static int _mode = NO_MODE; + if (mode < NO_MODE) mode = _mode; + + const int m = ((TMaskmode)mode == NO_MODE) ? (int) MODE_QUERY : mode; + _mask->set_mode(m); + + if (mode == _mode) + { + set_toolbar(FALSE); // Fast buttons update + } + else + { + set_toolbar(TRUE); // Full buttons update + _mode = mode; + } + + const char* t = ""; + switch(mode) + { + case MODE_QUERY : t = "Ricerca"; break; + case MODE_MOD : t = "Modifica"; break; + case NO_MODE : t = "Ricerca/Inserimento"; break; + case MODE_INS : t = "Inserimento"; break; + default : break; + } + + xvt_statbar_set(t); + + return _mode; +} + + +bool TRelation_application::autonum(TMask* m, bool rec) +{ + TToken_string k(get_next_key()); + + for (const char* n = k.get(0); n && *n; n = k.get()) + { + const short id = atoi(n); + if (id < 1) break; + const char* val = k.get(); + TMask_field& f = m->field(id); + if (rec || f.get().empty()) f.set(val); + if (rec) f.autosave(get_relation()); + } + return k.not_empty(); +} + + +void TRelation_application::query_mode(bool pre_ins) +{ + TMask* old = _mask; + const bool changing = changing_mask(MODE_QUERY) || old == NULL; + + if (changing && old) + old->close_modal(); + + _mask = get_mask(MODE_QUERY); + if (changing) + { + if (old) _mask->open_modal(); + if (_maskeys) delete _maskeys; + _maskeys = new TKey_array(_mask); + set_limits(); + } + + _mask->reset(); + + if (pre_ins) + { + set_mode(NO_MODE); + autonum(_mask, FALSE); + init_query_insert_mode(*_mask); + } + else + { + set_mode(MODE_QUERY); + init_query_mode(*_mask); + } +} + + +void TRelation_application::insert_mode() +{ + if (test_key(1, FALSE) == FALSE) + { + if (!autonum(_mask, FALSE)) + { + query_insert_mode(); + return; + } + } + + const bool changing = changing_mask(MODE_INS); + + TFilename workname; workname.temp("rim.$$"); + + if (changing) + { + _mask->set_workfile(workname); + _mask->save(); + _mask->close_modal(); + } + _mask = get_mask(MODE_INS); + if (changing) + { + _mask->reset(); + _mask->set_workfile(workname); + _mask->load(); + ::remove(workname); + _mask->open_modal(); + delete _maskeys; + _maskeys = new TKey_array(_mask); + } + + set_mode(MODE_INS); + init_insert_mode(*_mask); +} + +bool TRelation_application::modify_mode() +{ + int err = get_relation()->read(_isequal, _testandlock); + if (err != NOERR) + { + if (err == _islocked) + message_box("I dati sono gia' in uso ad un altro utente"); + else + error_box("Impossibile leggere i dati: errore %d", err); + query_mode(); + return FALSE; + } + + const bool changing = changing_mask(MODE_MOD); + + if (changing) + { + _mask->close_modal(); + } + + _mask = get_mask(MODE_MOD); + set_mode(MODE_MOD); + + err = read(*_mask); + + if (changing) + _mask->open_modal(); + + if (err != NOERR) + { + error_box("Errore di caricamento dati nella maschera %d", err); + query_mode(); + return FALSE; + } + + get_relation()->save_status(); + init_modify_mode(*_mask); + return TRUE; +} + + +TMask_field* TRelation_application::get_search_field() const +{ + if (_search_id > 0) return &_mask->field(_search_id); + const TChiave& k = _maskeys->key(1); + for (int i = 0; i < k.items(); i++) + { + TMask_field* f = &_mask->fld(k.pos(i)); + if (f->required()) return f; + } + return NULL; +} + +bool TRelation_application::search_mode() +{ + if (_mask->mode() != MODE_QUERY) + query_mode(); + + TMask_field* f = get_search_field(); + if (f) + if (f->on_key(K_F9)) + if (find(1)) + return modify_mode(); + + return FALSE; +} + + +bool TRelation_application::test_key(byte k, bool err) +{ + const TChiave& chiave = _maskeys->key(k); + bool onereq = FALSE, onefill = FALSE; + + for (int i = 0; i < chiave.items(); i++) + { + const int num = chiave.pos(i); + TMask_field& c = _mask->fld(num); + if (c.required()) + { + onereq = TRUE; + if (c.get().empty()) + { + if (err) + { + _mask->first_focus(-c.dlg()); + error_box("Manca un valore indispensabile per la ricerca"); + } + return FALSE; + } + } + else + if (k == 1 && !onereq && !onefill && c.get().not_empty()) + onefill = TRUE; + } + if (k == 1 && !onereq && !onefill) + { + if (err) + error_box("Manca un valore indispensabile per la ricerca"); + return FALSE; + } + return TRUE; +} + +// Guy: doesn't change fields +bool TRelation_application::find(byte k) +{ + const byte numkeys = _maskeys->items(); + + if (k == 0) + { + for (k = 1; k <= numkeys && !test_key(k, FALSE); k++); + if (k > numkeys) + return test_key(1, TRUE); + } + + file().setkey(k); + file().zero(); + const TChiave& chiave = _maskeys->key(k); + for (int i = 0; i < chiave.items(); i++) + { + const TMask_field& c = _mask->fld(chiave.pos(i)); + c.autosave(get_relation()); + } + + const int err = file().read(_isequal); + return err == NOERR; +} + + +bool TRelation_application::save(bool check_dirty) +{ + static bool was_dirty = FALSE; + + int err = NOERR; + const int mode = _mask->mode(); + + if (check_dirty) + { + const int dirty = _mask->dirty(); + if (mode == MODE_QUERY) + { + const bool cont = !dirty || yesno_box("Annullare i dati inseriti?"); + return cont; + } + + if (!dirty && !was_dirty) + { + if (mode == MODE_MOD) + { + get_relation()->restore_status(); + get_relation()->lfile().reread(_unlock); // Unlock main file + } + return TRUE; + } + + const KEY k = yesnocancel_box(mode == MODE_MOD ? "Registrare le modifiche?" + : "Registrare i dati inseriti?"); + if (k == K_ESC) + { + was_dirty = TRUE; + return FALSE; + } + if (k == K_NO) + { + get_relation()->restore_status(); + get_relation()->lfile().reread(_unlock); // Unlock main file + was_dirty = FALSE; + return TRUE; + } + if (_mask->last_key() == K_ESC || _mask->last_key() == K_QUIT) + { + _mask->get_mask_fields(); + if (!_mask->check_fields()) // Exit with ESC didn't check values + { + _mask->first_focus(-_mask->fld(_mask->focus_field()).dlg()); + was_dirty = TRUE; + return FALSE; + } + } + } + was_dirty = FALSE; + + if (mode == MODE_INS) + { + bool changed = TRUE; + while (changed) + { + err = write(*_mask); + if (err == _isreinsert) + changed = autonum(_mask, TRUE); + else + changed = FALSE; + } + if (err == NOERR) + { + get_relation()->save_status(); + set_limits(); + get_relation()->restore_status(); + } + } + else + err = rewrite(*_mask); + + switch(err) + { + case NOERR: + break; + case _isreinsert: + warning_box("Esiste gia' un documento con la stessa chiave"); + break; + default: + error_box("Impossibile registrare i dati: errore %d", err); + break; + } + return err == NOERR; +} + + +int TRelation_application::read(TMask& m) +{ + const TRelation *r = get_relation(); + m.autoload(r); + return NOERR; +} + + +int TRelation_application::write(const TMask& m) +{ + TRelation *r = get_relation(); + r->zero(); + m.autosave(r); + r->write(); + return r->status(); +} + + +int TRelation_application::rewrite(const TMask& m) +{ + TRelation *r = get_relation(); + r->zero(); + m.autosave(r); + r->rewrite(); + return r->status(); +} + + +bool TRelation_application::remove() +{ + CHECK(_mask->mode() == MODE_MOD, "You can call remove in MODE_MOD only"); + TRelation *r = get_relation(); + + r->restore_status(); + + if (protected_record(r->curr())) + return message_box("Registrazione non eliminabile"); + + if (yesno_box("Confermare l'eliminazione")) + { + r->restore_status(); + const int err = r->remove(); + if (err == NOERR) + set_limits(); + else + return error_box("Errore di cancellazione"); + } + return TRUE; +} + + +bool TRelation_application::main_loop() +{ + long recins = -1; + + query_mode(); + _mask->open_modal(); + + KEY k; + + // Provoca l'autopremimento per il messaggio di LINK + if (_lnflag) _mask->send_key(K_AUTO_ENTER, 0); + + do + { + // Seleziona il cursore a freccia + set_cursor(TASK_WIN, CURSOR_ARROW); + + // Dis/abilita cambio ditta + enable_menu_item(M_FILE_NEW, (_mask->mode() == MODE_QUERY)); + + + k = _mask->run(); + + // Seleziona il cursore a clessidra se necessario + if (k != K_QUIT && k != K_F9) set_cursor(TASK_WIN, CURSOR_WAIT); + + switch (k) + { + case K_ESC: + if (save(TRUE)) + query_mode(); + if (_lnflag) + k = K_QUIT; + break; + case K_QUIT: + if (save(TRUE)) + { + if (_mask->mode() == MODE_MOD && + (_autoins_caller.not_empty() || _lnflag)) + recins = file().recno(); + } + else k = K_ENTER; + break; + case K_ENTER: + if (find(0)) modify_mode(); + else insert_mode(); + break; + case K_SAVE: + if (save(FALSE)) + { + if (_autoins_caller.not_empty() || _lnflag) + { + recins = file().recno(); + k = K_QUIT; + } + else + modify_mode(); + } + break; + case K_INS: + if (_mask->mode() == MODE_QUERY) + insert_mode(); + else + if (save(TRUE)) + query_mode(TRUE); + break; + case K_DEL: + { + if (remove()) + query_mode(); + } + break; + case K_F9: + if (save(TRUE)); + search_mode(); + break; + default: + if (save(TRUE)) + { + setkey(); + int err = ~NOERR; + switch (k) + { + case K_HOME: + err = file().readat(_first, _testandlock); + break; + case K_NEXT: + err = file().reread(); + err = file().next(_testandlock); + break; + case K_PREV: + err = file().reread(); + err = file().prev(_testandlock); + break; + case K_END: + err = file().readat(_last, _testandlock); + break; + default: + break; + } + if (err == NOERR || err == _islocked) modify_mode(); + else query_mode(); + } + break; + } + } while (k != K_QUIT); + + if (_mask->is_open()) + _mask->close_modal(); + + _mask->set_mode(NO_MODE); + + if (recins > 0 && _autoins_caller.not_empty()) + { + TMessage msg(_autoins_caller, MSG_AI, format("%ld", recins)); + msg.send(); + } + if (recins > 0 && _lnflag) + { + TMessage msg(_autoins_caller, MSG_LN, format("%ld", recins)); + msg.send(); + } + + return k != K_QUIT; +} + + +bool TRelation_application::filter() +{ + TMailbox mail; + TMessage* msg = mail.next_s(MSG_FS); + + if (msg) + { + _mask = get_mask(MODE_MOD); + TToken_string body(msg->body()); + + short id = body.get_int(); + while (id > 0) + { + _search_id = id; + TEdit_field& f = (TEdit_field&)_mask->field(id); + TCursor* cur = f.browse()->cursor(); + TRectype& rec = cur->curr(); + rec.zero(); + + TString80 t; + const char* s; + while((s = body.get()) != NULL) + { + t = s; + const int u = t.find('='); + if (u < 0) + { + id = atoi(t); + break; + } + _fixed.add(t); + const short fid = atoi(t.left(u)); + const TFieldref* campo = _mask->field(fid).field(); + if (campo != NULL) + campo->write(t.mid(u+1), rec); + } + cur->setfilter(""); + cur->setregion(rec, rec); + if (s == NULL) id = 0; + } + } + + mail.restart(); + msg = mail.next_s(MSG_AI); + if (msg) _autoins_caller = msg->from(); + + mail.restart(); + msg = mail.next_s(MSG_LN); + if (msg) + { + TToken_string body(msg->body()); + const int key = body.get_int(); + const int max = _mask->fields(); + + _autoins_caller = msg->from(); + _lnflag = TRUE; + + const char* v = body.get(); + + for (int i = 0; i < max && v != NULL; i++) + { + TMask_field& f = _mask->fld(i); + + if (f.active() && f.dlg() > 0 && f.in_key(key)) + { + const TString s(v); + _fixed.add(format("%d=%s", f.dlg(), (const char*) s)); + v = body.get(); + } + } + } + + return TRUE; +} diff --git a/include/relapp.h b/include/relapp.h index d35441262..62e5c39de 100755 --- a/include/relapp.h +++ b/include/relapp.h @@ -1,94 +1,94 @@ -#ifndef __RELAPP_H -#define __RELAPP_H - -#ifndef __APPLICAT_H -#include -#endif - -#ifndef __RELATION_H -#include -#endif - - -#ifndef __MASK_H -#include -#endif - -class TKey_array; - -class TRelation_application : public TApplication -{ - TMask * _mask; - TKey_array* _maskeys; - long _first, _last; - int _search_id; - - TString _autoins_caller; - bool _lnflag; - TToken_string _fixed; - - virtual bool create(); - virtual bool destroy(); - - bool filter(); - bool test_key(byte k, bool err); - bool save(bool check_dirty); - void enable_query(); - void set_toolbar(bool all); - - int set_mode(int mode); // Seleziona il nuovo modo e ritorna il vecchio - void set_limits(byte what = 0x3); - void query_insert_mode() { query_mode(TRUE); } - void insert_mode(); // Entra in modo inserimento - virtual bool main_loop(); // Ciclo principale - TMask_field* get_search_field() const; - -protected: - TLocalisamfile& file() const { return *get_relation()->lfile(); } - void set_fixed(); // Fissa i campi non modificabili - bool search_mode(); // Attiva la maschera di ricerca - void query_mode(bool pre_ins = FALSE); // Entra in modo ricerca - bool modify_mode(); // Entra in modo modifica - void setkey(); - bool lnflag() const { return _lnflag;} - long first() const { return _first;} - long last() const { return _first;} - TMask& curr_mask() const { return *_mask; } - const TString& autoins_caller() const { return _autoins_caller;} - virtual bool menu(MENU_TAG m); - - virtual bool user_create() pure; - virtual bool user_destroy() pure; - virtual TMask* get_mask(int mode) pure; - virtual bool changing_mask(int mode) pure; - virtual TRelation* get_relation() const pure; - virtual int read(TMask& m); - virtual int write(const TMask& m); - virtual int rewrite(const TMask& m); - virtual bool remove(); - virtual const char* get_next_key() { return ""; } - virtual bool protected_record(TRectype&) { return FALSE; } - virtual void init_query_mode(TMask&) { } - virtual void init_query_insert_mode(TMask& m) { init_query_mode(m); } - virtual void init_insert_mode(TMask&) { } - virtual void init_modify_mode(TMask&) { } - virtual void write_enable(const bool on = TRUE) { get_relation()->write_enable(-1, on); } - void write_disable() { write_enable(FALSE); } - - bool autonum(TMask* m, bool rec); - void set_search_field(short id) { _search_id = id;} - bool has_filtered_cursor() const { return filtered() || force_cursor_usage();} - -public: - TRelation_application(); - virtual ~TRelation_application(); - bool filtered() const { return _fixed.not_empty(); } - void set_first(long first) { _first = first;} - void set_last(long last) { _last = last;} - bool find(byte key = 0); - virtual bool force_cursor_usage() const { return FALSE;} -}; - -#endif - - +#ifndef __RELAPP_H +#define __RELAPP_H + +#ifndef __APPLICAT_H +#include +#endif + +#ifndef __RELATION_H +#include +#endif + + +#ifndef __MASK_H +#include +#endif + +class TKey_array; + +class TRelation_application : public TApplication +{ + TMask * _mask; + TKey_array* _maskeys; + long _first, _last; + int _search_id; + + TString _autoins_caller; + bool _lnflag; + TToken_string _fixed; + + virtual bool create(); + virtual bool destroy(); + + bool filter(); + bool test_key(byte k, bool err); + bool save(bool check_dirty); + void enable_query(); + void set_toolbar(bool all); + + int set_mode(int mode); // Seleziona il nuovo modo e ritorna il vecchio + void set_limits(byte what = 0x3); + void query_insert_mode() { query_mode(TRUE); } + void insert_mode(); // Entra in modo inserimento + virtual bool main_loop(); // Ciclo principale + TMask_field* get_search_field() const; + +protected: + TLocalisamfile& file() const { return get_relation()->lfile(); } + void set_fixed(); // Fissa i campi non modificabili + bool search_mode(); // Attiva la maschera di ricerca + void query_mode(bool pre_ins = FALSE); // Entra in modo ricerca + bool modify_mode(); // Entra in modo modifica + void setkey(); + bool lnflag() const { return _lnflag;} + long first() const { return _first;} + long last() const { return _first;} + TMask& curr_mask() const { return *_mask; } + const TString& autoins_caller() const { return _autoins_caller;} + virtual bool menu(MENU_TAG m); + + virtual bool user_create() pure; + virtual bool user_destroy() pure; + virtual TMask* get_mask(int mode) pure; + virtual bool changing_mask(int mode) pure; + virtual TRelation* get_relation() const pure; + virtual int read(TMask& m); + virtual int write(const TMask& m); + virtual int rewrite(const TMask& m); + virtual bool remove(); + virtual const char* get_next_key() { return ""; } + virtual bool protected_record(TRectype&) { return FALSE; } + virtual void init_query_mode(TMask&) { } + virtual void init_query_insert_mode(TMask& m) { init_query_mode(m); } + virtual void init_insert_mode(TMask&) { } + virtual void init_modify_mode(TMask&) { } + virtual void write_enable(const bool on = TRUE) { get_relation()->write_enable(-1, on); } + void write_disable() { write_enable(FALSE); } + + bool autonum(TMask* m, bool rec); + void set_search_field(short id) { _search_id = id;} + bool has_filtered_cursor() const { return filtered() || force_cursor_usage();} + +public: + TRelation_application(); + virtual ~TRelation_application(); + bool filtered() const { return _fixed.not_empty(); } + void set_first(long first) { _first = first;} + void set_last(long last) { _last = last;} + bool find(byte key = 0); + virtual bool force_cursor_usage() const { return FALSE;} +}; + +#endif + + diff --git a/include/relation.cpp b/include/relation.cpp index 1c49c1158..5a4418b6a 100755 --- a/include/relation.cpp +++ b/include/relation.cpp @@ -1,1327 +1,1326 @@ -// $Id: relation.cpp,v 1.8 1994-09-20 12:24:54 guy Exp $ -// relation.cpp -// fv 12/8/93 -// relation class for isam files - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -// *** check if not already defined -#define NOTFOUND (-1) - -// *** maximum number of elements in a cursor working page -#define CMAXELPAGE 8000 - - -/////////////////////////////////////////////////////////// -// TRelationdef -/////////////////////////////////////////////////////////// - -class TRelationdef : public TObject -{ - // @DPRIV - friend class TRelation; - - const TRelation* _rel; // Relazione padre - int _num; // Posizione file - int _numto; // Posizione padre - byte _alias; // Alias - byte _key; // Chiave - TArray _fields; // Campi di join - TArray _exprs; // Condizioni di uguaglianza - TBit_array _forced; - bool _first_match; // primo match (ed esiste) - bool _allow_lock; // ????? - bool _write_enable; - -protected: - virtual void print_on(ostream& out) const; - -public: - // @FPUB - int num() const { return _num; } - int link() const { return _numto; } - byte alias() const { return _alias; } - bool& write_enable() { return _write_enable; } - TRectype& load_rec(TRectype& r, const TBaseisamfile* from) const; - - TRelationdef(const TRelation* rel, int file, byte key, - int linkto, const char* relexprs, byte alias, - bool allow_lock, bool write_enable = FALSE); - virtual ~TRelationdef() {} -}; -// @END - - -HIDDEN ostream& print_name(ostream& out, const TLocalisamfile* f) -{ - const int logicnum = f->num(); - if (logicnum == LF_TABCOM || logicnum == LF_TAB) - { - if (logicnum == LF_TABCOM) out << '%'; - out << ((TTable*)f)->name(); - } - else - out << logicnum; - return out; -} - - -TRelationdef::TRelationdef(const TRelation* rel, int idx_file, byte key, - int idx_to, const char* relexprs, byte alias, - bool allow_lock, bool write_enable) -: _num(idx_file), _key(key), _numto(idx_to), - _rel(rel), _fields(4), _exprs(4), _alias(alias), - _first_match(FALSE), _allow_lock(allow_lock), - _write_enable(write_enable) -{ - TToken_string rels(relexprs); - int i = 0; - TString80 r,s; - - for (const char* g = rels.get(); g; g = rels.get(), i++) - { - r = g; - int eq = r.find('='); - - CHECKS(eq > 0, "Ahoo! E l'uguale 'ndo sta'? ", (const char*)g); - - s = r.left(eq); // Parte a sinistra dell' = - -#ifdef DBG - TString80 n(s); - const int p = n.find('['); - if (p > 0) n.cut(p); - if (rel->file(_num)->curr().exist(n) == FALSE) - { - error_box("'%s' non e' un campo del file %d", - (const char*)n, rel->file(_num)->num()); - continue; - } -#endif - - if (r[eq+1] == '=') - { - _forced.set(i); - eq++; - } - - const TString80 xx(s); - _fields.add(new TFieldref(xx,0)); - - _exprs.add(new TExpression(r.mid(eq+1), _strexpr)); - } -} - - -void TRelationdef::print_on(ostream& out) const -{ - out << "JOIN "; print_name(out, _rel->file(_num)); - - if (_numto > 0) - { - out << " TO "; - const int alias = _rel->reldef(_numto-1)->alias(); - if (alias > 0) out << alias << '@'; - else print_name(out, _rel->file(_numto)); - } - - if (_key > 1) out << " KEY " << (int)_key; - - if (_alias > 0) out << " ALIAS " << (int)_alias; - - for (int i = 0; i < _fields.items(); i++) - { - if (i == 0) out << " INTO"; - out << ' ' << _fields[i] << '=' << _exprs[i]; - } -} - - - -/////////////////////////////////////////////////////////// -// TRelation -/////////////////////////////////////////////////////////// - -TRelation::TRelation(int logicnum, bool linkrecinst) -: _files(4) , _reldefs(4), _errors(NOERR) -{ - TLocalisamfile* f = new TLocalisamfile(logicnum, linkrecinst); - _files.add(f); -} - -TRelation::TRelation(const char* tabname, bool linkrecinst) -: _files(4) , _reldefs(4), _errors(NOERR) -{ - TTable* t = new TTable(tabname, linkrecinst); - _files.add(t); -} - -TRelation::~TRelation() -{} - -void TRelation::print_on(ostream& out) const -{ - const TLocalisamfile* f = file(); - - out << "USE "; print_name(out, f); - - const int k = f->getkey(); - if (k > 1) out << " KEY " << k; - out << endl; - - for (int r = 0; r < _reldefs.items(); r++) - out << _reldefs[r] << endl; -} - -void TRelation::restore_status() -{ - _status.restart(); - for (int i = 0; i < _files.items(); i++) - { - int err = _status.get_int(); - int recno = _status.get_int(); - if (recno >= 0l) file(i)->readat(recno); - else file(i)->curr().zero(); - file(i)->setstatus(err); - } - for (i = 0; i < _reldefs.items(); i++) - { - bool first_match = _status.get_int (); - reldef(i)->_first_match = first_match; - } -} - -void TRelation::save_status() -{ - _status.cut(0); - for (int i = 0; i < _files.items(); i++) - { - int err = file(i)->status(); - TRecnotype recno = file(i)->eof() ? -1l : file(i)->recno(); - _status.add (format ("%d",err)); - _status.add (format ("%d",recno)); - } - for (i = 0; i < _reldefs.items(); i++) - { - bool first_match = reldef(i)->_first_match; - _status.add (format ("%d",first_match)); - } -} - -int TRelation::log2ind(int log) const -{ - // returns _files index of logical number or - // NOTFOUND if not present - // sets error status - - if (log < 0) return alias2ind(byte(-log)); - - const int num = _files.items(); - if (log > 0) - { - for (int i = 0; i < num; i++) - if (file(i)->num() == log) return i; - } - return num ? 0 : NOTFOUND; -} - -int TRelation::alias2ind(byte alias) const -{ - if (alias < 1) return 0; - - for (int i = 0; i < _reldefs.items(); i++) - { - const TRelationdef& r = (const TRelationdef&)_reldefs[i]; - if (r.alias() == alias) return r.num(); - } - - return NOTFOUND; -} - -int TRelation::name2ind(const char* name) const -{ - const int num = name2log(name); - const int ind = log2ind(num); - return ind; -} - -TLocalisamfile* TRelation::lfile(int logicnum) const -{ - const int idx = log2ind(logicnum); - CHECKD(idx != NOTFOUND, "File not found n. ", logicnum); - return (TLocalisamfile*)_files.objptr(idx); -} - -TLocalisamfile* TRelation::lfile(const char* name) const -{ - const int idx = name2ind(name); - CHECKS(idx != NOTFOUND, "File or Table not found:", name); - return (TLocalisamfile*)_files.objptr(idx); -} - -void TRelation::write_enable(int logicnum, const bool on) - -{ - if (logicnum == - 1) - { - for (int i = 0; i < _reldefs.items(); i++) - reldef(i)->write_enable() = on; - } - else - { - const int idx = log2ind(logicnum); - CHECKD(idx != NOTFOUND, "File not found n. ", logicnum); - reldef(idx)->write_enable() = on; - } -} - -void TRelation::write_enable(const char* name, const bool on) - -{ - const int idx = name2ind(name); - CHECKS(idx != NOTFOUND, "File or Table not found:", name); - reldef(idx)->write_enable() = on; -} - -bool TRelation::add(int logicnum, const char* relexprs, int key, - int linkto, byte alias, bool allow_lock) -{ - const int idxto = log2ind(linkto); - if (idxto == NOTFOUND) - fatal_box("Can't join file %d to %d", logicnum, linkto); - - int idx = log2ind(logicnum); - TLocalisamfile* f = new TLocalisamfile(logicnum, idx == NOTFOUND); - idx = _files.add(f); - - if (relexprs && *relexprs) - { - TRelationdef* r = new TRelationdef(this, idx, key, idxto, - relexprs, alias, allow_lock); - _reldefs.add(r); - } - return _errors; -} - -bool TRelation::add(const char* tabname, const char* relexprs, int key, - int linkto, byte alias, bool allow_lock) - -{ - // look for file - const int idxto = log2ind(linkto); - if (idxto == NOTFOUND) - fatal_box("Can't link to file no. %d", linkto); - - int idx = name2ind(tabname); - TTable* f = new TTable(tabname, idx == NOTFOUND); - idx = _files.add(f); - - if (relexprs && *relexprs) - { - TRelationdef* r = new TRelationdef(this, idx, key, idxto, - relexprs, alias, allow_lock); - _reldefs.add(r); - } - - return _errors; -} - -TRectype& TRelationdef::load_rec(TRectype& r, const TBaseisamfile* from) const -{ - r.zero(); - - for (int j = 0 ; j < _fields.items(); j++) // for each field - { - // TString& s = (TString&) _fields[j]; - // r.put(s, from->get(s)); - TFieldref& s = (TFieldref&) _fields[j]; - s.write(s.read(from->curr()),r); - // r.put(s.name(), s.read(from->curr())); - } - - return r; -} - - -void TRelation::zero() -{ - for (int i = 0; i < _files.items(); i++) - file(i)->zero(); -} - -int TRelation::position_rels(TIsamop op, TReclock lockop, - TDate& atdate, int first) -{ - _errors = NOERR; - - // workhorse: position files for each active relation - for (int i = first; i < _reldefs.items(); i++) - { - TRelationdef& rd = *reldef(i); - TLocalisamfile* from = file(rd.num()); - TLocalisamfile* to = file(rd.link()); - TReclock lck = rd._allow_lock ? lockop : _nolock; - - if (to->curr().empty()) - { from->zero(); continue; } - - from->setkey(rd._key); - from->curr().zero(); - - // build record - if (rd._fields.items() && rd._exprs.items()) - { - for (int j = 0 ; j < rd._fields.items(); j++) // for each field - { - TExpression& expr = (TExpression&)rd._exprs[j]; - - // setvar for every variable - for (int k = 0; k < expr.numvar(); k++) - expr.setvar(k, to->get(expr.varname(k))); - - // eval expression and put result in field - - TFieldref& s = (TFieldref&) rd._fields[j]; - s.write(expr, from->curr()); - // TString& s = (TString&) rd._fields[j]; - // from->put(s, (const char*)expr); - } // for each field - } - - // read record: if not found, empty current record - TRectype rec(from->curr()); - from->read(op, lck, atdate); - if (from->bad()) - { - rd._first_match = (from->curr() == rec); - if (rd._first_match) - { - bool eq = TRUE; - - for (int kk = 0; eq && kk < rd._fields.items(); kk++) - { - if (rd._forced[kk]) - { - // TString& fl = (TString&)rd._fields[kk]; - // const TString f_fr(from->curr().get(fl)); - - TFieldref& fl = (TFieldref&)rd._fields[kk]; - const TString f_fr(fl.read(from->curr())); - - // const TFixed_string f_to(to->curr().get(fl)); - // eq = (f_fr == f_to); - TExpression& expr = (TExpression&)rd._exprs[kk]; - for (int k = 0; k < expr.numvar(); k++) - expr.setvar(k, to->get(expr.varname(k))); - eq = (f_fr == (const char*)expr); - } - } - if (eq) from->setstatus(NOERR); - else { rd._first_match = FALSE; from->curr().zero(); } - } - else from->curr().zero(); - } - else rd._first_match = TRUE; - } // for each relation - return _errors; -} - -bool TRelation::next_match(int logicnum, const char* fieldlist, int nkey) -{ - if (logicnum == file()->num()) - { - next(); - return file()->good(); - } - - const int i = log2ind(logicnum); - CHECKD(i != NOTFOUND,"Nonexistent file referenced in relation ",logicnum); - - for (int j = 0; j < _reldefs.items(); j++) - if (reldef(j)->num() == i) break; - - TLocalisamfile* from = file(i); - TLocalisamfile* to = file(reldef(j)->link()); - - reldef(j)->_first_match = FALSE; - - if (from->bad()) - return FALSE; // && vaffanculo() - - const TRecnotype last = from->recno(); - - bool ok = TRUE; // Corrispondenza trovata ? - - if (fieldlist == NULL) - { - TRectype rec(from->curr()); - reldef(j)->load_rec(rec, from); - from->setkey(reldef(j)->_key); - from->next(); - - ok = (from->good() && from->curr() == rec); - for (int kk = 0; ok && kk < reldef(j)->_fields.items(); kk++) - { - if (reldef(j)->_forced[kk]) - { - // TString& fl = (TString&)reldef(j)->_fields[kk]; - // const TFixed_string f_fr(from->curr().get(fl)); - // const TFixed_string f_to(to->curr().get(fl)); - TFieldref& fl = (TFieldref&)reldef(j)->_fields[kk]; - const TFixed_string f_fr(fl.read(from->curr())); - const TFixed_string f_to(fl.read(to->curr())); - - ok = (f_fr == f_to); - } - } - if (ok) from->setstatus(NOERR); - } - else - { - if (nkey > 0) - from->setkey(nkey); - TToken_string fields(fieldlist); - TToken_string old(80); - for (const char* f = fields.get(0); f; f = fields.get()) - old.add(from->curr().get(f)); - - from->next(); - - old.restart(); - - - for (f = fields.get(0); f && ok; f = fields.get()) - { - const TFixed_string v(from->curr().get(f)); - const char* o = old.get(); - if (v != o) - ok = FALSE; - } - } - - if (!ok) - { - from->readat(last); - return FALSE; - } - - // Riposiziona gli eventuali files successivi - position_rels(_isequal, _nolock, (TDate&)botime, j+1); - reldef(j)->_first_match = FALSE; - - return ok; -} - -bool TRelation::is_first_match(int logicnum) - // TRUE se c'e' un record ed e' il primo match (non si e' mai fatta - // position_rels) -{ - const int i = log2ind(logicnum); - CHECKD(i != NOTFOUND,"Nonexistent file referenced in relation ",logicnum); - - for (int j = 0; j < _reldefs.items(); j++) - if (reldef(j)->num() == i) return reldef(j)->_first_match; - const int err = file()->status(); - return err == NOERR; -} - - -#ifdef DBG - -bool TRelation::isconsistent(bool reset) -{ - const int MAXREL = 24; - int bad = 0; - TRecnotype recnos[MAXREL]; - - for (int i = 0; i < _files.items() && i < MAXREL; i++) - { - // must be file OK, non-empty record - bad |= file(i)->good() || file(i)->curr().empty(); - recnos[i] = file(i)->recno(); - } - - // if the above hold, check consistency - if (bad) - return _errors = bad; - - position_rels(_isequal, _nolock, (TDate&)botime); - for (i = 0; i < _files.items(); i++) - if (file(i)->recno() != recnos[i]) - { - bad = -1; - break; - } - - if (reset == FALSE) - // leave as before - for(i = 0; i < _files.items(); i++) - file(i)->readat(recnos[i]); - - return this->_errors = bad; -} - -#endif - - -int TRelation::write(bool force, TDate& atdate) -{ - _errors = NOERR; - - if (file(0)->curr().empty()) - return _errors; // *** no error returned ** - // programmer must be aware - - if ((_errors = file(0)->write(atdate)) != NOERR) - return _errors; - - - for (int i = 0; i < _reldefs.items(); i++) - { - TRelationdef& rd = *reldef(i); - const int log = rd.num(); - - if (!rd.write_enable() || - (file(log)->curr()).empty()) continue; - - int res = file(log)->write(atdate); - if (force && res == _isreinsert) - res = file(log)->rewrite(atdate); - if (_errors == NOERR) _errors = res; - } - return _errors; -} - -int TRelation::rewrite(bool force, TDate& atdate) -{ - _errors = file(0)->rewrite(atdate); // Riscrive testata - if (force && _errors == _iskeynotfound) // Se non la trova ... - _errors = file(0)->write(atdate); // ... forza la scrittura - - for (int i = 0; i < _reldefs.items(); i++) - { - TRelationdef& rd = *reldef(i); - const int log = rd.num(); - - if (!rd.write_enable() || - (file(log)->curr()).empty()) continue; - - int res = file(log)->rewrite(atdate); - if (force && res == _iskeynotfound) - res = file(log)->write(atdate); - if (_errors == NOERR) _errors = res; - } - - return _errors; -} - -int TRelation::remove(TDate& atdate) -{ - const int res = file(0)->remove(atdate); - if (_errors == NOERR && res != _iskeynotfound) _errors = res; - for (int i = 0; i < _reldefs.items(); i++) - { - TRelationdef& rd = *reldef(i); - const int log = rd.num(); - - if (!rd.write_enable() || - (file(log)->curr()).empty()) continue; - - const int res = file(log)->remove(atdate); - if (_errors == NOERR && res != _iskeynotfound) _errors = res; - } - return _errors; -} - - -/////////////////////////////////////////////////////////// -// TCursor -/////////////////////////////////////////////////////////// - - -HIDDEN bool __evalcondition(const TRectype& r,TExpression* cond) - -{ - for (int i = 0; i < cond->numvar(); i++) - { - const char* s = cond->varname(i); - // if (cond->type() == _numexpr) - // { - // real n(r.get(s)); - // cond->setvar(i, n); - // } - // else - cond->setvar(i, r.get(s)); - } - return (bool) *cond; -} - -FILE* TCursor::open_index(bool create) const -{ -#if XVT_OS == XVT_OS_SCOUNIX - const char* const r = "r"; - const char* const w = "w"; -#else - const char* const r = "rb"; - const char* const w = "wb"; -#endif - - FILE* f = fopen(_indexname, create ? w : r); - if (f == NULL) - fatal_box("Can't use cursor index for file %d\n", file()->filehnd()->ln); - - return f; -} - -TRecnotype TCursor::buildcursor(TRecnotype rp) -{ - TRecnotype ap = 0, junkl; - char s[82]; - int junk, l, pagecnt = 0; - Page p; - int pos; - const int kl = file()->filehnd()->i.Base[file()->filehnd()->i.PN].KeyLen; - const bool filtered = has_filter(); - - if (file()->filehnd()->i.Base[file()->filehnd()->i.PN].PEOD == 0) - return 0; - - FILE* _f = open_index(TRUE); - fseek(_f, 0L, SEEK_SET); - - l = strlen(to()); - BTrRead(&file()->filehnd()->i, (char*)(const char*) from(), s, &junkl, &junk); - if (junk == _iseof) return 0; - - TRecnotype* page = new TRecnotype [CMAXELPAGE]; - - if (GetAPage(&file()->filehnd()->i, &p, file()->filehnd()->i.CurPag, &junk) != NOERR) - fatal_box("Can't read index n. %d - file n. %d", file()->filehnd()->i.PN + 1, file()->filehnd()->ln); - - pos = file()->filehnd()->i.Pos - 1; - _pos = -1; - while (TRUE) - { - if (pos >= p.PA.PageHeader.NKey) - { - if (p.PA.PageHeader.Next == -1L) break; - file()->filehnd()->i.CurPag = p.PA.PageHeader.Next; - if (GetAPage(&file()->filehnd()->i, &p, file()->filehnd()->i.CurPag, &junk) != NOERR) - fatal_box("Can't read index n. %d - file n. %d", file()->filehnd()->i.PN + 1, file()->filehnd()->ln); - pos = 0; - } - const char* s0 = p.PA.AreaForKey + pos++ * (kl + 4); - if (l && (strncmp(to(), s0, l) < 0)) break; - - if (pagecnt == CMAXELPAGE) - { - if (filtered) pagecnt = filtercursor(pagecnt, page); - fwrite(page, sizeof(junkl), pagecnt, _f); - if (pos == -1) - for (int i = 0; i < pagecnt; i++) - if (page[i] == rp) - { - _pos = ap + i; - break; - } - ap += pagecnt; - pagecnt = 0; - } - page[pagecnt++] = *((long *)(s0 + kl)); - } - if (pagecnt) - { - if (filtered) pagecnt = filtercursor(pagecnt, page); - fwrite(page, sizeof(junkl), pagecnt, _f); - if (pos == -1) - for (int i = 0; i < pagecnt; i++) - if (page[i] == rp) - { - _pos = ap + i; - break; - } - ap += pagecnt; - } - if (_pos == -1 ) pos = 0; - delete page; - - fclose(_f); - return ap; -} - - -int TCursor::filtercursor(int pagecnt, TRecnotype* page) - -{ - int np = 0; - TRectype& rec = file()->curr(); - const bool tab = file()->tab(); - if (tab) - { - file()->filehnd()->r->Fd[0].RecOff += 3; - file()->filehnd()->r->Fd[0].Len -= 3; - } - // TRecfield* codtab = tab ? new TRecfield(rec, "CODTAB") : NULL; - for (int i = 0; i < pagecnt; i++) - { - CRead(&file()->filehnd()->f, rec.string(), page[i], _nolock); - // if (tab) *codtab = (const char*)(*codtab) + 3; - if ((_filterfunction ? _filterfunction(_if) : TRUE ) && - (_fexpr ? __evalcondition(rec, _fexpr) : TRUE)) - { - if (np < i) page[np] = page[i]; - np++; - } - } - if (tab) - { - file()->filehnd()->r->Fd[0].RecOff -= 3; - file()->filehnd()->r->Fd[0].Len += 3; - } - // if (tab) delete codtab; - return np; -} - - -bool TCursor::ok() const - -{ - if (file()->bad()) return FALSE; - - const TRectype& rec = file()->curr(); - TString key(rec.key(_nkey)), kf(from()), kt(to()); - if (file()->tab()) - { - kf.ltrim(3); - kt.ltrim(3); - } - - if (key < kf || (kt.not_empty() && kt < key.left(kt.len()))) - return FALSE; - if ((_filterfunction ? _filterfunction(_if) : TRUE ) && - (_fexpr ? __evalcondition(rec, _fexpr) : TRUE)) - return TRUE; - return FALSE; -} - -bool TCursor::changed() - -{ - isdef* fh = file()->filehnd(); - - if (_frozen && _lastrec != 0L) return _filename != fh->f.name; - -#if XVT_OS==XVT_OS_SCOUNIX - const TRecnotype eod = file()->eod(); -#else - int junk = 0; - const TRecnotype eod = cisgeteod(fh, &junk); - // GetHead(&fh->i, _nolock, &junk); -#endif - - if (_lastrec != eod || - (_lastkrec != fh->i.Base[_nkey -1].PEOD) || - (_filename != fh->f.name)) - { - _lastrec = eod; - _lastkrec = fh->i.Base[_nkey -1].PEOD; - _filename = fh->f.name; - return TRUE; - } - else return FALSE; -} - -TRecnotype TCursor::update() - -{ - file()->setkey(_nkey); - file()->read(_isgteq); - - const CURSOR old = get_cursor(TASK_WIN); - set_cursor(TASK_WIN, CURSOR_WAIT); - - TRecnotype totrec = buildcursor(file()->recno()); - // if (has_filter()) totrec = filtercursor(); - - set_cursor(TASK_WIN, old); - - return totrec; -} - - -void TCursor::filter(const char* filter, const TRectype *from, - const TRectype* to) - -{ - CHECK(!_frozen, "Impossibile filtrare un cursore congelato"); - - TString kf(_keyfrom), kto(_keyto), kfilter, tbpref; - - if (filter) - kfilter << filter; - - bool filterchanged = (filter != NULL) && (_filter != kfilter); - - if (file()->tab()) - { - TTable& f = (TTable&) *file(); - tbpref = f.name(); - } - if (from != NULL) - { - kf = tbpref; - kf << from->key(_nkey); - int p; - while ((p = kf.find('~')) != -1) kf[p] = ' '; - } - if (to != NULL) - { - kto = tbpref; - kto << to->key(_nkey); - int p; - while ((p = kto.find('~')) != -1) kto[p] = ' '; - } - if (filterchanged || (_keyfrom != kf) || (_keyto != kto)) - { - _pos = 0; - _totrec = 0; - _lastrec = 0; - if (filterchanged) - { - _filter = kfilter; - if (_fexpr) delete _fexpr; - TTypeexp type = (_filter.find('"') != -1) ? _strexpr : _numexpr; - if (_filter.not_empty()) - { - _fexpr = new TExpression(_filter, type); - if (_fexpr->type() == _numexpr) - for (int i = 0 ; i < _fexpr->numvar(); i++) - if (file()->curr().type(_fexpr->varname(i)) == _alfafld) - { - _fexpr->set_type(_strexpr); - break; - } - } - else _fexpr = NULL; - } - file()->setkey(_nkey); - _keyfrom = kf; - _keyto = kto; - } -} - -void TCursor::setkey(int nkey) - -{ - if (nkey != _nkey) - { - _lastrec = 0L; - _nkey = nkey; - file()->setkey(_nkey); - filter(NULL); - } -} - - -TRecnotype TCursor::read(TIsamop op, TReclock lockop, TDate& atdate) -{ - TRecnotype *page; - int pagecnt; - - file()->setkey(_nkey); - _if->file()->read(op, lockop, atdate); - const TRecnotype curpos = file()->recno(); - - if (changed()) - _totrec = update(); - - FILE* _f = open_index(); - - if (fseek(_f, 0L, SEEK_SET) != 0) - fatal_box("Can't repos cursor : File %d\n", file()->filehnd()->ln); - - page = new TRecnotype [CMAXELPAGE]; - _pos = -1; - - for (TRecnotype max = _totrec; _pos == -1 && max > 0; max -= pagecnt) - { - pagecnt = (max < CMAXELPAGE) ? (int)max : CMAXELPAGE; - fread(page, sizeof(TRecnotype), pagecnt, _f); - for (int i = 0; i < pagecnt; i++) - if (page[i] == curpos) - { - _pos = _totrec - max + i; - break; - } - } - if (_pos == -1) _pos = 0; - delete page; - fclose(_f); - - readrec(); - return _pos; -} - - -TCursor::TCursor(TRelation* r, const char* filter, int nkey, TRectype *from, TRectype* to) -: _frozen(FALSE), _filterfunction(NULL) - -{ - _if = r; - _nkey = nkey; - CHECKD(_nkey > 0 && _nkey <= file()->filehnd()->r->NKeys, "Bad key number : ", _nkey); - _indexname.temp("ci"); - - /* - #if XVT_OS==XVT_OS_SCOUNIX - _f = fopen(_indexname, "w+"); - #else - _f = fopen(_indexname, "wb+"); - #endif - if (_f == NULL) - fatal_box("Can't create cursor index on file %d: %s", - file()->num(), strerror(errno)); - */ - FILE* _f = open_index(TRUE); - fclose(_f); - - _pos = 0; - _totrec = 0; - _lastrec = 0; - _lastkrec = 0; - _filter << filter; - TTypeexp type = (_filter.find('"') != -1) ? _strexpr : _numexpr; - if (_filter.not_empty()) - { - _fexpr = new TExpression(_filter, type); - if (_fexpr->type() == _numexpr) - for (int i = 0 ; i < _fexpr->numvar(); i++) - if (file()->curr().type(_fexpr->varname(i)) == _alfafld) - { - _fexpr->set_type(_strexpr); - break; - } - } - else _fexpr = NULL; - file()->setkey(_nkey); - if (file()->tab()) - { - TTable& f = (TTable&) *file(); - _keyfrom = _keyto = f.name(); - } - if (from != NULL) - { - _keyfrom << from->key(_nkey); - int p; - while ((p = _keyfrom.find('~')) != -1) _keyfrom[p] = ' '; - } - if (to != NULL) - { - _keyto << to->key(_nkey); - int p; - while ((p = _keyto.find('~')) != -1) _keyto[p] = ' '; - } -} - - -TCursor::~TCursor() - -{ - // fclose(_f); - ::remove(_indexname); - if (_fexpr) delete _fexpr; -} - - -TRecnotype TCursor::readrec() - -{ - TRecnotype& nrec = file()->filehnd()->RecNo; - - if (_pos == items()) - { - file()->setstatus(_iseof); - curr().zero(); - return nrec = 0L; - } - file()->setstatus(NOERR); - - FILE* _f = open_index(); - - if ((fseek(_f, _pos * sizeof(TRecnotype), SEEK_SET) != 0) || - (fread(&nrec, sizeof(TRecnotype), 1, _f) != 1)) - fatal_box("Can't read record in file n. %d\n", file()->filehnd()->ln); - - fclose(_f); - - curr().setdirty(); - CRead(&file()->filehnd()->f, curr().string(), nrec, _nolock); - if (file()->tab()) - { - TRecfield codtab(curr(), "CODTAB"); - codtab = (const char*)codtab + 3; - } - repos(); - return nrec; -} - - -TRecnotype TCursor::operator =(const TRecnotype pos) - -{ - if (changed()) - _totrec = update(); - CHECKD(pos >= 0 && pos <= _totrec, "Bad cursor position : ", pos); - _pos = pos; - if (_pos > _totrec) _pos = _totrec; - readrec(); - return _pos; -} - - -TCursor& TCursor::operator +=(const TRecnotype npos) - -{ - if (changed()) - _totrec = update(); - _pos += npos; - if (_pos > _totrec) _pos = _totrec; - readrec(); - return *this; -} - - -TCursor& TCursor::operator -=(const TRecnotype npos) - -{ - if (changed()) - _totrec = update(); - _pos -= npos; - if (_pos < 0) _pos = 0; - readrec(); - return *this; -} - - -TCursor& TCursor::operator ++() - -{ - if (changed()) - _totrec = update(); - _pos++; - if (_pos > _totrec) _pos = _totrec; - readrec(); - return *this; -} - - -TCursor& TCursor::operator --() - -{ - if (changed()) - _totrec = update(); - if (_pos) _pos--; - readrec(); - return *this; -} - - -TRecnotype TCursor::items() - -{ - if (changed()) - _totrec = update(); - return _totrec; -} - -bool TCursor::next_match(int lognum, const char* fl, int nk) -{ - if (lognum == 0 || lognum == file()->num()) - {++(*this); return file()->good(); } - else return _if->next_match(lognum, fl, nk); -} - -bool TCursor::is_first_match(int ln) -{ - return (ln == 0 || ln == file()->num()) ? - (_pos == 0 && file()->good()) : (_if->is_first_match(ln)); -} - -/////////////////////////////////////////////////////////// -// TFieldRef -/////////////////////////////////////////////////////////// - -int name2log(const char* name) -{ - int log = 0; - - if (name && *name) - { - if (isdigit(*name)) - { - log = atoi(name); - if (strchr(name, '@')) log = -log; - } - else - { - const int len = strlen(name); - if (len == 3 || len == 4) - log = TTable::name2log(name); - } - - CHECKS(log != 0, "Non e' un file ne' una tabella: ", name); - } - - return log; -} - - -TFieldref::TFieldref() : _fileid(0), _name(0) {} - - -TFieldref::TFieldref(const TString& s, short defid) -{ - operator=(s); - if (_fileid == 0) _fileid = defid; -} - - -// A Fieldref should have the following format (only NAME is mandatory): -// FILE->NAME[FROM,TO] -TFieldref& TFieldref::operator =(const TString& s) -{ - int pos = s.find("->"); - if (pos > 0) - { - _id = s.left(pos); _id.strip(" "); - _fileid = name2log(_id); - pos += 2; - } else _fileid = pos = 0; - - int par = s.find('[', pos); - _name = s.sub(pos, par); _name.strip(" "); - - if (par > 0) - { - pos = par+1; - _from = atoi(&s[pos]); - if (_from > 0) _from--; else _from = 0; - par = s.find(',', pos); - if (par > 0) _to = atoi(&s[par+1]); else _to = -1; - } - else - { - _from = 0; - _to = -1; - } - - return *this; -} - -void TFieldref::print_on(ostream& out) const -{ - if (_id.not_empty()) out << _id << "->"; - out << _name; - if (_from > 0 || _to > 0) - { - out << '[' << (_from+1); - if (_to) out << ',' << _to; - out << ']'; - } -} - -const char* TFieldref::read(const TRectype& rec) const -{ - static TString80 buffer; - - if (_fileid >= CNF_GENERAL) - { - TToken_string s(_name, '.'); - TConfig c(_fileid - CNF_STUDIO, s.get()); - buffer = c.get(s.get()); - } - else - { - buffer = rec.get(_name); - if (_from > 0 || _to > 0) - { - const int l = buffer.len(); - const int from = (_from > l) ? l : _from; - const int to = (_to > l || _to < 1) ? l : _to; - if (to < l) buffer.cut(to); - if (from > 0) buffer.ltrim(from); - } - } - return buffer; -} - -const char* TFieldref::read(const TRelation* c) const -{ - const char * s; - - if (c == NULL) - { - TLocalisamfile f(_fileid); - s = read(f.curr()); - } - else - s = read(c->lfile(_id)->curr()); - - return s; -} - -void TFieldref::write(const char* val, TRelation* c) const -{ - TLocalisamfile* f = NULL; - TRectype* curr = NULL; - - if (c == NULL) - { - f = new TLocalisamfile(_fileid); - curr = &f->curr(); - } - else - curr = &c->lfile(_id)->curr(); - - write(val, *curr); - - if (f != NULL) delete f; -} - - -void TFieldref::write(const char* val, TRectype& rec) const -{ - if (_fileid >= CNF_GENERAL) return; - if (_from > 0) - { - TString80 campo(rec.get(_name)); - campo.overwrite(val, _from); - rec.put(_name, campo); - } - else - rec.put(_name, val); -} - -int TFieldref::len(TRectype &rec) const - -{ - if (_to >= 0) return _to - _from; - if (_fileid == 0) return rec.length(_name) - _from; - - TLocalisamfile f(_fileid); - const int len = f.curr().length(_name); - return len - _from; -} - -// *** EOF relation.cpp - +// $Id: relation.cpp,v 1.9 1994-09-21 11:16:30 guy Exp $ +// relation.cpp +// fv 12/8/93 +// relation class for isam files + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +// *** check if not already defined +#define NOTFOUND (-1) + +// *** maximum number of elements in a cursor working page +#define CMAXELPAGE 8000 + + +/////////////////////////////////////////////////////////// +// TRelationdef +/////////////////////////////////////////////////////////// + +class TRelationdef : public TObject +{ + // @DPRIV + friend class TRelation; + + const TRelation* _rel; // Relazione padre + int _num; // Posizione file + int _numto; // Posizione padre + byte _alias; // Alias + byte _key; // Chiave + TArray _fields; // Campi di join + TArray _exprs; // Condizioni di uguaglianza + TBit_array _forced; + bool _first_match : 1; // primo match (ed esiste) + bool _allow_lock : 1; // ????? + bool _write_enable; + +protected: + virtual void print_on(ostream& out) const; + +public: + // @FPUB + int num() const { return _num; } + int link() const { return _numto; } + byte alias() const { return _alias; } + bool& write_enable() { return _write_enable; } + TRectype& load_rec(TRectype& r, const TBaseisamfile& from) const; + + TRelationdef(const TRelation* rel, int file, byte key, + int linkto, const char* relexprs, byte alias, + bool allow_lock, bool write_enable = FALSE); + virtual ~TRelationdef() {} +}; +// @END + + +HIDDEN ostream& print_name(ostream& out, const TLocalisamfile& f) +{ + const int logicnum = f.num(); + if (logicnum == LF_TABCOM || logicnum == LF_TAB) + { + if (logicnum == LF_TABCOM) out << '%'; + out << ((TTable&)f).name(); + } + else + out << logicnum; + return out; +} + + +TRelationdef::TRelationdef(const TRelation* rel, int idx_file, byte key, + int idx_to, const char* relexprs, byte alias, + bool allow_lock, bool write_enable) +: _num(idx_file), _key(key), _numto(idx_to), + _rel(rel), _fields(4), _exprs(4), _alias(alias), + _first_match(FALSE), _allow_lock(allow_lock), + _write_enable(write_enable) +{ + TToken_string rels(relexprs); + int i = 0; + TString80 r,s; + + for (const char* g = rels.get(); g; g = rels.get(), i++) + { + r = g; + int eq = r.find('='); + + CHECKS(eq > 0, "Ahoo! E l'uguale 'ndo sta'? ", (const char*)g); + + s = r.left(eq); // Parte a sinistra dell' = + +#ifdef DBG + TString80 n(s); + const int p = n.find('['); + if (p > 0) n.cut(p); + if (rel->file(_num).curr().exist(n) == FALSE) + { + error_box("'%s' non e' un campo del file %d", + (const char*)n, rel->file(_num).num()); + continue; + } +#endif + + if (r[eq+1] == '=') + { + _forced.set(i); + eq++; + } + + const TString80 xx(s); + _fields.add(new TFieldref(xx,0)); + + _exprs.add(new TExpression(r.mid(eq+1), _strexpr)); + } +} + + +void TRelationdef::print_on(ostream& out) const +{ + out << "JOIN "; print_name(out, _rel->file(_num)); + + if (_numto > 0) + { + out << " TO "; + const int alias = _rel->reldef(_numto-1).alias(); + if (alias > 0) out << alias << '@'; + else print_name(out, _rel->file(_numto)); + } + + if (_key > 1) out << " KEY " << (int)_key; + + if (_alias > 0) out << " ALIAS " << (int)_alias; + + for (int i = 0; i < _fields.items(); i++) + { + if (i == 0) out << " INTO"; + out << ' ' << _fields[i] << '=' << _exprs[i]; + } +} + + + +/////////////////////////////////////////////////////////// +// TRelation +/////////////////////////////////////////////////////////// + +TRelation::TRelation(int logicnum, bool linkrecinst) +: _files(4) , _reldefs(4), _errors(NOERR) +{ + TLocalisamfile* f = new TLocalisamfile(logicnum, linkrecinst); + _files.add(f); +} + +TRelation::TRelation(const char* tabname, bool linkrecinst) +: _files(4) , _reldefs(4), _errors(NOERR) +{ + TTable* t = new TTable(tabname, linkrecinst); + _files.add(t); +} + +TRelation::~TRelation() +{} + +void TRelation::print_on(ostream& out) const +{ + const TLocalisamfile& f = file(); + + out << "USE "; print_name(out, f); + + const int k = f.getkey(); + if (k > 1) out << " KEY " << k; + out << endl; + + for (int r = 0; r < _reldefs.items(); r++) + out << _reldefs[r] << endl; +} + +void TRelation::restore_status() +{ + _status.restart(); + for (int i = 0; i < _files.items(); i++) + { + int err = _status.get_int(); + int recno = _status.get_int(); + if (recno >= 0l) file(i).readat(recno); + else file(i).curr().zero(); + file(i).setstatus(err); + } + for (i = 0; i < _reldefs.items(); i++) + { + bool first_match = _status.get_int (); + reldef(i)._first_match = first_match; + } +} + +void TRelation::save_status() +{ + _status.cut(0); + for (int i = 0; i < _files.items(); i++) + { + const int err = file(i).status(); + const TRecnotype recno = file(i).eof() ? -1l : file(i).recno(); + _status.add (err); + _status.add (recno); + } + for (i = 0; i < _reldefs.items(); i++) + { + const bool first_match = reldef(i)._first_match; + _status.add(format("%d",first_match)); + } +} + +int TRelation::log2ind(int log) const +{ + // returns _files index of logical number or + // NOTFOUND if not present + // sets error status + + if (log < 0) return alias2ind(byte(-log)); + + const int num = _files.items(); + if (log > 0) + { + for (int i = 0; i < num; i++) + if (file(i).num() == log) return i; + } + return num ? 0 : NOTFOUND; +} + +int TRelation::alias2ind(byte alias) const +{ + if (alias < 1) return 0; + + for (int i = 0; i < _reldefs.items(); i++) + { + const TRelationdef& r = (const TRelationdef&)_reldefs[i]; + if (r.alias() == alias) return r.num(); + } + + return NOTFOUND; +} + +int TRelation::name2ind(const char* name) const +{ + const int num = name2log(name); + const int ind = log2ind(num); + return ind; +} + +TLocalisamfile& TRelation::lfile(int logicnum) const +{ + const int idx = log2ind(logicnum); + CHECKD(idx != NOTFOUND, "File not found n. ", logicnum); + return (TLocalisamfile&)_files[idx]; +} + +TLocalisamfile& TRelation::lfile(const char* name) const +{ + const int idx = name2ind(name); + CHECKS(idx != NOTFOUND, "File or Table not found:", name); + return (TLocalisamfile&)_files[idx]; +} + +void TRelation::write_enable(int logicnum, const bool on) + +{ + if (logicnum == - 1) + { + for (int i = 0; i < _reldefs.items(); i++) + reldef(i).write_enable() = on; + } + else + { + const int idx = log2ind(logicnum); + CHECKD(idx != NOTFOUND, "File not found n. ", logicnum); + reldef(idx).write_enable() = on; + } +} + +void TRelation::write_enable(const char* name, const bool on) + +{ + const int idx = name2ind(name); + CHECKS(idx != NOTFOUND, "File or Table not found:", name); + reldef(idx).write_enable() = on; +} + +bool TRelation::add(int logicnum, const char* relexprs, int key, + int linkto, byte alias, bool allow_lock) +{ + const int idxto = log2ind(linkto); + if (idxto == NOTFOUND) + fatal_box("Can't join file %d to %d", logicnum, linkto); + + int idx = log2ind(logicnum); + TLocalisamfile* f = new TLocalisamfile(logicnum, idx == NOTFOUND); + idx = _files.add(f); + + if (relexprs && *relexprs) + { + TRelationdef* r = new TRelationdef(this, idx, key, idxto, + relexprs, alias, allow_lock); + _reldefs.add(r); + } + return _errors; +} + +bool TRelation::add(const char* tabname, const char* relexprs, int key, + int linkto, byte alias, bool allow_lock) + +{ + // look for file + const int idxto = log2ind(linkto); + if (idxto == NOTFOUND) + fatal_box("Can't link to file no. %d", linkto); + + int idx = name2ind(tabname); + TTable* f = new TTable(tabname, idx == NOTFOUND); + idx = _files.add(f); + + if (relexprs && *relexprs) + { + TRelationdef* r = new TRelationdef(this, idx, key, idxto, + relexprs, alias, allow_lock); + _reldefs.add(r); + } + + return _errors; +} + +TRectype& TRelationdef::load_rec(TRectype& r, const TBaseisamfile& from) const +{ + r.zero(); + + for (int j = 0 ; j < _fields.items(); j++) // for each field + { + // TString& s = (TString&) _fields[j]; + // r.put(s, from.get(s)); + TFieldref& s = (TFieldref&) _fields[j]; + s.write(s.read(from.curr()),r); + // r.put(s.name(), s.read(from.curr())); + } + + return r; +} + + +void TRelation::zero() +{ + for (int i = 0; i < _files.items(); i++) + file(i).zero(); +} + +int TRelation::position_rels(TIsamop op, TReclock lockop, + TDate& atdate, int first) +{ + _errors = NOERR; + + // workhorse: position files for each active relation + for (int i = first; i < _reldefs.items(); i++) + { + TRelationdef& rd = reldef(i); + TLocalisamfile& from = file(rd.num()); + TLocalisamfile& to = file(rd.link()); + TReclock lck = rd._allow_lock ? lockop : _nolock; + + if (to.curr().empty()) + { from.zero(); continue; } + + from.setkey(rd._key); + from.curr().zero(); + + // build record + if (rd._fields.items() && rd._exprs.items()) + { + for (int j = 0 ; j < rd._fields.items(); j++) // for each field + { + TExpression& expr = (TExpression&)rd._exprs[j]; + + // setvar for every variable + for (int k = 0; k < expr.numvar(); k++) + expr.setvar(k, to.get(expr.varname(k))); + + // eval expression and put result in field + + TFieldref& s = (TFieldref&) rd._fields[j]; + s.write(expr, from.curr()); + // TString& s = (TString&) rd._fields[j]; + // from.put(s, (const char*)expr); + } // for each field + } + + // read record: if not found, empty current record + TRectype rec(from.curr()); + from.read(op, lck, atdate); + if (from.bad()) + { + rd._first_match = (from.curr() == rec); + if (rd._first_match) + { + bool eq = TRUE; + + for (int kk = 0; eq && kk < rd._fields.items(); kk++) + { + if (rd._forced[kk]) + { + // TString& fl = (TString&)rd._fields[kk]; + // const TString f_fr(from.curr().get(fl)); + + TFieldref& fl = (TFieldref&)rd._fields[kk]; + const TString f_fr(fl.read(from.curr())); + + // const TFixed_string f_to(to.curr().get(fl)); + // eq = (f_fr == f_to); + TExpression& expr = (TExpression&)rd._exprs[kk]; + for (int k = 0; k < expr.numvar(); k++) + expr.setvar(k, to.get(expr.varname(k))); + eq = (f_fr == (const char*)expr); + } + } + if (eq) from.setstatus(NOERR); + else { rd._first_match = FALSE; from.curr().zero(); } + } + else from.curr().zero(); + } + else rd._first_match = TRUE; + } // for each relation + return _errors; +} + +bool TRelation::next_match(int logicnum, const char* fieldlist, int nkey) +{ + if (logicnum == file().num()) + { + next(); + return file().good(); + } + + const int i = log2ind(logicnum); + CHECKD(i != NOTFOUND,"Nonexistent file referenced in relation ",logicnum); + + for (int j = 0; j < _reldefs.items(); j++) + if (reldef(j).num() == i) break; + + TLocalisamfile& from = file(i); + TLocalisamfile& to = file(reldef(j).link()); + + reldef(j)._first_match = FALSE; + + if (from.bad()) + return FALSE; // && vaffanculo() + + const TRecnotype last = from.recno(); + + bool ok = TRUE; // Corrispondenza trovata ? + + if (fieldlist == NULL) + { + TRectype rec(from.curr()); + reldef(j).load_rec(rec, from); + from.setkey(reldef(j)._key); + from.next(); + + ok = (from.good() && from.curr() == rec); + for (int kk = 0; ok && kk < reldef(j)._fields.items(); kk++) + { + if (reldef(j)._forced[kk]) + { + // TString& fl = (TString&)reldef(j)._fields[kk]; + // const TFixed_string f_fr(from.curr().get(fl)); + // const TFixed_string f_to(to.curr().get(fl)); + TFieldref& fl = (TFieldref&)reldef(j)._fields[kk]; + const TFixed_string f_fr(fl.read(from.curr())); + const TFixed_string f_to(fl.read(to.curr())); + + ok = (f_fr == f_to); + } + } + if (ok) from.setstatus(NOERR); + } + else + { + if (nkey > 0) + from.setkey(nkey); + TToken_string fields(fieldlist); + TToken_string old(80); + for (const char* f = fields.get(0); f; f = fields.get()) + old.add(from.curr().get(f)); + + from.next(); + + old.restart(); + + + for (f = fields.get(0); f && ok; f = fields.get()) + { + const TFixed_string v(from.curr().get(f)); + const char* o = old.get(); + if (v != o) + ok = FALSE; + } + } + + if (!ok) + { + from.readat(last); + return FALSE; + } + + // Riposiziona gli eventuali files successivi + position_rels(_isequal, _nolock, (TDate&)botime, j+1); + reldef(j)._first_match = FALSE; + + return ok; +} + +bool TRelation::is_first_match(int logicnum) + // TRUE se c'e' un record ed e' il primo match (non si e' mai fatta + // position_rels) +{ + const int i = log2ind(logicnum); + CHECKD(i != NOTFOUND,"Nonexistent file referenced in relation ",logicnum); + + for (int j = 0; j < _reldefs.items(); j++) + if (reldef(j).num() == i) return reldef(j)._first_match; + const int err = file().status(); + return err == NOERR; +} + + +#ifdef DBG + +bool TRelation::isconsistent(bool reset) +{ + const int MAXREL = 24; + int bad = 0; + TRecnotype recnos[MAXREL]; + + for (int i = 0; i < _files.items() && i < MAXREL; i++) + { + // must be file OK, non-empty record + bad |= file(i).good() || file(i).curr().empty(); + recnos[i] = file(i).recno(); + } + + // if the above hold, check consistency + if (bad) + return _errors = bad; + + position_rels(_isequal, _nolock, (TDate&)botime); + for (i = 0; i < _files.items(); i++) + if (file(i).recno() != recnos[i]) + { + bad = -1; + break; + } + + if (reset == FALSE) + // leave as before + for(i = 0; i < _files.items(); i++) + file(i).readat(recnos[i]); + + return _errors = bad; +} + +#endif + + +int TRelation::write(bool force, TDate& atdate) +{ + _errors = NOERR; + + if (file(0).curr().empty()) + return _errors; // *** no error returned ** + // programmer must be aware + + if ((_errors = file(0).write(atdate)) != NOERR) + return _errors; + + + for (int i = 0; i < _reldefs.items(); i++) + { + TRelationdef& rd = reldef(i); + const int log = rd.num(); + + if (!rd.write_enable() || + (file(log).curr()).empty()) continue; + + int res = file(log).write(atdate); + if (force && res == _isreinsert) + res = file(log).rewrite(atdate); + if (_errors == NOERR) _errors = res; + } + return _errors; +} + +int TRelation::rewrite(bool force, TDate& atdate) +{ + _errors = file(0).rewrite(atdate); // Riscrive testata + if (force && _errors == _iskeynotfound) // Se non la trova ... + _errors = file(0).write(atdate); // ... forza la scrittura + + for (int i = 0; i < _reldefs.items(); i++) + { + TRelationdef& rd = reldef(i); + const int log = rd.num(); + + if (!rd.write_enable() || + (file(log).curr()).empty()) continue; + + int res = file(log).rewrite(atdate); + if (force && res == _iskeynotfound) + res = file(log).write(atdate); + if (_errors == NOERR) _errors = res; + } + + return _errors; +} + +int TRelation::remove(TDate& atdate) +{ + const int res = file(0).remove(atdate); + if (_errors == NOERR && res != _iskeynotfound) _errors = res; + for (int i = 0; i < _reldefs.items(); i++) + { + TRelationdef& rd = reldef(i); + const int log = rd.num(); + + if (!rd.write_enable() || + (file(log).curr()).empty()) continue; + + const int res = file(log).remove(atdate); + if (_errors == NOERR && res != _iskeynotfound) _errors = res; + } + return _errors; +} + + +/////////////////////////////////////////////////////////// +// TCursor +/////////////////////////////////////////////////////////// + + +HIDDEN bool __evalcondition(const TRectype& r,TExpression* cond) + +{ + for (int i = 0; i < cond->numvar(); i++) + { + const char* s = cond->varname(i); + // if (cond->type() == _numexpr) + // { + // real n(r.get(s)); + // cond->setvar(i, n); + // } + // else + cond->setvar(i, r.get(s)); + } + return (bool) *cond; +} + +FILE* TCursor::open_index(bool create) const +{ +#if XVT_OS == XVT_OS_SCOUNIX + const char* const r = "r"; + const char* const w = "w"; +#else + const char* const r = "rb"; + const char* const w = "wb"; +#endif + + FILE* f = fopen(_indexname, create ? w : r); + if (f == NULL) + fatal_box("Can't use cursor index for file %d\n", file().filehnd()->ln); + + return f; +} + +TRecnotype TCursor::buildcursor(TRecnotype rp) +{ + TRecnotype ap = 0, junkl; + char s[82]; + int junk, l, pagecnt = 0; + Page p; + int pos; + const int kl = file().filehnd()->i.Base[file().filehnd()->i.PN].KeyLen; + const bool filtered = has_filter(); + + if (file().filehnd()->i.Base[file().filehnd()->i.PN].PEOD == 0) + return 0; + + FILE* _f = open_index(TRUE); + fseek(_f, 0L, SEEK_SET); + + l = strlen(to()); + BTrRead(&file().filehnd()->i, (char*)(const char*) from(), s, &junkl, &junk); + if (junk == _iseof) return 0; + + TRecnotype* page = new TRecnotype [CMAXELPAGE]; + + if (GetAPage(&file().filehnd()->i, &p, file().filehnd()->i.CurPag, &junk) != NOERR) + fatal_box("Can't read index n. %d - file n. %d", file().filehnd()->i.PN + 1, file().filehnd()->ln); + + pos = file().filehnd()->i.Pos - 1; + _pos = -1; + while (TRUE) + { + if (pos >= p.PA.PageHeader.NKey) + { + if (p.PA.PageHeader.Next == -1L) break; + file().filehnd()->i.CurPag = p.PA.PageHeader.Next; + if (GetAPage(&file().filehnd()->i, &p, file().filehnd()->i.CurPag, &junk) != NOERR) + fatal_box("Can't read index n. %d - file n. %d", file().filehnd()->i.PN + 1, file().filehnd()->ln); + pos = 0; + } + const char* s0 = p.PA.AreaForKey + pos++ * (kl + 4); + if (l && (strncmp(to(), s0, l) < 0)) break; + + if (pagecnt == CMAXELPAGE) + { + if (filtered) pagecnt = filtercursor(pagecnt, page); + fwrite(page, sizeof(junkl), pagecnt, _f); + if (pos == -1) + for (int i = 0; i < pagecnt; i++) + if (page[i] == rp) + { + _pos = ap + i; + break; + } + ap += pagecnt; + pagecnt = 0; + } + page[pagecnt++] = *((long *)(s0 + kl)); + } + if (pagecnt) + { + if (filtered) pagecnt = filtercursor(pagecnt, page); + fwrite(page, sizeof(junkl), pagecnt, _f); + if (pos == -1) + for (int i = 0; i < pagecnt; i++) + if (page[i] == rp) + { + _pos = ap + i; + break; + } + ap += pagecnt; + } + if (_pos == -1 ) pos = 0; + delete page; + + fclose(_f); + return ap; +} + + +int TCursor::filtercursor(int pagecnt, TRecnotype* page) + +{ + int np = 0; + TRectype& rec = file().curr(); + const bool tab = file().tab(); + if (tab) + { + file().filehnd()->r->Fd[0].RecOff += 3; + file().filehnd()->r->Fd[0].Len -= 3; + } + // TRecfield* codtab = tab ? new TRecfield(rec, "CODTAB") : NULL; + for (int i = 0; i < pagecnt; i++) + { + CRead(&file().filehnd()->f, rec.string(), page[i], _nolock); + // if (tab) *codtab = (const char*)(*codtab) + 3; + if ((_filterfunction ? _filterfunction(_if) : TRUE ) && + (_fexpr ? __evalcondition(rec, _fexpr) : TRUE)) + { + if (np < i) page[np] = page[i]; + np++; + } + } + if (tab) + { + file().filehnd()->r->Fd[0].RecOff -= 3; + file().filehnd()->r->Fd[0].Len += 3; + } + // if (tab) delete codtab; + return np; +} + + +bool TCursor::ok() const + +{ + if (file().bad()) return FALSE; + + const TRectype& rec = file().curr(); + TString key(rec.key(_nkey)), kf(from()), kt(to()); + if (file().tab()) + { + kf.ltrim(3); + kt.ltrim(3); + } + + if (key < kf || (kt.not_empty() && kt < key.left(kt.len()))) + return FALSE; + if ((_filterfunction ? _filterfunction(_if) : TRUE ) && + (_fexpr ? __evalcondition(rec, _fexpr) : TRUE)) + return TRUE; + return FALSE; +} + +bool TCursor::changed() + +{ + isdef* fh = file().filehnd(); + + if (_frozen && _lastrec != 0L) return _filename != fh->f.name; + +#if XVT_OS==XVT_OS_SCOUNIX + const TRecnotype eod = file().eod(); +#else + int junk = 0; + const TRecnotype eod = cisgeteod(fh, &junk); + // GetHead(&fh->i, _nolock, &junk); +#endif + + if (_lastrec != eod || + (_lastkrec != fh->i.Base[_nkey -1].PEOD) || + (_filename != fh->f.name)) + { + _lastrec = eod; + _lastkrec = fh->i.Base[_nkey -1].PEOD; + _filename = fh->f.name; + return TRUE; + } + else return FALSE; +} + +TRecnotype TCursor::update() + +{ + file().setkey(_nkey); + file().read(_isgteq); + + const CURSOR old = get_cursor(TASK_WIN); + set_cursor(TASK_WIN, CURSOR_WAIT); + + TRecnotype totrec = buildcursor(file().recno()); + // if (has_filter()) totrec = filtercursor(); + + set_cursor(TASK_WIN, old); + + return totrec; +} + + +void TCursor::filter(const char* filter, const TRectype *from, + const TRectype* to) + +{ + CHECK(!_frozen, "Impossibile filtrare un cursore congelato"); + + TString kf(_keyfrom), kto(_keyto), kfilter, tbpref; + + if (filter) + kfilter << filter; + + bool filterchanged = (filter != NULL) && (_filter != kfilter); + + if (file().tab()) + { + TTable& f = (TTable&)file(); + tbpref = f.name(); + } + if (from != NULL) + { + kf = tbpref; + kf << from->key(_nkey); + int p; + while ((p = kf.find('~')) != -1) kf[p] = ' '; + } + if (to != NULL) + { + kto = tbpref; + kto << to->key(_nkey); + int p; + while ((p = kto.find('~')) != -1) kto[p] = ' '; + } + if (filterchanged || (_keyfrom != kf) || (_keyto != kto)) + { + _pos = 0; + _totrec = 0; + _lastrec = 0; + if (filterchanged) + { + _filter = kfilter; + if (_fexpr) delete _fexpr; + TTypeexp type = (_filter.find('"') != -1) ? _strexpr : _numexpr; + if (_filter.not_empty()) + { + _fexpr = new TExpression(_filter, type); + if (_fexpr->type() == _numexpr) + for (int i = 0 ; i < _fexpr->numvar(); i++) + if (file().curr().type(_fexpr->varname(i)) == _alfafld) + { + _fexpr->set_type(_strexpr); + break; + } + } + else _fexpr = NULL; + } + file().setkey(_nkey); + _keyfrom = kf; + _keyto = kto; + } +} + +void TCursor::setkey(int nkey) + +{ + if (nkey != _nkey) + { + _lastrec = 0L; + _nkey = nkey; + file().setkey(_nkey); + filter(NULL); + } +} + + +TRecnotype TCursor::read(TIsamop op, TReclock lockop, TDate& atdate) +{ + TRecnotype *page; + int pagecnt; + + file().setkey(_nkey); + _if->file().read(op, lockop, atdate); + const TRecnotype curpos = file().recno(); + + if (changed()) + _totrec = update(); + + FILE* _f = open_index(); + + if (fseek(_f, 0L, SEEK_SET) != 0) + fatal_box("Can't repos cursor : File %d\n", file().filehnd()->ln); + + page = new TRecnotype [CMAXELPAGE]; + _pos = -1; + + for (TRecnotype max = _totrec; _pos == -1 && max > 0; max -= pagecnt) + { + pagecnt = (max < CMAXELPAGE) ? (int)max : CMAXELPAGE; + fread(page, sizeof(TRecnotype), pagecnt, _f); + for (int i = 0; i < pagecnt; i++) + if (page[i] == curpos) + { + _pos = _totrec - max + i; + break; + } + } + if (_pos == -1) _pos = 0; + delete page; + fclose(_f); + + readrec(); + return _pos; +} + + +TCursor::TCursor(TRelation* r, const char* filter, int nkey, TRectype *from, TRectype* to) +: _frozen(FALSE), _filterfunction(NULL) + +{ + _if = r; + _nkey = nkey; + CHECKD(_nkey > 0 && _nkey <= file().filehnd()->r->NKeys, "Bad key number : ", _nkey); + _indexname.temp("ci"); + + /* + #if XVT_OS==XVT_OS_SCOUNIX + _f = fopen(_indexname, "w+"); + #else + _f = fopen(_indexname, "wb+"); + #endif + if (_f == NULL) + fatal_box("Can't create cursor index on file %d: %s", + file().num(), strerror(errno)); + */ + FILE* _f = open_index(TRUE); + fclose(_f); + + _pos = 0; + _totrec = 0; + _lastrec = 0; + _lastkrec = 0; + _filter << filter; + TTypeexp type = (_filter.find('"') != -1) ? _strexpr : _numexpr; + if (_filter.not_empty()) + { + _fexpr = new TExpression(_filter, type); + if (_fexpr->type() == _numexpr) + for (int i = 0 ; i < _fexpr->numvar(); i++) + if (file().curr().type(_fexpr->varname(i)) == _alfafld) + { + _fexpr->set_type(_strexpr); + break; + } + } + else _fexpr = NULL; + file().setkey(_nkey); + if (file().tab()) + { + TTable& f = (TTable&)file(); + _keyfrom = _keyto = f.name(); + } + if (from != NULL) + { + _keyfrom << from->key(_nkey); + int p; + while ((p = _keyfrom.find('~')) != -1) _keyfrom[p] = ' '; + } + if (to != NULL) + { + _keyto << to->key(_nkey); + int p; + while ((p = _keyto.find('~')) != -1) _keyto[p] = ' '; + } +} + + +TCursor::~TCursor() + +{ + // fclose(_f); + ::remove(_indexname); + if (_fexpr) delete _fexpr; +} + + +TRecnotype TCursor::readrec() + +{ + TRecnotype& nrec = file().filehnd()->RecNo; + + if (_pos == items()) + { + file().setstatus(_iseof); + curr().zero(); + return nrec = 0L; + } + file().setstatus(NOERR); + + FILE* _f = open_index(); + + if ((fseek(_f, _pos * sizeof(TRecnotype), SEEK_SET) != 0) || + (fread(&nrec, sizeof(TRecnotype), 1, _f) != 1)) + fatal_box("Can't read record in file n. %d\n", file().filehnd()->ln); + + fclose(_f); + + curr().setdirty(); + CRead(&file().filehnd()->f, curr().string(), nrec, _nolock); + if (file().tab()) + { + TRecfield codtab(curr(), "CODTAB"); + codtab = (const char*)codtab + 3; + } + repos(); + return nrec; +} + + +TRecnotype TCursor::operator =(const TRecnotype pos) + +{ + if (changed()) + _totrec = update(); + CHECKD(pos >= 0 && pos <= _totrec, "Bad cursor position : ", pos); + _pos = pos; + if (_pos > _totrec) _pos = _totrec; + readrec(); + return _pos; +} + + +TCursor& TCursor::operator +=(const TRecnotype npos) + +{ + if (changed()) + _totrec = update(); + _pos += npos; + if (_pos > _totrec) _pos = _totrec; + readrec(); + return *this; +} + + +TCursor& TCursor::operator -=(const TRecnotype npos) + +{ + if (changed()) + _totrec = update(); + _pos -= npos; + if (_pos < 0) _pos = 0; + readrec(); + return *this; +} + + +TCursor& TCursor::operator ++() + +{ + if (changed()) + _totrec = update(); + _pos++; + if (_pos > _totrec) _pos = _totrec; + readrec(); + return *this; +} + + +TCursor& TCursor::operator --() + +{ + if (changed()) + _totrec = update(); + if (_pos) _pos--; + readrec(); + return *this; +} + + +TRecnotype TCursor::items() + +{ + if (changed()) + _totrec = update(); + return _totrec; +} + +bool TCursor::next_match(int lognum, const char* fl, int nk) +{ + if (lognum == 0 || lognum == file().num()) + {++(*this); return file().good(); } + else return _if->next_match(lognum, fl, nk); +} + +bool TCursor::is_first_match(int ln) +{ + return (ln == 0 || ln == file().num()) ? + (_pos == 0 && file().good()) : (_if->is_first_match(ln)); +} + +/////////////////////////////////////////////////////////// +// TFieldRef +/////////////////////////////////////////////////////////// + +int name2log(const char* name) +{ + int log = 0; + + if (name && *name) + { + if (isdigit(*name)) + { + log = atoi(name); + if (strchr(name, '@')) log = -log; + } + else + { + const int len = strlen(name); + if (len == 3 || len == 4) + log = TTable::name2log(name); + } + + CHECKS(log != 0, "Non e' un file ne' una tabella: ", name); + } + + return log; +} + + +TFieldref::TFieldref() : _fileid(0), _name(0) {} + + +TFieldref::TFieldref(const TString& s, short defid) +{ + operator=(s); + if (_fileid == 0) _fileid = defid; +} + + +// A Fieldref should have the following format (only NAME is mandatory): +// FILE->NAME[FROM,TO] +TFieldref& TFieldref::operator =(const TString& s) +{ + int pos = s.find("->"); + if (pos > 0) + { + _id = s.left(pos); _id.strip(" "); + _fileid = name2log(_id); + pos += 2; + } else _fileid = pos = 0; + + int par = s.find('[', pos); + _name = s.sub(pos, par); _name.strip(" "); + + if (par > 0) + { + pos = par+1; + _from = atoi(&s[pos]); + if (_from > 0) _from--; else _from = 0; + par = s.find(',', pos); + if (par > 0) _to = atoi(&s[par+1]); else _to = -1; + } + else + { + _from = 0; + _to = -1; + } + + return *this; +} + +void TFieldref::print_on(ostream& out) const +{ + if (_id.not_empty()) out << _id << "->"; + out << _name; + if (_from > 0 || _to > 0) + { + out << '[' << (_from+1); + if (_to) out << ',' << _to; + out << ']'; + } +} + +const char* TFieldref::read(const TRectype& rec) const +{ + static TString80 buffer; + + if (_fileid >= CNF_GENERAL) + { + TToken_string s(_name, '.'); + TConfig c(_fileid - CNF_STUDIO, s.get()); + buffer = c.get(s.get()); + } + else + { + buffer = rec.get(_name); + if (_from > 0 || _to > 0) + { + const int l = buffer.len(); + const int from = (_from > l) ? l : _from; + const int to = (_to > l || _to < 1) ? l : _to; + if (to < l) buffer.cut(to); + if (from > 0) buffer.ltrim(from); + } + } + return buffer; +} + +const char* TFieldref::read(const TRelation* c) const +{ + const char * s; + + if (c == NULL) + { + TLocalisamfile f(_fileid); + s = read(f.curr()); + } + else + s = read(c->lfile(_id).curr()); + + return s; +} + +void TFieldref::write(const char* val, TRelation* c) const +{ + TLocalisamfile* f = NULL; + TRectype* curr = NULL; + + if (c == NULL) + { + f = new TLocalisamfile(_fileid); + curr = &f->curr(); + } + else + curr = &c->lfile(_id).curr(); + + write(val, *curr); + + if (f != NULL) delete f; +} + + +void TFieldref::write(const char* val, TRectype& rec) const +{ + if (_fileid >= CNF_GENERAL) return; + if (_from > 0) + { + TString80 campo(rec.get(_name)); + campo.overwrite(val, _from); + rec.put(_name, campo); + } + else + rec.put(_name, val); +} + +int TFieldref::len(TRectype &rec) const + +{ + if (_to >= 0) return _to - _from; + if (_fileid == 0) return rec.length(_name) - _from; + + TLocalisamfile f(_fileid); + const int len = f.curr().length(_name); + return len - _from; +} + +// *** EOF relation.cpp + diff --git a/include/relation.h b/include/relation.h index 69cc06c32..5bb41a941 100755 --- a/include/relation.h +++ b/include/relation.h @@ -1,270 +1,269 @@ -/* $Id: relation.h,v 1.3 1994-09-07 17:00:18 guy Exp $ */ -// join.h -// fv 12/8/93 -// join class for isam files - -#ifndef __RELATION_H -#define __RELATION_H - -#ifndef __ISAM_H -#include -#endif - -#ifndef __ARRAY_H -#include -#endif - - -// @C - -class TRelation : public TObject -{ - friend class TRelationdef; - - // class TRelation : public TLocalisamfile - // @END - - // @DPRIV - TToken_string _status; // stato della relazione - TArray _files; // file descriptors - TArray _reldefs; // TRelationdef array - int _errors; - // @END - - // @FPROT -protected: - virtual void print_on(ostream& out) const; - - int log2ind(int logicnum) const; - int alias2ind(byte alias) const; - int name2ind(const char* name) const; - - TRelationdef* reldef(int i) const { return (TRelationdef*)&_reldefs[i]; } - TLocalisamfile* file(int i = 0) const { return (TLocalisamfile*)&_files[i]; } - - // @LONGDES - // position_rels fa tutto il lavoro: se non trova un record - // adatto su un file, svuota il record corrente e non ritorna errore. - // write etc. poi procedono normalmente - // @END - int position_rels(TIsamop op = _isequal, TReclock lockop = _nolock, TDate& atdate = (TDate&)botime, int first = 0); - - friend class TCursor; - -public: - // @FPUB - int update() { return position_rels(_isequal, _nolock);} - void zero(); - virtual int next(TReclock lockop = _nolock) { return file()->next(lockop) == NOERR ? position_rels(_isequal, lockop) : file()->status(); } - virtual int prev(TReclock lockop = _nolock) { return file()->prev(lockop) == NOERR ? position_rels(_isequal, lockop) : file()->status(); } - virtual int next(TDate& atdate) { return file()->next(atdate) == NOERR ? position_rels(_isequal, _nolock, atdate) : file()->status(); } - virtual int prev(TDate& atdate) { return file()->prev(atdate) == NOERR ? position_rels(_isequal, _nolock, atdate) : file()->status(); } - virtual int first(TReclock lockop = _nolock) { return file()->first(lockop) == NOERR ? position_rels(_isequal, lockop) : file()->status(); } - virtual int last(TReclock lockop = _nolock) { return file()->last(lockop) == NOERR ? position_rels(_isequal, lockop) : file()->status(); } - virtual int skip(TRecnotype nrec, TReclock lockop = _nolock) { return file()->skip(nrec, lockop) == NOERR ? position_rels(_isequal, lockop) : file()->status(); } - virtual int read(TIsamop op = _isgteq, TReclock lockop = _nolock, TDate& atdate = (TDate&)botime) { return file()->read(op, lockop, atdate) == NOERR ? position_rels(_isequal, lockop, atdate) : file()->status();} - - TLocalisamfile* lfile(int logicnum = 0) const; - TLocalisamfile* lfile(const char* name) const; - void write_enable(int logicnum = -1, const bool on = TRUE) ; - void write_enable(const char* name, const bool on = TRUE) ; - void write_disable(int logicnum = -1) { write_enable(logicnum, FALSE); } - void write_disable(const char* name) { write_enable(name, FALSE); } - - TRectype& curr(int logicnum = 0) const { return lfile(logicnum)->curr(); } - // next_match for 0ne-to-many relations; positions logicnum (!= main) - // on next matching record; returns TRUE or FALSE if no more matches; in - // any case relation is kept consistent except when inconsistent in - // first place - bool next_match(int logicnum, const char* fieldlist = NULL, int nkey = 0); - - // @DES add relation - // @FPUB - bool add(int logicnum, const char* relexprs, int key = 1, - int linkto = 0, byte alias = 0, bool allow_lock = FALSE); - bool add(const char* tabname, const char* relexprs, int key = 1, - int linkto = 0, byte alias = 0, bool allow_lock = FALSE); - - - // @DES write methods - // @FPUB - virtual int write (bool force = TRUE, TDate& atdate = (TDate&)botime); - virtual int rewrite(bool force = TRUE, TDate& atdate = (TDate&)botime); - virtual int remove (TDate& atdate = (TDate&)botime); - - // @DES checking methods - // @FPUB - bool eof( int logicnum = 0) { return lfile(logicnum)->eof(); } - bool bof( int logicnum = 0) { return lfile(logicnum)->bof(); } - - // @N - // status(), good() and bad() return the status of the relation when called - // with no args, or the status of the file when called with - // a logical number - // @END - - bool status(int logicnum = 0) { return lfile(logicnum)->status(); } - bool good( int logicnum = 0) { return lfile(logicnum)->good(); } - bool bad( int logicnum = 0) { return lfile(logicnum)->bad(); } - bool empty( int logicnum = 0) { return lfile(logicnum)->empty(); } - // @END - - // @LONGDES - // isconsistent() returns TRUE if every file in the relation is - // OK, current record is non-empty, and relation is consistent. - // If it's not and reset is TRUE, it tries to reset the relation - // to a consistent state (based on main record) -- no further check - // is done. - // Also called internally by update and remove. - // @END - bool isconsistent(bool reset = FALSE); - - // TRUE se c'e' un record ed e' il primo match (non si e' mai fatta - // position_rels) - bool is_first_match(int logicnum); - - void save_status () ; - void restore_status () ; - - // @DES positioning operators. return status - // @FPUB - - TRecnotype operator +=(const TRecnotype npos) { return skip(npos); } - TRecnotype operator -=(const TRecnotype npos) { return skip(-npos); } - TRecnotype operator ++() { return next(); } - TRecnotype operator --() { return prev(); } - - TRelation(int logicnum, bool linkrecinst = TRUE); - TRelation(const char* tabname, bool linkrecinst = TRUE); - virtual ~TRelation(); -}; - -// @C -// Classe TCursor : public TObject -// -// @END - -class TExpression; - -typedef bool (*FILTERFUNCTION)(const TRelation* r); - -class TCursor : public TObject -{ - // @DPRIV - TRelation* _if; - int _nkey; - TRecnotype _pos; // Posizione corrente - TRecnotype _totrec; - TRecnotype _lastrec; - TRecnotype _lastkrec; - TFilename _filename; - TString _filter; // Filtro - TString _keyfrom; // chiave iniziale - TString _keyto; // chiave finale - TExpression* _fexpr; // Espressione relativo filtro - bool _frozen; - FILTERFUNCTION _filterfunction; - TFilename _indexname; - // @END - - // @FPRIV - virtual TRecnotype buildcursor(TRecnotype rp); - int filtercursor(int pagecnt, TRecnotype* page); - bool changed(); - - FILE* open_index(bool create = FALSE) const; - TRecnotype update(); - - -protected: - TRecnotype readrec(); - void filter(const char* filter, const TRectype* from = NULL, - const TRectype* to = NULL); - -public: - // @FPUB - TRecnotype operator =(const TRecnotype nr); // Assegnazione - TCursor& operator +=(const TRecnotype nr); // Scorri avanti - TCursor& operator -=(const TRecnotype nr); // Scorri indietro - TCursor& operator ++(); // Avanti di un record - TCursor& operator --(); // Indietro di un record - TRecnotype pos() const { return _pos; } - TRecnotype items(); - TRecnotype size() const { return file()->eod(); } - const TString& from() const { return _keyfrom; } - const TString& to() const { return _keyto; } - - TRectype& curr(int log = 0) const { return _if->curr(log); } - TRectype& curr(const char * tab) const - { return _if->lfile(tab)->curr(); } - TRecnotype read(TIsamop op = _isgteq, TReclock lockop = _nolock, TDate& atdate = (TDate&)botime); - virtual bool ok() const; - - const char* filter() const { return _filter; } - void freeze(bool on = TRUE) { _frozen = on; } - bool frozen() const { return _frozen; } - void setfilter(const char* filter_expr) { filter(filter_expr); } - void setregion(const TRectype& from, const TRectype& to) - { filter(NULL,&from, &to); } - - TRelation* relation() const { return _if; } - TLocalisamfile* file(int lnum = 0) const { return _if->lfile(lnum); } - TLocalisamfile* file(const char* name) const { return _if->lfile(name); } - int repos() { return _if->position_rels(); } - - void setkey() { file()->setkey(_nkey); } - void setkey(int nkey); - int key() const { return _nkey; } - - bool next_match(int lognum, const char* fl = NULL, int nk = 0); - bool is_first_match(int ln); - - void set_filterfunction(FILTERFUNCTION ff) { _filterfunction = ff; _lastrec = 0L;} - bool has_filter() const { return _filter.not_empty() || _filterfunction; } - - void save_status () { _if->save_status(); } - void restore_status () { _if->restore_status(); } - - TCursor(TRelation* f, const char* filter = "", int key = 1, TRectype* from = NULL, TRectype* to = NULL); - virtual ~TCursor(); -}; - - -// @C -// Classe TFieldref : public TObject -// @END - -class TFieldref : public TObject -{ - // @DPRIV - short _fileid; // Numero del file - TString16 _id; // Nome tabella o stringa col numero del file - TString16 _name; // Nome del campo - int _from, _to; // Substring - -protected: - virtual void print_on(ostream& out) const; - -public: - // @FPUB - TFieldref(); - TFieldref(const TString&, short defid); - - TFieldref& operator =(const TString& s); // Operatore di assegnazione - - virtual bool ok() const { return _name.not_empty(); } // Vero se il numero del file e' valido - - int file() const { return _fileid; } // ritorna il file - const char* name() const { return (const char*) _name; } // ritorna il nome del campo - int from() const { return _from; } - int to() const { return _to; } - int len(TRectype &rec) const; - const char* read(const TRelation* = NULL) const; - const char* read(const TRectype&) const; - void write(const char* val, TRelation* = NULL) const; - void write(const char* val, TRectype& rec) const; -}; -// Converte una stringa in numero logico o numero tabella -int name2log(const char* name); -#endif -// ** EOF relation.h +/* $Id: relation.h,v 1.4 1994-09-21 11:16:32 guy Exp $ */ +// join.h +// fv 12/8/93 +// join class for isam files + +#ifndef __RELATION_H +#define __RELATION_H + +#ifndef __ARRAY_H +#include +#endif + +#ifndef __ISAM_H +#include +#endif + +// @C + +class TRelation : public TObject +{ + friend class TRelationdef; + + // class TRelation : public TLocalisamfile + // @END + + // @DPRIV + TToken_string _status; // stato della relazione + TArray _files; // file descriptors + TArray _reldefs; // TRelationdef array + int _errors; + // @END + + // @FPROT +protected: + virtual void print_on(ostream& out) const; + + int log2ind(int logicnum) const; + int alias2ind(byte alias) const; + int name2ind(const char* name) const; + + TRelationdef& reldef(int i) const { return (TRelationdef&)_reldefs[i]; } + TLocalisamfile& file(int i = 0) const { return (TLocalisamfile&)_files[i]; } + + // @LONGDES + // position_rels fa tutto il lavoro: se non trova un record + // adatto su un file, svuota il record corrente e non ritorna errore. + // write etc. poi procedono normalmente + // @END + int position_rels(TIsamop op = _isequal, TReclock lockop = _nolock, TDate& atdate = (TDate&)botime, int first = 0); + + friend class TCursor; + +public: + // @FPUB + int update() { return position_rels(_isequal, _nolock);} + void zero(); + virtual int next(TReclock lockop = _nolock) { return file().next(lockop) == NOERR ? position_rels(_isequal, lockop) : file().status(); } + virtual int prev(TReclock lockop = _nolock) { return file().prev(lockop) == NOERR ? position_rels(_isequal, lockop) : file().status(); } + virtual int next(TDate& atdate) { return file().next(atdate) == NOERR ? position_rels(_isequal, _nolock, atdate) : file().status(); } + virtual int prev(TDate& atdate) { return file().prev(atdate) == NOERR ? position_rels(_isequal, _nolock, atdate) : file().status(); } + virtual int first(TReclock lockop = _nolock) { return file().first(lockop) == NOERR ? position_rels(_isequal, lockop) : file().status(); } + virtual int last(TReclock lockop = _nolock) { return file().last(lockop) == NOERR ? position_rels(_isequal, lockop) : file().status(); } + virtual int skip(TRecnotype nrec, TReclock lockop = _nolock) { return file().skip(nrec, lockop) == NOERR ? position_rels(_isequal, lockop) : file().status(); } + virtual int read(TIsamop op = _isgteq, TReclock lockop = _nolock, TDate& atdate = (TDate&)botime) { return file().read(op, lockop, atdate) == NOERR ? position_rels(_isequal, lockop, atdate) : file().status();} + + TLocalisamfile& lfile(int logicnum = 0) const; + TLocalisamfile& lfile(const char* name) const; + void write_enable(int logicnum = -1, const bool on = TRUE) ; + void write_enable(const char* name, const bool on = TRUE) ; + void write_disable(int logicnum = -1) { write_enable(logicnum, FALSE); } + void write_disable(const char* name) { write_enable(name, FALSE); } + + TRectype& curr(int logicnum = 0) const { return lfile(logicnum).curr(); } + // next_match for 0ne-to-many relations; positions logicnum (!= main) + // on next matching record; returns TRUE or FALSE if no more matches; in + // any case relation is kept consistent except when inconsistent in + // first place + bool next_match(int logicnum, const char* fieldlist = NULL, int nkey = 0); + + // @DES add relation + // @FPUB + bool add(int logicnum, const char* relexprs, int key = 1, + int linkto = 0, byte alias = 0, bool allow_lock = FALSE); + bool add(const char* tabname, const char* relexprs, int key = 1, + int linkto = 0, byte alias = 0, bool allow_lock = FALSE); + + + // @DES write methods + // @FPUB + virtual int write (bool force = TRUE, TDate& atdate = (TDate&)botime); + virtual int rewrite(bool force = TRUE, TDate& atdate = (TDate&)botime); + virtual int remove (TDate& atdate = (TDate&)botime); + + // @DES checking methods + // @FPUB + bool eof( int logicnum = 0) { return lfile(logicnum).eof(); } + bool bof( int logicnum = 0) { return lfile(logicnum).bof(); } + + // @N + // status(), good() and bad() return the status of the relation when called + // with no args, or the status of the file when called with + // a logical number + // @END + + bool status(int logicnum = 0) { return lfile(logicnum).status(); } + bool good( int logicnum = 0) { return lfile(logicnum).good(); } + bool bad( int logicnum = 0) { return lfile(logicnum).bad(); } + bool empty( int logicnum = 0) { return lfile(logicnum).empty(); } + // @END + + // @LONGDES + // isconsistent() returns TRUE if every file in the relation is + // OK, current record is non-empty, and relation is consistent. + // If it's not and reset is TRUE, it tries to reset the relation + // to a consistent state (based on main record) -- no further check + // is done. + // Also called internally by update and remove. + // @END + bool isconsistent(bool reset = FALSE); + + // TRUE se c'e' un record ed e' il primo match (non si e' mai fatta + // position_rels) + bool is_first_match(int logicnum); + + void save_status () ; + void restore_status () ; + + // @DES positioning operators. return status + // @FPUB + + TRecnotype operator +=(const TRecnotype npos) { return skip(npos); } + TRecnotype operator -=(const TRecnotype npos) { return skip(-npos); } + TRecnotype operator ++() { return next(); } + TRecnotype operator --() { return prev(); } + + TRelation(int logicnum, bool linkrecinst = TRUE); + TRelation(const char* tabname, bool linkrecinst = TRUE); + virtual ~TRelation(); +}; + +// @C +// Classe TCursor : public TObject +// +// @END + +class TExpression; + +typedef bool (*FILTERFUNCTION)(const TRelation* r); + +class TCursor : public TObject +{ + // @DPRIV + TRelation* _if; + int _nkey; + TRecnotype _pos; // Posizione corrente + TRecnotype _totrec; + TRecnotype _lastrec; + TRecnotype _lastkrec; + TFilename _filename; + TString _filter; // Filtro + TString _keyfrom; // chiave iniziale + TString _keyto; // chiave finale + TExpression* _fexpr; // Espressione relativo filtro + bool _frozen; + FILTERFUNCTION _filterfunction; + TFilename _indexname; + // @END + + // @FPRIV + virtual TRecnotype buildcursor(TRecnotype rp); + int filtercursor(int pagecnt, TRecnotype* page); + bool changed(); + + FILE* open_index(bool create = FALSE) const; + TRecnotype update(); + + +protected: + TRecnotype readrec(); + void filter(const char* filter, const TRectype* from = NULL, + const TRectype* to = NULL); + +public: + // @FPUB + TRecnotype operator =(const TRecnotype nr); // Assegnazione + TCursor& operator +=(const TRecnotype nr); // Scorri avanti + TCursor& operator -=(const TRecnotype nr); // Scorri indietro + TCursor& operator ++(); // Avanti di un record + TCursor& operator --(); // Indietro di un record + TRecnotype pos() const { return _pos; } + TRecnotype items(); + TRecnotype size() const { return file().eod(); } + const TString& from() const { return _keyfrom; } + const TString& to() const { return _keyto; } + + TRectype& curr(int log = 0) const { return _if->curr(log); } + TRectype& curr(const char * tab) const + { return _if->lfile(tab).curr(); } + TRecnotype read(TIsamop op = _isgteq, TReclock lockop = _nolock, TDate& atdate = (TDate&)botime); + virtual bool ok() const; + + const char* filter() const { return _filter; } + void freeze(bool on = TRUE) { _frozen = on; } + bool frozen() const { return _frozen; } + void setfilter(const char* filter_expr) { filter(filter_expr); } + void setregion(const TRectype& from, const TRectype& to) + { filter(NULL,&from, &to); } + + TRelation* relation() const { return _if; } + TLocalisamfile& file(int lnum = 0) const { return _if->lfile(lnum); } + TLocalisamfile& file(const char* name) const { return _if->lfile(name); } + int repos() { return _if->position_rels(); } + + void setkey() { file().setkey(_nkey); } + void setkey(int nkey); + int key() const { return _nkey; } + + bool next_match(int lognum, const char* fl = NULL, int nk = 0); + bool is_first_match(int ln); + + void set_filterfunction(FILTERFUNCTION ff) { _filterfunction = ff; _lastrec = 0L;} + bool has_filter() const { return _filter.not_empty() || _filterfunction; } + + void save_status () { _if->save_status(); } + void restore_status () { _if->restore_status(); } + + TCursor(TRelation* f, const char* filter = "", int key = 1, TRectype* from = NULL, TRectype* to = NULL); + virtual ~TCursor(); +}; + + +// @C +// Classe TFieldref : public TObject +// @END + +class TFieldref : public TObject +{ + // @DPRIV + short _fileid; // Numero del file + TString16 _id; // Nome tabella o stringa col numero del file + TString16 _name; // Nome del campo + int _from, _to; // Substring + +protected: + virtual void print_on(ostream& out) const; + +public: + // @FPUB + TFieldref(); + TFieldref(const TString&, short defid); + + TFieldref& operator =(const TString& s); // Operatore di assegnazione + + virtual bool ok() const { return _name.not_empty(); } // Vero se il numero del file e' valido + + int file() const { return _fileid; } // ritorna il file + const char* name() const { return (const char*) _name; } // ritorna il nome del campo + int from() const { return _from; } + int to() const { return _to; } + int len(TRectype &rec) const; + const char* read(const TRelation* = NULL) const; + const char* read(const TRectype&) const; + void write(const char* val, TRelation* = NULL) const; + void write(const char* val, TRectype& rec) const; +}; +// Converte una stringa in numero logico o numero tabella +int name2log(const char* name); +#endif +// ** EOF relation.h diff --git a/include/sheet.cpp b/include/sheet.cpp index afd995f32..da6087784 100755 --- a/include/sheet.cpp +++ b/include/sheet.cpp @@ -1,753 +1,753 @@ -#include -#include -#include -#include -#include -#include -#include - -TSheet::TSheet(short x, short y, short dx, short dy, - const char* title, const char* head, byte buttons, - long first, WINDOW parent) -: _curr(first), _last_update(-1), _checkable(FALSE), - _check_enabled(TRUE), _buttonmask(buttons) -{ - const char* g; - - TToken_string new_head(512); - TToken_string h(head); - TString item(80); - - for(_columns = 0; (g = h.get()) != NULL; _columns++) - { - CHECK(_columns < MAX_COL, "To many columns in sheet "); - item = g; - - const int et = item.find('@'); - if (et >= 0) - { - _size[_columns] = atoi(item.mid(et+1)); - item.cut(et); - if (_columns == 0 && et == 0) - _checkable = _size[0] == 1; - } else _size[_columns] = item.len(); - - item.trim(); - new_head.add(item); - } - set_row(new_head, -1); - - for (int i = 0; i < MAX_BUT; i++) _button[i] = NULL_WIN; - - if (parent == NULL_WIN) parent = TASK_WIN; - - long flags = WSF_CLOSE | WSF_SIZE | WSF_VSCROLL | WSF_HSCROLL ; - WIN_TYPE wt = W_DOC; - - if (parent != TASK_WIN) - { - wt = W_PLAIN; - flags = WSF_VSCROLL; - } - - if (dx == 0) // Calculates window width - { - RCT r; get_client_rect(parent, &r); - dx = r.right/CHARX -6; - - const int larg = width(); - if (dx > larg) dx = larg; - } - if (dy == 0) dy = 20; // Calculates window height - - create(x, y, dx, dy, title, flags, wt, parent); - if (wt != W_PLAIN) // If normal sheet add buttons - { - _visible_rows = rows()- head_on() - 3; - - add_button(DLG_SELECT, "Selezione" ); - if (buttons & 0x1) add_button(DLG_NEWREC, "Gestione"); - if (buttons & 0x2) add_button(DLG_NEWREC, "Nuovo"); - if (buttons & 0x4) add_button(DLG_DELREC, "Elimina"); - if (buttons & 0x8) add_button(DLG_QUIT, "Fine"); - else add_button(DLG_CANCEL, "Annulla"); - } -} - -void TSheet::add_button(short id, const char* caption, KEY key) -{ -#if XVT_OS == XVT_OS_WIN - const int BUT_HEIGHT = 2; -#else - const int BUT_HEIGHT = 1; -#endif - - WINDOW b = xvt_create_control(WC_PUSHBUTTON, 0, 0, 11, BUT_HEIGHT, caption, win(), 0, 0, id); - for (int i = 0; i < MAX_BUT; i++) - if (_button[i] == NULL_WIN) - { - _button[i] = b; - _key[i] = key; - break; - } -} - -void TSheet::repos_buttons() const -{ - for (int buttons = 0; _button[buttons] != NULL_WIN; buttons++) - if (buttons == MAX_BUT-1) { buttons++; break; } - if (buttons == 0) return; - - RCT wr; get_client_rect(win(), &wr); - RCT br; get_client_rect(_button[0], &br); - - int space = (wr.right - buttons * br.right) / (buttons+1); - if (space < 0) space = 0; - - int x = space; - const int y = wr.bottom - br.bottom-4; - for (int b = 0; b < buttons; b++, x += br.right+space) - { - RCT r; set_rect(&r, x, y, x+br.right, y+br.bottom); - move_window(_button[b], &r); - } -} - -void TSheet::open() -{ - set_scroll_max(width(), items()); - _last_update = -1; - - if (!is_visible(_curr)) set_first(_curr); - - if (buttons_on()) - { - // Abilita selezione se c'e' almeno un elemento - xvt_enable_control(_button[0], items() > 0); - repos_buttons(); - } - TScroll_window::open(); - force_update(); -} - - -void TSheet::set_first(long n) -{ - update_thumb(-1, n); -} - - -void TSheet::set_row(const TToken_string& row, byte i) -{ - if (i > 64) i = 0; else i++; - if (_page.objptr(i) == NULL) - _page.add(row, i); - else - ((TToken_string&)_page[i]) = row; -} - - -void TSheet::build_page(long from) -{ - const long f = (from < 0) ? first() : from; - - if (_last_update != f) - { - int r = visible_rows(); - if (f+r > items()) - r = int(items()-f); - if (r > 0) - page_build(f, r); - _last_update = f; - } -} - - -short TSheet::reserved_rows() const -{ - return buttons_on() ? 3 : 0; -} - - -void TSheet::handler(WINDOW win, EVENT* ep) -{ - switch(ep->type) - { - case E_FOCUS: - invert_row(selected()); - break; - case E_MOUSE_DOWN: - if (ep->v.mouse.button) - { - dispatch_e_char(win, K_ESC); - return; - } - case E_MOUSE_DBL: - { - const short y = ep->v.mouse.where.v / CHARY; - const short f = head_on() ? 1 : 0; - if (y >= f) - { - long vec = selected(); - long nuo = first()+y-f; - select(nuo); - if (ep->type == E_MOUSE_DBL) - dispatch_e_char(win, K_ENTER); - else if (_checkable && _check_enabled && vec == nuo) - { - _checked.not(nuo); - force_update(); - } - } - else - dispatch_e_char(win, y ? K_UP : K_PREV); - } - break; - case E_CONTROL: - switch(ep->v.ctl.id) - { - case DLG_OK : - case DLG_SELECT: - dispatch_e_char(win, K_ENTER); break; - case DLG_CANCEL: - case DLG_QUIT : - dispatch_e_char(win, K_ESC); break; - case DLG_NEWREC: - dispatch_e_char(win, K_INS); break; - case DLG_DELREC: - dispatch_e_char(win, K_DEL); break; - default: - { - const WINDOW b = ep->v.ctl.ci.win; - for (int i = 0; i < MAX_BUT; i++) - if (_button[i] == b) - { - stop_run(_key[i]); - break; - } - } - break; - } - break; - case E_SIZE: - { - _last_update = -1; - _visible_rows = ep->v.size.height/CHARY - (head_on() ? 1 : 0); - if (buttons_on()) - { - _visible_rows -= reserved_rows(); - repos_buttons(); - } - force_update(); - } - break; - default: - break; - } - - TScroll_window::handler(win, ep); -} - - -PNT TSheet::log2dev(long x, long y) const -{ - if (autoscrolling()) x -= origin().x; - return TWindow::log2dev(x, y); -} - -bool TSheet::on_key(KEY key) -{ - switch(key) - { - case K_ENTER: - if (items() < 1) key = K_ESC; - case K_ESC: - stop_run(key); - case K_DEL: - if ((_buttonmask & 0x4) && items()) - stop_run(key); - break; - case K_INS: - if (_buttonmask & 0x3) - stop_run(K_INS); - break; - case K_LHOME: - select(0); - return TRUE; - case K_LEND: - select(items()-1); - return TRUE; - case K_PREV: - select(selected()-visible_rows()); - return TRUE; - case K_UP: - select(selected()-1); - return TRUE; - case K_NEXT: - select(selected()+visible_rows()); - return TRUE; - case K_DOWN: - select(selected()+1); - return TRUE; - case K_CTRL+'P': - print(); - break; - default: - for (int i = 0; i < MAX_BUT; i++) - if (_key[i] == key) - { - stop_run(key); - break; - } - break; - } - - if (_checkable && _check_enabled && items() > 0) - { - bool ok = TRUE; - switch(key) - { - case K_SPACE: _checked.not(selected()); break; - case K_F2 : uncheck(-1); break; - case K_F3 : check(-1); break; - default : ok = FALSE; break; - } - if (ok) force_update(); - } - return TScroll_window::on_key(key); -} - - -void TSheet::select(long n) -{ - if (n < 0) n = 0; else - if (n >= items()) n = items()-1; - - invert_row(_curr); - _curr = n; - - if (is_visible(_curr)) - invert_row(_curr); - else - { - const long s = (_curr < first()) ? _curr : _curr-visible_rows()+1; - set_first(s); - force_update(); - } -} - - -void TSheet::check(long n, bool on) -{ - if (n < 0) - { - if (on) - { - _checked.set(items()-1); // Force the size of Bit_array - _checked.set(); - } - else - _checked.reset(); - } - else - _checked.set(n, on); -} - - -// Converte il numero di riga assoluto nell'indice dell'array _page -int TSheet::row_to_page(long n) const -{ - long i = (n < 0) ? 0L : n-first()+1; - - if (i < 0 || i > visible_rows()) - { - error_box("Line out of screen"); - i = 0L; - } - - return (int)i; -} - - -// Converte il numero di riga assoluto nella coordinata y sulla finestra -int TSheet::row_to_win(long n) const -{ - int y = row_to_page(n); - - if (y < 1) y = 0; else - if (!head_on()) y--; - - return y; -} - - -// Calcola la larghezza totale dello sheet virtuale -int TSheet::width() const -{ - int width = 0; - for (int c = 0; c < _columns; c++) - width += _size[c]+(c > 0); - return width; -} - -void TSheet::invert_row(long n) -{ - if (win() != NULL_WIN && is_visible(n)) - { - const short y = row_to_win(n); - autoscroll(FALSE); - invert_bar(0,y,columns(),y+1); - autoscroll(TRUE); - } -} - - -bool TSheet::update_row(long n) -{ - const int i = row_to_page(n); - if (i >= _page.items()) return FALSE; - - TToken_string& t = (TToken_string&)(_page[i]); - t.restart(); - - const short y = row_to_win(n); - const char* s; - - int x = 0; - for (int j = 0; (s = t.get()) != NULL; x += _size[j++]+1) - { - int x1 = x; - if (n < 0) // Centra le testate - x1 += (_size[j]-strlen(s)) / 2; - else - if (_checkable && j == 0) - s = _checked[n] ? "X" : " "; - stringat(x1, y, s); - } - - return TRUE; -} - - -TToken_string& TSheet::row(long n) -{ - if (n < 0) n = selected(); - if (!is_visible(n)) - { - build_page(n); - set_first(n); - } - short idx = row_to_page(n); - return (TToken_string&)_page[idx]; -} - - -void TSheet::update() -{ - if (_last_update < 0) - { - set_color(COLOR_BLACK, COLOR_WHITE); - set_brush(COLOR_WHITE); - set_pen(COLOR_BLACK); - set_font(FF_FIXED); - _visible_rows = rows() - reserved_rows() - head_on(); - } - - if (head_on()) - { - const int height = visible_rows()+1; - const int width = columns()+1; - short x = -1; - for (int c = 0; c < _columns; c++) - { - x += _size[c] + 1; - line(x,0,x,height); - } - autoscroll(FALSE); - set_brush(MASK_BACK_COLOR); - bar(0,0,width,1); - if (buttons_on()) - bar(0, height, width, height+reserved_rows()+1); - autoscroll(TRUE); - } - - build_page(); - if (head_on()) update_row(-1); - - long last = first() + visible_rows(); - if (last > items()) last = items(); - for (long n = first(); n < last; n++) update_row(n); - - if (get_front_window() == win()) - invert_row(selected()); -} - -void TSheet::print() -{ - TPrinter& pr = MainApp()->printer(); - TPrintrow row; - bool ok = pr.open(); - - set_cursor(TASK_WIN, CURSOR_WAIT); - int step = visible_rows(); - for (long n = 0L; ok && n < items(); n += step) - { - set_first(n); - build_page(); - - if ((n+step) > items()) step = int(items()-n); - for (int i = 1; ok && i <= step; i++) - { - const char* s; - - TToken_string& t = (TToken_string&)_page[i]; - t.restart(); - - row.reset(); - for (int j = 0, x = 0; (s = t.get()) != NULL; x += _size[j++]+1) - row.put(s, x); - - ok = pr.print(row); - } - } - set_cursor(TASK_WIN, CURSOR_ARROW); - - if (ok) - { - pr.formfeed(); - pr.close(); - } - set_focus(); -} - -/////////////////////////////////////////////////////////// -// TArray_sheet -/////////////////////////////////////////////////////////// - -TArray_sheet::TArray_sheet(short x, short y, short dx, short dy, - const char* caption, const char* head, byte buttons, WINDOW parent) -: TSheet(x, y, dx, dy, caption, head, buttons, 0L, parent) -{} - -void TArray_sheet::page_build(long first, byte num) -{ - for (byte i = 0; i < num; i++) - set_row(data(first+i), i); -} - -long TArray_sheet::add(const TToken_string& s) -{ - const long n = _data.add(s, -1); - set_scroll_max(-1, n); - return n; -} - -long TArray_sheet::insert(const TToken_string& s, long n) -{ - _data.insert(s, (int)n); - set_scroll_max(-1, items()); - return n; -} - - -/////////////////////////////////////////////////////////// -// TCursor_sheet -/////////////////////////////////////////////////////////// - -TCursor_sheet::TCursor_sheet(TCursor* cursor, const char* fields, - const char* title, const char* head, byte buttons) -: TSheet(-1,-1, 0, 0, title,head,buttons,cursor->pos()), - _cursor(cursor), _records(cursor->items()) -{ - TToken_string fldlst(fields); - int campi = 0; - for (const char* t = fldlst.get(); t; t = fldlst.get(), campi++) - if (*t > ' ' && *t != '\"') - { - TFieldref fr(t, 0); - TRecfield* rf = new TRecfield(_cursor->curr(fr.file()), - fr.name(), fr.from(), fr.to() - 1); - _fields.add(rf, campi); - } -} - - -KEY TCursor_sheet::run() -{ - _records = _cursor->items(); - _cursor->freeze(TRUE); - const KEY k = TSheet::run(); - _cursor->freeze(FALSE); - return k; -} - - -void TCursor_sheet::page_build(long first, byte rows) -{ - TToken_string l(256); - - *_cursor = (TRecnotype)first; - for (byte r = 0; r < rows; r++, ++(*_cursor)) - { - l.cut(0); - const int last = _fields.last(); - for (int i = 0; i <= last; i++) - { - TRecfield* rf = (TRecfield*)_fields.objptr(i); - TFixed_string s(rf ? (const char*)*rf : ""); - l.add(s); - } - set_row(l, r); - } -} - -/////////////////////////////////////////////////////////// -// TBrowse_sheet -/////////////////////////////////////////////////////////// - -TBrowse_sheet::TBrowse_sheet(TCursor* cursor, const char* fields, - const char* title, const char* head, byte buttons, - TEdit_field* f, TToken_string* s) -: TCursor_sheet(cursor, fields, title, head, buttons), _field(f) - -{ -#if XVT_OS == XVT_OS_WIN - xvt_create_control(WC_EDIT, 1, -3, f->size()+1, 1, f->get(), win(), - CTL_FLAG_DISABLED, 0L, 100); -#else - xvt_create_control(WC_EDIT, 1, -3, f->size()+2, 1, f->get(), win(), - CTL_FLAG_DISABLED, 0L, 100); -#endif - - if (s && s->items() > 2) - { - int maxlen = 0; - SLIST lst = slist_new(); - for (const char* item = s->get(0); item; item = s->get()) - { - item = s->get(); - const int len = strlen(item); - if (len > maxlen) maxlen = len; - slist_add(lst, (SLIST_ELT)NULL, (char*)item, 0L); - } - - WINDOW listbox = xvt_create_control(WC_LISTBUTTON, f->size()+3, -3, maxlen+3, 3, - "", win(), 0, 0L, 99); - win_list_add(listbox, -1, (char*)lst); - slist_dispose(lst); - - TString16 id; id << f->dlg(); - const int sel = s->get_pos(id) >> 1; - win_list_set_sel(listbox, sel, TRUE); - } -} - - -short TBrowse_sheet::reserved_rows() const -{ - return TSheet::reserved_rows() + 1; -} - - -void TBrowse_sheet::repos_buttons() const -{ - TSheet::repos_buttons(); // Repos toolbar - - RCT wr; get_client_rect(win(), &wr); // Get window size - - int left = CHARX; // left coord of next control to draw - - for (int id = 99; id <= 100; id++) - { - const WINDOW w = get_ctl_window(win(), id); - if (w != NULL_WIN) - { - RCT r; get_client_rect(w, &r); - r.left = left; - r.top = wr.bottom - 4*CHARY + 4; - r.right += r.left; - r.bottom += r.top; - move_window(w, &r); - left = r.right+CHARX; // Increase left coord - } - } -} - - -bool TBrowse_sheet::on_key(KEY k) -{ - WINDOW ctl = get_ctl_window(win(), 100); - - const bool alnum = (k >= '0' && k <= '9') || - (k >= 'A' && k <= 'Z') || - (k >= 'a' && k <= 'z') || - k == ' '; - if (alnum || k == K_BACKSPACE || k == K_DEL) - { - const long oldsel = selected(); - const TString old(_field->get()); - - TString val(old.size()+1); val = old; - if (alnum) - { - if (val.len() >= field().size()) - val.cut(0); - val << char(k); - } - else val.rtrim(1); - field().set(val); - - ((TBrowse*)field().browse())->do_input(FALSE); - _cursor->read(); - if (_cursor->file()->bad()) - { - beep(); - field().set(val = old); - *_cursor = oldsel; - } - else - select(_cursor->pos()); - - if (ctl != NULL_WIN) set_title(ctl, (char*)(const char*)field().get()); - return TRUE; - } - else - { - field().reset(); - if (ctl != NULL_WIN) set_title(ctl, ""); - } - - return TSheet::on_key(k); -} - - -void TBrowse_sheet::handler(WINDOW win, EVENT* ep) -{ - if (ep->type == E_CONTROL && ep->v.ctl.id == 99) - { - const int what = win_list_get_sel_index(ep->v.ctl.ci.win); - if (what >= 0) - stop_run(K_CTRL + what); - else - set_front_window(win); - return; - } - TCursor_sheet::handler(win, ep); -} - - -KEY TBrowse_sheet::run() -{ - const bool spork = field().dirty(); // Store field status - const TString old(field().get()); - - const KEY key = TCursor_sheet::run(); - - if (key == K_ESC || key == K_F9 || key == K_INS) - { - field().set(old); // Restore field status - field().set_dirty(spork); - } - - return key; -} +#include +#include +#include +#include +#include +#include +#include + +TSheet::TSheet(short x, short y, short dx, short dy, + const char* title, const char* head, byte buttons, + long first, WINDOW parent) +: _curr(first), _last_update(-1), _checkable(FALSE), + _check_enabled(TRUE), _buttonmask(buttons) +{ + const char* g; + + TToken_string new_head(512); + TToken_string h(head); + TString item(80); + + for(_columns = 0; (g = h.get()) != NULL; _columns++) + { + CHECK(_columns < MAX_COL, "To many columns in sheet "); + item = g; + + const int et = item.find('@'); + if (et >= 0) + { + _size[_columns] = atoi(item.mid(et+1)); + item.cut(et); + if (_columns == 0 && et == 0) + _checkable = _size[0] == 1; + } else _size[_columns] = item.len(); + + item.trim(); + new_head.add(item); + } + set_row(new_head, -1); + + for (int i = 0; i < MAX_BUT; i++) _button[i] = NULL_WIN; + + if (parent == NULL_WIN) parent = TASK_WIN; + + long flags = WSF_CLOSE | WSF_SIZE | WSF_VSCROLL | WSF_HSCROLL ; + WIN_TYPE wt = W_DOC; + + if (parent != TASK_WIN) + { + wt = W_PLAIN; + flags = WSF_VSCROLL; + } + + if (dx == 0) // Calculates window width + { + RCT r; get_client_rect(parent, &r); + dx = r.right/CHARX -6; + + const int larg = width(); + if (dx > larg) dx = larg; + } + if (dy == 0) dy = 20; // Calculates window height + + create(x, y, dx, dy, title, flags, wt, parent); + if (wt != W_PLAIN) // If normal sheet add buttons + { + _visible_rows = rows()- head_on() - 3; + + add_button(DLG_SELECT, "Selezione" ); + if (buttons & 0x1) add_button(DLG_NEWREC, "Gestione"); + if (buttons & 0x2) add_button(DLG_NEWREC, "Nuovo"); + if (buttons & 0x4) add_button(DLG_DELREC, "Elimina"); + if (buttons & 0x8) add_button(DLG_QUIT, "Fine"); + else add_button(DLG_CANCEL, "Annulla"); + } +} + +void TSheet::add_button(short id, const char* caption, KEY key) +{ +#if XVT_OS == XVT_OS_WIN + const int BUT_HEIGHT = 2; +#else + const int BUT_HEIGHT = 1; +#endif + + WINDOW b = xvt_create_control(WC_PUSHBUTTON, 0, 0, 11, BUT_HEIGHT, caption, win(), 0, 0, id); + for (int i = 0; i < MAX_BUT; i++) + if (_button[i] == NULL_WIN) + { + _button[i] = b; + _key[i] = key; + break; + } +} + +void TSheet::repos_buttons() const +{ + for (int buttons = 0; _button[buttons] != NULL_WIN; buttons++) + if (buttons == MAX_BUT-1) { buttons++; break; } + if (buttons == 0) return; + + RCT wr; get_client_rect(win(), &wr); + RCT br; get_client_rect(_button[0], &br); + + int space = (wr.right - buttons * br.right) / (buttons+1); + if (space < 0) space = 0; + + int x = space; + const int y = wr.bottom - br.bottom-4; + for (int b = 0; b < buttons; b++, x += br.right+space) + { + RCT r; set_rect(&r, x, y, x+br.right, y+br.bottom); + move_window(_button[b], &r); + } +} + +void TSheet::open() +{ + set_scroll_max(width(), items()); + _last_update = -1; + + if (!is_visible(_curr)) set_first(_curr); + + if (buttons_on()) + { + // Abilita selezione se c'e' almeno un elemento + xvt_enable_control(_button[0], items() > 0); + repos_buttons(); + } + TScroll_window::open(); + force_update(); +} + + +void TSheet::set_first(long n) +{ + update_thumb(-1, n); +} + + +void TSheet::set_row(const TToken_string& row, byte i) +{ + if (i > 64) i = 0; else i++; + if (_page.objptr(i) == NULL) + _page.add(row, i); + else + ((TToken_string&)_page[i]) = row; +} + + +void TSheet::build_page(long from) +{ + const long f = (from < 0) ? first() : from; + + if (_last_update != f) + { + int r = visible_rows(); + if (f+r > items()) + r = int(items()-f); + if (r > 0) + page_build(f, r); + _last_update = f; + } +} + + +short TSheet::reserved_rows() const +{ + return buttons_on() ? 3 : 0; +} + + +void TSheet::handler(WINDOW win, EVENT* ep) +{ + switch(ep->type) + { + case E_FOCUS: + invert_row(selected()); + break; + case E_MOUSE_DOWN: + if (ep->v.mouse.button) + { + dispatch_e_char(win, K_ESC); + return; + } + case E_MOUSE_DBL: + { + const short y = ep->v.mouse.where.v / CHARY; + const short f = head_on() ? 1 : 0; + if (y >= f) + { + long vec = selected(); + long nuo = first()+y-f; + select(nuo); + if (ep->type == E_MOUSE_DBL) + dispatch_e_char(win, K_ENTER); + else if (_checkable && _check_enabled && vec == nuo) + { + _checked.not(nuo); + force_update(); + } + } + else + dispatch_e_char(win, y ? K_UP : K_PREV); + } + break; + case E_CONTROL: + switch(ep->v.ctl.id) + { + case DLG_OK : + case DLG_SELECT: + dispatch_e_char(win, K_ENTER); break; + case DLG_CANCEL: + case DLG_QUIT : + dispatch_e_char(win, K_ESC); break; + case DLG_NEWREC: + dispatch_e_char(win, K_INS); break; + case DLG_DELREC: + dispatch_e_char(win, K_DEL); break; + default: + { + const WINDOW b = ep->v.ctl.ci.win; + for (int i = 0; i < MAX_BUT; i++) + if (_button[i] == b) + { + stop_run(_key[i]); + break; + } + } + break; + } + break; + case E_SIZE: + { + _last_update = -1; + _visible_rows = ep->v.size.height/CHARY - (head_on() ? 1 : 0); + if (buttons_on()) + { + _visible_rows -= reserved_rows(); + repos_buttons(); + } + force_update(); + } + break; + default: + break; + } + + TScroll_window::handler(win, ep); +} + + +PNT TSheet::log2dev(long x, long y) const +{ + if (autoscrolling()) x -= origin().x; + return TWindow::log2dev(x, y); +} + +bool TSheet::on_key(KEY key) +{ + switch(key) + { + case K_ENTER: + if (items() < 1) key = K_ESC; + case K_ESC: + stop_run(key); + case K_DEL: + if ((_buttonmask & 0x4) && items()) + stop_run(key); + break; + case K_INS: + if (_buttonmask & 0x3) + stop_run(K_INS); + break; + case K_LHOME: + select(0); + return TRUE; + case K_LEND: + select(items()-1); + return TRUE; + case K_PREV: + select(selected()-visible_rows()); + return TRUE; + case K_UP: + select(selected()-1); + return TRUE; + case K_NEXT: + select(selected()+visible_rows()); + return TRUE; + case K_DOWN: + select(selected()+1); + return TRUE; + case K_CTRL+'P': + print(); + break; + default: + for (int i = 0; i < MAX_BUT; i++) + if (_key[i] == key) + { + stop_run(key); + break; + } + break; + } + + if (_checkable && _check_enabled && items() > 0) + { + bool ok = TRUE; + switch(key) + { + case K_SPACE: _checked.not(selected()); break; + case K_F2 : uncheck(-1); break; + case K_F3 : check(-1); break; + default : ok = FALSE; break; + } + if (ok) force_update(); + } + return TScroll_window::on_key(key); +} + + +void TSheet::select(long n) +{ + if (n < 0) n = 0; else + if (n >= items()) n = items()-1; + + invert_row(_curr); + _curr = n; + + if (is_visible(_curr)) + invert_row(_curr); + else + { + const long s = (_curr < first()) ? _curr : _curr-visible_rows()+1; + set_first(s); + force_update(); + } +} + + +void TSheet::check(long n, bool on) +{ + if (n < 0) + { + if (on) + { + _checked.set(items()-1); // Force the size of Bit_array + _checked.set(); + } + else + _checked.reset(); + } + else + _checked.set(n, on); +} + + +// Converte il numero di riga assoluto nell'indice dell'array _page +int TSheet::row_to_page(long n) const +{ + long i = (n < 0) ? 0L : n-first()+1; + + if (i < 0 || i > visible_rows()) + { + error_box("Line out of screen"); + i = 0L; + } + + return (int)i; +} + + +// Converte il numero di riga assoluto nella coordinata y sulla finestra +int TSheet::row_to_win(long n) const +{ + int y = row_to_page(n); + + if (y < 1) y = 0; else + if (!head_on()) y--; + + return y; +} + + +// Calcola la larghezza totale dello sheet virtuale +int TSheet::width() const +{ + int width = 0; + for (int c = 0; c < _columns; c++) + width += _size[c]+(c > 0); + return width; +} + +void TSheet::invert_row(long n) +{ + if (win() != NULL_WIN && is_visible(n)) + { + const short y = row_to_win(n); + autoscroll(FALSE); + invert_bar(0,y,columns(),y+1); + autoscroll(TRUE); + } +} + + +bool TSheet::update_row(long n) +{ + const int i = row_to_page(n); + if (i >= _page.items()) return FALSE; + + TToken_string& t = (TToken_string&)(_page[i]); + t.restart(); + + const short y = row_to_win(n); + const char* s; + + int x = 0; + for (int j = 0; (s = t.get()) != NULL; x += _size[j++]+1) + { + int x1 = x; + if (n < 0) // Centra le testate + x1 += (_size[j]-strlen(s)) / 2; + else + if (_checkable && j == 0) + s = _checked[n] ? "X" : " "; + stringat(x1, y, s); + } + + return TRUE; +} + + +TToken_string& TSheet::row(long n) +{ + if (n < 0) n = selected(); + if (!is_visible(n)) + { + build_page(n); + set_first(n); + } + short idx = row_to_page(n); + return (TToken_string&)_page[idx]; +} + + +void TSheet::update() +{ + if (_last_update < 0) + { + set_color(COLOR_BLACK, COLOR_WHITE); + set_brush(COLOR_WHITE); + set_pen(COLOR_BLACK); + set_font(FF_FIXED); + _visible_rows = rows() - reserved_rows() - head_on(); + } + + if (head_on()) + { + const int height = visible_rows()+1; + const int width = columns()+1; + short x = -1; + for (int c = 0; c < _columns; c++) + { + x += _size[c] + 1; + line(x,0,x,height); + } + autoscroll(FALSE); + set_brush(MASK_BACK_COLOR); + bar(0,0,width,1); + if (buttons_on()) + bar(0, height, width, height+reserved_rows()+1); + autoscroll(TRUE); + } + + build_page(); + if (head_on()) update_row(-1); + + long last = first() + visible_rows(); + if (last > items()) last = items(); + for (long n = first(); n < last; n++) update_row(n); + + if (get_front_window() == win()) + invert_row(selected()); +} + +void TSheet::print() +{ + TPrinter& pr = MainApp()->printer(); + TPrintrow row; + bool ok = pr.open(); + + set_cursor(TASK_WIN, CURSOR_WAIT); + int step = visible_rows(); + for (long n = 0L; ok && n < items(); n += step) + { + set_first(n); + build_page(); + + if ((n+step) > items()) step = int(items()-n); + for (int i = 1; ok && i <= step; i++) + { + const char* s; + + TToken_string& t = (TToken_string&)_page[i]; + t.restart(); + + row.reset(); + for (int j = 0, x = 0; (s = t.get()) != NULL; x += _size[j++]+1) + row.put(s, x); + + ok = pr.print(row); + } + } + set_cursor(TASK_WIN, CURSOR_ARROW); + + if (ok) + { + pr.formfeed(); + pr.close(); + } + set_focus(); +} + +/////////////////////////////////////////////////////////// +// TArray_sheet +/////////////////////////////////////////////////////////// + +TArray_sheet::TArray_sheet(short x, short y, short dx, short dy, + const char* caption, const char* head, byte buttons, WINDOW parent) +: TSheet(x, y, dx, dy, caption, head, buttons, 0L, parent) +{} + +void TArray_sheet::page_build(long first, byte num) +{ + for (byte i = 0; i < num; i++) + set_row(data(first+i), i); +} + +long TArray_sheet::add(const TToken_string& s) +{ + const long n = _data.add(s, -1); + set_scroll_max(-1, n); + return n; +} + +long TArray_sheet::insert(const TToken_string& s, long n) +{ + _data.insert(s, (int)n); + set_scroll_max(-1, items()); + return n; +} + + +/////////////////////////////////////////////////////////// +// TCursor_sheet +/////////////////////////////////////////////////////////// + +TCursor_sheet::TCursor_sheet(TCursor* cursor, const char* fields, + const char* title, const char* head, byte buttons) +: TSheet(-1,-1, 0, 0, title,head,buttons,cursor->pos()), + _cursor(cursor), _records(cursor->items()) +{ + TToken_string fldlst(fields); + int campi = 0; + for (const char* t = fldlst.get(); t; t = fldlst.get(), campi++) + if (*t > ' ' && *t != '\"') + { + TFieldref fr(t, 0); + TRecfield* rf = new TRecfield(_cursor->curr(fr.file()), + fr.name(), fr.from(), fr.to() - 1); + _fields.add(rf, campi); + } +} + + +KEY TCursor_sheet::run() +{ + _records = _cursor->items(); + _cursor->freeze(TRUE); + const KEY k = TSheet::run(); + _cursor->freeze(FALSE); + return k; +} + + +void TCursor_sheet::page_build(long first, byte rows) +{ + TToken_string l(256); + + *_cursor = (TRecnotype)first; + for (byte r = 0; r < rows; r++, ++(*_cursor)) + { + l.cut(0); + const int last = _fields.last(); + for (int i = 0; i <= last; i++) + { + TRecfield* rf = (TRecfield*)_fields.objptr(i); + TFixed_string s(rf ? (const char*)*rf : ""); + l.add(s); + } + set_row(l, r); + } +} + +/////////////////////////////////////////////////////////// +// TBrowse_sheet +/////////////////////////////////////////////////////////// + +TBrowse_sheet::TBrowse_sheet(TCursor* cursor, const char* fields, + const char* title, const char* head, byte buttons, + TEdit_field* f, TToken_string* s) +: TCursor_sheet(cursor, fields, title, head, buttons), _field(f) + +{ +#if XVT_OS == XVT_OS_WIN + xvt_create_control(WC_EDIT, 1, -3, f->size()+1, 1, f->get(), win(), + CTL_FLAG_DISABLED, 0L, 100); +#else + xvt_create_control(WC_EDIT, 1, -3, f->size()+2, 1, f->get(), win(), + CTL_FLAG_DISABLED, 0L, 100); +#endif + + if (s && s->items() > 2) + { + int maxlen = 0; + SLIST lst = slist_new(); + for (const char* item = s->get(0); item; item = s->get()) + { + item = s->get(); + const int len = strlen(item); + if (len > maxlen) maxlen = len; + slist_add(lst, (SLIST_ELT)NULL, (char*)item, 0L); + } + + WINDOW listbox = xvt_create_control(WC_LISTBUTTON, f->size()+3, -3, maxlen+3, 3, + "", win(), 0, 0L, 99); + win_list_add(listbox, -1, (char*)lst); + slist_dispose(lst); + + TString16 id; id << f->dlg(); + const int sel = s->get_pos(id) >> 1; + win_list_set_sel(listbox, sel, TRUE); + } +} + + +short TBrowse_sheet::reserved_rows() const +{ + return TSheet::reserved_rows() + 1; +} + + +void TBrowse_sheet::repos_buttons() const +{ + TSheet::repos_buttons(); // Repos toolbar + + RCT wr; get_client_rect(win(), &wr); // Get window size + + int left = CHARX; // left coord of next control to draw + + for (int id = 99; id <= 100; id++) + { + const WINDOW w = get_ctl_window(win(), id); + if (w != NULL_WIN) + { + RCT r; get_client_rect(w, &r); + r.left = left; + r.top = wr.bottom - 4*CHARY + 4; + r.right += r.left; + r.bottom += r.top; + move_window(w, &r); + left = r.right+CHARX; // Increase left coord + } + } +} + + +bool TBrowse_sheet::on_key(KEY k) +{ + WINDOW ctl = get_ctl_window(win(), 100); + + const bool alnum = (k >= '0' && k <= '9') || + (k >= 'A' && k <= 'Z') || + (k >= 'a' && k <= 'z') || + k == ' '; + if (alnum || k == K_BACKSPACE || k == K_DEL) + { + const long oldsel = selected(); + const TString old(_field->get()); + + TString val(old.size()+1); val = old; + if (alnum) + { + if (val.len() >= field().size()) + val.cut(0); + val << char(k); + } + else val.rtrim(1); + field().set(val); + + ((TBrowse*)field().browse())->do_input(FALSE); + _cursor->read(); + if (_cursor->file().bad()) + { + beep(); + field().set(val = old); + *_cursor = oldsel; + } + else + select(_cursor->pos()); + + if (ctl != NULL_WIN) set_title(ctl, (char*)(const char*)field().get()); + return TRUE; + } + else + { + field().reset(); + if (ctl != NULL_WIN) set_title(ctl, ""); + } + + return TSheet::on_key(k); +} + + +void TBrowse_sheet::handler(WINDOW win, EVENT* ep) +{ + if (ep->type == E_CONTROL && ep->v.ctl.id == 99) + { + const int what = win_list_get_sel_index(ep->v.ctl.ci.win); + if (what >= 0) + stop_run(K_CTRL + what); + else + set_front_window(win); + return; + } + TCursor_sheet::handler(win, ep); +} + + +KEY TBrowse_sheet::run() +{ + const bool spork = field().dirty(); // Store field status + const TString old(field().get()); + + const KEY key = TCursor_sheet::run(); + + if (key == K_ESC || key == K_F9 || key == K_INS) + { + field().set(old); // Restore field status + field().set_dirty(spork); + } + + return key; +} diff --git a/include/viswin.cpp b/include/viswin.cpp index 47a276684..d11a533fb 100755 --- a/include/viswin.cpp +++ b/include/viswin.cpp @@ -1,1891 +1,1888 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef __PRINTER_H -typedef void (*LINKHANDLER) (int, const char *); -#endif - -#if XVT_OS == XVT_OS_WIN -extern "C" -{ -#include -} -#endif - -#define BUTTONROW_SIZE 3 -#define W_X1 (origin().x+5) -#define W_Y1 (origin().y+1) -#define W_X2 (origin().x+columns()) -#define W_Y2 (origin().y+rows()+1-BUTTONROW_SIZE) -#define TEXTROWS (rows() - 1 - BUTTONROW_SIZE) -#define TEXTCOLUMNS (columns() - 6) - -#define DLG_QUIT_TITLE "Fine" -#define DLG_EDIT_TITLE "Edit" -#define DLG_LINK_TITLE "Collega" -#define DLG_PRINT_TITLE "Stampa" - -#if XVT_OS == XVT_OS_WIN -#define BACKGROUND MASK_BACK_COLOR -#define FOREGROUND COLOR_BLACK -#else -#define BACKGROUND COLOR_BLACK -#define FOREGROUND COLOR_WHITE -#endif - -#define K_CTRL_DOWN (K_CTRL + K_DOWN) -#define K_CTRL_UP (K_CTRL + K_UP) -#define K_SHIFT_UP (K_SHIFT + K_UP) -#define K_SHIFT_DOWN (K_SHIFT + K_DOWN) -#define K_SHIFT_LEFT (K_SHIFT + K_RIGHT) -#define K_SHIFT_RIGHT (K_SHIFT + K_LEFT) -#define K_ALT_RIGHT (K_CTRL + 'K') -#define K_ALT_LEFT (K_CTRL + 'L') -#define CTRL_C ('C') -#define CTRL_E ('E') -#define CTRL_S ('S') -#define CTRL_R ('R') - -// vista la mania degli 883, eccoti un po' di concerti di Mozart -const long E_ADDLINE = 488l; -const long E_ADDLINE_ONSCREEN = 467l; - - -void TViswin::exec_link() -{ - if (_linkID != -1) - { - LINKHANDLER pl = MainApp ()->printer ().getlinkhandler (); - if (pl) - (*pl) (_linkID, _multiple ? (const char *) _multiple_link : - _linktxt); - - // dai opzione per rifare la stampa se e' arrivato un messaggio - // dall'applicazione chiamata - // schiaffa indi il tutto in una funzione - TMailbox m; - if (m.next_s(MSG_LN) != NULL) - { - if (yesno_box("Si desidera riaggiornare la stampa?")) - { - ((TPrint_application*)MainApp())->repeat_print(); -#if XVT_OS == XVT_OS_WIN - xvt_statbar_set (""); - xvt_statbar_refresh (); -#endif - stop_run(K_ENTER); - } - } - - set_focus(); - check_link(); - _need_update = TRUE; - force_update(); - do_events(); - check_link (&_point); - } - else - beep(); -} - - - -void TViswin::display_link (long y, long x1, long x2, const char *d) -{ - if (!_link_displayed) - { - paint_link (y, x1, x2); - _link_displayed = TRUE; -#if XVT_OS == XVT_OS_WIN - xvt_statbar_set (d); - xvt_statbar_refresh (); -#endif - xvt_enable_control (_link_button, TRUE); - } -} - - -void TViswin::erase_link (long y, long x1, long x2) -{ - if (_link_displayed) - { - paint_link (y, x1, x2); - _link_displayed = FALSE; -#if XVT_OS == XVT_OS_WIN - xvt_statbar_set (""); - xvt_statbar_refresh (); -#endif - xvt_enable_control (_link_button, FALSE); - } -} - -void TViswin::paint_link (long y, long x1, long x2) -{ - if (adjust_box (x1, x2, y)) - invert_bar ((int) (x1 + 6l), (int) (y + 1l), (int) (x2 + 6l), (int) (y + 2l)); -} - -bool TViswin::adjust_box (long &x1, long &x2, long y) -{ - if (y < origin ().y || y > origin ().y + _textrows) - return FALSE; - if (origin ().x > x1) - x1 = origin ().x; - if (origin ().x + _textcolumns < x2) - x2 = origin ().x + _textcolumns; - return TRUE; -} - -bool TViswin::check_link (TPoint * p) -{ - static char descr[128], pdescr[128]; - static int old_id = -1, plinkID = -1; - static long y, x1, x2; - static long py, px1, px2; - - if (p == NULL) // erase and go - - { - if (old_id != -1) - { - erase_link (y, x1, x2); - old_id = _linkID = plinkID = -1; - py = px1 = px2 = x1 = y = x2 = 0l; - } - return FALSE; - } - - // poi se e' il caso lo si risistema - if (p == &_point) - plinkID = -1; - - for (int i = 0; i < _hotspots->items (); i++) - { - TToken_string & t = (TToken_string &) (*_hotspots)[i]; - t.restart (); - long ty = t.get_long (); - long tx1 = t.get_long (); - long tx2 = t.get_long (); - if (p->y == ty && p->x < tx2 && p->x >= tx1) - { - // ci siamo - int id = (int) t.get_long (4); - - if (ty != y || tx1 != x1 || tx2 != x2) - { - if (old_id != -1) - erase_link (y, x1, x2); - TToken_string & ttt = (TToken_string &) (*_links)[id]; - ttt.restart (); - strcpy (descr, ttt.get ()); - strcat (descr, t.get (3)); - strcpy (_linktxt, t.get (3)); - if (_multiple) - { - // get all parts of the same color - const char *cp; - _txt.read_line (ty); - _multiple_link = ""; - - while (cp = _txt.piece ()) - { - if (_txt.get_foreground () == *(ttt.get (1)) && - _txt.get_background () == *(ttt.get (2))) - _multiple_link.add (cp); - } - } - old_id = _linkID = id; - y = ty; - x1 = tx1; - x2 = tx2; - display_link (y, x1, x2, descr); - } - if (p == &_point) - { - strcpy (pdescr, descr); - plinkID = id; - px1 = x1; - px2 = x2; - py = y; - } - return TRUE; - } - } - // non sono su un bottone: puo' esserci il point - if (old_id != -1 && plinkID == -1) - { - old_id = _linkID = -1; - erase_link (y, x1, x2); - x1 = x2 = y = 0l; - } - // se point e' su un bottone, evidenzia quello - else if (plinkID != -1 && (x1 != px1 || x2 != px2 || y != py)) - { - // erase old one - erase_link (y, x1, x2); - old_id = _linkID = plinkID; - x1 = px1; - x2 = px2; - y = py; - strcpy (descr, pdescr); - display_link (y, x1, x2, descr); - return TRUE; - } - return FALSE; -} - -bool TViswin::in_text (const TPoint & p) const -{ - if (p.x > 5 && p.x < columns () && p.y > 0 && p.y < (rows () - 3)) - return TRUE; - return FALSE; -} - - -bool TViswin::need_paint_sel (bool smart) -{ - TPoint p1, p2; - adjust_selection (p1, p2); - long end = origin ().y + _textrows; - bool r = _isselection; - if (smart) - r = r && ( - (origin ().y >= p1.y - 1 && origin ().y <= p2.y + 1) || - (end >= p1.y - 1 && end <= p2.y + 1)); - return r; -} - -void TViswin::erase_selection () -{ - if (_sel_displayed) - paint_selection (); - _sel_displayed = FALSE; -} - -void TViswin::display_selection () -{ - if (!_sel_displayed) - paint_selection (); - _sel_displayed = TRUE; -} - -void TViswin::adjust_selection (TPoint & p1, TPoint & p2) -{ - if (_sel_start.y < _sel_end.y) - { - p1 = _sel_start; - p2 = _sel_end; - } - else - { - p1 = _sel_end; - p2 = _sel_start; - } -} - -void TViswin::shift_screen (scroll dir) -{ - RCT r; - - if (_scrolling) - return; - _scrolling = TRUE; - // origin() e' gia' stata modificata - switch (dir) - { - case up: - case down: - set_rect (&r, 0, CHARY + 2, (int) (CHARX * (_textcolumns + 6)), (int) (CHARY * (_textrows + 1))); - win_scroll_rect (win (), &r, 0, dir == down ? CHARY : -CHARY); - paint_row (dir == up ? origin ().y + _textrows - 1 : origin ().y); - break; - case left: - case right: - set_rect (&r, CHARX * 6, 0, (int) (CHARX * (_textcolumns + 6) + 2), (int) (CHARY * (_textrows + 1) - 2)); - win_scroll_rect (win (), &r, dir == right ? CHARX : -CHARX, 0); - paint_column (dir == left ? origin ().x + _textcolumns - 1 : origin ().x, - dir == left); - break; - default: - break; - } - _scrolling = FALSE; -} - -WINDOW TViswin::add_button (short id, const char *caption) -{ - const int BUT_HEIGHT = -#if XVT_OS == XVT_OS_WIN - 2 -#else - 1 -#endif - ; - WINDOW b = xvt_create_control (WC_PUSHBUTTON, 0, 0, 11, - BUT_HEIGHT, caption, win (), 0, 0, id); - - for (int i = 0; i < MAXBUT; i++) - if (_button[i] == NULL_WIN) - { - _button[i] = b; - break; - } - return b; -} - -void TViswin::repos_buttons () -{ - for (int buttons = 0; _button[buttons] != NULL_WIN; buttons++) - if (buttons == MAXBUT - 1) - { - buttons++; - break; - } - - if (buttons == 0) - return; - - autoscroll (FALSE); - set_mode (M_COPY); - set_brush (MASK_BACK_COLOR); - bar (5, rows () - 3, columns () + 1, rows () + 1); - autoscroll (TRUE); - - RCT wr; - get_client_rect (win (), &wr); - RCT br; - get_client_rect (_button[0], &br); - - int space = (wr.right - buttons * br.right) / (buttons + 1); - if (space < 0) - space = 0; - - int x = space; - const int y = wr.bottom - br.bottom - 4; - for (int b = 0; b < buttons; b++, x += br.right + space) - { - RCT r; - set_rect (&r, x, y, x + br.right, y + br.bottom); - move_window (_button[b], &r); - } -} - -void TViswin::open () -{ - set_scroll_max (MAXLEN, _txt.lines () <= _textrows ? _txt.lines () : _txt.lines () - _textrows); - repos_buttons (); - TScroll_window ::open (); - _need_update = TRUE; - force_update (); -} - -// prints the window contents -void TViswin::paint_screen () -{ - bool first = TRUE; - for (long j = 0; j < _textrows; j++) - { - long rw = origin ().y + j; - if (rw < _txt.lines ()) - paint_row (rw); - else if (!_isopen) - { -#if XVT_OS == XVT_OS_WIN - autoscroll (FALSE); - set_mode (M_COPY); - set_pen (COLOR_BLACK); - - PNT b, e; - b.h = CHARX * 5; - b.v = (CHARY * (int) (j + 1l - origin ().y)) - 2; - e.h = CHARX * columns (); - e.v = b.v; - win_move_to (win (), b); - win_draw_line (win (), e); - set_pen (COLOR_LTGRAY); - e.v++; - b.v++; - win_move_to (win (), b); - win_draw_line (win (), e); - set_brush (COLOR_DKGRAY); - bar (5, (int) (j + 1l - origin ().y), (int) columns (), (int) (rows () - 3l)); - autoscroll (TRUE); - break; -#endif - } - } -} - -void TViswin::paint_background (long j, int row) -{ - if (!_isbackground) - return; - int rw = (int) (j % (long) _formlen); - TString & rwd = (TString &) (*_bg)[rw]; - int cnt = 0; - char ch; - - char curcol = 'n'; - char curpen = 'n'; - char curpat = 'n'; - char curwid = '1'; - - unsigned int x1, x2; - PNT b, e; - while (ch = rwd[cnt++]) - { - switch (ch) - { - case 'v': // verticale intera - - x1 = (unsigned char) rwd[cnt++] + 5; - b.h = e.h = x1 * CHARX + CHARX / 2; - b.v = row * CHARY; - e.v = (row + 1) * CHARY; - win_move_to (win (), b); - win_draw_line (win (), e); - break; - case 'o': // verticale pezzo sopra - - x1 = (unsigned char) rwd[cnt++] + 5; - b.h = e.h = x1 * CHARX + CHARX / 2; - b.v = row * CHARY; - e.v = (row + 1) * CHARY - CHARY / 2; - win_move_to (win (), b); - win_draw_line (win (), e); - break; - case 'u': // verticale pezzo sotto - - x1 = (unsigned char) rwd[cnt++] + 5; - b.h = e.h = x1 * CHARX + CHARX / 2; - b.v = row * CHARY + CHARY / 2; - e.v = (row + 1) * CHARY; - win_move_to (win (), b); - win_draw_line (win (), e); - break; - case 'h': // orizzontale intera - - x1 = (unsigned char) rwd[cnt++] + 5; - x2 = (unsigned char) rwd[cnt++] + 5; - b.v = e.v = row * CHARY + CHARY / 2; - b.h = x1 * CHARX; - e.h = (x2 + 1) * CHARX; - win_move_to (win (), b); - win_draw_line (win (), e); - break; - case 'r': // orizzontale scorciata agli estremi - - x1 = (unsigned char) rwd[cnt++] + 5; - x2 = (unsigned char) rwd[cnt++] + 5; - b.v = e.v = row * CHARY + CHARY / 2; - b.h = x1 * CHARX + CHARX / 2; - e.h = x2 * CHARX + CHARX / 2; - win_move_to (win (), b); - win_draw_line (win (), e); - break; - case 'W': - curwid = rwd[cnt++]; - set_pen (trans_color (curcol), curwid - '0', trans_brush (curpat), - trans_pen (curpen)); - break; - case 'P': - curpen = rwd[cnt++]; - set_pen (trans_color (curcol), curwid - '0', trans_brush (curpat), - trans_pen (curpen)); - break; - case 'B': - curpat = rwd[cnt++]; - set_pen (trans_color (curcol), curwid - '0', trans_brush (curpat), - trans_pen (curpen)); - break; - case 'C': - curcol = rwd[cnt++]; - set_pen (trans_color (curcol), curwid - '0', trans_brush (curpat), - trans_pen (curpen)); - break; - default: - break; - } - } - // restore default pen - set_pen (COLOR_BLACK); -} - -void TViswin::paint_row (long j) -{ - // int or = (int)origin().x; - long y = origin ().y; - TPoint p1, p2; - if (need_paint_sel (FALSE)) - adjust_selection (p1, p2); - int row = (int) (j + 1l - y); - static char fill[] = " " - " "; - autoscroll (FALSE); - set_font (FF_FIXED, 0); - set_mode (M_COPY); - set_opaque_text (TRUE); - set_color (FOREGROUND, BACKGROUND); - printat (0, row, "%05ld", j + 1); - if (_scrolling) - { - hide_pen (); - set_brush (COLOR_WHITE); - RCT r; - r.top = row * CHARY; - r.left = CHARX * 5, - r.bottom = r.top + CHARY + 2; - r.right = CHARX * 255; - win_draw_rect (win (), &r); - } - const char *cp; - int pos = 0; - _txt.read_line (j, origin ().x); - while (cp = _txt.piece ()) - { -#if XVT_OS != XVT_OS_SCOUNIX - int st = _txt.get_style (); - long bg = trans_color (_txt.get_background ()); - long fg = trans_color (_txt.get_foreground ()); - set_font (FF_FIXED, st & 0x000f); - set_color (fg, bg); -#else - set_color (COLOR_BLACK, COLOR_WHITE); -#endif - printat (6 + pos, row, "%s", cp); -#if XVT_OS == XVT_OS_WIN - if (st & underlined) - { - PNT b, e; - - set_pen (COLOR_BLACK); - b.h = CHARX * (6 + pos); - b.v = (row + 1) * CHARY; - e.h = CHARX * (6 + pos + strlen (cp)); - e.v = (row + 1) * CHARY; - win_move_to (win (), b); - win_draw_line (win (), e); - } -#endif - pos += strlen (cp); - } - if (_scrolling && (pos < _textcolumns)) - { - set_color (COLOR_BLACK, COLOR_WHITE); - printat (6 + pos, row, "%s", fill); - } -#if XVT_OS == XVT_OS_WIN // paint page limits - if ((j % _formlen) == (_formlen - 1)) // last row - - { - PNT b, e; - - b.h = CHARX * 5; - b.v = (row + 1) * CHARY - 1; - e.h = CHARX * 132; - e.v = (row + 1) * CHARY - 1; - set_pen (COLOR_LTGRAY, 2, PAT_SOLID, P_DASH); - win_move_to (win (), b); - win_draw_line (win (), e); - } -#endif - paint_background (j, row); - autoscroll (TRUE); -} - -void TViswin::paint_column (long j, bool end) -{ - paint_header (); - set_opaque_text (TRUE); - set_mode (M_COPY); - TPoint p1, p2; - if (need_paint_sel (FALSE)) - adjust_selection (p1, p2); - set_color (COLOR_BLACK, COLOR_WHITE); - - autoscroll (FALSE); - for (long l = 0l; l < _textrows && l < (_txt.lines () - origin ().y); l++) - { - const char *c = (const char *) _txt.line (origin ().y + l); -#if XVT_OS != XVT_OS_SCOUNIX - int st = _txt.get_style ((int) j); - set_font (FF_FIXED, st & 0x000f); - long bg = trans_color (_txt.get_background ((int) j)); - long fg = trans_color (_txt.get_foreground ((int) j)); - set_color (fg, bg); -#endif - int col = end ? (int) (_textcolumns + 5) : 6; - printat (col, (int) l + 1, "%c", - (unsigned int) j < strlen (c) ? c[(int) j] : ' '); -#if XVT_OS == XVT_OS_WIN - if ((st & underlined) && strlen (c) > (word) j) - { - PNT b, e; - - set_pen (COLOR_BLACK); - b.h = CHARX * col; - b.v = (int) (l + 2l) * CHARY; - e.h = CHARX * (col + 1); - e.v = (int) (l + 2l) * CHARY; - win_move_to (win (), b); - win_draw_line (win (), e); - } -#endif - paint_background ((int) l, (int) l + 1); - } - autoscroll (TRUE); -} - -void TViswin::draw_crossbars () - // prints reference crossbars -{ -#if XVT_OS == XVT_OS_WIN - - if (_cross.v > CHARY && _cross.v < (rows () - 3) * CHARY && - _cross.h > CHARX * 5 && _cross.h < columns () * CHARX) - { - set_pen (COLOR_BLACK); - set_mode (M_XOR); - - PNT b1, e1, b2, e2; - - autoscroll (FALSE); - b1.h = _cross.h; - b1.v = CHARY; - e1.h = _cross.h; - e1.v = ((rows () - 3) * CHARY); - b2.h = CHARX * 5; - b2.v = _cross.v; - e2.h = CHARX * columns (); - e2.v = _cross.v; - win_move_to (win (), b1); - win_draw_line (win (), e1); - win_move_to (win (), b2); - win_draw_line (win (), e2); - autoscroll (TRUE); - } -#endif -} - -void TViswin::display_crossbar () -{ - if (!_cross_displayed) - draw_crossbars (); - _cross_displayed = TRUE; -} - -void TViswin::erase_crossbar () -{ - if (_cross_displayed) - draw_crossbars (); - _cross_displayed = FALSE; -} - -void TViswin::display_point () -{ - - if (!_point_displayed) - paint_point (); - _point_displayed = TRUE; -} - -void TViswin::erase_point () -{ - if (_point_displayed) - paint_point (); - _point_displayed = FALSE; -} - -void TViswin::paint_point (bool erase) -{ - autoscroll (FALSE); - static bool wasbar; - - if (_isbar) - { - invert_bar (6, (int) (_point.y - origin ().y + 1l), - (int) columns (), (int) (_point.y - origin ().y + 2l)); - invert_bar ((int) (_point.x - origin ().x + 6l), 1, - (int) (_point.x - origin ().x + 7l), (int) (rows () - 3l)); - } - else - { - invert_bar ((int) (_point.x - origin ().x + 6l), (int) (_point.y - origin ().y + 1l), - (int) (_point.x - origin ().x + 7l), (int) (_point.y - origin ().y + 2l)); - invert_bar (0, (int) (_point.y - origin ().y + 1l), 5, - (int) (_point.y - origin ().y + 2l)); - invert_bar ((int) (_point.x - origin ().x + 6l), 0, - (int) (_point.x - origin ().x + 7l), 1); - } - autoscroll (TRUE); - wasbar = _isbar; -} - -// draw screen header -void TViswin::paint_header () -{ - set_mode (M_COPY); - set_opaque_text (TRUE); - set_color (FOREGROUND, BACKGROUND); - set_font (FF_FIXED, 0); - TString htmpst (10); - for (int i = 1; i < 26; i++) - { - htmpst.format ("%d", i); - htmpst.right_just (10, '.'); - printat (i * 10 - 4, (int) origin ().y, "%s", (const char *) htmpst); - } - autoscroll (FALSE); - set_color (COLOR_WHITE, BACKGROUND); - printat (0, 0, "P.%3ld ", ((origin ().y) / _formlen) + 1l); - autoscroll (TRUE); -} - -void TViswin::paint_selection () -{ - TPoint p1, p2; - adjust_selection (p1, p2); - - // paint rows - for (long l = p1.y; l <= p2.y; l++) - { - int top, left, right; - top = (int) (l - origin ().y + 1); - if (top > 0 && top <= _textrows) - { - left = p1.y == l ? (int) (p1.x - origin ().x + 6l) : 6; - right = p2.y == l ? (int) (p2.x - origin ().x + 6l) : - (int) (_textcolumns + 6l); - autoscroll (FALSE); - invert_bar (left, top, right, top + 1); - autoscroll (TRUE); - } - } -} - -void TViswin::paint_waitbar (bool xor) -{ -#if XVT_OS == XVT_OS_WIN - static int pic; -#endif - autoscroll (FALSE); - if (xor) - { -#if XVT_OS == XVT_OS_WIN - cpb_win_picture_draw_at (win (), _picture[pic], 4, 4 + (int) (rows () - 3l) * CHARY); - if (pic == 3) - pic = 0; - else - pic++; -#else - invert_bar (3, rows () - 2, 4, rows () - 1); -#endif - } - else - { -#if XVT_OS == XVT_OS_WIN - cpb_win_picture_draw_at (win (), _picture[pic], 4, - 4 + (int) (rows () - 3l) * CHARY); - if (pic == 3) - pic = 0; - else - pic++; -#else - printat (3, rows () - 2, "%c", '*'); -#endif - } - autoscroll (TRUE); -} - -void TViswin::update () -{ - if (_scrolling) - return; - - erase_point (); - autoscroll (FALSE); - set_mode (M_COPY); - set_brush (MASK_BACK_COLOR); - bar (5, rows () - 3, columns () + 1, rows () + 1); - - if (_need_update) - { - if (_isselection) - erase_selection (); - clear (COLOR_WHITE); - set_mode (M_COPY); - set_brush (MASK_BACK_COLOR); - autoscroll (FALSE); - bar (0, 0, columns () + 1, 1); - bar (0, 0, 5, rows () + 1); - bar (5, rows () - 3, columns () + 1, rows () + 1); - if (_isopen) - paint_waitbar (FALSE); -#if XVT_OS == XVT_OS_WIN -else - cpb_win_picture_draw_at (win (), _modpic, 4, - 4 + (int) (rows () - 3l) * CHARY); -#endif - autoscroll (TRUE); - paint_header (); - paint_screen (); - if (_isselection) - display_selection (); - } - display_point (); - autoscroll (TRUE); - _need_update = TRUE; - _need_scroll = none; -} - -void TViswin::abort_print () -{ - if (yesno_box ("Interruzione della stampa su video?")) - { - _txt.freeze (); - freeze (); - set_focus (); - close_print (); - } -} - -void TViswin::handler (WINDOW win, EVENT * ep) -{ - int kdiff_x, kdiff_y; - PNT newcross; - TPoint p; - static bool ignore = FALSE; - bool tlnk = FALSE; - int kdiff; - long new_origin; - switch (ep->type) - { - case E_USER: - if (ep->v.user.id == E_ADDLINE) - { - set_scroll_max (MAXLEN - 1, _txt.lines () <= _textrows ? - _txt.lines () : _txt.lines () - _textrows); - } - else if (ep->v.user.id == E_ADDLINE_ONSCREEN) - { - set_scroll_max (MAXLEN - 1, _txt.lines () <= _textrows ? _txt.lines () : _txt.lines () - _textrows); - erase_point (); - if (need_paint_sel (FALSE)) - erase_selection (); - paint_row (_txt.lines () - 1l); - if (need_paint_sel (FALSE)) - display_selection (); - display_point (); - if (_txt.lines () > 1l) - _need_update = FALSE; - else - force_update (); - } - autoscroll (FALSE); - _textrows = TEXTROWS; - _textcolumns = TEXTCOLUMNS; - autoscroll (TRUE); - break; - case E_CONTROL: - if (ep->v.ctl.ci.type == WC_PUSHBUTTON) - switch (ep->v.ctl.id) - { - case DLG_QUIT: - if (_isopen) - abort_print (); - else - { -#if XVT_OS == XVT_OS_WIN - xvt_statbar_set (""); - xvt_statbar_refresh (); -#endif - stop_run (K_ENTER); - } - break; - case DLG_PRINT: - _txt.print (); - break; - case DLG_EDIT: - check_link (); - call_editor (); - _need_update = TRUE; - update (); - check_link (&_point); - break; - case DLG_LINK: - exec_link(); - break; - } - break; - case E_TIMER: - if (ep->v.timer.id == _timer) - { - kill_timer (_timer); - _istimer = FALSE; - } - else if (ep->v.timer.id == _wtimer) - { - paint_waitbar (); - kill_timer (_wtimer); - if (_isopen) - _wtimer = set_timer (win, 150l); - } - break; - case E_MOUSE_DBL: - break; - case E_MOUSE_DOWN: - p = ep->v.mouse.where; - trap_mouse (win); - - if (ep->v.mouse.button == 0) // left button: text selection - - { - if (need_paint_sel (FALSE)) - { - erase_selection (); - _isselection = FALSE; - } - if (!in_text (p) || (p.y + origin ().y) >= _txt.lines ()) - { - ignore = TRUE; - break; - } - - erase_point (); - _sel_start = ep->v.mouse.where; - _sel_start.x += (origin ().x - 6); - _sel_start.y += (origin ().y - 1); - _sel_end = _sel_start; - _selecting = TRUE; - } - else - { - // show crossbars - _cross = ep->v.mouse.where; - display_crossbar (); - _iscross = TRUE; - } - break; - case E_MOUSE_UP: - release_mouse (); - - if (ep->v.mouse.button == 0) // left button: text selection/move - // point - - { - p = ep->v.mouse.where; - - if (_isopen && (p.x >= 4 && p.x) <= 6 && - (p.y >= (int) rows () - 3 && p.y <= (int) rows () - 1)) - { - abort_print (); - ignore = TRUE; - } - if (ignore) - { - ignore = FALSE; - _selecting = FALSE; - break; - } - // confirm selection & store - p.x += (origin ().x - 6); - p.y += (origin ().y - 1); - - if (_sel_start == p) - { - if (_isselection) - { - _isselection = FALSE; - erase_selection (); - } - if (_sel_start == _point && !_selecting) - { - dispatch_e_char (win, K_F5); - } - else - { - TPoint xx; - _point.x = p.x; - _point.y = p.y; - if (_point.y > _txt.lines ()) - _point.y = _txt.lines () - 1l; - if (_point.y < 0) - _point.y = 0; - if (_point.x < 0) - _point.x = 0; - if (_point.x > 255) - _point.x = 255; - - check_link (&_point); - display_point (); - } - } - else - { - _sel_end.x = p.x; - _sel_end.y = p.y; - if (_sel_end.y >= _txt.lines ()) - _sel_end.y = _txt.lines () - 1l; - if (_sel_end.y < 0) - _sel_end.y = 0; - if (_sel_end.x < 0) - _sel_end.x = 0; - if (_sel_end.x > 255) - _sel_end.x = 255; - _point = _sel_end; - _isselection = TRUE; - check_link (&_point); - display_point (); - } - _selecting = FALSE; - } - else - { - erase_crossbar (); - _iscross = FALSE; - } - break; - case E_MOUSE_MOVE: - { - if (!_selecting && !_iscross) // no buttons pressed - - { - p = ep->v.mouse.where; - if (in_text (p)) - { - p.x += (origin ().x - 6); - p.y += (origin ().y - 1); - check_link (&p); - } - } - if (_selecting || _iscross) - { - p = ep->v.mouse.where; - if (_selecting) - _isselection = TRUE;; - { - _isselection = TRUE; - } - // scroll if necessary - if (p.y >= _textrows + 1l) - { - if (_isselection) - erase_selection (); - if (_iscross) - erase_crossbar (); - dispatch_e_scroll (win, K_DOWN); - if (_isselection) - display_selection (); - if (_iscross) - display_crossbar (); - } - else if (p.y <= 0l) - { - if (_isselection) - erase_selection (); - if (_iscross) - erase_crossbar (); - dispatch_e_scroll (win, K_UP); - if (_isselection) - display_selection (); - if (_iscross) - display_crossbar (); - } - else if (p.x <= 5l) - { - if (_isselection) - erase_selection (); - if (_iscross) - erase_crossbar (); - dispatch_e_scroll (win, K_LEFT); - if (_isselection) - display_selection (); - if (_iscross) - display_crossbar (); - } - else if (p.x >= _textcolumns + 6) - { - if (_isselection) - erase_selection (); - if (_iscross) - erase_crossbar (); - dispatch_e_scroll (win, K_RIGHT); - if (_isselection) - display_selection (); - if (_iscross) - display_crossbar (); - } - if (_selecting) - { - if (in_text (p)) - { - p.x += (origin ().x - 6); - p.y += (origin ().y - 1); - _point = p; - if (_point.y >= _txt.lines ()) - _point.y = _txt.lines () - 1l; - } - if (_point != _sel_end) - { - erase_selection (); - _sel_end = _point; - display_selection (); - } - } - } - if (_iscross) - { - newcross = ep->v.mouse.where; - if (_cross.h != newcross.h || _cross.v != newcross.v) - { - erase_crossbar (); - _cross = newcross; - display_crossbar (); - } - } - } - break; - case E_SIZE: - if (is_open ()) - { - check_link (); - erase_point (); - if (_isselection) - erase_selection (); - autoscroll (FALSE); - _textrows = TEXTROWS; - _textcolumns = TEXTCOLUMNS; - autoscroll (TRUE); - repos_buttons (); - display_point (); - _need_update = TRUE; - force_update (); - do_events (); - check_link (&_point); - } - break; - case E_HSCROLL: - case E_VSCROLL: - { - erase_point (); - tlnk = TRUE; - switch (ep->v.scroll.what) - { - case SC_PAGE_UP: - if (ep->type == E_VSCROLL) - { - if (origin ().y > 0) - { - kdiff = (int) (_point.y - origin ().y); - new_origin = origin ().y > _textrows ? - origin ().y - _textrows + 1l : 0; - _point.y = new_origin + kdiff; - check_link (); - update_thumb (origin ().x, new_origin); - _need_update = TRUE; - update (); // ORRIIIBILE! - - check_link (&_point); - _need_update = FALSE; - } - else - beep (); - } - else - { - if (origin ().x > 0) - { - kdiff = (int) (_point.x - origin ().x); - new_origin = origin ().x > _textcolumns ? - origin ().x - _textcolumns + 1 : 0; - _point.x = new_origin + kdiff; - check_link (); - update_thumb(new_origin, _point.y); - _need_update = TRUE; - update (); // AAAARGH! - - check_link (&_point); - _need_update = FALSE; - } - else - beep (); - } - break; - case SC_LINE_UP: - if (ep->type == E_VSCROLL) - { - _need_update = FALSE; - if (origin ().y > 0l) - { - _point.y--; - if (need_paint_sel ()) - erase_selection (); - check_link (); - update_thumb (origin ().x, origin ().y - 1l); - _need_scroll = down; - } - else - beep (); - } - else - { - _need_update = FALSE; - if (origin ().x > 0l) - { - if (need_paint_sel (FALSE)) - erase_selection (); - check_link (); - update_thumb (origin ().x - 1l, origin ().y); - _point.x--; - _need_scroll = right; - } - else - beep (); - } - break; - case SC_PAGE_DOWN: - if (ep->type == E_VSCROLL) - { - if ((origin ().y + _textrows) < _txt.lines ()) - { - kdiff = (int) (_point.y - origin ().y); - new_origin = (_txt.lines () - origin ().y) > - (_textrows * 2l) ? - origin ().y + _textrows - 1 : _txt.lines () - _textrows; - _point.y = new_origin + kdiff; - check_link (); - update_thumb (origin ().x, new_origin); - _need_update = TRUE; - update (); // AAAARGH! - - check_link (&_point); - _need_update = FALSE; - } - else - beep (); - } - else - { - if ((origin ().x + _textcolumns) < 256) - { - kdiff = (int) (_point.x - origin ().x); - new_origin = (256 - origin ().x) > _textcolumns ? - origin ().x + _textcolumns - 1 : 256 - _textcolumns; - _point.x = new_origin + kdiff; - check_link (); - update_thumb (new_origin, origin ().y); - _need_update = TRUE; - update (); // AAAARGH! - - check_link (&_point); - _need_update = FALSE; - } - else - beep (); - } - break; - case SC_LINE_DOWN: - if (ep->type == E_VSCROLL) - { - _need_update = FALSE; - if ((origin ().y + _textrows) < _txt.lines ()) - { - if (need_paint_sel ()) - erase_selection (); - check_link (); - update_thumb (origin ().x, origin ().y + 1l); - _point.y++; - _need_scroll = up; - } - else - beep (); - } - else - { - _need_update = FALSE; - if ((origin ().x + _textcolumns) < 255) - { - if (need_paint_sel (FALSE)) - erase_selection (); - check_link (); - update_thumb (origin ().x + 1l, origin ().y); - _need_scroll = left; - _point.x++; - } - else - beep (); - } - break; - case SC_THUMB: - - check_link (); - kdiff_x = (int) (_point.x - origin ().x); - kdiff_y = (int) (_point.y - origin ().y); - - p.x = ep->type == E_VSCROLL ? origin ().x : ep->v.scroll.pos; - p.y = ep->type == E_HSCROLL ? origin ().y : ep->v.scroll.pos; - - if ((p.y + _textrows) >= _txt.lines ()) - p.y = _txt.lines () - _textrows; - if ((p.x + _textcolumns) >= 255) - p.x = 255 - _textcolumns; - - update_thumb (p.x, p.y); - - _point.x = ep->type == E_VSCROLL ? origin ().x : - origin ().x + kdiff_x; - _point.y = ep->type == E_HSCROLL ? origin ().y : - origin ().y + kdiff_y; - _need_update = TRUE; - update (); - check_link (&_point); - break; - - default: - break; - } - // for failed scrollings - if (!_selecting && _need_scroll == none) - { - check_link (&_point); - display_point (); - } - } - break; - default: - break; - } - if (_need_scroll != none) - { - _need_update = FALSE; - scroll tmp = _need_scroll; - _need_scroll = none; - shift_screen (tmp); - if (!_selecting) - { - check_link (&_point); - display_point (); - } - if (_isselection) - display_selection (); - } - if (ep->type != E_UPDATE || _need_update) - TWindow ::handler (win, ep); - else if (ep->type == E_UPDATE) - update (); -} - -bool TViswin::on_key (KEY key) -{ - EVENT_TYPE type = E_USER; - - if (_istimer) - return TRUE; - _timer = set_timer (win (), 50l); - _istimer = TRUE; - - if (key == K_UP || key == K_DOWN || key == K_LEFT || key == K_RIGHT) - if (_selflag) - key += K_SHIFT; - - if (_selecting && key != K_SHIFT_UP && key != K_SHIFT_DOWN - && key != K_SHIFT_LEFT && key != K_SHIFT_RIGHT) - _selecting = FALSE; - - switch (key) - { - case CTRL_E: - if (_isedit) - { - check_link (); - call_editor (); - set_focus (); - _need_update = TRUE; - update (); - check_link (&_point); - } - break; - case CTRL_C: - exec_link(); - break; - case CTRL_S: - if (_isprint) - _txt.print (); - break; - case CTRL_R: - _need_update = TRUE; - check_link (); - force_update (); - do_events (); - check_link (&_point); - break; - case K_ESC: - if (_isopen) - abort_print (); - else - { - -#if XVT_OS == XVT_OS_WIN - xvt_statbar_set (""); - xvt_statbar_refresh (); -#endif - stop_run (K_ESC); - } - break; - case K_ENTER: - if (_isselection) - { - erase_selection (); - _isselection = FALSE; - } - break; - case K_TAB: - if (_curbut == (_buttons - 1)) - _curbut = 0; - else - _curbut++; - break; - case K_BTAB: - if (_curbut == 0) - _curbut = _buttons - 1; - else - _curbut--; - break; - case K_SPACE: - case K_CTRL_ENTER: - if (_linkID != -1) - { - exec_link(); - } - else - dispatch_e_char (_button[_curbut], K_SPACE); - break; - case K_LHOME: - _need_update = TRUE; - update_thumb (0, 0); - _point.set (0, 0); - check_link (&_point); - force_update (); - break; - case K_LEND: - _need_update = TRUE; - update_thumb (0, _txt.lines () - _textrows); - _point.set (0, _txt.lines () - 1); - check_link (&_point); - force_update (); - break; - case K_RIGHT: - case K_LEFT: - case K_WRIGHT: - case K_WLEFT: - case K_ALT_RIGHT: - case K_ALT_LEFT: - case K_SHIFT_RIGHT: - case K_SHIFT_LEFT: - type = E_HSCROLL; - break; - case K_UP: - case K_DOWN: - case K_NEXT: - case K_PREV: - case K_CTRL_UP: - case K_CTRL_DOWN: - case K_SHIFT_UP: - case K_SHIFT_DOWN: - type = E_VSCROLL; - break; - case K_F5: - check_link (); - erase_point (); - _isbar = !_isbar; - _need_update = TRUE; - force_update (); - do_events (); - check_link (&_point); - break; - case K_F6: - _selflag = !_selflag; - break; - default: - break; - } - - switch (type) - { - case E_HSCROLL: - case E_VSCROLL: - { - erase_point (); - check_link (); - switch (key) - { - case K_PREV: - dispatch_e_scroll (win(), K_PREV); - break; - case K_NEXT: - dispatch_e_scroll (win(), K_NEXT); - break; - case K_WRIGHT: - dispatch_e_scroll (win(), K_BTAB); - break; - case K_WLEFT: - dispatch_e_scroll (win(), K_TAB); - break; - case K_CTRL_UP: - dispatch_e_scroll (win(), K_UP); - break; - case K_CTRL_DOWN: - dispatch_e_scroll (win(), K_DOWN); - break; - case K_ALT_LEFT: - dispatch_e_scroll (win(), K_LEFT); - break; - case K_ALT_RIGHT: - dispatch_e_scroll (win(), K_RIGHT); - break; - case K_UP: - case K_SHIFT_UP: - _need_update = FALSE; - if (key == K_SHIFT_UP) - { - if (need_paint_sel (FALSE)) - erase_selection (); - if (!_selecting) - { - _sel_start = _point; - _selecting = TRUE; - } - } - if (_point.y > 0l) - { - if (_point.y == origin ().y) - { - if (need_paint_sel ()) - erase_selection (); - update_thumb (origin ().x, --_point.y); - _need_scroll = down; - } - else - _point.y--; - if (key == K_SHIFT_UP) - { - _sel_end = _point; - _isselection = TRUE; - } - } - else - beep (); - break; - case K_LEFT: - case K_SHIFT_LEFT: - _need_update = FALSE; - if (_point.x > 0l) - { - if (key == K_SHIFT_LEFT) - { - if (need_paint_sel (FALSE)) - erase_selection (); - if (!_selecting) - { - _sel_start = _point; - _selecting = TRUE; - } - } - if (_point.x == origin ().x) - { - _need_update = FALSE; - if (need_paint_sel (FALSE)) - erase_selection (); - update_thumb (--_point.x, origin ().y); - _need_scroll = right; - } - else - _point.x--; - if (key == K_SHIFT_LEFT) - { - _sel_end = _point; - _isselection = TRUE; - } - } - else - beep (); - break; - case K_DOWN: - case K_SHIFT_DOWN: - _need_update = FALSE; - if (_point.y < (_txt.lines () - 1)) - { - if (key == K_SHIFT_DOWN) - { - if (need_paint_sel (FALSE)) - erase_selection (); - if (!_selecting) - { - _sel_start = _point; - _selecting = TRUE; - } - } - if (_point.y == origin ().y + _textrows - 1) - { - if (need_paint_sel ()) - erase_selection (); - // check_link(); - update_thumb (origin ().x, (++_point.y) - _textrows + 1); - _need_scroll = up; - } - else - _point.y++; - if (key == K_SHIFT_DOWN) - { - _sel_end = _point; - _isselection = TRUE; - } - } - else - beep (); - break; - case K_RIGHT: - case K_SHIFT_RIGHT: - _need_update = FALSE; - if (_point.x < 256) - { - if (key == K_SHIFT_RIGHT) - { - if (need_paint_sel (FALSE)) - erase_selection (); - if (!_selecting) - { - _sel_start = _point; - _selecting = TRUE; - } - } - if (_point.x == (origin ().x + _textcolumns - 1)) - { - if (need_paint_sel (FALSE)) - erase_selection (); - // check_link(); - update_thumb ((++_point.x) - _textcolumns + 1l, origin ().y); - _need_scroll = left; - } - else - _point.x++; - if (key == K_SHIFT_RIGHT) - { - _sel_end = _point; - _isselection = TRUE; - } - } - else - beep (); - break; - default: - break; - } - if (_need_scroll != none) - { - _need_update = FALSE; - scroll tmp = _need_scroll; - _need_scroll = none; - shift_screen (tmp); - } - if (_isselection) - display_selection (); - check_link (&_point); - force_update (); - } - break; -default: - break; -} - return TWindow::on_key (key); -} - -bool TViswin::call_editor () -{ - TConfig cnf (CONFIG_STUDIO, "Main"); - TString editor (cnf.get ("Editor")); - - bool ok = FALSE; - - if (!editor.empty ()) - { - TString newfilename; - - static FILE_SPEC fs; - get_default_dir (&fs.dir); - strcpy (fs.type, "txt"); - save_dir (); - if (save_file_dlg (&fs, "Salva il file con il nome:") == FL_OK) - { - restore_dir (); - char path[256]; - dir_to_str (&fs.dir, path, sizeof (path)); - newfilename << path << '/' << fs.name; - - TPoint p1, p2; - if (_isselection) - adjust_selection (p1, p2); - - if (_txt.write (newfilename, _isselection ? &p1 : NULL, - _isselection ? &p2 : NULL)) - { - newfilename.insert (" ", 0); - newfilename.insert (editor, 0); - TExternal_app edit (newfilename); - if (edit.run (TRUE)) - beep (); - else - ok = TRUE; - } - } - else - restore_dir (); - } - else - warning_box ("Nessun editor specificato nei parametri studio"); - return ok; -} - -void TViswin::add_line (const char *l) -{ - if (_isopen && !_frozen) - { - if (_txt.frozen ()) // error writing files - - { - close_print (); - return; - } - _txt.append (l); - EVENT ev; - ev.type = E_USER; - ev.v.user.id = (_txt.lines () - origin ().y) <= _textrows ? - E_ADDLINE_ONSCREEN : E_ADDLINE; - dispatch_event (win (), &ev); - do_events (); - } -} - -void TViswin::close_print () -{ - _isopen = FALSE; - kill_timer (_wtimer); - _need_update = TRUE; - force_update (); -} - -TViswin ::TViswin (const char *fname, - const char *title, - bool editbutton, - bool printbutton, - bool linkbutton): - _filename (fname), _txt (fname, BUFFERSIZE), _islink (linkbutton), _isedit (editbutton), - _isprint (printbutton), _isbar (FALSE), _istimer (FALSE), _iscross (FALSE), - _isselection (FALSE), _sel_displayed (FALSE), _cross_displayed (FALSE), - _link_displayed (FALSE), _point_displayed (FALSE), _selecting (FALSE), - _scrolling (FALSE), _selflag (FALSE), _need_update (TRUE), _need_scroll (none), - _multiple (FALSE), - _frozen (FALSE) -{ - if (title == NULL) - title = (fname ? fname : "Anteprima di stampa"); - - _isopen = fname == NULL; - if (_isopen) - _filename = _txt.name (); - - for (int i = 0; i < MAXBUT; i++) - _button[i] = NULL_WIN; - - const int larg = 76; - const int alt = 20; - RCT r; - get_client_rect (TASK_WIN, &r); - int maxlarg = r.right / CHARX - 6; // Calculates max window width - - int maxalt = r.bottom / CHARY - 6; - if (larg > maxlarg) - maxlarg = larg; - if (alt > maxalt) - maxalt = alt; - -#if XVT_OS == XVT_OS_WIN - for (i = 0; i < 4; i++) - _picture[i] = cpb_picture_load (BMP_MODULE1 + i); - _modpic = cpb_picture_load (BMP_MODULE); -#endif - - create (-1, -1, maxlarg, maxalt, title, - WSF_CLOSE | WSF_HSCROLL | WSF_VSCROLL | WSF_SIZE); - - set_opaque_text (TRUE); - set_font (FF_FIXED); - - add_button (DLG_QUIT, DLG_QUIT_TITLE); - _buttons = 1; - - if (_isedit) - { - add_button (DLG_EDIT, DLG_EDIT_TITLE); - _buttons++; - } - if (_islink) - { - _link_button = add_button (DLG_LINK, DLG_LINK_TITLE); - _buttons++; - xvt_enable_control (_link_button, FALSE); - } - if (_isprint) - { - add_button (DLG_PRINT, DLG_PRINT_TITLE); - _buttons++; - } - - //#if XVT_OS == XVT_OS_SCOUNIX - // maximize(); - // #endif - - _curbut = 0; - - if (_isopen) - _wtimer = set_timer (win (), 150l); - - _point.set (0, 0); - autoscroll (FALSE); - _textrows = TEXTROWS; - _textcolumns = TEXTCOLUMNS; - autoscroll (TRUE); - - _links = &(MainApp ()->printer ().links ()); - _multiple = MainApp ()->printer ().ismultiplelink (); - _bg = MainApp ()->printer ().getbgdesc (); - _isbackground = _bg->items () > 0; - _formlen = MainApp ()->printer ().formlen (); - - for (i = 0; i < _links->items (); i++) - { - TToken_string & t = (TToken_string &) (*_links)[i]; - char f = *(t.get (1)); - char b = *(t.get (2)); - t.restart (); - _txt.set_hotspots (f, b); - } - _hotspots = &(_txt.hotspots ()); -} - -TViswin ::~TViswin () -{ -#if XVT_OS == XVT_OS_WIN - for (int i = 0; i < 4; i++) - picture_free (_picture[i]); -#endif -} +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __PRINTER_H +typedef void (*LINKHANDLER) (int, const char *); +#endif + +#if XVT_OS == XVT_OS_WIN +extern "C" +{ +#include +} +#endif + +#define BUTTONROW_SIZE 3 +#define W_X1 (origin().x+5) +#define W_Y1 (origin().y+1) +#define W_X2 (origin().x+columns()) +#define W_Y2 (origin().y+rows()+1-BUTTONROW_SIZE) +#define TEXTROWS (rows() - 1 - BUTTONROW_SIZE) +#define TEXTCOLUMNS (columns() - 6) + +#define DLG_QUIT_TITLE "Fine" +#define DLG_EDIT_TITLE "~Edit" +#define DLG_LINK_TITLE "~Collega" +#define DLG_PRINT_TITLE "~Stampa" + +#if XVT_OS == XVT_OS_WIN +#define BACKGROUND MASK_BACK_COLOR +#define FOREGROUND COLOR_BLACK +#else +#define BACKGROUND COLOR_BLACK +#define FOREGROUND COLOR_WHITE +#endif + +#define K_CTRL_DOWN (K_CTRL + K_DOWN) +#define K_CTRL_UP (K_CTRL + K_UP) +#define K_SHIFT_UP (K_SHIFT + K_UP) +#define K_SHIFT_DOWN (K_SHIFT + K_DOWN) +#define K_SHIFT_LEFT (K_SHIFT + K_RIGHT) +#define K_SHIFT_RIGHT (K_SHIFT + K_LEFT) +#define K_ALT_RIGHT (K_CTRL + 'K') +#define K_ALT_LEFT (K_CTRL + 'L') +#define CTRL_C ('C') +#define CTRL_E ('E') +#define CTRL_S ('S') +#define CTRL_R ('R') + +// vista la mania degli 883, eccoti un po' di concerti di Mozart +const long E_ADDLINE = 488l; +const long E_ADDLINE_ONSCREEN = 467l; + + +void TViswin::exec_link() +{ + if (_linkID != -1) + { + LINKHANDLER pl = main_app().printer().getlinkhandler(); + if (pl) + pl(_linkID, _multiple ? (const char*)_multiple_link : (const char*)_linktxt); + + // dai opzione per rifare la stampa se e' arrivato un messaggio + // dall'applicazione chiamata + // schiaffa indi il tutto in una funzione + TMailbox m; + if (m.next_s(MSG_LN) != NULL) + { + if (yesno_box("Si desidera riaggiornare la stampa?")) + { + ((TPrint_application*)MainApp())->repeat_print(); +#if XVT_OS == XVT_OS_WIN + xvt_statbar_set (""); + xvt_statbar_refresh (); +#endif + stop_run(K_ENTER); + } + } + + set_focus(); + check_link(); + _need_update = TRUE; + force_update(); + do_events(); + check_link (&_point); + } + else + beep(); +} + + + +void TViswin::display_link (long y, long x1, long x2, const char *d) +{ + if (!_link_displayed) + { + paint_link (y, x1, x2); + _link_displayed = TRUE; +#if XVT_OS == XVT_OS_WIN + xvt_statbar_set (d); + xvt_statbar_refresh (); +#endif + xvt_enable_control (_link_button, TRUE); + } +} + + +void TViswin::erase_link (long y, long x1, long x2) +{ + if (_link_displayed) + { + paint_link (y, x1, x2); + _link_displayed = FALSE; +#if XVT_OS == XVT_OS_WIN + xvt_statbar_set (""); + xvt_statbar_refresh (); +#endif + xvt_enable_control (_link_button, FALSE); + } +} + +void TViswin::paint_link (long y, long x1, long x2) +{ + if (adjust_box (x1, x2, y)) + invert_bar ((int) (x1 + 6l), (int) (y + 1l), (int) (x2 + 6l), (int) (y + 2l)); +} + +bool TViswin::adjust_box (long &x1, long &x2, long y) +{ + if (y < origin ().y || y > origin ().y + _textrows) + return FALSE; + if (origin ().x > x1) + x1 = origin ().x; + if (origin ().x + _textcolumns < x2) + x2 = origin ().x + _textcolumns; + return TRUE; +} + +bool TViswin::check_link (TPoint * p) +{ + static char descr[128], pdescr[128]; + static int old_id = -1, plinkID = -1; + static long y, x1, x2; + static long py, px1, px2; + + if (p == NULL) // erase and go + { + if (old_id != -1) + { + erase_link (y, x1, x2); + old_id = _linkID = plinkID = -1; + py = px1 = px2 = x1 = y = x2 = 0l; + } + return FALSE; + } + + // poi se e' il caso lo si risistema + if (p == &_point) + plinkID = -1; + + for (int i = 0; i < _hotspots->items (); i++) + { + TToken_string & t = (TToken_string &) (*_hotspots)[i]; + t.restart (); + long ty = t.get_long (); + long tx1 = t.get_long (); + long tx2 = t.get_long (); + if (p->y == ty && p->x < tx2 && p->x >= tx1) + { + // ci siamo + int id = (int) t.get_long (4); + + if (ty != y || tx1 != x1 || tx2 != x2) + { + if (old_id != -1) + erase_link (y, x1, x2); + TToken_string & ttt = (TToken_string &) (*_links)[id]; + ttt.restart (); + strcpy (descr, ttt.get ()); + strcat (descr, t.get (3)); + _linktxt = t.get(3); + if (_multiple) + { + // get all parts of the same color + const char *cp; + _txt.read_line (ty); + _multiple_link = ""; + + while (cp = _txt.piece ()) + { + if (_txt.get_foreground () == *(ttt.get (1)) && + _txt.get_background () == *(ttt.get (2))) + _multiple_link.add (cp); + } + } + old_id = _linkID = id; + y = ty; + x1 = tx1; + x2 = tx2; + display_link (y, x1, x2, descr); + } + if (p == &_point) + { + strcpy (pdescr, descr); + plinkID = id; + px1 = x1; + px2 = x2; + py = y; + } + return TRUE; + } + } + // non sono su un bottone: puo' esserci il point + if (old_id != -1 && plinkID == -1) + { + old_id = _linkID = -1; + erase_link (y, x1, x2); + x1 = x2 = y = 0l; + } + // se point e' su un bottone, evidenzia quello + else if (plinkID != -1 && (x1 != px1 || x2 != px2 || y != py)) + { + // erase old one + erase_link (y, x1, x2); + old_id = _linkID = plinkID; + x1 = px1; + x2 = px2; + y = py; + strcpy (descr, pdescr); + display_link (y, x1, x2, descr); + return TRUE; + } + return FALSE; +} + +bool TViswin::in_text (const TPoint & p) const +{ + if (p.x > 5 && p.x < columns () && p.y > 0 && p.y < (rows () - 3)) + return TRUE; + return FALSE; +} + + +bool TViswin::need_paint_sel (bool smart) +{ + TPoint p1, p2; + adjust_selection (p1, p2); + long end = origin ().y + _textrows; + bool r = _isselection; + if (smart) + r = r && ( + (origin ().y >= p1.y - 1 && origin ().y <= p2.y + 1) || + (end >= p1.y - 1 && end <= p2.y + 1)); + return r; +} + +void TViswin::erase_selection () +{ + if (_sel_displayed) + paint_selection (); + _sel_displayed = FALSE; +} + +void TViswin::display_selection () +{ + if (!_sel_displayed) + paint_selection (); + _sel_displayed = TRUE; +} + +void TViswin::adjust_selection (TPoint & p1, TPoint & p2) +{ + if (_sel_start.y < _sel_end.y) + { + p1 = _sel_start; + p2 = _sel_end; + } + else + { + p1 = _sel_end; + p2 = _sel_start; + } +} + +void TViswin::shift_screen (scroll dir) +{ + RCT r; + + if (_scrolling) + return; + _scrolling = TRUE; + // origin() e' gia' stata modificata + switch (dir) + { + case up: + case down: + set_rect (&r, 0, CHARY + 2, (int) (CHARX * (_textcolumns + 6)), (int) (CHARY * (_textrows + 1))); + win_scroll_rect (win (), &r, 0, dir == down ? CHARY : -CHARY); + paint_row (dir == up ? origin ().y + _textrows - 1 : origin ().y); + break; + case left: + case right: + set_rect (&r, CHARX * 6, 0, (int) (CHARX * (_textcolumns + 6) + 2), (int) (CHARY * (_textrows + 1) - 2)); + win_scroll_rect (win (), &r, dir == right ? CHARX : -CHARX, 0); + paint_column (dir == left ? origin ().x + _textcolumns - 1 : origin ().x, + dir == left); + break; + default: + break; + } + _scrolling = FALSE; +} + +WINDOW TViswin::add_button (short id, const char *caption) +{ + const int BUT_HEIGHT = +#if XVT_OS == XVT_OS_WIN + 2 +#else + 1 +#endif + ; + WINDOW b = xvt_create_control (WC_PUSHBUTTON, 0, 0, 11, + BUT_HEIGHT, caption, win (), 0, 0, id); + + for (int i = 0; i < MAXBUT; i++) + if (_button[i] == NULL_WIN) + { + _button[i] = b; + break; + } + return b; +} + +void TViswin::repos_buttons () +{ + for (int buttons = 0; _button[buttons] != NULL_WIN; buttons++) + if (buttons == MAXBUT - 1) + { + buttons++; + break; + } + + if (buttons == 0) + return; + + autoscroll (FALSE); + set_mode (M_COPY); + set_brush (MASK_BACK_COLOR); + bar (5, rows () - 3, columns () + 1, rows () + 1); + autoscroll (TRUE); + + RCT wr; + get_client_rect (win (), &wr); + RCT br; + get_client_rect (_button[0], &br); + + int space = (wr.right - buttons * br.right) / (buttons + 1); + if (space < 0) + space = 0; + + int x = space; + const int y = wr.bottom - br.bottom - 4; + for (int b = 0; b < buttons; b++, x += br.right + space) + { + RCT r; + set_rect (&r, x, y, x + br.right, y + br.bottom); + move_window (_button[b], &r); + } +} + +void TViswin::open () +{ + set_scroll_max (MAXLEN, _txt.lines () <= _textrows ? _txt.lines () : _txt.lines () - _textrows); + repos_buttons (); + TScroll_window ::open (); + _need_update = TRUE; + force_update (); +} + +// prints the window contents +void TViswin::paint_screen () +{ + bool first = TRUE; + for (long j = 0; j < _textrows; j++) + { + long rw = origin ().y + j; + if (rw < _txt.lines ()) + paint_row (rw); + else if (!_isopen) + { +#if XVT_OS == XVT_OS_WIN + autoscroll (FALSE); + set_mode (M_COPY); + set_pen (COLOR_BLACK); + + PNT b, e; + b.h = CHARX * 5; + b.v = (CHARY * (int) (j + 1l - origin ().y)) - 2; + e.h = CHARX * columns (); + e.v = b.v; + win_move_to (win (), b); + win_draw_line (win (), e); + set_pen (COLOR_LTGRAY); + e.v++; + b.v++; + win_move_to (win (), b); + win_draw_line (win (), e); + set_brush (COLOR_DKGRAY); + bar (5, (int) (j + 1l - origin ().y), (int) columns (), (int) (rows () - 3l)); + autoscroll (TRUE); + break; +#endif + } + } +} + +void TViswin::paint_background (long j, int row) +{ + if (!_isbackground) + return; + int rw = (int) (j % (long) _formlen); + TString & rwd = (TString &) (*_bg)[rw]; + int cnt = 0; + char ch; + + char curcol = 'n'; + char curpen = 'n'; + char curpat = 'n'; + char curwid = '1'; + + unsigned int x1, x2; + PNT b, e; + while (ch = rwd[cnt++]) + { + switch (ch) + { + case 'v': // verticale intera + + x1 = (unsigned char) rwd[cnt++] + 5; + b.h = e.h = x1 * CHARX + CHARX / 2; + b.v = row * CHARY; + e.v = (row + 1) * CHARY; + win_move_to (win (), b); + win_draw_line (win (), e); + break; + case 'o': // verticale pezzo sopra + + x1 = (unsigned char) rwd[cnt++] + 5; + b.h = e.h = x1 * CHARX + CHARX / 2; + b.v = row * CHARY; + e.v = (row + 1) * CHARY - CHARY / 2; + win_move_to (win (), b); + win_draw_line (win (), e); + break; + case 'u': // verticale pezzo sotto + + x1 = (unsigned char) rwd[cnt++] + 5; + b.h = e.h = x1 * CHARX + CHARX / 2; + b.v = row * CHARY + CHARY / 2; + e.v = (row + 1) * CHARY; + win_move_to (win (), b); + win_draw_line (win (), e); + break; + case 'h': // orizzontale intera + + x1 = (unsigned char) rwd[cnt++] + 5; + x2 = (unsigned char) rwd[cnt++] + 5; + b.v = e.v = row * CHARY + CHARY / 2; + b.h = x1 * CHARX; + e.h = (x2 + 1) * CHARX; + win_move_to (win (), b); + win_draw_line (win (), e); + break; + case 'r': // orizzontale scorciata agli estremi + + x1 = (unsigned char) rwd[cnt++] + 5; + x2 = (unsigned char) rwd[cnt++] + 5; + b.v = e.v = row * CHARY + CHARY / 2; + b.h = x1 * CHARX + CHARX / 2; + e.h = x2 * CHARX + CHARX / 2; + win_move_to (win (), b); + win_draw_line (win (), e); + break; + case 'W': + curwid = rwd[cnt++]; + set_pen (trans_color (curcol), curwid - '0', trans_brush (curpat), + trans_pen (curpen)); + break; + case 'P': + curpen = rwd[cnt++]; + set_pen (trans_color (curcol), curwid - '0', trans_brush (curpat), + trans_pen (curpen)); + break; + case 'B': + curpat = rwd[cnt++]; + set_pen (trans_color (curcol), curwid - '0', trans_brush (curpat), + trans_pen (curpen)); + break; + case 'C': + curcol = rwd[cnt++]; + set_pen (trans_color (curcol), curwid - '0', trans_brush (curpat), + trans_pen (curpen)); + break; + default: + break; + } + } + // restore default pen + set_pen (COLOR_BLACK); +} + +void TViswin::paint_row (long j) +{ + // int or = (int)origin().x; + long y = origin ().y; + TPoint p1, p2; + if (need_paint_sel (FALSE)) + adjust_selection (p1, p2); + int row = (int) (j + 1l - y); + static char fill[] = " " + " "; + autoscroll (FALSE); + set_font (FF_FIXED, 0); + set_mode (M_COPY); + set_opaque_text (TRUE); + set_color (FOREGROUND, BACKGROUND); + printat (0, row, "%05ld", j + 1); + if (_scrolling) + { + hide_pen (); + set_brush (COLOR_WHITE); + RCT r; + r.top = row * CHARY; + r.left = CHARX * 5, + r.bottom = r.top + CHARY + 2; + r.right = CHARX * 255; + win_draw_rect (win (), &r); + } + const char *cp; + int pos = 0; + _txt.read_line (j, origin ().x); + while (cp = _txt.piece ()) + { +#if XVT_OS != XVT_OS_SCOUNIX + int st = _txt.get_style (); + long bg = trans_color (_txt.get_background ()); + long fg = trans_color (_txt.get_foreground ()); + set_font (FF_FIXED, st & 0x000f); + set_color (fg, bg); +#else + set_color (COLOR_BLACK, COLOR_WHITE); +#endif + printat (6 + pos, row, "%s", cp); +#if XVT_OS == XVT_OS_WIN + if (st & underlined) + { + PNT b, e; + + set_pen (COLOR_BLACK); + b.h = CHARX * (6 + pos); + b.v = (row + 1) * CHARY; + e.h = CHARX * (6 + pos + strlen (cp)); + e.v = (row + 1) * CHARY; + win_move_to (win (), b); + win_draw_line (win (), e); + } +#endif + pos += strlen (cp); + } + if (_scrolling && (pos < _textcolumns)) + { + set_color (COLOR_BLACK, COLOR_WHITE); + printat (6 + pos, row, "%s", fill); + } +#if XVT_OS == XVT_OS_WIN // paint page limits + if ((j % _formlen) == (_formlen - 1)) // last row + + { + PNT b, e; + + b.h = CHARX * 5; + b.v = (row + 1) * CHARY - 1; + e.h = CHARX * 132; + e.v = (row + 1) * CHARY - 1; + set_pen (COLOR_LTGRAY, 2, PAT_SOLID, P_DASH); + win_move_to (win (), b); + win_draw_line (win (), e); + } +#endif + paint_background (j, row); + autoscroll (TRUE); +} + +void TViswin::paint_column (long j, bool end) +{ + paint_header (); + set_opaque_text (TRUE); + set_mode (M_COPY); + TPoint p1, p2; + if (need_paint_sel (FALSE)) + adjust_selection (p1, p2); + set_color (COLOR_BLACK, COLOR_WHITE); + + autoscroll (FALSE); + for (long l = 0l; l < _textrows && l < (_txt.lines () - origin ().y); l++) + { + const char *c = (const char *) _txt.line (origin ().y + l); +#if XVT_OS != XVT_OS_SCOUNIX + int st = _txt.get_style ((int) j); + set_font (FF_FIXED, st & 0x000f); + long bg = trans_color (_txt.get_background ((int) j)); + long fg = trans_color (_txt.get_foreground ((int) j)); + set_color (fg, bg); +#endif + int col = end ? (int) (_textcolumns + 5) : 6; + printat (col, (int) l + 1, "%c", + (unsigned int) j < strlen (c) ? c[(int) j] : ' '); +#if XVT_OS == XVT_OS_WIN + if ((st & underlined) && strlen (c) > (word) j) + { + PNT b, e; + + set_pen (COLOR_BLACK); + b.h = CHARX * col; + b.v = (int) (l + 2l) * CHARY; + e.h = CHARX * (col + 1); + e.v = (int) (l + 2l) * CHARY; + win_move_to (win (), b); + win_draw_line (win (), e); + } +#endif + paint_background ((int) l, (int) l + 1); + } + autoscroll (TRUE); +} + +void TViswin::draw_crossbars () + // prints reference crossbars +{ +#if XVT_OS == XVT_OS_WIN + + if (_cross.v > CHARY && _cross.v < (rows () - 3) * CHARY && + _cross.h > CHARX * 5 && _cross.h < columns () * CHARX) + { + set_pen (COLOR_BLACK); + set_mode (M_XOR); + + PNT b1, e1, b2, e2; + + autoscroll (FALSE); + b1.h = _cross.h; + b1.v = CHARY; + e1.h = _cross.h; + e1.v = ((rows () - 3) * CHARY); + b2.h = CHARX * 5; + b2.v = _cross.v; + e2.h = CHARX * columns (); + e2.v = _cross.v; + win_move_to (win (), b1); + win_draw_line (win (), e1); + win_move_to (win (), b2); + win_draw_line (win (), e2); + autoscroll (TRUE); + } +#endif +} + +void TViswin::display_crossbar () +{ + if (!_cross_displayed) + draw_crossbars (); + _cross_displayed = TRUE; +} + +void TViswin::erase_crossbar () +{ + if (_cross_displayed) + draw_crossbars (); + _cross_displayed = FALSE; +} + +void TViswin::display_point () +{ + + if (!_point_displayed) + paint_point (); + _point_displayed = TRUE; +} + +void TViswin::erase_point () +{ + if (_point_displayed) + paint_point (); + _point_displayed = FALSE; +} + +void TViswin::paint_point (bool erase) +{ + autoscroll (FALSE); + static bool wasbar; + + if (_isbar) + { + invert_bar (6, (int) (_point.y - origin ().y + 1l), + (int) columns (), (int) (_point.y - origin ().y + 2l)); + invert_bar ((int) (_point.x - origin ().x + 6l), 1, + (int) (_point.x - origin ().x + 7l), (int) (rows () - 3l)); + } + else + { + invert_bar ((int) (_point.x - origin ().x + 6l), (int) (_point.y - origin ().y + 1l), + (int) (_point.x - origin ().x + 7l), (int) (_point.y - origin ().y + 2l)); + invert_bar (0, (int) (_point.y - origin ().y + 1l), 5, + (int) (_point.y - origin ().y + 2l)); + invert_bar ((int) (_point.x - origin ().x + 6l), 0, + (int) (_point.x - origin ().x + 7l), 1); + } + autoscroll (TRUE); + wasbar = _isbar; +} + +// draw screen header +void TViswin::paint_header () +{ + set_mode (M_COPY); + set_opaque_text (TRUE); + set_color (FOREGROUND, BACKGROUND); + set_font (FF_FIXED, 0); + TString htmpst (10); + for (int i = 1; i < 26; i++) + { + htmpst.format ("%d", i); + htmpst.right_just (10, '.'); + printat (i * 10 - 4, (int) origin ().y, "%s", (const char *) htmpst); + } + autoscroll (FALSE); + set_color (COLOR_WHITE, BACKGROUND); + printat (0, 0, "P.%3ld ", ((origin ().y) / _formlen) + 1l); + autoscroll (TRUE); +} + +void TViswin::paint_selection () +{ + TPoint p1, p2; + adjust_selection (p1, p2); + + // paint rows + for (long l = p1.y; l <= p2.y; l++) + { + int top, left, right; + top = (int) (l - origin ().y + 1); + if (top > 0 && top <= _textrows) + { + left = p1.y == l ? (int) (p1.x - origin ().x + 6l) : 6; + right = p2.y == l ? (int) (p2.x - origin ().x + 6l) : + (int) (_textcolumns + 6l); + autoscroll (FALSE); + invert_bar (left, top, right, top + 1); + autoscroll (TRUE); + } + } +} + +void TViswin::paint_waitbar (bool xor) +{ +#if XVT_OS == XVT_OS_WIN + static int pic; +#endif + autoscroll (FALSE); + if (xor) + { +#if XVT_OS == XVT_OS_WIN + cpb_win_picture_draw_at (win (), _picture[pic], 4, 4 + (int) (rows () - 3l) * CHARY); + if (pic == 3) + pic = 0; + else + pic++; +#else + invert_bar (3, rows () - 2, 4, rows () - 1); +#endif + } + else + { +#if XVT_OS == XVT_OS_WIN + cpb_win_picture_draw_at (win (), _picture[pic], 4, + 4 + (int) (rows () - 3l) * CHARY); + if (pic == 3) + pic = 0; + else + pic++; +#else + printat (3, rows () - 2, "%c", '*'); +#endif + } + autoscroll (TRUE); +} + +void TViswin::update () +{ + if (_scrolling) + return; + + erase_point (); + autoscroll (FALSE); + set_mode (M_COPY); + set_brush (MASK_BACK_COLOR); + bar (5, rows () - 3, columns () + 1, rows () + 1); + + if (_need_update) + { + if (_isselection) + erase_selection (); + clear (COLOR_WHITE); + set_mode (M_COPY); + set_brush (MASK_BACK_COLOR); + autoscroll (FALSE); + bar (0, 0, columns () + 1, 1); + bar (0, 0, 5, rows () + 1); + bar (5, rows () - 3, columns () + 1, rows () + 1); + if (_isopen) + paint_waitbar (FALSE); +#if XVT_OS == XVT_OS_WIN +else + cpb_win_picture_draw_at (win(), _modpic, 4, + 4 + (int) (rows () - 3l) * CHARY); +#endif + autoscroll (TRUE); + paint_header (); + paint_screen (); + if (_isselection) + display_selection (); + } + display_point (); + autoscroll (TRUE); + _need_update = TRUE; + _need_scroll = none; +} + +void TViswin::abort_print () +{ + if (yesno_box ("Interruzione della stampa su video?")) + { + _txt.freeze (); + freeze (); + set_focus (); + close_print (); + } +} + +void TViswin::handler (WINDOW win, EVENT * ep) +{ + int kdiff_x, kdiff_y; + PNT newcross; + TPoint p; + static bool ignore = FALSE; + bool tlnk = FALSE; + int kdiff; + long new_origin; + switch (ep->type) + { + case E_USER: + if (ep->v.user.id == E_ADDLINE) + { + set_scroll_max (MAXLEN - 1, _txt.lines () <= _textrows ? + _txt.lines () : _txt.lines () - _textrows); + } + else if (ep->v.user.id == E_ADDLINE_ONSCREEN) + { + set_scroll_max (MAXLEN - 1, _txt.lines () <= _textrows ? _txt.lines () : _txt.lines () - _textrows); + erase_point (); + if (need_paint_sel (FALSE)) + erase_selection (); + paint_row (_txt.lines () - 1l); + if (need_paint_sel (FALSE)) + display_selection (); + display_point (); + if (_txt.lines () > 1l) + _need_update = FALSE; + else + force_update (); + } + autoscroll (FALSE); + _textrows = TEXTROWS; + _textcolumns = TEXTCOLUMNS; + autoscroll (TRUE); + break; + case E_CONTROL: + if (ep->v.ctl.ci.type == WC_PUSHBUTTON) + switch (ep->v.ctl.id) + { + case DLG_QUIT: + if (_isopen) + abort_print (); + else + { +#if XVT_OS == XVT_OS_WIN + xvt_statbar_set (""); + xvt_statbar_refresh (); +#endif + stop_run (K_ENTER); + } + break; + case DLG_PRINT: + _txt.print (); + break; + case DLG_EDIT: + check_link (); + call_editor (); + _need_update = TRUE; + update (); + check_link (&_point); + break; + case DLG_LINK: + exec_link(); + break; + } + break; + case E_TIMER: + if (ep->v.timer.id == _timer) + { + kill_timer (_timer); + _istimer = FALSE; + } + else if (ep->v.timer.id == _wtimer) + { + paint_waitbar (); + kill_timer (_wtimer); + if (_isopen) + _wtimer = set_timer (win, 150l); + } + break; + case E_MOUSE_DBL: + break; + case E_MOUSE_DOWN: + p = ep->v.mouse.where; + trap_mouse (win); + + if (ep->v.mouse.button == 0) // left button: text selection + + { + if (need_paint_sel (FALSE)) + { + erase_selection (); + _isselection = FALSE; + } + if (!in_text (p) || (p.y + origin ().y) >= _txt.lines ()) + { + ignore = TRUE; + break; + } + + erase_point (); + _sel_start = ep->v.mouse.where; + _sel_start.x += (origin ().x - 6); + _sel_start.y += (origin ().y - 1); + _sel_end = _sel_start; + _selecting = TRUE; + } + else + { + // show crossbars + _cross = ep->v.mouse.where; + display_crossbar (); + _iscross = TRUE; + } + break; + case E_MOUSE_UP: + release_mouse (); + + if (ep->v.mouse.button == 0) // left button: text selection/move + // point + + { + p = ep->v.mouse.where; + + if (_isopen && (p.x >= 4 && p.x) <= 6 && + (p.y >= (int) rows () - 3 && p.y <= (int) rows () - 1)) + { + abort_print (); + ignore = TRUE; + } + if (ignore) + { + ignore = FALSE; + _selecting = FALSE; + break; + } + // confirm selection & store + p.x += (origin ().x - 6); + p.y += (origin ().y - 1); + + if (_sel_start == p) + { + if (_isselection) + { + _isselection = FALSE; + erase_selection (); + } + if (_sel_start == _point && !_selecting) + { + dispatch_e_char (win, K_F5); + } + else + { + TPoint xx; + _point.x = p.x; + _point.y = p.y; + if (_point.y > _txt.lines ()) + _point.y = _txt.lines () - 1l; + if (_point.y < 0) + _point.y = 0; + if (_point.x < 0) + _point.x = 0; + if (_point.x > 255) + _point.x = 255; + + check_link (&_point); + display_point (); + } + } + else + { + _sel_end.x = p.x; + _sel_end.y = p.y; + if (_sel_end.y >= _txt.lines ()) + _sel_end.y = _txt.lines () - 1l; + if (_sel_end.y < 0) + _sel_end.y = 0; + if (_sel_end.x < 0) + _sel_end.x = 0; + if (_sel_end.x > 255) + _sel_end.x = 255; + _point = _sel_end; + _isselection = TRUE; + check_link (&_point); + display_point (); + } + _selecting = FALSE; + } + else + { + erase_crossbar (); + _iscross = FALSE; + } + break; + case E_MOUSE_MOVE: + { + if (!_selecting && !_iscross) // no buttons pressed + + { + p = ep->v.mouse.where; + if (in_text (p)) + { + p.x += (origin ().x - 6); + p.y += (origin ().y - 1); + check_link (&p); + } + } + if (_selecting || _iscross) + { + p = ep->v.mouse.where; + if (_selecting) + _isselection = TRUE;; + { + _isselection = TRUE; + } + // scroll if necessary + if (p.y >= _textrows + 1l) + { + if (_isselection) + erase_selection (); + if (_iscross) + erase_crossbar (); + dispatch_e_scroll (win, K_DOWN); + if (_isselection) + display_selection (); + if (_iscross) + display_crossbar (); + } + else if (p.y <= 0l) + { + if (_isselection) + erase_selection (); + if (_iscross) + erase_crossbar (); + dispatch_e_scroll (win, K_UP); + if (_isselection) + display_selection (); + if (_iscross) + display_crossbar (); + } + else if (p.x <= 5l) + { + if (_isselection) + erase_selection (); + if (_iscross) + erase_crossbar (); + dispatch_e_scroll (win, K_LEFT); + if (_isselection) + display_selection (); + if (_iscross) + display_crossbar (); + } + else if (p.x >= _textcolumns + 6) + { + if (_isselection) + erase_selection (); + if (_iscross) + erase_crossbar (); + dispatch_e_scroll (win, K_RIGHT); + if (_isselection) + display_selection (); + if (_iscross) + display_crossbar (); + } + if (_selecting) + { + if (in_text (p)) + { + p.x += (origin ().x - 6); + p.y += (origin ().y - 1); + _point = p; + if (_point.y >= _txt.lines ()) + _point.y = _txt.lines () - 1l; + } + if (_point != _sel_end) + { + erase_selection (); + _sel_end = _point; + display_selection (); + } + } + } + if (_iscross) + { + newcross = ep->v.mouse.where; + if (_cross.h != newcross.h || _cross.v != newcross.v) + { + erase_crossbar (); + _cross = newcross; + display_crossbar (); + } + } + } + break; + case E_SIZE: + if (is_open ()) + { + check_link (); + erase_point (); + if (_isselection) + erase_selection (); + autoscroll (FALSE); + _textrows = TEXTROWS; + _textcolumns = TEXTCOLUMNS; + autoscroll (TRUE); + repos_buttons (); + display_point (); + _need_update = TRUE; + force_update (); + do_events (); + check_link (&_point); + } + break; + case E_HSCROLL: + case E_VSCROLL: + { + erase_point (); + tlnk = TRUE; + switch (ep->v.scroll.what) + { + case SC_PAGE_UP: + if (ep->type == E_VSCROLL) + { + if (origin ().y > 0) + { + kdiff = (int) (_point.y - origin ().y); + new_origin = origin ().y > _textrows ? + origin ().y - _textrows + 1l : 0; + _point.y = new_origin + kdiff; + check_link (); + update_thumb (origin ().x, new_origin); + _need_update = TRUE; + update (); // ORRIIIBILE! + + check_link (&_point); + _need_update = FALSE; + } + else + beep (); + } + else + { + if (origin ().x > 0) + { + kdiff = (int) (_point.x - origin ().x); + new_origin = origin ().x > _textcolumns ? + origin ().x - _textcolumns + 1 : 0; + _point.x = new_origin + kdiff; + check_link (); + update_thumb(new_origin, _point.y); + _need_update = TRUE; + update (); // AAAARGH! + + check_link (&_point); + _need_update = FALSE; + } + else + beep (); + } + break; + case SC_LINE_UP: + if (ep->type == E_VSCROLL) + { + _need_update = FALSE; + if (origin ().y > 0l) + { + _point.y--; + if (need_paint_sel ()) + erase_selection (); + check_link (); + update_thumb (origin ().x, origin ().y - 1l); + _need_scroll = down; + } + else + beep (); + } + else + { + _need_update = FALSE; + if (origin ().x > 0l) + { + if (need_paint_sel (FALSE)) + erase_selection (); + check_link (); + update_thumb (origin ().x - 1l, origin ().y); + _point.x--; + _need_scroll = right; + } + else + beep (); + } + break; + case SC_PAGE_DOWN: + if (ep->type == E_VSCROLL) + { + if ((origin ().y + _textrows) < _txt.lines ()) + { + kdiff = (int) (_point.y - origin ().y); + new_origin = (_txt.lines () - origin ().y) > + (_textrows * 2l) ? + origin ().y + _textrows - 1 : _txt.lines () - _textrows; + _point.y = new_origin + kdiff; + check_link (); + update_thumb (origin ().x, new_origin); + _need_update = TRUE; + update (); // AAAARGH! + + check_link (&_point); + _need_update = FALSE; + } + else + beep (); + } + else + { + if ((origin ().x + _textcolumns) < 256) + { + kdiff = (int) (_point.x - origin ().x); + new_origin = (256 - origin ().x) > _textcolumns ? + origin ().x + _textcolumns - 1 : 256 - _textcolumns; + _point.x = new_origin + kdiff; + check_link (); + update_thumb (new_origin, origin ().y); + _need_update = TRUE; + update (); // AAAARGH! + + check_link (&_point); + _need_update = FALSE; + } + else + beep (); + } + break; + case SC_LINE_DOWN: + if (ep->type == E_VSCROLL) + { + _need_update = FALSE; + if ((origin ().y + _textrows) < _txt.lines ()) + { + if (need_paint_sel ()) + erase_selection (); + check_link (); + update_thumb (origin ().x, origin ().y + 1l); + _point.y++; + _need_scroll = up; + } + else + beep (); + } + else + { + _need_update = FALSE; + if ((origin ().x + _textcolumns) < 255) + { + if (need_paint_sel (FALSE)) + erase_selection (); + check_link (); + update_thumb (origin ().x + 1l, origin ().y); + _need_scroll = left; + _point.x++; + } + else + beep (); + } + break; + case SC_THUMB: + + check_link (); + kdiff_x = (int) (_point.x - origin ().x); + kdiff_y = (int) (_point.y - origin ().y); + + p.x = ep->type == E_VSCROLL ? origin ().x : ep->v.scroll.pos; + p.y = ep->type == E_HSCROLL ? origin ().y : ep->v.scroll.pos; + + if ((p.y + _textrows) >= _txt.lines ()) + p.y = _txt.lines () - _textrows; + if ((p.x + _textcolumns) >= 255) + p.x = 255 - _textcolumns; + + update_thumb (p.x, p.y); + + _point.x = ep->type == E_VSCROLL ? origin ().x : + origin ().x + kdiff_x; + _point.y = ep->type == E_HSCROLL ? origin ().y : + origin ().y + kdiff_y; + _need_update = TRUE; + update (); + check_link (&_point); + break; + + default: + break; + } + // for failed scrollings + if (!_selecting && _need_scroll == none) + { + check_link (&_point); + display_point (); + } + } + break; + default: + break; + } + if (_need_scroll != none) + { + _need_update = FALSE; + scroll tmp = _need_scroll; + _need_scroll = none; + shift_screen (tmp); + if (!_selecting) + { + check_link (&_point); + display_point (); + } + if (_isselection) + display_selection (); + } + if (ep->type != E_UPDATE || _need_update) + TWindow ::handler (win, ep); + else if (ep->type == E_UPDATE) + update (); +} + +bool TViswin::on_key (KEY key) +{ + EVENT_TYPE type = E_USER; + + if (_istimer) + return TRUE; + _timer = set_timer (win (), 50l); + _istimer = TRUE; + + if (key == K_UP || key == K_DOWN || key == K_LEFT || key == K_RIGHT) + if (_selflag) + key += K_SHIFT; + + if (_selecting && key != K_SHIFT_UP && key != K_SHIFT_DOWN + && key != K_SHIFT_LEFT && key != K_SHIFT_RIGHT) + _selecting = FALSE; + + switch (key) + { + case CTRL_E: + if (_isedit) + { + check_link (); + call_editor (); + set_focus (); + _need_update = TRUE; + update (); + check_link (&_point); + } + break; + case CTRL_C: + exec_link(); + break; + case CTRL_S: + if (_isprint) + _txt.print (); + break; + case CTRL_R: + _need_update = TRUE; + check_link (); + force_update (); + do_events (); + check_link (&_point); + break; + case K_ESC: + if (_isopen) + abort_print (); + else + { + +#if XVT_OS == XVT_OS_WIN + xvt_statbar_set (""); + xvt_statbar_refresh (); +#endif + stop_run (K_ESC); + } + break; + case K_ENTER: + if (_isselection) + { + erase_selection (); + _isselection = FALSE; + } + break; + case K_TAB: + if (_curbut == (_buttons - 1)) + _curbut = 0; + else + _curbut++; + break; + case K_BTAB: + if (_curbut == 0) + _curbut = _buttons - 1; + else + _curbut--; + break; + case K_SPACE: + case K_CTRL_ENTER: + if (_linkID != -1) + { + exec_link(); + } + else + dispatch_e_char (_button[_curbut], K_SPACE); + break; + case K_LHOME: + _need_update = TRUE; + update_thumb (0, 0); + _point.set (0, 0); + check_link (&_point); + force_update (); + break; + case K_LEND: + _need_update = TRUE; + update_thumb (0, _txt.lines () - _textrows); + _point.set (0, _txt.lines () - 1); + check_link (&_point); + force_update (); + break; + case K_RIGHT: + case K_LEFT: + case K_WRIGHT: + case K_WLEFT: + case K_ALT_RIGHT: + case K_ALT_LEFT: + case K_SHIFT_RIGHT: + case K_SHIFT_LEFT: + type = E_HSCROLL; + break; + case K_UP: + case K_DOWN: + case K_NEXT: + case K_PREV: + case K_CTRL_UP: + case K_CTRL_DOWN: + case K_SHIFT_UP: + case K_SHIFT_DOWN: + type = E_VSCROLL; + break; + case K_F5: + check_link (); + erase_point (); + _isbar = !_isbar; + _need_update = TRUE; + force_update (); + do_events (); + check_link (&_point); + break; + case K_F6: + _selflag = !_selflag; + break; + default: + break; + } + + switch (type) + { + case E_HSCROLL: + case E_VSCROLL: + { + erase_point (); + check_link (); + switch (key) + { + case K_PREV: + dispatch_e_scroll (win(), K_PREV); + break; + case K_NEXT: + dispatch_e_scroll (win(), K_NEXT); + break; + case K_WRIGHT: + dispatch_e_scroll (win(), K_BTAB); + break; + case K_WLEFT: + dispatch_e_scroll (win(), K_TAB); + break; + case K_CTRL_UP: + dispatch_e_scroll (win(), K_UP); + break; + case K_CTRL_DOWN: + dispatch_e_scroll (win(), K_DOWN); + break; + case K_ALT_LEFT: + dispatch_e_scroll (win(), K_LEFT); + break; + case K_ALT_RIGHT: + dispatch_e_scroll (win(), K_RIGHT); + break; + case K_UP: + case K_SHIFT_UP: + _need_update = FALSE; + if (key == K_SHIFT_UP) + { + if (need_paint_sel (FALSE)) + erase_selection (); + if (!_selecting) + { + _sel_start = _point; + _selecting = TRUE; + } + } + if (_point.y > 0l) + { + if (_point.y == origin ().y) + { + if (need_paint_sel ()) + erase_selection (); + update_thumb (origin ().x, --_point.y); + _need_scroll = down; + } + else + _point.y--; + if (key == K_SHIFT_UP) + { + _sel_end = _point; + _isselection = TRUE; + } + } + else + beep (); + break; + case K_LEFT: + case K_SHIFT_LEFT: + _need_update = FALSE; + if (_point.x > 0l) + { + if (key == K_SHIFT_LEFT) + { + if (need_paint_sel (FALSE)) + erase_selection (); + if (!_selecting) + { + _sel_start = _point; + _selecting = TRUE; + } + } + if (_point.x == origin ().x) + { + _need_update = FALSE; + if (need_paint_sel (FALSE)) + erase_selection (); + update_thumb (--_point.x, origin ().y); + _need_scroll = right; + } + else + _point.x--; + if (key == K_SHIFT_LEFT) + { + _sel_end = _point; + _isselection = TRUE; + } + } + else + beep (); + break; + case K_DOWN: + case K_SHIFT_DOWN: + _need_update = FALSE; + if (_point.y < (_txt.lines () - 1)) + { + if (key == K_SHIFT_DOWN) + { + if (need_paint_sel (FALSE)) + erase_selection (); + if (!_selecting) + { + _sel_start = _point; + _selecting = TRUE; + } + } + if (_point.y == origin ().y + _textrows - 1) + { + if (need_paint_sel ()) + erase_selection (); + // check_link(); + update_thumb (origin ().x, (++_point.y) - _textrows + 1); + _need_scroll = up; + } + else + _point.y++; + if (key == K_SHIFT_DOWN) + { + _sel_end = _point; + _isselection = TRUE; + } + } + else + beep (); + break; + case K_RIGHT: + case K_SHIFT_RIGHT: + _need_update = FALSE; + if (_point.x < 256) + { + if (key == K_SHIFT_RIGHT) + { + if (need_paint_sel (FALSE)) + erase_selection (); + if (!_selecting) + { + _sel_start = _point; + _selecting = TRUE; + } + } + if (_point.x == (origin ().x + _textcolumns - 1)) + { + if (need_paint_sel (FALSE)) + erase_selection (); + // check_link(); + update_thumb ((++_point.x) - _textcolumns + 1l, origin ().y); + _need_scroll = left; + } + else + _point.x++; + if (key == K_SHIFT_RIGHT) + { + _sel_end = _point; + _isselection = TRUE; + } + } + else + beep (); + break; + default: + break; + } + if (_need_scroll != none) + { + _need_update = FALSE; + scroll tmp = _need_scroll; + _need_scroll = none; + shift_screen (tmp); + } + if (_isselection) + display_selection (); + check_link (&_point); + force_update (); + } + break; +default: + break; +} + return TWindow::on_key (key); +} + +bool TViswin::call_editor () +{ + TConfig cnf (CONFIG_STUDIO, "Main"); + TString editor (cnf.get ("Editor")); + + bool ok = FALSE; + + if (!editor.empty ()) + { + TString newfilename; + + static FILE_SPEC fs; + get_default_dir (&fs.dir); + strcpy (fs.type, "txt"); + save_dir (); + if (save_file_dlg (&fs, "Salva il file con il nome:") == FL_OK) + { + restore_dir (); + char path[256]; + dir_to_str (&fs.dir, path, sizeof (path)); + newfilename << path << '/' << fs.name; + + TPoint p1, p2; + if (_isselection) + adjust_selection (p1, p2); + + if (_txt.write (newfilename, _isselection ? &p1 : NULL, + _isselection ? &p2 : NULL)) + { + newfilename.insert (" ", 0); + newfilename.insert (editor, 0); + TExternal_app edit (newfilename); + if (edit.run (TRUE)) + beep (); + else + ok = TRUE; + } + } + else + restore_dir (); + } + else + warning_box ("Nessun editor specificato nei parametri studio"); + return ok; +} + +void TViswin::add_line (const char *l) +{ + if (_isopen && !_frozen) + { + if (_txt.frozen ()) // error writing files + + { + close_print (); + return; + } + _txt.append (l); + EVENT ev; + ev.type = E_USER; + ev.v.user.id = (_txt.lines () - origin ().y) <= _textrows ? + E_ADDLINE_ONSCREEN : E_ADDLINE; + dispatch_event (win (), &ev); + do_events (); + } +} + +void TViswin::close_print () +{ + _isopen = FALSE; + kill_timer (_wtimer); + _need_update = TRUE; + force_update (); +} + +TViswin ::TViswin (const char *fname, + const char *title, + bool editbutton, + bool printbutton, + bool linkbutton): + _filename (fname), _txt (fname, BUFFERSIZE), _islink (linkbutton), _isedit (editbutton), + _isprint (printbutton), _isbar (FALSE), _istimer (FALSE), _iscross (FALSE), + _isselection (FALSE), _sel_displayed (FALSE), _cross_displayed (FALSE), + _link_displayed (FALSE), _point_displayed (FALSE), _selecting (FALSE), + _scrolling (FALSE), _selflag (FALSE), _need_update (TRUE), _need_scroll (none), + _multiple (FALSE), + _frozen (FALSE) +{ + if (title == NULL) + title = (fname ? fname : "Anteprima di stampa"); + + _isopen = fname == NULL; + if (_isopen) + _filename = _txt.name (); + + for (int i = 0; i < MAXBUT; i++) + _button[i] = NULL_WIN; + + const int larg = 76; + const int alt = 20; + RCT r; + get_client_rect (TASK_WIN, &r); + int maxlarg = r.right / CHARX - 6; // Calculates max window width + + int maxalt = r.bottom / CHARY - 6; + if (larg > maxlarg) + maxlarg = larg; + if (alt > maxalt) + maxalt = alt; + +#if XVT_OS == XVT_OS_WIN + for (i = 0; i < 4; i++) + _picture[i] = cpb_picture_load (BMP_MODULE1 + i); + _modpic = cpb_picture_load (BMP_MODULE); +#endif + + create (-1, -1, maxlarg, maxalt, title, + WSF_CLOSE | WSF_HSCROLL | WSF_VSCROLL | WSF_SIZE); + + set_opaque_text (TRUE); + set_font (FF_FIXED); + + add_button (DLG_QUIT, DLG_QUIT_TITLE); + _buttons = 1; + + if (_isedit) + { + add_button (DLG_EDIT, DLG_EDIT_TITLE); + _buttons++; + } + if (_islink) + { + _link_button = add_button (DLG_LINK, DLG_LINK_TITLE); + _buttons++; + xvt_enable_control (_link_button, FALSE); + } + if (_isprint) + { + add_button (DLG_PRINT, DLG_PRINT_TITLE); + _buttons++; + } + + //#if XVT_OS == XVT_OS_SCOUNIX + // maximize(); + // #endif + + _curbut = 0; + + if (_isopen) + _wtimer = set_timer (win (), 150l); + + _point.set (0, 0); + autoscroll (FALSE); + _textrows = TEXTROWS; + _textcolumns = TEXTCOLUMNS; + autoscroll (TRUE); + + _links = &(main_app().printer ().links ()); + _multiple = main_app().printer ().ismultiplelink (); + _bg = main_app().printer ().getbgdesc (); + _isbackground = _bg->items () > 0; + _formlen = main_app().printer ().formlen (); + + for (i = 0; i < _links->items (); i++) + { + TToken_string & t = (TToken_string &) (*_links)[i]; + char f = *(t.get (1)); + char b = *(t.get (2)); + t.restart (); + _txt.set_hotspots (f, b); + } + _hotspots = &(_txt.hotspots ()); +} + +TViswin ::~TViswin () +{ +#if XVT_OS == XVT_OS_WIN + for (int i = 0; i < 4; i++) + picture_free (_picture[i]); +#endif +} diff --git a/include/viswin.h b/include/viswin.h index adcef8012..e53737a06 100755 --- a/include/viswin.h +++ b/include/viswin.h @@ -1,143 +1,143 @@ -/* This is really -*-c++-*- */ -#ifndef __VISWIN_H -#define __VISWIN_H - -#ifndef __ARRAY_H -#include -#endif - -#ifndef __WINDOW_H -#include -#endif - -#ifndef __STRINGS_H -#include -#endif - -#ifndef __TEXTFILE_H -#include -#endif - -class TViswin : public TScroll_window -{ - enum { MAXBUT = 4, MAXLEN = 256, BUFFERSIZE = 256, MAXPIC=4}; - enum scroll { none, up, down, left, right }; - - TFilename _filename; // name of visfile - bool _islink; // "link" button present - bool _isedit; // "edit" button present - bool _isprint; // "print" button present - bool _iscross; // crossbars being drawn - bool _selecting; // selection in progress - bool _isselection; // selection active - bool _isbar; // X-bar drawn instead of cursor at point - bool _scrolling; // scrolling in progress - bool _need_update; // full update required - bool _istimer; // timer successivo attivo? - bool _isopen; // new lines may arrive - bool _selflag; - bool _sel_displayed; - bool _link_displayed; - bool _cross_displayed; - bool _point_displayed; - long _timer; // timer per evitare autorepeat tasti - long _wtimer; // wait timer before close() - scroll _need_scroll; // scrolling required? - bool _wasneeded; // flag for smart painting - WINDOW _button[MAXBUT]; // button array - int _curbut; // button which currently has focus - int _buttons; // button count - WINDOW _link_button; - - long _textrows; // righe di testo - long _textcolumns; // indovina indovinello - - TTextfile _txt; // text being displayed - long _firstline; // 1rst text line being displayed - long _lastline; // last text line being displayed - - int _formlen; // length of a page - - TPoint _point; // current point position - PNT _cross; // current crossbar point - TPoint _sel_start; // start of selection (column, line of FILE) - TPoint _sel_end; // end of selection (ibidem) - - TArray* _links; // admitted links - TArray* _hotspots; // hotspots - - bool need_paint_sel(bool smart = TRUE); - PICTURE _picture[MAXPIC]; // pictures - PICTURE _modpic; - bool _multiple; - char _linktxt[80]; - int _linkID; - TToken_string _multiple_link; - - TArray* _bg; - bool _isbackground; - bool _frozen; - -protected: - - virtual bool on_key (KEY); - virtual void open(); - - void shift_screen(scroll); - void paint_screen(); - void draw_crossbars(); - - void paint_header(); - void paint_point(bool erase = FALSE); - void paint_row(long r); - void paint_column(long r, bool end); - void paint_selection(); - void paint_waitbar(bool xor = TRUE); - void paint_background(long, int); - bool call_editor(); - bool in_text(const TPoint& p) const; - WINDOW add_button(short id, const char* caption); - void repos_buttons(); - void adjust_selection(TPoint& p1, TPoint& p2); - void display_selection(); - void erase_selection(); - void display_crossbar(); - void erase_crossbar(); - void display_point(); - void erase_point(); - bool check_link(TPoint* where = NULL); - bool adjust_box(long& x1, long& x2, long y); - void paint_link(long, long, long); - void erase_link(long, long, long); - void display_link(long, long, long, const char*); - void freeze() { _frozen = TRUE; } - void exec_link(); - -protected: - - virtual void update(); - virtual void handler(WINDOW win, EVENT* ep); - -public: - - // gestione "collegamenti": vengono passati il testo completo, - // il punto di inizio selezione e quello di fine selezione; se - // non c'e' selezione non viene chiamata affatto (il bottone non fa nulla) - // Se serve, si faccia stop_run() qui dentro - virtual void process_link(TTextfile& txt, TPoint start, TPoint end) { } - void close_print(); - bool frozen() { return _frozen; } - void abort_print(); - - void add_line(const char* l); - - TViswin (const char* fname = NULL, - const char* title = NULL, - bool editbutton = TRUE, - bool printbutton = TRUE, - bool linkbutton = TRUE); - - virtual ~TViswin (); -}; - -#endif +/* This is really -*-c++-*- */ +#ifndef __VISWIN_H +#define __VISWIN_H + +#ifndef __ARRAY_H +#include +#endif + +#ifndef __WINDOW_H +#include +#endif + +#ifndef __STRINGS_H +#include +#endif + +#ifndef __TEXTFILE_H +#include +#endif + +class TViswin : public TScroll_window +{ + enum { MAXBUT = 4, MAXLEN = 256, BUFFERSIZE = 256, MAXPIC=4}; + enum scroll { none, up, down, left, right }; + + TFilename _filename; // name of visfile + bool _islink; // "link" button present + bool _isedit; // "edit" button present + bool _isprint; // "print" button present + bool _iscross; // crossbars being drawn + bool _selecting; // selection in progress + bool _isselection; // selection active + bool _isbar; // X-bar drawn instead of cursor at point + bool _scrolling; // scrolling in progress + bool _need_update; // full update required + bool _istimer; // timer successivo attivo? + bool _isopen; // new lines may arrive + bool _selflag; + bool _sel_displayed; + bool _link_displayed; + bool _cross_displayed; + bool _point_displayed; + long _timer; // timer per evitare autorepeat tasti + long _wtimer; // wait timer before close() + scroll _need_scroll; // scrolling required? + bool _wasneeded; // flag for smart painting + WINDOW _button[MAXBUT]; // button array + int _curbut; // button which currently has focus + int _buttons; // button count + WINDOW _link_button; + + long _textrows; // righe di testo + long _textcolumns; // indovina indovinello + + TTextfile _txt; // text being displayed + long _firstline; // 1rst text line being displayed + long _lastline; // last text line being displayed + + int _formlen; // length of a page + + TPoint _point; // current point position + PNT _cross; // current crossbar point + TPoint _sel_start; // start of selection (column, line of FILE) + TPoint _sel_end; // end of selection (ibidem) + + TArray* _links; // admitted links + TArray* _hotspots; // hotspots + + bool need_paint_sel(bool smart = TRUE); + PICTURE _picture[MAXPIC]; // pictures + PICTURE _modpic; + bool _multiple; + TString80 _linktxt; + int _linkID; + TToken_string _multiple_link; + + TArray* _bg; + bool _isbackground; + bool _frozen; + +protected: + + virtual bool on_key (KEY); + virtual void open(); + + void shift_screen(scroll); + void paint_screen(); + void draw_crossbars(); + + void paint_header(); + void paint_point(bool erase = FALSE); + void paint_row(long r); + void paint_column(long r, bool end); + void paint_selection(); + void paint_waitbar(bool xor = TRUE); + void paint_background(long, int); + bool call_editor(); + bool in_text(const TPoint& p) const; + WINDOW add_button(short id, const char* caption); + void repos_buttons(); + void adjust_selection(TPoint& p1, TPoint& p2); + void display_selection(); + void erase_selection(); + void display_crossbar(); + void erase_crossbar(); + void display_point(); + void erase_point(); + bool check_link(TPoint* where = NULL); + bool adjust_box(long& x1, long& x2, long y); + void paint_link(long, long, long); + void erase_link(long, long, long); + void display_link(long, long, long, const char*); + void freeze() { _frozen = TRUE; } + void exec_link(); + +protected: + + virtual void update(); + virtual void handler(WINDOW win, EVENT* ep); + +public: + + // gestione "collegamenti": vengono passati il testo completo, + // il punto di inizio selezione e quello di fine selezione; se + // non c'e' selezione non viene chiamata affatto (il bottone non fa nulla) + // Se serve, si faccia stop_run() qui dentro + virtual void process_link(TTextfile& txt, TPoint start, TPoint end) { } + void close_print(); + bool frozen() { return _frozen; } + void abort_print(); + + void add_line(const char* l); + + TViswin (const char* fname = NULL, + const char* title = NULL, + bool editbutton = TRUE, + bool printbutton = TRUE, + bool linkbutton = TRUE); + + virtual ~TViswin (); +}; + +#endif