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,6 +213,9 @@ public:
// @cmember Aggiorna la lista completa degli identificatori dei campi di output da un campo
void copy_output(const TBrowse * b);
// @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);

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,6 +51,9 @@ bool fatal_box(
// @comm Il programma viene interrotto al momento in cui si e' verificato l'errore.
{
buildmsg();
if (__batch)
__errors.add(msg);
else
xvt_dm_post_fatal_exit(msg);
return false;
}
@ -29,6 +68,9 @@ bool error_box(
// e l'icona punto esclamativo.
{
buildmsg();
if (__batch)
__errors.add(msg);
else
xvt_dm_post_error(msg);
return false;
}
@ -42,6 +84,9 @@ bool warning_box(
// e l'icona punto di domanda.
{
buildmsg();
if (__batch)
__warnings.add(msg);
else
xvt_dm_post_warning(msg);
return 0;
}
@ -55,6 +100,9 @@ bool message_box(
// e l'icona informazioni.
{
buildmsg();
if (__batch)
__warnings.add(msg);
else
xvt_dm_post_message(msg);
return false;
}
@ -68,6 +116,9 @@ bool sorry_box(
// e l'icona informazioni.
{
buildmsg();
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);
}
@ -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;
@ -2688,8 +2695,26 @@ void TMask::post_error_message(const char* msg, int sev)
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

@ -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();
};
@ -39,6 +44,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,6 +608,9 @@ 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;
@ -640,7 +704,8 @@ TSpreadsheet::TSpreadsheet(
TSpreadsheet::~TSpreadsheet()
{
delete _row_properties;
if (_saved_properties != NULL)
delete _saved_properties;
}
TMask& TSpreadsheet::sheet_mask() const
@ -2346,21 +2411,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;
}
row = 0;
TRow_property* p = (TRow_property*)_properties.objptr(row);
if (p == NULL)
{
if (create)
if (p == NULL && create)
{
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
{
if (has_filtered_cursor())
{
const TEdit_field& f = get_search_field();
return *f.browse()->cursor();
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;
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,6 +1410,13 @@ void TRelation_application::main_loop()
}
}
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

@ -25,6 +25,7 @@
#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
@ -74,6 +75,7 @@ class TRelation_application : public TSkeleton_application
int _autodelete;
// @cmember:(INTERNAL) Flag di navigazione tramite toolbar
bool _navigating;
bool _locked;
private:
// @cmember:(INTERNAL) Carica la transazione corrente (protocollo via .ini)
@ -106,7 +108,7 @@ private:
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;
virtual TCursor* get_filtered_cursor() const;
// @cmember:(INTERNAL) Sistema il bottone ricerca se necessario
void set_find_button();
@ -195,7 +197,7 @@ protected:
// @cmember Richiede se il record corrente e' protetto (non cancellabile)
virtual bool protected_record(TRectype&)
{ return false; }
{ return _locked; }
// @cmember Richiede se il record corrente e' protetto (non cancellabile)
virtual bool protected_record(TRelation &);
@ -205,7 +207,7 @@ protected:
// @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); }

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