From 24ed90d54eb79602809210197fe1ebe596cf87a8 Mon Sep 17 00:00:00 2001 From: bonazzi Date: Mon, 18 Jul 2016 20:06:53 +0000 Subject: [PATCH] Patch level : 10.0 274 Files correlati : ca2.exe Ricompilazione Demo : [ ] Commento : MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Corretto comportamento dei sorted_cursor per le maschere. Ora la ricerca viene fatta sulla chiave di sort. Aggiunta modalità batch delle transazioni. Viene generato un log e l'esecuzione non viene interrotta da segnalazioni ( Da collaudare meglio alla prima occasione). Resa possibile la visualizzazione di record bloccati da un altro utente. Queste funzionalità sono presenti nelle relapp dall patch 274 e successive. git-svn-id: svn://10.65.10.50/branches/R_10_00@23210 c028cbd2-c16b-5b4b-a496-9718f37d4682 --- include/brwbut.cpp | 63 +++++ include/brwbut.h | 5 +- include/checks.cpp | 90 ++++++- include/checks.h | 13 +- include/mask.cpp | 29 ++- include/mask.h | 5 + include/maskfld.cpp | 14 +- include/maskfld.h | 5 + include/msksheet.cpp | 236 ++++++++++++++++-- include/msksheet.h | 6 + include/relapp.cpp | 168 +++++++++---- include/relapp.h | 568 ++++++++++++++++++++++--------------------- include/relation.cpp | 117 ++++++++- include/relation.h | 8 +- 14 files changed, 963 insertions(+), 364 deletions(-) diff --git a/include/brwbut.cpp b/include/brwbut.cpp index 55f2fe29a..18f457c31 100644 --- a/include/brwbut.cpp +++ b/include/brwbut.cpp @@ -1,6 +1,8 @@ #include #include +#include #include +#include #include #include #include @@ -385,6 +387,67 @@ bool TBrowse::parse_copy(const TString& what, const TBrowse& b) return true; } +void TBrowse::update_filter(TEdit_field * f) +{ + if (!f->in_key(0)) + { + TString rf = get_user_read_filter(); rf.trim(); + + if (rf.not_empty()) + { + TExpression e(rf); + bool ok = true; + + for (int i = e.numvar()-1; ok && i >= 0; i--) + { + TString s = e.varname(i); + TString id; + int fileid = 0; + int pos = s.find("->"); + + if (pos > 0) + { + id = s.left(pos); id.strip(" "); + fileid = name2log(id); + pos += 2; + } + else + { + pos = s.find('.'); + if (pos > 0) + { + id = s.left(pos); id.strip(" "); + fileid = name2log(id); + pos++; + } + else + pos = 0; + } + if (fileid < CNF_GENERAL) + { + s.ltrim(pos); + int par = s.find('[', pos); + + if (par >= 0) + s.cut(par); + TRelation * r = cursor()->relation(); + ok = (fileid == 0 && r->curr().exist(s)) || (r->log2ind(fileid) >= 0 && r->curr(fileid).exist(s)); + } + } + if (ok) + { + if (_filter.blank()) + _filter = rf; + else + { + _filter.insert("(", 0); + _filter << ")&&(" << rf << ')'; + } + } + } + } +} + void TBrowse::replace_cursor(TCursor* c) { if (_relation != NULL) diff --git a/include/brwbut.h b/include/brwbut.h index 7dfdecebc..0612b005b 100644 --- a/include/brwbut.h +++ b/include/brwbut.h @@ -213,7 +213,10 @@ public: // @cmember Aggiorna la lista completa degli identificatori dei campi di output da un campo void copy_output(const TBrowse * b); - // @cmember Cambia il cursore senza darne il possesso (come nella COPY USE) + // @cmember Aggiorna il filtro con l'espressione per l'utente + void update_filter(TEdit_field * f); + + // @cmember Cambia il cursore senza darne il possesso (come nella COPY USE) void replace_cursor(TCursor* c); // @cmember Aggiunge un campo di output alla posizione diff --git a/include/checks.cpp b/include/checks.cpp index 5b0673f0d..4d494d3ae 100755 --- a/include/checks.cpp +++ b/include/checks.cpp @@ -3,8 +3,44 @@ #include #include #include +#include + +#ifdef WIN32 +#define buildmsg() char msg[1024];va_list argptr;va_start(argptr,fmt);_vsnprintf_s(msg,sizeof(msg),_TRUNCATE,fmt,argptr);va_end(argptr);msg[1023] = '\0'; +#else +#define buildmsg() char msg[1024];va_list argptr;va_start(argptr,fmt);vsprintf(msg,fmt,argptr);va_end(argptr) +#endif + +static bool __batch = false; +TString_array __errors; +TString_array __warnings; + +bool is_batch() +{ + return __batch; +} + +void batch(bool on) +{ + __batch = on; + if (on) + { + __errors.destroy(); + __warnings.destroy(); + } +} + +TString_array & errors() +{ + return __errors; +} + +TString_array & warnings() +{ + return __warnings; +} + -#define buildmsg() char msg[1024];va_list argptr;va_start(argptr,fmt);vsnprintf_s(msg,sizeof(msg),_TRUNCATE,fmt,argptr);va_end(argptr); // @doc EXTERNAL @@ -15,7 +51,10 @@ bool fatal_box( // @comm Il programma viene interrotto al momento in cui si e' verificato l'errore. { buildmsg(); - xvt_dm_post_fatal_exit(msg); + if (__batch) + __errors.add(msg); + else + xvt_dm_post_fatal_exit(msg); return false; } @@ -29,7 +68,10 @@ bool error_box( // e l'icona punto esclamativo. { buildmsg(); - xvt_dm_post_error(msg); + if (__batch) + __errors.add(msg); + else + xvt_dm_post_error(msg); return false; } @@ -42,7 +84,10 @@ bool warning_box( // e l'icona punto di domanda. { buildmsg(); - xvt_dm_post_warning(msg); + if (__batch) + __warnings.add(msg); + else + xvt_dm_post_warning(msg); return 0; } @@ -55,7 +100,10 @@ bool message_box( // e l'icona informazioni. { buildmsg(); - xvt_dm_post_message(msg); + if (__batch) + __warnings.add(msg); + else + xvt_dm_post_message(msg); return false; } @@ -68,7 +116,10 @@ bool sorry_box( // e l'icona informazioni. { buildmsg(); - xvt_dm_post_note(msg); + if (__batch) + __warnings.add(msg); + else + xvt_dm_post_note(msg); return false; } @@ -78,6 +129,11 @@ bool noyes_box( ...) // @parmvar Uno o piu' parametri corrispondenti ai codici in

{ buildmsg(); + if (__batch) + { + __errors.add(msg); + return true; + } ASK_RESPONSE r = xvt_dm_post_ask("No", "Si", NULL, msg); return r == RESP_DEFAULT; } @@ -88,6 +144,11 @@ int noyesall_box( ...) // @parmvar Uno o piu' parametri corrispondenti ai codici in

{ buildmsg(); + if (__batch) + { + __errors.add(msg); + return K_NO; + } ASK_RESPONSE r = xvt_dm_post_ask("No", "Si", "Si Tutti", msg); return r == RESP_DEFAULT ? K_YES : (r == RESP_2 ? K_NO : K_SPACE); } @@ -106,6 +167,11 @@ bool yesno_box( // @flag 0 | Se viene premuto il taso NO { buildmsg(); + if (__batch) + { + __errors.add(msg); + return false; + } ASK_RESPONSE r = xvt_dm_post_ask("Si", "No", NULL, msg); return r == RESP_DEFAULT; } @@ -116,6 +182,11 @@ int yesnoall_box( ...) // @parmvar Uno o piu' parametri corrispondenti ai codici in

{ buildmsg(); + if (__batch) + { + __errors.add(msg); + return K_NO; + } ASK_RESPONSE r = xvt_dm_post_ask("No", "Si", "No Tutti", msg); return r == RESP_DEFAULT ? K_NO : (r == RESP_2 ? K_YES : K_SPACE); } @@ -139,7 +210,7 @@ bool yesnofatal_box( // // @xref { - buildmsg(); + buildmsg(); #ifdef DBG char user[32]; xvt_sys_get_user_name(user, sizeof(user)); @@ -170,6 +241,11 @@ int yesnocancel_box( // @xref { buildmsg(); + if (__batch) + { + __errors.add(msg); + return K_NO; + } ASK_RESPONSE r = xvt_dm_post_ask("Si", "No", "Annulla", msg); return r == RESP_DEFAULT ? K_YES : (r == RESP_2 ? K_NO : K_ESC); } diff --git a/include/checks.h b/include/checks.h index 1e535001b..491eb73cc 100755 --- a/include/checks.h +++ b/include/checks.h @@ -1,6 +1,12 @@ #ifndef __CHECKS_H #define __CHECKS_H - + +#ifndef __STDTYPES_H +#include +#endif + +class TString_array; + #ifdef __cplusplus extern "C" { #endif @@ -21,6 +27,11 @@ extern "C" { bool cantaccess_box(const char* filename); bool __trace(const char* fmt, ...); bool __tracemem(const char* fmt); + + void batch(bool on = true); + bool is_batch(); + TString_array & errors(); + TString_array & warnings(); #ifdef __cplusplus } #endif diff --git a/include/mask.cpp b/include/mask.cpp index bc3a378e9..8ea1fd86c 100755 --- a/include/mask.cpp +++ b/include/mask.cpp @@ -90,7 +90,7 @@ WINDOW TMask::curr_win() const return page_win(_page > 0 && _page < _pages ? _page : 0); } -TMask::TMask() : _mask_num(0) +TMask::TMask() : _mask_num(0), _sheet_first_selection_row(-1) { init_mask(); } TMask::TMask(const char* title, int pages, int cols, int rows, @@ -870,6 +870,13 @@ long TMask::handler(WINDOW w, EVENT* ep) case 2: _last_sheet->reset_columns_order(); break; case 3: _last_sheet->on_key(K_F11); break; case 4: _last_sheet->esporta(); break; + case 5: _last_sheet->clear_range_selection(); break; + case 6: + _last_sheet->select_range(_sheet_first_selection_row); + _sheet_first_selection_row = -1; + break; + case 7: _last_sheet->copy_rows(); break; + case 8: _last_sheet->paste_rows(); break; default: break; } return 0L; @@ -2687,9 +2694,27 @@ void TMask::post_error_message(const char* msg, int sev) if (_error_message == msg) return; // Ignora messaggio duplicato; on_idle(); - } + } + if (is_batch()) + { + if (sev > 2) + errors().add(msg); + else + warnings().add(msg); + } + else + { _error_message = msg; _error_severity = sev; + } +} + +KEY TMask::check_mask() + + // @comm Se la finestra non era aperta la apre in modo modale +{ + start_run(); + return stop_run(K_ENTER) ? K_ENTER : K_ESC; } // @doc INTERNAL diff --git a/include/mask.h b/include/mask.h index dbc30f59e..c39650c2f 100755 --- a/include/mask.h +++ b/include/mask.h @@ -98,6 +98,9 @@ class TMask : public TWindow // @cmember:(INTERNAL) Puntatore allo sheet che contiene la maschera (puo' essere NULL) TSheet_field* _sheet; + // @cmember:(INTERNAL) Numero della prima riga di selezione nello sheet + long _sheet_first_selection_row; + // @cmember:(INTERNAL) Handler per gestire i tasti speciali nelle maschere MASK_HANDLER _handler; @@ -475,6 +478,8 @@ public: { return _toolwin; } WINDOW toolbar() const { return _toolbar; } + // @cmember verifica la mascher senza eseguirla + KEY check_mask(); }; // @doc EXTERNAL diff --git a/include/maskfld.cpp b/include/maskfld.cpp index 70950bf32..0a1f5b9e8 100755 --- a/include/maskfld.cpp +++ b/include/maskfld.cpp @@ -788,7 +788,7 @@ bool TMask_field::warning_box( xvt_dm_post_speech(_msg, 1, true); xvtil_statbar_set(_msg); beep(1); - } + } else { mask().post_error_message(_msg, 2); @@ -805,6 +805,15 @@ bool TMask_field::yesno_box(const char* fmt, ...) const return yes; } +bool TMask_field::noyes_box(const char* fmt, ...) const +{ + set_focus(); + build_msg(); + const bool yes = ::noyes_box("%s", _msg); + set_focus(); + return yes; +} + KEY TMask_field::yesnocancel_box(const char* fmt, ...) const { set_focus(); @@ -2035,7 +2044,6 @@ word TEdit_field::class_id() const void TEdit_field::set_len(short w) { - CHECKD(w > 0 && w <= 50, "Invalid field length ", w); _size = w; } @@ -2256,7 +2264,7 @@ bool TEdit_field::parse_item(TScanner& scanner) scanner.line(); } scanner.push(); - + browse()->update_filter(this); if (tablename.full()) { tablename.insert("MTB", 0); diff --git a/include/maskfld.h b/include/maskfld.h index 4ca99d767..49d88f80c 100755 --- a/include/maskfld.h +++ b/include/maskfld.h @@ -256,6 +256,9 @@ public: // @cmember Ritorna true se si tratta di campo fantasma bool ghost() const { return _flags.ghost; } + // @cmember Ritorna true se il campo e' un numero romano + bool persistent() const + { return _flags.persistent; } // @cmember Controlla se il campo appartiene ad una chiave di ricerca virtual bool in_key(word) const @@ -403,6 +406,8 @@ public: virtual bool error_box(const char* fmt, ...) const; // @cmember Crea una yesno-box relativamente al campo (chiama ) virtual bool yesno_box(const char* fmt, ...) const; + // @cmember Crea una noyes-box relativamente al campo (chiama ) + virtual bool noyes_box(const char* fmt, ...) const; // @cmember Crea una yesnocancel-box relativamente al campo (chiama ) virtual KEY yesnocancel_box(const char* fmt, ...) const; diff --git a/include/msksheet.cpp b/include/msksheet.cpp index 08c1b9acd..be4bcdb40 100755 --- a/include/msksheet.cpp +++ b/include/msksheet.cpp @@ -25,6 +25,11 @@ class TCell_property : public TObject public: void set(COLOR back, COLOR fore) { _back = back; _fore = fore; } bool get(COLOR& back, COLOR& fore) const; + + virtual TCell_property & copy(const TCell_property & p); + virtual TObject* dup() const { return new TCell_property(*this); } + + TCell_property(const TCell_property & p); TCell_property(); }; @@ -38,6 +43,19 @@ bool TCell_property::get(COLOR& back, COLOR& fore) const } return false; } + +TCell_property & TCell_property::copy(const TCell_property & p) +{ + _back = p._back; + _fore = p._fore; + return *this; +} + +TCell_property::TCell_property(const TCell_property & p) +{ + copy + (p); +} TCell_property::TCell_property() : _back(COLOR_INVALID), _fore(COLOR_INVALID) { } @@ -58,10 +76,33 @@ public: TBit_array & disabled() { return _disabled;} const TBit_array & disabled() const { return _disabled;} + + virtual TRow_property & copy(const TRow_property & r); + virtual TObject* dup() const { return new TRow_property(*this); } + + TRow_property(const TRow_property & p); TRow_property(); virtual ~TRow_property() { } }; +TRow_property & TRow_property::copy(const TRow_property & p) +{ + _disabled = p._disabled; + _back = p._back; + _fore = p._fore; + _height = p._height; + if (p._cell_prop != NULL) + _cell_prop = new TArray(*p._cell_prop); + else + _cell_prop = NULL; + return *this; +} + +TRow_property::TRow_property(const TRow_property & p) +{ + copy(p); +} + TRow_property::TRow_property() : _back(COLOR_INVALID), _fore(COLOR_INVALID), _height(-1), _cell_prop(NULL) { } @@ -146,13 +187,18 @@ class TSpreadsheet : public TControl // @cmember:(INTERNAL) Array di TToken_strings contenenti le righe TString_array _str; + // @cmember:(INTERNAL) Array di TToken_strings contenenti le righe copiate + TString_array _copied_rows; // @cmember:(INTERNAL) Array delle colonne disattivate (solo visualizzazione) TBit_array _column_disabled; + // @cmember:(INTERNAL) righe selezionate + int _from; + int _to; + // @cmember:(INTERNAL) Array delle proprieta' delle righe TArray _properties; - // @cmember:(INTERNAL) Array delle proprieta' standard di tutte le righe - TRow_property* _row_properties; + TArray * _saved_properties; // @cmember:(INTERNAL) Maschera in cui e' contenuto lo spreadsheet TMask _mask; @@ -403,6 +449,12 @@ public: bool point2cell(const PNT& pnt, short& id, long& row) const; + bool get_range_selection(int & from, int & to) const ; + void clear_range_selection(); + void select_range(int row); + void copy_rows(); + void paste_rows(); + // @cmember Costruttore TSpreadsheet(WINDOW parent, short dlg, short x, short y, short dx, short dy, const char* maskname, int maskno, const char* head, TSheet_field* owner); // @cmember Distruttore @@ -436,8 +488,8 @@ TSpreadsheet::TSpreadsheet( _edit_field(NULL), _cur_row(0), _cur_rec(0), _cur_col(1), _row_dirty(false), _cell_dirty(false), _check_enabled(true), _needs_update(-1), _selection_posted(-1), _ignore_button(0), _save_columns_order(false), - _f9_target(NULL), _auto_append(false), _first_nav_column_id(-1),_last_nav_column_id(-1), - _row_properties(NULL) + _f9_target(NULL), _auto_append(false), _first_nav_column_id(-1), _last_nav_column_id(-1), + _from(-1), _to(-1), _saved_properties(NULL) { int m_width[MAX_COL], v_width[MAX_COL]; int fixed_cols = 0; // Number of fixed columns @@ -512,6 +564,15 @@ TSpreadsheet::TSpreadsheet( XI_OBJ* itf = get_interface(parent); XI_RCT rct = coord2rct(itf, x, y, dx, dy); + + if (x > 0 && dx < 0) + { + RCT max_rct; xvt_vobj_get_client_rect((WINDOW)xi_get_window(itf), &max_rct); + const short MAXX = max_rct.right; + + if (MAXX > 80 * CHARX) + rct.left += (MAXX - 80 * CHARX) / 2; + } rct.right -= 2*XI_FU_MULTIPLE; // toglie scroll-bar // Controlla se posso bloccare anche questa colonna @@ -547,7 +608,10 @@ TSpreadsheet::TSpreadsheet( l->active_back_color = FOCUS_BACK_COLOR; l->white_space_color = MASK_DARK_COLOR; l->rule_color = MASK_DARK_COLOR; - +#ifdef LINUX + l->scroll_on_thumb_track = true; +#endif + // Definizione della prima colonna (numero di riga) word attr = XI_ATR_RJUST; if (sheet_mask().id2pos(FIRST_FIELD-1) >= 0) @@ -640,7 +704,8 @@ TSpreadsheet::TSpreadsheet( TSpreadsheet::~TSpreadsheet() { - delete _row_properties; + if (_saved_properties != NULL) + delete _saved_properties; } TMask& TSpreadsheet::sheet_mask() const @@ -2345,21 +2410,15 @@ void TSpreadsheet::set_row_height(const int row, const int height) TRow_property* TSpreadsheet::get_property(int row, bool create) { - if (row < 0) - { - if (_row_properties == NULL && create) - _row_properties = new TRow_property; - return _row_properties; - } + if (row < 0) + row = 0; TRow_property* p = (TRow_property*)_properties.objptr(row); - if (p == NULL) + + if (p == NULL && create) { - if (create) - { - p = new TRow_property; - _properties.add(p, row); - } + p = new TRow_property; + _properties.add(p, row); } return p; } @@ -2639,6 +2698,11 @@ bool TSpreadsheet::error_box(const char* msg) const int r = _cur_row; const int c = _cur_col; + if (is_batch()) + { + errors().add(msg); + return false; + } if (ADVANCED_GRAPHICS && ANIMATED_BOXES) xvt_dm_popup_error(msg); else @@ -2691,6 +2755,101 @@ bool TSpreadsheet::point2cell(const PNT& pnt, short& id, long& row) const return inside; } +bool TSpreadsheet::get_range_selection(int & from, int & to) const +{ + from = _from; + to = _to; + return _from >= 0; +} + +void TSpreadsheet::clear_range_selection() +{ + _from = _to = -1; + if (_saved_properties) + { + const int it = items(); + for (int r = 0; r < it; r++) + { + TRow_property* prop = (TRow_property*)_saved_properties->objptr(r); + COLOR back = NORMAL_BACK_COLOR; + COLOR fore = NORMAL_COLOR; + + if (prop != NULL) + prop->get(-1, back, fore); + set_back_and_fore_color(back, fore, r, -1); + } + delete _saved_properties; + _saved_properties = NULL; + } +} + +void TSpreadsheet::select_range(int row) +{ + int from = _from; + int to = _to; + + if (row < 0) + row = selected(); + if (_saved_properties == NULL) + _saved_properties = new TArray(_properties); + + if (_from < 0) + _from = _to = row; + else + { + if (row < _from) + from = _from = row; + else + from = _to = row; + } + if (from < 0) + from = 0; + if (from >_from) + from = _from; + if (to < 0) + to = items(); + if (to < _to) + to = _to; + for (int r = from; r <= to; r++) + { + TRow_property* prop = (TRow_property*)_saved_properties->objptr(r); + COLOR back = NORMAL_BACK_COLOR; + COLOR fore = NORMAL_COLOR; + + if (prop != NULL) + prop->get(-1, back, fore); + if (r >= _from && r <= _to) + back = blend_colors(back, FOCUS_BACK_COLOR, 0.75); + set_back_and_fore_color(back, fore, r, -1); + } +} + +void TSpreadsheet::copy_rows() +{ + int from = _from > 0 ? _from : 0; + int to = _to < items() - 1 ? _to : items() - 1; + + _copied_rows.destroy(); + for (int i = from; i <= to; i++) + _copied_rows.add(_str.row(i)); +} + +void TSpreadsheet::paste_rows() +{ + int row = selected(); + int nrows = _copied_rows.items(); + + if (row >= _str.items() - 1) + { + row = _str.items() - 1; + _str.add(_copied_rows.row(--nrows)); + } + + for (int i = nrows - 1; i >= 0; i--) + _str.insert(_copied_rows.row(i), row + 1); +} + + /////////////////////////////////////////////////////////// // TSheet_field /////////////////////////////////////////////////////////// @@ -3692,6 +3851,47 @@ static TString& clean_white_space(TString& str) return str; } +bool TSheet_field::get_range_selection(int &from, int & to) const +{ + TSpreadsheet* s = (TSpreadsheet*)_ctl; + + return s->get_range_selection(from, to); +} + +void TSheet_field::clear_range_selection() +{ + TSpreadsheet* s = (TSpreadsheet*)_ctl; + + s->clear_range_selection(); + force_update(); + s->set_focus_cell(s->_cur_row, s->_cur_col); +} + +void TSheet_field::select_range(int row) +{ + TSpreadsheet* s = (TSpreadsheet*)_ctl; + + s->select_range(row); + force_update(); + s->set_focus_cell(s->_cur_row, s->_cur_col); +} + +void TSheet_field::copy_rows() +{ + TSpreadsheet* s = (TSpreadsheet*)_ctl; + + s->copy_rows(); +} + +void TSheet_field::paste_rows() +{ + TSpreadsheet* s = (TSpreadsheet*)_ctl; + + s->paste_rows(); + on_key(K_CTRL + 'V'); + force_update(); + s->set_focus_cell(s->_cur_row, s->_cur_col); +} /////////////////////////////////////////////////////////// // TSheet_recordset /////////////////////////////////////////////////////////// diff --git a/include/msksheet.h b/include/msksheet.h index b05b87bed..23043d15e 100755 --- a/include/msksheet.h +++ b/include/msksheet.h @@ -285,6 +285,12 @@ public: // @cmember Trasferisce i valori dalla riga alla maschera

void update_mask(int n) { row2mask(n, row(n)); } + bool get_range_selection(int & from, int & to) const ; + void clear_range_selection(); + void select_range(int row = -1); + void copy_rows(); + void paste_rows(); + bool esporta() const; // @cmember Restituisce il numero della colonna corrente diff --git a/include/relapp.cpp b/include/relapp.cpp index fa3058c49..ceee299c2 100755 --- a/include/relapp.cpp +++ b/include/relapp.cpp @@ -16,7 +16,8 @@ TRelation_application::TRelation_application() : _mask(NULL), _search_id(-1), _lnflag(0), - _autodelete(0), _navigating(false) + _autodelete(0), _navigating(false), + _locked(false) { } TRelation_application::~TRelation_application() @@ -34,16 +35,22 @@ bool TRelation_application::has_filtered_cursor() const } -TCursor& TRelation_application::get_filtered_cursor() const +TCursor * TRelation_application::get_filtered_cursor() const { - const TEdit_field& f = get_search_field(); - return *f.browse()->cursor(); + if (has_filtered_cursor()) + { + const TEdit_field& f = get_search_field(); + + return f.browse()->cursor(); + } + else + return NULL; } void TRelation_application::setkey() { if (has_filtered_cursor()) - get_filtered_cursor().setkey(); + get_filtered_cursor()->setkey(); else file().setkey(1); } @@ -99,19 +106,19 @@ void TRelation_application::set_limits( if (f.browse() != NULL) f.browse()->do_input(true); - TCursor& cur = get_filtered_cursor(); - cur.setkey(); - if (cur.items() > 0) + TCursor* cur = get_filtered_cursor(); + cur->setkey(); + if (cur->items() > 0) { - TBaseisamfile& f = cur.file(); + TBaseisamfile& f = cur->file(); if (what & 0x1) { - cur = 0; + *cur = 0; _first = f.recno(); } if (what & 0x2) { - cur = cur.items() - 1; + *cur = cur->items() - 1; _last = f.recno(); } } @@ -270,7 +277,7 @@ void TRelation_application::enable_query() } bool TRelation_application::can_I_write(const TRelation* rel) const -{ return user_can_write(rel); } +{ return !_locked && user_can_write(rel); } bool TRelation_application::can_I_read(const TRelation* rel) const { return user_can_read(rel); } @@ -542,24 +549,30 @@ void TRelation_application::insert_mode() bool TRelation_application::modify_mode() { TRelation* rel = get_relation(); + const TReclock block = can_I_write(rel) ? _testandlock : _nolock; + int err = rel->read(_isequal, block); + if (!can_I_read(rel)) { warning_box(TR("I dati non sono accessibili per l'utente %s"), (const char*)user()); query_mode(); return FALSE; } - - const TReclock block = can_I_write(rel) ? _testandlock : _nolock; - int err = rel->read(_isequal, block); + _locked = false; if (err != NOERR) { if (err == _islocked) - message_box(TR("I dati sono già usati da un altro utente")); + { + _locked = true; + message_box(TR("I dati sono già usati da un altro programma, scrittura disabilitata")); + } else + { error_box(FR("Impossibile leggere i dati: errore %d"), err); - if (!is_transaction()) - query_mode(); - return FALSE; + if (!is_transaction()) + query_mode(); + return false; + } } const bool changing = changing_mask(MODE_MOD); @@ -890,7 +903,9 @@ int TRelation_application::delete_mode() r.restore_status(); can_delete = remove(); } + cur.freeze(false); query_mode(); + cur.freeze(true); } _autodelete = FALSE; } @@ -1395,7 +1410,14 @@ void TRelation_application::main_loop() } } - k = _mask->run(); + if (_curr_trans_mode == TM_BATCH) + { + batch(); + k = _mask->check_mask(); + batch(false); + } + else + k = _mask->run(); switch (k) { @@ -1445,7 +1467,7 @@ void TRelation_application::main_loop() else insert_mode(); } - if (_curr_trans_mode == TM_AUTOMATIC) + if (_curr_trans_mode == TM_AUTOMATIC || _curr_trans_mode == TM_BATCH) _mask->send_key(K_CTRL+'R', 0); break; case K_SAVE: @@ -1489,7 +1511,7 @@ void TRelation_application::main_loop() else insert_mode(); } - if (_curr_trans_mode == TM_AUTOMATIC) + if (_curr_trans_mode == TM_AUTOMATIC || _curr_trans_mode == TM_BATCH) _mask->send_key(K_CTRL+'R', 0); break; case K_DEL: @@ -1525,32 +1547,82 @@ void TRelation_application::main_loop() err = file().readat(_first, _testandlock); break; case K_NEXT: - err = file().reread(); - if (has_filtered_cursor()) { - TCursor& cur = get_filtered_cursor(); - cur.curr() = file().curr(); - cur.read(); - ++cur; - file().curr() = cur.curr(); - err = get_relation()->read(_isequal, _testandlock); + TCursor* c = get_filtered_cursor(); + + if (!has_filtered_cursor() || c->curr().num() != file().curr().num()) + { + for (TEdit_field* e = (TEdit_field *) _mask->get_key_field(1, TRUE); e; e = (TEdit_field *) _mask->get_key_field(1, FALSE)) + { + if (e->shown() && e->browse() != NULL) // Ignora campi invisibili o senza check + { + TCursor* b = e->browse()->cursor(); + + if (b && b->curr().num() == file().curr().num()) + { + c = b; + break; + } + } + } + } + + TCursor* cur = c ; + + if (c == NULL) + cur = new TCursor(get_relation()); + + err = file().reread(); + cur->curr() = file().curr(); + cur->read(); + ++(*cur); + while (cur->pos() < cur->items() && !can_I_read(cur->relation())) + ++(*cur); + file().curr() = cur->curr(); + if (can_I_read(cur->relation())) + err = get_relation()->read(_isequal, _testandlock); + if (c == NULL) + delete cur; } - else - err = file().next(_testandlock); break; case K_PREV: - file().reread(); - if (has_filtered_cursor()) { - TCursor& cur = get_filtered_cursor(); - cur.curr() = file().curr(); - cur.read(); - --cur; - file().curr() = cur.curr(); - err = get_relation()->read(_isequal, _testandlock); + TCursor* c = get_filtered_cursor(); + + if (!has_filtered_cursor() || c->curr().num() != file().curr().num()) + { + for (TEdit_field* e = (TEdit_field *) _mask->get_key_field(1, TRUE); e; e = (TEdit_field *) _mask->get_key_field(1, FALSE)) + { + if (e->shown() && e->browse() != NULL) // Ignora campi invisibili o senza check + { + TCursor* b = e->browse()->cursor(); + + if (b && b->curr().num() == file().curr().num()) + { + c = b; + break; + } + } + } + } + + TCursor* cur = c ; + + if (c == NULL) + cur = new TCursor(get_relation()); + + file().reread(); + cur->curr() = file().curr(); + cur->read(); + --(*cur); + while (cur->pos() > 0 && !can_I_read(cur->relation())) + --(*cur); + file().curr() = cur->curr(); + if (can_I_read(cur->relation())) + err = get_relation()->read(_isequal, _testandlock); + if (c == NULL) + delete cur; } - else - err = file().prev(_testandlock); break; case K_END: err = file().readat(_last, _testandlock); @@ -1601,6 +1673,18 @@ void TRelation_application::main_loop() ini.set("Result", err == NOERR ? "CANCEL" : "ERROR"); ini.set("Error", err); } + if (_curr_trans_mode == TM_BATCH) + { + TString_array & errs = errors(); + + FOR_EACH_ARRAY_ROW(errs, r, s) + ini.set("ErrMsg", *s, "Main", false, r); + + TString_array & warns = warnings(); + + FOR_EACH_ARRAY_ROW(warns, r1, s1) + ini.set("WarningMsg", *s1, "Main", false, r1); + } } _trans_counter++; diff --git a/include/relapp.h b/include/relapp.h index 4b0e08049..836072a74 100755 --- a/include/relapp.h +++ b/include/relapp.h @@ -1,283 +1,285 @@ -#ifndef __RELAPP_H -#define __RELAPP_H - -#ifndef __APPLICAT_H -#include -#endif - -#ifndef __CONFIG_H -#include -#endif - -#ifndef __RELATION_H -#include -#endif - -#ifndef __MASK_H -#include -#endif - -#define TRANSACTION_RUN "RUN" // Run application (eventually sets firm) -#define TRANSACTION_INSERT "INSERT" // Create a new record and fill it -#define TRANSACTION_MODIFY "MODIFY" // Load and modify an existing record -#define TRANSACTION_DELETE "DELETE" // Delete an existing record -#define TRANSACTION_LINK "LINK" // Load an existing record and interactively edit it -#define TM_INTERACTIVE 'I' -#define TM_AUTOMATIC 'A' -#define TM_REMAIN 'R' -// @doc EXTERNAL - -// @class TRelation_application | Classe per la gestione di una applicazione di manutenzione di uno -// o piu' archivi utilizzando una relazione -// -// @base public | TApplication -class TRelation_application : public TSkeleton_application - -// @author:(INTERNAL) Guido - -// @access:(INTERNAL) Private Member -{ - // @cmember:(INTERNAL) Maschera corrente dell'applicazione - TMask* _mask; - // @cmember:(INTERNAL) Primo record - TRecnotype _first; - // @cmember:(INTERNAL) Ultimo record - TRecnotype _last; - // @cmember:(INTERNAL) Campo da utilizzare col bottone Ricerca - int _search_id; - - // @cmember:(INTERNAL) Nome del programma chiamante - TString _autoins_caller; - // @cmember:(INTERNAL) Numero del record nuovo/editato - long _recins; - - // @cmember:(INTERNAL) Indica se e' stato chiamato col messaggio di link - byte _lnflag; - // @cmember:(INTERNAL) Contiene il codice del campo e il valore fisso - TToken_string _fixed; - // @cmember:(INTERNAL) Messaggio da passare all'utente per indicare che e' stata fatta la rinumerazione - TString _renum_message; - - // @cmember:(INTERNAL) Nomi dei file .ini con la transazione da eseguire - TString_array _trans_ini; - // @cmember:(INTERNAL) Numero di file .ini di transazioni - int _ntransactions; - // @cmember:(INTERNAL) Indice del file .ini di _ini con la transazione da eseguire - int _trans_counter; - // @cmember:(INTERNAL) Azione della transazione corrente - TString _curr_transaction; - // @cmember:(INTERNAL) Modalità di esecuzione della transazione corrente (Automatica o interattiva) - char _curr_trans_mode; - // @cmember:(INTERNAL) Transazione ricevuta da ..... - TString _curr_trans_from; - // @cmember:(INTERNAL) Flag di cancellazione automatica veloce - int _autodelete; - // @cmember:(INTERNAL) Flag di navigazione tramite toolbar - bool _navigating; - -private: - // @cmember:(INTERNAL) Carica la transazione corrente (protocollo via .ini) - bool load_transaction() ; - - // @cmember:(INTERNAL) Setta i campi fissati da - bool filter(); - // @cmember:(INTERNAL) Controlla se una chiave e' completa ed esiste su file - bool test_key(word k, bool err); - // @cmember:(INTERNAL) Abilita la ricerca sulla maschera - void enable_query(); - // @cmember:(INTERNAL) Setta i limiti - void set_limits(byte what = 0x3); - // @cmember:(INTERNAL) Abilita i vari bottoni di ricerca della toolbar - void set_toolbar(); - - // @Setta i filtri di lettura - void set_key_filter(); - // @cmember:(INTERNAL) Posiziona l'applicazione in modo richiesta/inserimento (chiama ) - void query_insert_mode() - { query_mode(TRUE); } - // @cmember:(INTERNAL) Entra in modo inserimento - void insert_mode(); - // @cmember:(INTERNAL) Cancella il record corrente - bool relation_remove(); - // @cmember:(INTERNAL) Ritorna il campo di ricerca della maschera - TEdit_field& get_search_field() const; - - // @cmember:(INTERNAL) Permette di autonumerare un record - bool autonum(TMask* m, bool rec); - // @cmember:(INTERNAL) Controlla se il ha un filtro - virtual bool has_filtered_cursor() const; - virtual TCursor& get_filtered_cursor() const; - - // @cmember:(INTERNAL) Sistema il bottone ricerca se necessario - void set_find_button(); - short mask_field_dirty() const; - -// @access Protected Member -protected: // TApplication - // @cmember Effettua i controlli all'inizio dell'applicazione - virtual bool create(); - // @cmember Effettua i controlli alla fine dell'applicazione - virtual bool destroy(); - // @cmember Controlla se e' possibile modificare la ditta corrente durante l'esecuzione dell'applicazione - virtual bool firm_change_enabled() const; - // @cmember Aggiorna i limiti di ricerca sul cambio ditta - virtual void on_firm_change(); - -// @access Protected Member -protected: - // @cmember Ritorna il descrittore del file principale della relazione - TLocalisamfile& file() const - { return get_relation()->lfile(); } - // @cmember Ritorna il primo record - TRecnotype first() const - { return _first;} - // @cmember Ritorna l'ultimo record - TRecnotype last() const - { return _last;} - // @cmember Ritorna il nome del programma chiamante - const TString& autoins_caller() const - { return _autoins_caller;} - // @cmember:(INTERNAL) Seleziona il nuovo modo e ritorna il vecchio - int set_mode(int mode); - - // @cmember Ciclo principale - virtual void main_loop(); - - // @cmember Inizializzazione dei dati dell'utente - virtual bool user_create() pure; - // @cmember Distruzione dei dati dell'utente - virtual bool user_destroy() pure; - - // @cmember Fissa i campi non modificabili - void set_fixed(); - // @cmember Attiva la maschera di ricerca - bool search_mode(); - // @cmember Attiva la maschera di eliminazione - int delete_mode(); - // @cmember Entra in modo di ricerca - void query_mode(bool pre_ins = FALSE); - // @cmember Entra in modo modifica - bool modify_mode(); - // @cmember Legge i campi chiave della maschera e setta il cursore relativo - void setkey(); - // @cmember Indica se la futura ritornera' una maschera diversa - // dalla corrente. - // La richiesta della maschera da utilizzare per ogni fase di lavoro - // (ricerca, inserimento, modifica) avviene sempre in due tempi: e - // . Cio' serve per gestire correttamente le applicazioni - // con maschere multiple. - virtual bool changing_mask(int mode) { return false; } - // @cmember Richiede la maschera da usare - virtual TMask* get_mask(int mode) pure; - - // @cmember:(INTERNAL) Annulla la modifica di un record: toglie il lock - void edit_cancel(); - // @cmember:(INTERNAL) Salva i contenuti della maschera su file - virtual bool save(bool check_dirty); - // @cmember Legge dalla relazione i valori nella maschera

- virtual int read(TMask& m); - // @cmember Scrive sulla relazione i valori dalla maschera

- virtual int write(const TMask& m); - // @cmember Riscrive sulla relazione i valori dalla maschera

- virtual int rewrite(const TMask& m); - // @cmember Cancella il record corrente - virtual bool remove(); - - // @cmember Deve ritornare una stringa nella forma CAMPO1VALORE1CAMPO2VALORE2... - // CAMPOnVALOREn contenente le coppie NUMERO_CAMPO_MASCHERA - VALORE_DA_ASSEGNARE - // che descrivono il prossimo codice libero da utilizzare per la autonumerazione. - // Nel caso di banale numerazione progressiva potrebbe essere implementata come - // return format("%d%s", F_NUM, get_relation()-items()); - virtual const char* get_next_key() - { return ""; } - virtual bool get_next_key(TToken_string& key) - { return false; } - - // @cmember Richiede se il record corrente e' protetto (non cancellabile) - virtual bool protected_record(TRectype&) - { return false; } - - // @cmember Richiede se il record corrente e' protetto (non cancellabile) - virtual bool protected_record(TRelation &); - - virtual bool can_I_write(const TRelation* rel) const; - virtual bool can_I_read(const TRelation* rel) const; - - // @cmember Inizializza la maschera per il modo ricerca - virtual void init_query_mode(TMask&) - { } - // @cmember Inizializza la maschera per il modo ricerca ed inserimento (chiama ) - virtual void init_query_insert_mode(TMask& m) - { init_query_mode(m); } - // @cmember Inizializza la maschera per il modo inserimento - virtual void init_insert_mode(TMask&) - { } - // @cmember Inizializza la maschera per il modo modifica - virtual void init_modify_mode(TMask&) - { } - - // @cmember Indica se abilitare/disabilitare la scrittura sul file - // principale (vedi ) - virtual void write_enable(bool on = TRUE) - { get_relation()->write_enable(0, on); } - // @cmember Indica se disabilitare la scrittura sul file principale (vedi ) - void write_disable() - { write_enable(FALSE); } - - // @cmember Dopo aver salvato si predispone per un nuovo inserimento - virtual bool save_and_new() const; - // @cmember Deve uscire dal programma dopo aver salvato con successo? - virtual bool save_and_quit() const; - - // @cmember Impone il campo da utilizzare col bottone Ricerca - void set_search_field(short id) - { _search_id = id;} - byte autodeleting() const { return _autodelete; } - bool navigating() const { return _navigating; } - bool parse_command_line(); - void ini2query_mask(); - void ini2insert_mask(); - void edit_mask2ini(); - virtual void ini2sheet(TConfig& ini, TSheet_field &sheet); - virtual void sheet2ini(TSheet_field &sheet,TConfig& ini); - virtual void ini2mask(TConfig& ini, TMask& m, bool query); - virtual bool mask2mail(const TMask& m); - // @cmember Breve descrizione del tipo documento corrente - virtual const char* record_description(const TRelation& r) const; - -// @access Public Member -public: - virtual void mask2ini(const TMask& m, TConfig& ini); - // @cmember Ritorna la relazione da modificare - virtual TRelation* get_relation() const pure; - - // @cmember Ricalcola l'attivazione dei bottoni di navigazione - void update_navigation_bar(); - - // @cmember Ritorna la maschera corrente - TMask& curr_mask() const - { return *_mask; } - - // @cmember Ritorna se sono stati posti dei filtri sul file corrente - virtual bool filtered() const - { return _fixed.not_empty(); } - // @cmember Cerca un record corrispondente alla chiave

(0 prima chiave completa) - virtual bool find(word key = 0); - // @cmember Costruisce il membro - void set_link(TMask & m, const char * keyexpr); - // @cmember Ritorna TRUE se e' stato chiamato col messaggio di link - bool lnflag() const { return _lnflag != 0;} - // @cmember Ritorna TRUE se e' una transazione - virtual bool is_transaction() const { return _curr_transaction.not_empty(); } - - virtual word class_id() const { return CLASS_RELATION_APPLICATION; } - - // @cmember Costruttore - TRelation_application(); - // @cmember Distruttore - virtual ~TRelation_application(); -}; - -#endif - - +#ifndef __RELAPP_H +#define __RELAPP_H + +#ifndef __APPLICAT_H +#include +#endif + +#ifndef __CONFIG_H +#include +#endif + +#ifndef __RELATION_H +#include +#endif + +#ifndef __MASK_H +#include +#endif + +#define TRANSACTION_RUN "RUN" // Run application (eventually sets firm) +#define TRANSACTION_INSERT "INSERT" // Create a new record and fill it +#define TRANSACTION_MODIFY "MODIFY" // Load and modify an existing record +#define TRANSACTION_DELETE "DELETE" // Delete an existing record +#define TRANSACTION_LINK "LINK" // Load an existing record and interactively edit it +#define TM_INTERACTIVE 'I' +#define TM_AUTOMATIC 'A' +#define TM_REMAIN 'R' +#define TM_BATCH 'B' +// @doc EXTERNAL + +// @class TRelation_application | Classe per la gestione di una applicazione di manutenzione di uno +// o piu' archivi utilizzando una relazione +// +// @base public | TApplication +class TRelation_application : public TSkeleton_application + +// @author:(INTERNAL) Guido + +// @access:(INTERNAL) Private Member +{ + // @cmember:(INTERNAL) Maschera corrente dell'applicazione + TMask* _mask; + // @cmember:(INTERNAL) Primo record + TRecnotype _first; + // @cmember:(INTERNAL) Ultimo record + TRecnotype _last; + // @cmember:(INTERNAL) Campo da utilizzare col bottone Ricerca + int _search_id; + + // @cmember:(INTERNAL) Nome del programma chiamante + TString _autoins_caller; + // @cmember:(INTERNAL) Numero del record nuovo/editato + long _recins; + + // @cmember:(INTERNAL) Indica se e' stato chiamato col messaggio di link + byte _lnflag; + // @cmember:(INTERNAL) Contiene il codice del campo e il valore fisso + TToken_string _fixed; + // @cmember:(INTERNAL) Messaggio da passare all'utente per indicare che e' stata fatta la rinumerazione + TString _renum_message; + + // @cmember:(INTERNAL) Nomi dei file .ini con la transazione da eseguire + TString_array _trans_ini; + // @cmember:(INTERNAL) Numero di file .ini di transazioni + int _ntransactions; + // @cmember:(INTERNAL) Indice del file .ini di _ini con la transazione da eseguire + int _trans_counter; + // @cmember:(INTERNAL) Azione della transazione corrente + TString _curr_transaction; + // @cmember:(INTERNAL) Modalità di esecuzione della transazione corrente (Automatica o interattiva) + char _curr_trans_mode; + // @cmember:(INTERNAL) Transazione ricevuta da ..... + TString _curr_trans_from; + // @cmember:(INTERNAL) Flag di cancellazione automatica veloce + int _autodelete; + // @cmember:(INTERNAL) Flag di navigazione tramite toolbar + bool _navigating; + bool _locked; + +private: + // @cmember:(INTERNAL) Carica la transazione corrente (protocollo via .ini) + bool load_transaction() ; + + // @cmember:(INTERNAL) Setta i campi fissati da + bool filter(); + // @cmember:(INTERNAL) Controlla se una chiave e' completa ed esiste su file + bool test_key(word k, bool err); + // @cmember:(INTERNAL) Abilita la ricerca sulla maschera + void enable_query(); + // @cmember:(INTERNAL) Setta i limiti + void set_limits(byte what = 0x3); + // @cmember:(INTERNAL) Abilita i vari bottoni di ricerca della toolbar + void set_toolbar(); + + // @Setta i filtri di lettura + void set_key_filter(); + // @cmember:(INTERNAL) Posiziona l'applicazione in modo richiesta/inserimento (chiama ) + void query_insert_mode() + { query_mode(TRUE); } + // @cmember:(INTERNAL) Entra in modo inserimento + void insert_mode(); + // @cmember:(INTERNAL) Cancella il record corrente + bool relation_remove(); + // @cmember:(INTERNAL) Ritorna il campo di ricerca della maschera + TEdit_field& get_search_field() const; + + // @cmember:(INTERNAL) Permette di autonumerare un record + bool autonum(TMask* m, bool rec); + // @cmember:(INTERNAL) Controlla se il ha un filtro + virtual bool has_filtered_cursor() const; + virtual TCursor* get_filtered_cursor() const; + + // @cmember:(INTERNAL) Sistema il bottone ricerca se necessario + void set_find_button(); + short mask_field_dirty() const; + +// @access Protected Member +protected: // TApplication + // @cmember Effettua i controlli all'inizio dell'applicazione + virtual bool create(); + // @cmember Effettua i controlli alla fine dell'applicazione + virtual bool destroy(); + // @cmember Controlla se e' possibile modificare la ditta corrente durante l'esecuzione dell'applicazione + virtual bool firm_change_enabled() const; + // @cmember Aggiorna i limiti di ricerca sul cambio ditta + virtual void on_firm_change(); + +// @access Protected Member +protected: + // @cmember Ritorna il descrittore del file principale della relazione + TLocalisamfile& file() const + { return get_relation()->lfile(); } + // @cmember Ritorna il primo record + TRecnotype first() const + { return _first;} + // @cmember Ritorna l'ultimo record + TRecnotype last() const + { return _last;} + // @cmember Ritorna il nome del programma chiamante + const TString& autoins_caller() const + { return _autoins_caller;} + // @cmember:(INTERNAL) Seleziona il nuovo modo e ritorna il vecchio + int set_mode(int mode); + + // @cmember Ciclo principale + virtual void main_loop(); + + // @cmember Inizializzazione dei dati dell'utente + virtual bool user_create() pure; + // @cmember Distruzione dei dati dell'utente + virtual bool user_destroy() pure; + + // @cmember Fissa i campi non modificabili + void set_fixed(); + // @cmember Attiva la maschera di ricerca + bool search_mode(); + // @cmember Attiva la maschera di eliminazione + int delete_mode(); + // @cmember Entra in modo di ricerca + void query_mode(bool pre_ins = FALSE); + // @cmember Entra in modo modifica + bool modify_mode(); + // @cmember Legge i campi chiave della maschera e setta il cursore relativo + void setkey(); + // @cmember Indica se la futura ritornera' una maschera diversa + // dalla corrente. + // La richiesta della maschera da utilizzare per ogni fase di lavoro + // (ricerca, inserimento, modifica) avviene sempre in due tempi: e + // . Cio' serve per gestire correttamente le applicazioni + // con maschere multiple. + virtual bool changing_mask(int mode) { return false; } + // @cmember Richiede la maschera da usare + virtual TMask* get_mask(int mode) pure; + + // @cmember:(INTERNAL) Annulla la modifica di un record: toglie il lock + void edit_cancel(); + // @cmember:(INTERNAL) Salva i contenuti della maschera su file + virtual bool save(bool check_dirty); + // @cmember Legge dalla relazione i valori nella maschera

+ virtual int read(TMask& m); + // @cmember Scrive sulla relazione i valori dalla maschera

+ virtual int write(const TMask& m); + // @cmember Riscrive sulla relazione i valori dalla maschera

+ virtual int rewrite(const TMask& m); + // @cmember Cancella il record corrente + virtual bool remove(); + + // @cmember Deve ritornare una stringa nella forma CAMPO1VALORE1CAMPO2VALORE2... + // CAMPOnVALOREn contenente le coppie NUMERO_CAMPO_MASCHERA - VALORE_DA_ASSEGNARE + // che descrivono il prossimo codice libero da utilizzare per la autonumerazione. + // Nel caso di banale numerazione progressiva potrebbe essere implementata come + // return format("%d%s", F_NUM, get_relation()-items()); + virtual const char* get_next_key() + { return ""; } + virtual bool get_next_key(TToken_string& key) + { return false; } + + // @cmember Richiede se il record corrente e' protetto (non cancellabile) + virtual bool protected_record(TRectype&) + { return _locked; } + + // @cmember Richiede se il record corrente e' protetto (non cancellabile) + virtual bool protected_record(TRelation &); + + virtual bool can_I_write(const TRelation* rel) const; + virtual bool can_I_read(const TRelation* rel) const; + + // @cmember Inizializza la maschera per il modo ricerca + virtual void init_query_mode(TMask&) + { _locked = false; } + // @cmember Inizializza la maschera per il modo ricerca ed inserimento (chiama ) + virtual void init_query_insert_mode(TMask& m) + { init_query_mode(m); } + // @cmember Inizializza la maschera per il modo inserimento + virtual void init_insert_mode(TMask&) + { } + // @cmember Inizializza la maschera per il modo modifica + virtual void init_modify_mode(TMask&) + { } + + // @cmember Indica se abilitare/disabilitare la scrittura sul file + // principale (vedi ) + virtual void write_enable(bool on = TRUE) + { get_relation()->write_enable(0, on); } + // @cmember Indica se disabilitare la scrittura sul file principale (vedi ) + void write_disable() + { write_enable(FALSE); } + + // @cmember Dopo aver salvato si predispone per un nuovo inserimento + virtual bool save_and_new() const; + // @cmember Deve uscire dal programma dopo aver salvato con successo? + virtual bool save_and_quit() const; + + // @cmember Impone il campo da utilizzare col bottone Ricerca + void set_search_field(short id) + { _search_id = id;} + byte autodeleting() const { return _autodelete; } + bool navigating() const { return _navigating; } + bool parse_command_line(); + void ini2query_mask(); + void ini2insert_mask(); + void edit_mask2ini(); + virtual void ini2sheet(TConfig& ini, TSheet_field &sheet); + virtual void sheet2ini(TSheet_field &sheet,TConfig& ini); + virtual void ini2mask(TConfig& ini, TMask& m, bool query); + virtual bool mask2mail(const TMask& m); + // @cmember Breve descrizione del tipo documento corrente + virtual const char* record_description(const TRelation& r) const; + +// @access Public Member +public: + virtual void mask2ini(const TMask& m, TConfig& ini); + // @cmember Ritorna la relazione da modificare + virtual TRelation* get_relation() const pure; + + // @cmember Ricalcola l'attivazione dei bottoni di navigazione + void update_navigation_bar(); + + // @cmember Ritorna la maschera corrente + TMask& curr_mask() const + { return *_mask; } + + // @cmember Ritorna se sono stati posti dei filtri sul file corrente + virtual bool filtered() const + { return _fixed.not_empty(); } + // @cmember Cerca un record corrispondente alla chiave

(0 prima chiave completa) + virtual bool find(word key = 0); + // @cmember Costruisce il membro + void set_link(TMask & m, const char * keyexpr); + // @cmember Ritorna TRUE se e' stato chiamato col messaggio di link + bool lnflag() const { return _lnflag != 0;} + // @cmember Ritorna TRUE se e' una transazione + virtual bool is_transaction() const { return _curr_transaction.not_empty(); } + + virtual word class_id() const { return CLASS_RELATION_APPLICATION; } + + // @cmember Costruttore + TRelation_application(); + // @cmember Distruttore + virtual ~TRelation_application(); +}; + +#endif + + diff --git a/include/relation.cpp b/include/relation.cpp index de2007e8b..0079f4b29 100755 --- a/include/relation.cpp +++ b/include/relation.cpp @@ -1533,7 +1533,7 @@ void TCursor::setkey(int nkey) } } -int TCursor::test(TIsamop op, TReclock lockop) const +int TCursor::test(TIsamop op, TReclock lockop) { TLocalisamfile& curfile = file(); const TRectype& currec = curfile.curr(); @@ -2049,7 +2049,9 @@ const char* TSorted_cursor::fill_sort_key(TString& k) { const bool is_up = is_upper(s); const char last = s.right(1)[0]; - if (last == '-' || last == '+') + const bool align = last == '*'; + + if (last == '-' || last == '+' || align) s.rtrim(1); const TFieldref f(s,0); @@ -2072,7 +2074,7 @@ const char* TSorted_cursor::fill_sort_key(TString& k) } else { - // if (is_up) // Test inutile: tutte le chiavi sono maiuscole 08-02-2016 + if (is_up) // Test inutile: tutte le chiavi sono maiuscole 08-02-2016 sf.upper(); } switch (fld_type) @@ -2080,9 +2082,24 @@ const char* TSorted_cursor::fill_sort_key(TString& k) case _boolfld: case _charfld: case _memofld: - case _alfafld: sf.left_just(fld_len); break; + case _alfafld: sf.left_just(fld_len > 0 ? fld_len : 50); break; + case _intfld: + case _longfld: + case _intzerofld: + case _longzerofld: sf.right_just(fld_len > 0 ? fld_len : 50); break; case _datefld: break; // Gia' lungo 8! - default : sf.right_just(fld_len); break; + case _realfld: + if (align) + { + real r(sf); + sf = r.string(fld_len > 0 ? fld_len : 50, fld_len > 0 ? (fld_len-4)/2 : 10); + } + else + sf.right_just(fld_len > 0 ? fld_len : 50); + break; + default : + sf.left_just(fld_len > 0 ? fld_len : 50); + break; } k << sf; } @@ -2103,6 +2120,96 @@ bool TSorted_cursor::changed() return rt; } +int TSorted_cursor::test(TIsamop op, TReclock lockop) + +{ + int err = NOERR; + + if (items() == 0L) + { + err = _isemptyfile; + file().setstatus(err); + return err; + } + + TString256 searching; fill_sort_key(searching); + searching.rtrim(); + const int cmplen = searching.len(); + + TRecnotype first = 0L; + TRecnotype last = items()-1; + TRecnotype found = -1L; + + FOR_EACH_ARRAY_ROW(fpkey(), i, s) + { + const int cmp = searching.compare(*s, cmplen); + if (cmp <= 0) + last = (i + 1) * pagesize() - 1; + else + first = i * pagesize(); + } + + const bool ghiacciato = !frozen(); + if (ghiacciato) freeze(true); + + TString256 testing; + while (first <= last) + { + const TRecnotype test = (first+last)/2; + TCursor::operator=(test); // verif + fill_sort_key(testing); + const int cmp = searching.compare(testing, cmplen); + if (cmp == 0) + { + if (op != _isgreat) + { + if (found < 0l || test < found) + found = test; + last = test-1; + } + else + first = test+1; + } + else + { + if (cmp < 0) + { + last = test-1; + if (op != _isequal) + { + if (found < 0l || test < found) + found = test; + } + } + else + first = test+1; + } + } + + if (found >= 0L) + { + TCursor::operator=(found); // verif + file().setstatus(NOERR); + if (lockop != _nolock) + lock(lockop); + } + else + { + + found = items()-1; + if (found >= 0) + TCursor::operator=(found); + err = op == _isequal ? _iskeynotfound : _iseof; + file().setstatus(err); + } + + if (ghiacciato) + freeze(false); + + return err; +} + + TRecnotype TSorted_cursor::read(TIsamop op, TReclock lockop) { TString256 searching; fill_sort_key(searching); diff --git a/include/relation.h b/include/relation.h index 8a1732ab6..3585c0771 100755 --- a/include/relation.h +++ b/include/relation.h @@ -367,8 +367,8 @@ public: // @cmember Ritorna il descrittore della tabella TRectype& curr(const char * tab) const { return _if->lfile(tab).curr(); } - //@cmember Testa la presenza di un record senza spostare il cursore - int test(TIsamop op = _isequal, TReclock lockop = _nolock) const; + //@cmember Testa la presenza di un record + virtual int test(TIsamop op = _isequal, TReclock lockop = _nolock); // @cmember Legge il record virtual TRecnotype read(TIsamop op = _isgteq, TReclock lockop = _nolock); // @cmember Mette un lock sul record @@ -508,6 +508,10 @@ public: // @cmember Si sposta alla posizione

TRecnotype operator =(const TRecnotype nr) { return TCursor::operator =(nr); } + + //@cmember Testa la presenza di un record + virtual int test(TIsamop op = _isequal, TReclock lockop = _nolock); + // @cmember Trova l'indice del record corrente virtual TRecnotype read(TIsamop op = _isgteq, TReclock lockop = _nolock);