Patch level : 10.0 274

Files correlati     :  ca2.exe 
Ricompilazione Demo : [ ]
Commento            :

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
This commit is contained in:
bonazzi 2016-07-18 20:06:53 +00:00
parent 3469b56f48
commit 24ed90d54e
14 changed files with 963 additions and 364 deletions

View File

@ -1,6 +1,8 @@
#include <dongle.h>
#include <execp.h>
#include <expr.h>
#include <msksheet.h>
#include <postman.h>
#include <recarray.h>
#include <recset.h>
#include <relapp.h>
@ -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)

View File

@ -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 <pos>

View File

@ -3,8 +3,44 @@
#include <diction.h>
#include <dongle.h>
#include <keys.h>
#include <strings.h>
#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 <p fmt>
{
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 <p fmt>
{
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 <p fmt>
{
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 <m yesno_box> <m yesnofatal_box>
{
buildmsg();
buildmsg();
#ifdef DBG
char user[32]; xvt_sys_get_user_name(user, sizeof(user));
@ -170,6 +241,11 @@ int yesnocancel_box(
// @xref <m yesno_box> <m yesnofatal_box>
{
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);
}

View File

@ -1,6 +1,12 @@
#ifndef __CHECKS_H
#define __CHECKS_H
#ifndef __STDTYPES_H
#include <stdtypes.h>
#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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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 <f yesno_box>)
virtual bool yesno_box(const char* fmt, ...) const;
// @cmember Crea una noyes-box relativamente al campo (chiama <f yesno_box>)
virtual bool noyes_box(const char* fmt, ...) const;
// @cmember Crea una yesnocancel-box relativamente al campo (chiama <f yesnocancel_box>)
virtual KEY yesnocancel_box(const char* fmt, ...) const;

View File

@ -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
///////////////////////////////////////////////////////////

View File

@ -285,6 +285,12 @@ public:
// @cmember Trasferisce i valori dalla riga alla maschera <p n>
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

View File

@ -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++;

View File

@ -1,283 +1,285 @@
#ifndef __RELAPP_H
#define __RELAPP_H
#ifndef __APPLICAT_H
#include <applicat.h>
#endif
#ifndef __CONFIG_H
#include <config.h>
#endif
#ifndef __RELATION_H
#include <relation.h>
#endif
#ifndef __MASK_H
#include <mask.h>
#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 <md TRelation_application::_fixed>
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 <mf TRelation_application::query_mode>)
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 <c TCursor> 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 <mf TRelation_application::get_mask> ritornera' una maschera diversa
// dalla corrente.
// <nl>La richiesta della maschera da utilizzare per ogni fase di lavoro
// (ricerca, inserimento, modifica) avviene sempre in due tempi: <mf TRelation_application::changing_mask> e
// <mf TRelation_application::get_mask>. 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 <p m>
virtual int read(TMask& m);
// @cmember Scrive sulla relazione i valori dalla maschera <p m>
virtual int write(const TMask& m);
// @cmember Riscrive sulla relazione i valori dalla maschera <p m>
virtual int rewrite(const TMask& m);
// @cmember Cancella il record corrente
virtual bool remove();
// @cmember Deve ritornare una stringa nella forma CAMPO1<pipe>VALORE1<pipe>CAMPO2<pipe>VALORE2<pipe>...
// <pipe>CAMPOn<pipe>VALOREn contenente le coppie NUMERO_CAMPO_MASCHERA - VALORE_DA_ASSEGNARE
// che descrivono il prossimo codice libero da utilizzare per la autonumerazione.
// <nl>Nel caso di banale numerazione progressiva potrebbe essere implementata come
// return format("%d<pipe>%s", F_NUM, get_relation()-<gt>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 <mf TRelation_application::init_query_mode>)
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 <mf TRealtion::write_enable>)
virtual void write_enable(bool on = TRUE)
{ get_relation()->write_enable(0, on); }
// @cmember Indica se disabilitare la scrittura sul file principale (vedi <mf TRealtion::write_enable>)
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 <p key> (0 prima chiave completa)
virtual bool find(word key = 0);
// @cmember Costruisce il membro <md TRelation_application::_fixed>
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 <applicat.h>
#endif
#ifndef __CONFIG_H
#include <config.h>
#endif
#ifndef __RELATION_H
#include <relation.h>
#endif
#ifndef __MASK_H
#include <mask.h>
#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 <md TRelation_application::_fixed>
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 <mf TRelation_application::query_mode>)
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 <c TCursor> 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 <mf TRelation_application::get_mask> ritornera' una maschera diversa
// dalla corrente.
// <nl>La richiesta della maschera da utilizzare per ogni fase di lavoro
// (ricerca, inserimento, modifica) avviene sempre in due tempi: <mf TRelation_application::changing_mask> e
// <mf TRelation_application::get_mask>. 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 <p m>
virtual int read(TMask& m);
// @cmember Scrive sulla relazione i valori dalla maschera <p m>
virtual int write(const TMask& m);
// @cmember Riscrive sulla relazione i valori dalla maschera <p m>
virtual int rewrite(const TMask& m);
// @cmember Cancella il record corrente
virtual bool remove();
// @cmember Deve ritornare una stringa nella forma CAMPO1<pipe>VALORE1<pipe>CAMPO2<pipe>VALORE2<pipe>...
// <pipe>CAMPOn<pipe>VALOREn contenente le coppie NUMERO_CAMPO_MASCHERA - VALORE_DA_ASSEGNARE
// che descrivono il prossimo codice libero da utilizzare per la autonumerazione.
// <nl>Nel caso di banale numerazione progressiva potrebbe essere implementata come
// return format("%d<pipe>%s", F_NUM, get_relation()-<gt>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 <mf TRelation_application::init_query_mode>)
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 <mf TRealtion::write_enable>)
virtual void write_enable(bool on = TRUE)
{ get_relation()->write_enable(0, on); }
// @cmember Indica se disabilitare la scrittura sul file principale (vedi <mf TRealtion::write_enable>)
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 <p key> (0 prima chiave completa)
virtual bool find(word key = 0);
// @cmember Costruisce il membro <md TRelation_application::_fixed>
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

View File

@ -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);

View File

@ -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 <p nr>
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);