Patch level : 2.1 nopatch

Files correlati     : ba1.exe ba8.exe
Ricompilazione Demo : [ ]
Commento            :

ba1 Tolte righe commentate inutili
ba8 Migliorata gestione query per quanto rigurda: date; memo; selezioni Dal/Al.


git-svn-id: svn://10.65.10.50/trunk@11990 c028cbd2-c16b-5b4b-a496-9718f37d4682
This commit is contained in:
guy 2004-04-22 15:53:08 +00:00
parent 912337c3e7
commit 5738d39723
14 changed files with 1102 additions and 321 deletions

View File

@ -30,18 +30,10 @@ void TDir_sheet::add ()
d.zero(); d.zero();
d.put(nitems, _nordir, _sysdirop); d.put(nitems, _nordir, _sysdirop);
_items = nitems; _items = nitems;
/*
isfdptr *newopenf = new isfdptr[_items];
for (int i = 0; i<_items; i++)
newopenf[i] = i<(_items-1) ? openf[i] : NULL;
delete openf;
openf = newopenf;
*/
} }
TDir_sheet::TDir_sheet(const char* title, byte buttons, const char* colonne) TDir_sheet::TDir_sheet(const char* title, byte buttons, const char* colonne)
:TSheet(0, 0, 0, 0, title, colonne, buttons) : TSheet(0, 0, 0, 0, title, colonne, buttons)
{ {
_dir = new TDir; _dir = new TDir;
_rec = new TTrec; _rec = new TTrec;
@ -55,7 +47,6 @@ TDir_sheet::~TDir_sheet()
delete _rec; delete _rec;
} }
void TDir_sheet::get_row(long n, TToken_string& l) void TDir_sheet::get_row(long n, TToken_string& l)
{ {
n++; n++;
@ -73,7 +64,6 @@ void TDir_sheet::get_row(long n, TToken_string& l)
TRec_sheet::TRec_sheet(int logicnum, const char * tab) TRec_sheet::TRec_sheet(int logicnum, const char * tab)
: _descr(NULL), _tab(tab) : _descr(NULL), _tab(tab)
{ {
_external = FALSE; _external = FALSE;
_dir = new TDir; _dir = new TDir;

View File

@ -139,7 +139,7 @@ public:
~TTable_mask(); ~TTable_mask();
}; };
// Converte un nome di tabella nel suo numero loigico // Converte un nome di tabella nel suo numero logico
int TTable_mask::name2num(const TString& name) const int TTable_mask::name2num(const TString& name) const
{ {
int num = 0; int num = 0;
@ -643,6 +643,13 @@ inline bool tok_get_bool(TToken_string& tok, int pos)
return str && *str > ' '; return str && *str > ' ';
} }
static void add_where_clause(TString& where, const char* field, const char* cmp, const char* expr)
{
if (where.not_empty())
where << "AND";
where << '(' << field << cmp << expr << ')';
}
// Genera una query SQL a partire dallo spreadsheet F_SHEET // Genera una query SQL a partire dallo spreadsheet F_SHEET
void TQuery_mask::sheet2sql() void TQuery_mask::sheet2sql()
{ {
@ -653,7 +660,7 @@ void TQuery_mask::sheet2sql()
const bool multiple = _tree.has_son(); const bool multiple = _tree.has_son();
TToken_string from(50, ','), groupby(50, ','), orderby(50, ','); TToken_string from(50, ','), groupby(50, ','), orderby(50, ',');
TString where; TString where, expr_from, expr_to;
TString field; TString field;
FOR_EACH_SHEET_ROW(sheet, i, row) FOR_EACH_SHEET_ROW(sheet, i, row)
@ -672,7 +679,25 @@ void TQuery_mask::sheet2sql()
orderby.add(field); orderby.add(field);
if (tok_get_bool(*row, 4)) // Group if (tok_get_bool(*row, 4)) // Group
groupby.add(field); groupby.add(field);
expr_from = row->get(5); expr_from.trim();
expr_to = row->get(6); expr_to.trim();
if (expr_from.not_empty() || expr_to.not_empty())
{
if (expr_from == expr_to)
{
add_where_clause(where, field, "=", expr_from);
}
else
{
if (expr_from.not_empty())
add_where_clause(where, field, ">=", expr_from);
if (expr_to.not_empty())
add_where_clause(where, field, "<=", expr_to);
}
}
} }
} }
tree2sql(from, where); tree2sql(from, where);
@ -680,7 +705,8 @@ void TQuery_mask::sheet2sql()
TString sql; TString sql;
sql << "SELECT " << select << '\n'; sql << "SELECT " << select << '\n';
sql << "FROM " << from << '\n'; sql << "FROM " << from << '\n';
sql << "WHERE " << where << '\n'; if (!where.blank())
sql << "WHERE " << where << '\n';
if (groupby.not_empty()) if (groupby.not_empty())
sql << "GROUP BY " << groupby << '\n'; sql << "GROUP BY " << groupby << '\n';
if (orderby.not_empty()) if (orderby.not_empty())
@ -833,7 +859,10 @@ bool TQuery_mask::save_fields_sheet(TXmlItem& xml)
field.SetAttr("Group", tok_get_bool(*row,4)); field.SetAttr("Group", tok_get_bool(*row,4));
const char* str = row->get(5); const char* str = row->get(5);
if (str && *str > ' ') if (str && *str > ' ')
field.SetAttr("Expr", str); field.SetAttr("ExprFrom", str);
str = row->get(6);
if (str && *str > ' ')
field.SetAttr("ExprTo", str);
} }
} }
return ok; return ok;
@ -939,7 +968,8 @@ bool TQuery_mask::load_fields_sheet(TXmlItem& xml)
row.add(field.GetBoolAttr("Hidden") ? "X" : "",2); row.add(field.GetBoolAttr("Hidden") ? "X" : "",2);
row.add(field.GetBoolAttr("Sort") ? "X" : "",3); row.add(field.GetBoolAttr("Sort") ? "X" : "",3);
row.add(field.GetBoolAttr("Group") ? "X" : "",4); row.add(field.GetBoolAttr("Group") ? "X" : "",4);
row.add(field.GetAttr("Expr"),5); row.add(field.GetAttr("ExprFrom"),5);
row.add(field.GetAttr("ExprTo"),6);
} }
sheet.force_update(); sheet.force_update();
} }
@ -1072,7 +1102,7 @@ bool TQuery_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{ {
next_page(1001); next_page(1001);
bool ok = true; bool ok = true;
if (_sql_dirty) if (_sql_dirty && !field(F_SQL).empty())
ok = yesno_box(TR("Attenzione: la query verra' rigenerata\n" ok = yesno_box(TR("Attenzione: la query verra' rigenerata\n"
"annullando eventuali modifiche manuali.\n" "annullando eventuali modifiche manuali.\n"
"Si desidera proseguire?")); "Si desidera proseguire?"));

View File

@ -98,11 +98,12 @@ SPREADSHEET F_SHEET -5
BEGIN BEGIN
PROMPT 0 13 "" PROMPT 0 13 ""
ITEM "Tabella@12F" ITEM "Tabella@12F"
ITEM "Colonna@32F" ITEM "Colonna@30F"
ITEM "Nas.@3" ITEM "Nas.@3"
ITEM "Ord.@3" ITEM "Ord.@3"
ITEM "Grp.@3" ITEM "Grp.@3"
ITEM "Condizione@50" ITEM "Da@30"
ITEM "A@30"
END END
BUTTON F_MOVEUP 2 2 BUTTON F_MOVEUP 2 2
@ -233,10 +234,14 @@ BEGIN
PROMPT 35 2 "Raggruppa" PROMPT 35 2 "Raggruppa"
END END
MEMO 106 58 8 STRING 106 70 50
BEGIN BEGIN
PROMPT 1 3 "Condizione " PROMPT 1 3 "Da "
FLAGS "D" END
STRING 107 70 50
BEGIN
PROMPT 1 4 "A "
END END
BUTTON DLG_CANCEL 10 2 BUTTON DLG_CANCEL 10 2

View File

@ -81,7 +81,7 @@ bool TVariant::is_zero() const
case _datefld: return !as_date().ok(); case _datefld: return !as_date().ok();
case _longfld: return _ptr == NULL; case _longfld: return _ptr == NULL;
case _realfld: return as_real().is_zero(); case _realfld: return as_real().is_zero();
case _alfafld: return as_string().blank(); case _alfafld: return real::is_null(as_string());
default: break; default: break;
} }
return true; return true;
@ -248,6 +248,87 @@ TVariant& TVariant::sub(const TVariant& var)
return *this; return *this;
} }
///////////////////////////////////////////////////////////
// TTable name converter
///////////////////////////////////////////////////////////
class TTable_names : public TObject
{
TAssoc_array _names;
TArray _ids;
protected:
void fill();
void add_file(int logic, const TString& table);
public:
const TString& name(int logic_num);
int logic_num(const TString& name);
} _table_names;
void TTable_names::add_file(int logic, const TString& table)
{
TString8* id = new TString8;
id->format("%d", logic);
_names.add(table, id);
_ids.add(table, logic);
}
void TTable_names::fill()
{
FileDes dir;
CGetFile(LF_DIR, &dir, _nolock, NORDIR);
const int nfiles = (int)dir.EOD;
TFilename n;
for (int logic = LF_USER; logic < nfiles; logic++)
{
const FileDes& fd = prefix().get_filedes(logic);
n = fd.SysName; n = n.name(); n.upper();
if (_names.objptr(n) == NULL)
add_file(logic, n);
}
}
int TTable_names::logic_num(const TString& name)
{
TString* str = (TString*)_names.objptr(name);
if (str == NULL)
{
fill();
str = (TString*)_names.objptr(name);
}
if (str == NULL)
{
if (isdigit(name[0]))
add_file(atoi(name), name); else
if (name[0] == '%')
add_file(LF_TABCOM, name); else
if (name.len() == 3)
add_file(LF_TAB, name); else
str = (TString*)_names.objptr(name);
}
return str == NULL ? 0 : atoi(*str);
}
const TString& TTable_names::name(int logic_num)
{
TString* str = (TString*)_ids.objptr(logic_num);
if (str == NULL)
{
fill();
str = (TString*)_ids.objptr(logic_num);
}
return str == NULL ? (const TString&)EMPTY_STRING : *str;
}
const TString& logic2table(int logic_num)
{ return _table_names.name(logic_num); }
int table2logic(const TString& name)
{ return _table_names.logic_num(name); }
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
// Utility // Utility
@ -584,7 +665,6 @@ bool TRecordset::ask_variables(bool all)
set_var(*name, var); set_var(*name, var);
} }
} }
move_to(-1);
} }
return ok; return ok;
} }
@ -654,12 +734,8 @@ class TSQLite : public TObject
{ {
sqlite* _handle; sqlite* _handle;
TFilename _currdb; TFilename _currdb;
TAssoc_array _names;
protected: protected:
void logicnum2name(int logicnum, TString& name) const;
int name2logicnum(const TString& name) const;
TVariant& get_sql_value(const TRectype& curr, const RecFieldDes& fd, TVariant& tmp) const; TVariant& get_sql_value(const TRectype& curr, const RecFieldDes& fd, TVariant& tmp) const;
void build_curr_path(TFilename& name) const; void build_curr_path(TFilename& name) const;
@ -763,7 +839,7 @@ bool TSQLite::create_dbf_times()
if (!ok) if (!ok)
{ {
TString sql; TString sql;
sql << "CREATE TABLE " << DBF_TIMES_TABLE << " (name,time);\n" sql << "CREATE TABLE " << DBF_TIMES_TABLE << " (name TEXT,time NUMERIC);\n"
<< "CREATE UNIQUE INDEX " << DBF_TIMES_TABLE << "_1 ON " << DBF_TIMES_TABLE << " (name);"; << "CREATE UNIQUE INDEX " << DBF_TIMES_TABLE << "_1 ON " << DBF_TIMES_TABLE << " (name);";
ok = exec(sql); ok = exec(sql);
} }
@ -773,7 +849,6 @@ bool TSQLite::create_dbf_times()
bool TSQLite::set_dbf_time(const TString& table, long last) bool TSQLite::set_dbf_time(const TString& table, long last)
{ {
TString sql; TString sql;
// sql << "INSERT OR REPLACE INTO " << DBF_TIMES_TABLE << " VALUES("
sql << "REPLACE INTO " << DBF_TIMES_TABLE << " VALUES(" sql << "REPLACE INTO " << DBF_TIMES_TABLE << " VALUES("
<< '\'' << table << "','" << last << "');"; << '\'' << table << "','" << last << "');";
return exec(sql); return exec(sql);
@ -795,37 +870,6 @@ long TSQLite::get_dbf_time(const TString& table)
return last; return last;
} }
void TSQLite::logicnum2name(int logicnum, TString& name) const
{
const FileDes& fd = prefix().get_filedes(logicnum);
const TFilename n = fd.SysName;
name = n.name(); name.upper();
}
int TSQLite::name2logicnum(const TString& name) const
{
TString* cod = (TString*)_names.objptr(name);
if (cod == NULL)
{
FileDes dir;
CGetFile(LF_DIR, &dir, _nolock, NORDIR);
const int nfiles = (int)dir.EOD;
TString8 n;
for (int logic = LF_USER; logic < nfiles; logic++)
{
logicnum2name(logic, n);
cod = new TString4; cod->format("%d", logic);
((TAssoc_array&)_names).add(n, cod);
}
cod = (TString*)_names.objptr(name);
if (cod == NULL) // Continua ostinatamente a non esistere?
return 0;
}
return atoi(*cod);
}
TVariant& TSQLite::get_sql_value(const TRectype& curr, const RecFieldDes& fd, TVariant& tmp) const TVariant& TSQLite::get_sql_value(const TRectype& curr, const RecFieldDes& fd, TVariant& tmp) const
{ {
switch (fd.TypeF) switch (fd.TypeF)
@ -836,8 +880,20 @@ TVariant& TSQLite::get_sql_value(const TRectype& curr, const RecFieldDes& fd, TV
case _wordfld : case _wordfld :
case _intzerofld : case _intzerofld :
case _longzerofld: tmp.set(curr.get_long(fd.Name)); break; case _longzerofld: tmp.set(curr.get_long(fd.Name)); break;
case _datefld : tmp.set(curr.get_date(fd.Name)); break; case _datefld :
{
const TDate date = curr.get_date(fd.Name);
tmp.set(date.date2ansi());
}
break;
case _boolfld : tmp.set(curr.get_bool(fd.Name)); break; case _boolfld : tmp.set(curr.get_bool(fd.Name)); break;
case _memofld:
{
TString memo = curr.get(fd.Name);
memo.replace('\n', char(0xB6)); // Simbolo di paragrafo
tmp.set(memo);
}
break;
default : tmp.set(curr.get(fd.Name)); break; default : tmp.set(curr.get(fd.Name)); break;
} }
return tmp; return tmp;
@ -866,13 +922,8 @@ bool TSQLite::esporta(const TRectype& rec, ostream& sql) const
for (int i = 0; i < rd.NFields; i++) for (int i = 0; i < rd.NFields; i++)
{ {
if (i > 0) sql << '\t'; if (i > 0) sql << '\t';
if (rd.Fd[i].TypeF == _memofld) get_sql_value(rec, rd.Fd[i], tmp);
sql << "\\N"; sql << tmp.as_string();
else
{
get_sql_value(rec, rd.Fd[i], tmp);
sql << tmp.as_string();
}
} }
sql << '\n'; sql << '\n';
return true; return true;
@ -880,7 +931,7 @@ bool TSQLite::esporta(const TRectype& rec, ostream& sql) const
bool TSQLite::import(int logicnum) bool TSQLite::import(int logicnum)
{ {
TString table; logicnum2name(logicnum, table); const TString& table = logic2table(logicnum);
long last = get_dbf_time(table); long last = get_dbf_time(table);
if (logicnum >= LF_USER) // Dummy test if (logicnum >= LF_USER) // Dummy test
@ -905,26 +956,33 @@ bool TSQLite::import(int logicnum)
for (int i = 0; i < rd.NFields; i++) for (int i = 0; i < rd.NFields; i++)
{ {
if (i > 0) sql << ','; if (i > 0) sql << ',';
sql << rd.Fd[i].Name; sql << rd.Fd[i].Name << ' ';
switch (rd.Fd[i].TypeF)
{
case _alfafld:
case _memofld: sql << "TEXT"; break;
case _datefld: sql << "DATE"; break;
default : sql << "NUMERIC"; break;
}
} }
sql << ");"; sql << ");";
if (!exec(sql)) if (!exec(sql))
return false; return false;
// Create main index // Creazione indici
// sql.cut(0) << "CREATE UNIQUE INDEX " << table << "_1 ON "<< table << "\n("; for (int index = 0; index < rd.NKeys; index++)
sql.cut(0) << "CREATE INDEX " << table << "_1 ON "<< table << "\n(";
const KeyDes& kd = rd.Ky[0];
for (int k = 0; k < kd.NkFields; k++)
{ {
if (k > 0) sql << ','; sql.cut(0) << "CREATE INDEX " << table << '_' << (index+1) << " ON "<< table << "\n(";
const int ndx = kd.FieldSeq[k] % MaxFields; const KeyDes& kd = rd.Ky[index];
sql << rd.Fd[ndx].Name; for (int k = 0; k < kd.NkFields; k++)
{
if (k > 0) sql << ',';
const int ndx = kd.FieldSeq[k] % MaxFields;
sql << rd.Fd[ndx].Name;
}
sql << ");";
exec(sql);
} }
sql << ");";
if (!exec(sql))
return false;
TRelation rel(logicnum); TRelation rel(logicnum);
TCursor cur(&rel); TCursor cur(&rel);
@ -995,7 +1053,7 @@ bool TSQLite::parse_select_from(const char* szSql)
if (table[i] <= ' ' || table[i] == ';') if (table[i] <= ' ' || table[i] == ';')
{ table.cut(i); break; } { table.cut(i); break; }
} }
const int logicnum = name2logicnum(table); const int logicnum = table2logic(table);
if (logicnum > 0) if (logicnum > 0)
import(logicnum); import(logicnum);
} }
@ -1004,8 +1062,7 @@ bool TSQLite::parse_select_from(const char* szSql)
} }
TSQLite::TSQLite() : _handle(NULL) TSQLite::TSQLite() : _handle(NULL)
{ { }
}
TSQLite::~TSQLite() TSQLite::~TSQLite()
{ {
@ -1033,7 +1090,21 @@ int TSQL_recordset::on_get_items(int argc, char** values, char** columns)
TRecordset_column_info* info = new TRecordset_column_info; TRecordset_column_info* info = new TRecordset_column_info;
info->_name = columns[i]; info->_name = columns[i];
info->_width = 1; info->_width = 1;
info->_type = _realfld; info->_type = _alfafld;
const char* fldtype = columns[argc+i];
if (fldtype != NULL)
{
if (xvt_str_compare_ignoring_case(fldtype, "DATE") == 0)
{
info->_type = _datefld;
info->_width = 10;
} else
if (xvt_str_compare_ignoring_case(fldtype, "NUMERIC") == 0)
{
info->_type = _realfld;
}
}
_column.add(info); _column.add(info);
} }
} }
@ -1045,8 +1116,6 @@ int TSQL_recordset::on_get_items(int argc, char** values, char** columns)
const int len = strlen(values[i]); const int len = strlen(values[i]);
if (len > info._width) if (len > info._width)
info._width = len; info._width = len;
if (info._type != _alfafld && isalpha(*values[i]))
info._type = _alfafld;
} }
} }
@ -1057,8 +1126,7 @@ int TSQL_recordset::on_get_items(int argc, char** values, char** columns)
static int query_get_items(void* jolly, int argc, char** values, char** columns) static int query_get_items(void* jolly, int argc, char** values, char** columns)
{ {
TSQL_recordset* q = (TSQL_recordset*)jolly; TSQL_recordset* q = (TSQL_recordset*)jolly;
q->on_get_items(argc, values, columns); return q->on_get_items(argc, values, columns);
return SQLITE_OK;
} }
void TSQL_recordset::parsed_sql_text(TString& sql) const void TSQL_recordset::parsed_sql_text(TString& sql) const
@ -1088,12 +1156,20 @@ void TSQL_recordset::parsed_sql_text(TString& sql) const
} }
} }
bool TSQL_recordset::ask_variables(bool all)
{
_page.destroy();
return TRecordset::ask_variables(all);
}
TRecnotype TSQL_recordset::items() const TRecnotype TSQL_recordset::items() const
{ {
if (_items == 0) if (_items == 0)
{ {
TString sql; parsed_sql_text(sql); TString sql; parsed_sql_text(sql);
_TheDataBase.exec("PRAGMA show_datatypes = ON;", NULL, NULL);
_TheDataBase.exec(sql, query_get_items, (TSQL_recordset*)this); _TheDataBase.exec(sql, query_get_items, (TSQL_recordset*)this);
_TheDataBase.exec("PRAGMA show_datatypes = OFF;", NULL, NULL);
} }
return _items; return _items;
} }
@ -1110,33 +1186,41 @@ const TRecordset_column_info& TSQL_recordset::column_info(unsigned int c) const
return (const TRecordset_column_info&)_column[c]; return (const TRecordset_column_info&)_column[c];
} }
static int query_get_rows(void* jolly, int argc, char** values, char** columns) int TSQL_recordset::on_get_rows(int argc, char** values, char** columns)
{ {
TArray& arr = *(TArray*)jolly;
TArray* a = new TArray; TArray* a = new TArray;
for (int c = 0; c < argc; c++) for (int c = 0; c < argc; c++)
{ {
TVariant* var = new TVariant; TVariant* var = new TVariant;
if (is_numeric(values[c])) switch (column_info(c)._type)
var->set(real(values[c])); {
else case _alfafld: var->set(values[c]); break;
var->set(values[c]); case _datefld: var->set(TDate(values[c])); break;
default : var->set(real(values[c])); break;
}
a->add(var, c); a->add(var, c);
} }
arr.add(a); _page.add(a);
return SQLITE_OK; return SQLITE_OK;
} }
static int query_get_rows(void* jolly, int argc, char** values, char** columns)
{
TSQL_recordset* rs = (TSQL_recordset*)jolly;
return rs->on_get_rows(argc, values, columns);
}
bool TSQL_recordset::move_to(TRecnotype n) bool TSQL_recordset::move_to(TRecnotype n)
{ {
_current_row = n; _current_row = n;
if (n < 0 || n >= items()) if (n < 0 || n >= items())
{ {
_page.destroy(); // Forza rilettura la prossiva volta _page.destroy(); // Forza rilettura la prossiva volta
_first_row = 0;
return false; return false;
} }
if (n < _firstrow || n >= _firstrow+_page.items()) if (n < _first_row || n >= _first_row+_page.items())
{ {
TString sql; parsed_sql_text(sql); TString sql; parsed_sql_text(sql);
if (sql.find("LIMIT ") < 0) if (sql.find("LIMIT ") < 0)
@ -1147,12 +1231,12 @@ bool TSQL_recordset::move_to(TRecnotype n)
sql.trim(); sql.trim();
_page.destroy(); _page.destroy();
if (n >= _pagesize) if (n >= _pagesize)
_firstrow = n-_pagesize/8; // Prendo qualche riga dalla pagina precedente, per velocizzare il pagina su _first_row = n-_pagesize/8; // Prendo qualche riga dalla pagina precedente, per velocizzare il pagina su
else else
_firstrow = n; _first_row = n;
sql << "\nLIMIT " << _pagesize << " OFFSET " << _firstrow << ';'; sql << "\nLIMIT " << _pagesize << " OFFSET " << _first_row << ';';
} }
_TheDataBase.exec(sql, query_get_rows, &_page); _TheDataBase.exec(sql, query_get_rows, this);
} }
return true; return true;
@ -1162,13 +1246,13 @@ const TArray* TSQL_recordset::row(TRecnotype n)
{ {
const TArray* a = NULL; const TArray* a = NULL;
if (move_to(n)) if (move_to(n))
a = (const TArray*)_page.objptr(n-_firstrow); a = (const TArray*)_page.objptr(n-_first_row);
return a; return a;
} }
const TVariant& TSQL_recordset::get(unsigned int c) const const TVariant& TSQL_recordset::get(unsigned int c) const
{ {
const TArray* a = (const TArray*)_page.objptr(_current_row-_firstrow); const TArray* a = (const TArray*)_page.objptr(_current_row-_first_row);
if (a != NULL) if (a != NULL)
{ {
const TVariant* s = (const TVariant*)a->objptr(c); const TVariant* s = (const TVariant*)a->objptr(c);

View File

@ -113,7 +113,7 @@ public: // Absolutely needed methods
virtual const TString_array& variables() const { return _varnames; } virtual const TString_array& variables() const { return _varnames; }
virtual const TVariant& get_var(const char* name) const; virtual const TVariant& get_var(const char* name) const;
virtual bool set_var(const char* name, const TVariant& var, bool create = false); virtual bool set_var(const char* name, const TVariant& var, bool create = false);
bool ask_variables(bool all); virtual bool ask_variables(bool all);
virtual const TString& query_text() const; virtual const TString& query_text() const;
virtual const TVariant& get(const char* column_name) const; virtual const TVariant& get(const char* column_name) const;
@ -130,7 +130,7 @@ class TSQL_recordset : public TRecordset
{ {
TString _sql; TString _sql;
TRecnotype _firstrow, _pagesize, _items, _current_row; TRecnotype _first_row, _pagesize, _items, _current_row;
TArray _column; TArray _column;
TArray _page; TArray _page;
@ -145,6 +145,7 @@ public: // TRecordset
virtual unsigned int columns() const; virtual unsigned int columns() const;
virtual const TRecordset_column_info& column_info(unsigned int c) const; virtual const TRecordset_column_info& column_info(unsigned int c) const;
virtual const TVariant& get(unsigned int column) const; virtual const TVariant& get(unsigned int column) const;
virtual bool ask_variables(bool all);
const TString& query_text() const { return _sql; } const TString& query_text() const { return _sql; }
public: public:
@ -152,6 +153,7 @@ public:
// Internal use only // Internal use only
virtual int on_get_items(int argc, char** values, char** columns); virtual int on_get_items(int argc, char** values, char** columns);
virtual int on_get_rows(int argc, char** values, char** columns);
const TArray* row(TRecnotype n); const TArray* row(TRecnotype n);
TSQL_recordset(const char* sql); TSQL_recordset(const char* sql);
@ -179,7 +181,8 @@ public:
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
bool select_custom_file(TFilename& path, const char* ext); bool select_custom_file(TFilename& path, const char* ext);
const TString& logic2table(int logic_num);
int table2logic(const TString& name);
#endif #endif

View File

@ -208,16 +208,28 @@ void TReport_field_mask::update()
void TReport_field_mask::vedo_non_vedo() void TReport_field_mask::vedo_non_vedo()
{ {
const char type = get(F_TYPE)[0]; const char type = get(F_TYPE)[0];
const bool is_text = strchr("DNPSTV", type) != NULL; const bool is_currency = type == 'P' || type == 'V';
const bool is_numeric = is_currency || type == 'N';
const bool is_text = is_numeric || strchr("DST", type) != NULL;
show(F_HIDE_ZEROES, strchr("DNPV", type) != NULL), show(F_HIDE_ZEROES, is_numeric || type == 'D'),
show(F_HALIGN, is_text); show(F_HALIGN, is_text);
if (is_numeric)
{
disable(F_HALIGN);
set(F_HALIGN, "R"); // Allineo a destra i numeri
}
else
enable(F_HALIGN);
show(F_VALIGN, is_text); show(F_VALIGN, is_text);
show(F_TEXT, is_text); show(F_TEXT, is_text && !is_currency);
show(F_FGCOLOR, type != 'I'); show(F_FGCOLOR, type != 'I');
show(F_BGCOLOR, type != 'L' && type != 'I'); show(F_BGCOLOR, type != 'L');
show(F_FONT_SELECT, is_text); show(F_FONT_SELECT, is_text);
show(F_SOURCE, (is_text || type == 'I') && type != 'T'); show(F_SOURCE, (is_text || type == 'I') && type != 'T');
show(F_CODVAL, is_currency); // Codice valuta di riferimento
show(F_LINK, strchr("DNS", type) != NULL); // Chi puo' essere un link?
if (is_running()) if (is_running())
force_update(); force_update();
@ -276,6 +288,8 @@ void TReport_field_mask::set_field(const TReport_field& rf)
set(F_DISABLED, rf.deactivated() ? "X" : ""); set(F_DISABLED, rf.deactivated() ? "X" : "");
set(F_HIDE_ZEROES, rf.zeroes_hidden() ? "X" : ""); set(F_HIDE_ZEROES, rf.zeroes_hidden() ? "X" : "");
set(F_GROUPS, rf.groups()); set(F_GROUPS, rf.groups());
set(F_CODVAL, rf.codval());
set(F_LINK, rf.link());
str[0] = rf.horizontal_alignment(); str[0] = rf.horizontal_alignment();
set(F_HALIGN, str); set(F_HALIGN, str);
@ -302,7 +316,8 @@ void TReport_field_mask::get_field(TReport_field& rf) const
rf.activate(!get_bool(F_DISABLED)); rf.activate(!get_bool(F_DISABLED));
rf.hide_zeroes(get_bool(F_HIDE_ZEROES)); rf.hide_zeroes(get_bool(F_HIDE_ZEROES));
rf.set_groups(get(F_GROUPS)); rf.set_groups(get(F_GROUPS));
rf.set_codval(get(F_CODVAL));
rf.set_link(get(F_LINK));
rf.set_horizontal_alignment(get(F_HALIGN)[0]); rf.set_horizontal_alignment(get(F_HALIGN)[0]);
rf.set_vertical_alignment(get(F_VALIGN)[0]); rf.set_vertical_alignment(get(F_VALIGN)[0]);
rf.set_border(get_int(F_BORDER)); rf.set_border(get_int(F_BORDER));

View File

@ -9,31 +9,33 @@
#define F_SEC_PROPERTIES 108 #define F_SEC_PROPERTIES 108
#define F_REP_PROPERTIES 109 #define F_REP_PROPERTIES 109
#define F_TYPE 109 #define F_TYPE 120
#define F_ID 110 #define F_ID 121
#define F_X 111 #define F_X 122
#define F_Y 112 #define F_Y 123
#define F_DX 113 #define F_DX 124
#define F_DY 114 #define F_DY 125
#define F_TEXT 115 #define F_TEXT 126
#define F_SOURCE 116 #define F_SOURCE 127
#define F_HALIGN 117 #define F_HALIGN 128
#define F_VALIGN 118 #define F_VALIGN 129
#define F_BORDER 119 #define F_BORDER 130
#define F_FGCOLOR 120 #define F_FGCOLOR 131
#define F_BGCOLOR 121 #define F_BGCOLOR 132
#define F_FONT_SELECT 122 #define F_FONT_SELECT 133
#define F_HIDDEN 123 #define F_HIDDEN 134
#define F_DISABLED 124 #define F_DISABLED 135
#define F_HIDE_ZEROES 125 #define F_HIDE_ZEROES 136
#define F_PRESCRIPT 126 #define F_PRESCRIPT 137
#define F_POSTSCRIPT 127 #define F_POSTSCRIPT 138
#define F_GROUPS 128 #define F_GROUPS 139
#define F_CODVAL 140
#define F_LINK 141
#define F_LEVEL 130 #define F_LEVEL 160
#define F_GROUP_BY 131 #define F_GROUP_BY 161
#define F_HIDE_IF_NEEDED 132 #define F_HIDE_IF_NEEDED 162
#define F_PAGE_BREAK 133 #define F_PAGE_BREAK 163
#define F_SQL 201 #define F_SQL 201
#define F_IMPORT_QRY 202 #define F_IMPORT_QRY 202

View File

@ -67,6 +67,17 @@ BEGIN
PROMPT 1 3 "Gruppi " PROMPT 1 3 "Gruppi "
END END
STRING F_CODVAL 32 8
BEGIN
PROMPT 1 4 "Divisa "
FLAGS "U"
END
STRING F_LINK 34
BEGIN
PROMPT 21 4 "Collegamento "
END
MEMO F_TEXT 68 4 MEMO F_TEXT 68 4
BEGIN BEGIN
PROMPT 1 5 "@bTesto" PROMPT 1 5 "@bTesto"

View File

@ -962,14 +962,30 @@ void TReport_field::draw_rect(TWindow& win) const
advanced_draw_rect(win, r, border(), fore_color(), back_color()); advanced_draw_rect(win, r, border(), fore_color(), back_color());
} }
void TReport_field::draw_text(TWindow& win, const char* text) const COLOR TReport_field::link_color() const
{
return COLOR_BLUE;
}
void TReport_field::draw_text(TWindow& win, const char* text, TReport_draw_mode rdm) const
{ {
const TRectangle& rct = get_rect(); const TRectangle& rct = get_rect();
RCT r; win.log2dev(rct, r); RCT r; win.log2dev(rct, r);
advanced_draw_rect(win, r, border(), fore_color(), back_color()); advanced_draw_rect(win, r, border(), fore_color(), back_color());
xvt_dwin_set_font(win.win(), font().get_xvt_font(win)); if (rdm == rdm_print_preview && link().not_empty())
win.set_color(fore_color(), back_color()); {
XVT_FNTID lnkfont = xvt_font_create();
xvt_font_copy(lnkfont, font().get_xvt_font(win), XVT_FA_ALL);
xvt_font_set_style(lnkfont, XVT_FS_UNDERLINE);
xvt_dwin_set_font(win.win(), lnkfont);
win.set_color(link_color(), back_color());
}
else
{
xvt_dwin_set_font(win.win(), font().get_xvt_font(win));
win.set_color(fore_color(), back_color());
}
if (rct.height() > 100) if (rct.height() > 100)
{ {
@ -991,7 +1007,7 @@ void TReport_field::draw_text(TWindow& win, const char* text) const
for (int row = 0; row < rows; row++) for (int row = 0; row < rows; row++)
{ {
TRectangle rctline = rct; TRectangle rctline = rct;
rctline.y = ybase+100*row; rctline.y = ybase + 100*row;
rctline.set_height(100); rctline.set_height(100);
win.log2dev(rctline, r); win.log2dev(rctline, r);
if (halign == 'J' && row == rows-1) if (halign == 'J' && row == rows-1)
@ -1003,6 +1019,18 @@ void TReport_field::draw_text(TWindow& win, const char* text) const
advanced_draw_text(win, text, r, _halign, _valign); advanced_draw_text(win, text, r, _halign, _valign);
} }
void TReport_field::get_currency(TCurrency& cur) const
{
if (_codval.not_empty())
{
TVariant val;
section().report().evaluate(_codval, val, _alfafld);
cur.force_value(val.as_string());
}
cur.set_price(_type == 'P');
cur.set_num(_var.as_real());
}
const TString& TReport_field::formatted_text() const const TString& TReport_field::formatted_text() const
{ {
if (_hide_zeroes && _var.is_zero()) if (_hide_zeroes && _var.is_zero())
@ -1041,17 +1069,10 @@ const TString& TReport_field::formatted_text() const
} }
break; break;
case 'P': case 'P':
{
TString& tmp = get_tmp_string();
TPrice cur(_var.as_real());
tmp = cur.string(true);
return tmp;
}
break;
case 'V': case 'V':
{ {
TString& tmp = get_tmp_string(); TString& tmp = get_tmp_string();
TCurrency cur(_var.as_real()); TCurrency cur; get_currency(cur);
tmp = cur.string(true); tmp = cur.string(true);
return tmp; return tmp;
} }
@ -1136,12 +1157,7 @@ void TReport_field::draw(TWindow& win, TReport_draw_mode rdm) const
} }
break; break;
case 'R': draw_rect(win); break; case 'R': draw_rect(win); break;
case 'T': draw_text(win, _picture); break; case 'T': draw_text(win, _picture, rdm); break;
case 'N':
case 'P':
case 'V':
if (zeroes_hidden() && _var.as_real().is_zero())
break;
default : default :
if (rdm == rdm_edit) if (rdm == rdm_edit)
{ {
@ -1153,15 +1169,16 @@ void TReport_field::draw(TWindow& win, TReport_draw_mode rdm) const
if (id() > 0) if (id() > 0)
{ {
TString16 str; str << id(); TString16 str; str << id();
draw_text(win, str); draw_text(win, str, rdm);
} }
else else
draw_text(win, _field); draw_text(win, _field, rdm);
} }
else else // Real printing
{ {
const TString& str = formatted_text(); const TString& str = formatted_text();
draw_text(win, str); if (!str.blank())
draw_text(win, str, rdm);
} }
break; break;
} }
@ -1242,6 +1259,8 @@ void TReport_field::save(TXmlItem& root) const
}; };
fld.SetAttr("border", border()); fld.SetAttr("border", border());
fld.SetAttr("text", picture()); fld.SetAttr("text", picture());
fld.SetAttr("codval", codval());
fld.SetAttr("link", link());
if (field().not_empty()) if (field().not_empty())
fld.AddChild("source") << field(); fld.AddChild("source") << field();
_prescript.save(fld, "prescript"); _prescript.save(fld, "prescript");
@ -1266,6 +1285,8 @@ bool TReport_field::load(const TXmlItem& fld)
set_horizontal_alignment(get_chr_attr(fld, "align", 'L')); set_horizontal_alignment(get_chr_attr(fld, "align", 'L'));
set_vertical_alignment(get_chr_attr(fld, "valign", 'B')); set_vertical_alignment(get_chr_attr(fld, "valign", 'B'));
set_picture(fld.GetAttr("text")); set_picture(fld.GetAttr("text"));
set_codval(fld.GetAttr("codval"));
set_link(fld.GetAttr("link"));
TXmlItem* src = fld.FindFirstChild("source"); TXmlItem* src = fld.FindFirstChild("source");
if (src != NULL) if (src != NULL)
src->GetEnclosedText(_field); src->GetEnclosedText(_field);
@ -1321,6 +1342,63 @@ TReport_field::~TReport_field()
delete _font; delete _font;
} }
///////////////////////////////////////////////////////////
// TReport_link
///////////////////////////////////////////////////////////
void TReport_link::set(const char* field, const TVariant& var)
{
_fields.add(field, var, true);
}
const TVariant& TReport_link::get(const char* field) const
{
const TVariant* var = (const TVariant*)_fields.objptr(field);
return var != NULL ? *var : NULL_VARIANT;
}
void TReport_link::add_rect(const RCT& rct)
{
// Non memorizzo tutti i rettangoli del link, ma la loro unione
if (xvt_rect_is_empty(&_rct))
_rct = rct;
else
{
if (rct.left < _rct.left) _rct.left = rct.left;
if (rct.top < _rct.top) _rct.top = rct.top;
if (rct.right > _rct.right) _rct.right = rct.right;
if (rct.bottom > _rct.bottom) _rct.bottom = rct.bottom;
}
}
int TReport_link::hit_test(const PNT& p) const
{
if (p.v < _rct.top)
return -1;
if (p.v > _rct.bottom)
return +1;
if (p.h < _rct.left)
return -1;
if (p.h > _rct.right)
return +1;
return 0;
}
int TReport_link::compare(const TSortable& s) const
{
const TReport_link& lnk = (const TReport_link&)s;
int cmp = _rct.top - lnk._rct.top;
if (cmp == 0)
cmp = _rct.left - lnk._rct.left;
return cmp;
}
TReport_link::TReport_link(const char* table)
: _table(table)
{
xvt_rect_set_empty(&_rct);
}
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
// TReport // TReport
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
@ -1608,6 +1686,7 @@ bool TReport::execute_prescript()
{ {
bool ok = true; bool ok = true;
warm_restart();
if (_prescript.ok()) if (_prescript.ok())
{ {
TString80 str; TString80 str;
@ -1863,6 +1942,25 @@ bool TReport::execute_usr_word(unsigned int opcode, TVariant_stack& stack)
return true; return true;
} }
bool TReport::on_link(const TReport_link& lnk)
{
const TString& table = lnk.table();
const int logicnum = table2logic(table);
if (logicnum >= LF_USER)
{
TRectype rec(logicnum);
TAssoc_array& fields = lnk.fields();
FOR_EACH_ASSOC_OBJECT(fields, h, k, o)
{
const TVariant* var = (const TVariant*)o;
rec.put(k, var->as_string());
}
return rec.edit();
}
return false;
}
TReport::TReport() : _lpi(6), _recordset(NULL), _curr_field(NULL) TReport::TReport() : _lpi(6), _recordset(NULL), _curr_field(NULL)
{ {
// Brutte inizializzazioni, ma inevitabili // Brutte inizializzazioni, ma inevitabili

View File

@ -218,7 +218,7 @@ class TReport_field : public TSortable
short _border; short _border;
char _halign, _valign; char _halign, _valign;
TBit_array _groups; TBit_array _groups;
TString _picture, _field; TString _picture, _field, _codval, _link;
TVariant _var; TVariant _var;
TReport_script _prescript, _postscript; TReport_script _prescript, _postscript;
@ -230,6 +230,7 @@ protected:
void copy(const TReport_field& rf); void copy(const TReport_field& rf);
TFieldtypes var_type() const; TFieldtypes var_type() const;
const TString& formatted_text() const; const TString& formatted_text() const;
void get_currency(TCurrency& cur) const;
public: public:
virtual TObject* dup() const { return new TReport_field(*this); } virtual TObject* dup() const { return new TReport_field(*this); }
@ -284,11 +285,16 @@ public:
void set_groups(const TString& groups); void set_groups(const TString& groups);
const TString& groups() const; const TString& groups() const;
bool in_group(int group) const; bool in_group(int group) const;
void set_codval(const char* cod) { _codval = cod; }
const TString& codval() const { return _codval; }
void set_link(const char* l) { _link = l; }
const TString& link() const { return _link; } // TABLE.FIELD
void set_fore_color(COLOR c) { _fgcolor = c; } void set_fore_color(COLOR c) { _fgcolor = c; }
COLOR fore_color() const { return _fgcolor; } COLOR fore_color() const { return _fgcolor; }
void set_back_color(COLOR c) { _bgcolor = c; } void set_back_color(COLOR c) { _bgcolor = c; }
COLOR back_color() const { return _bgcolor; } COLOR back_color() const { return _bgcolor; }
COLOR link_color() const;
void set_border(short b) { _border = b; } void set_border(short b) { _border = b; }
short border() const { return _border; } short border() const { return _border; }
void set_horizontal_alignment(char a) { _halign = a; } void set_horizontal_alignment(char a) { _halign = a; }
@ -306,7 +312,7 @@ public:
void offset(const TPoint& pt); void offset(const TPoint& pt);
virtual void draw_rect(TWindow& win) const; virtual void draw_rect(TWindow& win) const;
virtual void draw_text(TWindow& win, const char* text) const; virtual void draw_text(TWindow& win, const char* text, TReport_draw_mode mode) const;
virtual void draw(TWindow& win, TReport_draw_mode mode) const; virtual void draw(TWindow& win, TReport_draw_mode mode) const;
void save(TXmlItem& root) const; void save(TXmlItem& root) const;
@ -317,6 +323,29 @@ public:
virtual ~TReport_field(); virtual ~TReport_field();
}; };
class TReport_link : public TSortable
{
TString _table;
TAssoc_array _fields;
RCT _rct;
protected:
virtual int compare(const TSortable& s) const;
public:
const TString& table() const { return _table; }
void set(const char* field, const TVariant& value);
const TVariant& get(const char* field) const;
void add_rect(const RCT& rct); // Aggiunge un rettangolo al link
int hit_test(const PNT& p) const;
TAssoc_array& fields() const { return (TAssoc_array&)_fields; }
TReport_link(const char* table);
virtual ~TReport_link() { }
};
// Internal usage only
typedef void (*FLDMSG_FUNC)(TReport_field& rf, void* jolly); typedef void (*FLDMSG_FUNC)(TReport_field& rf, void* jolly);
class TReport : public TAlex_virtual_machine class TReport : public TAlex_virtual_machine
@ -355,6 +384,8 @@ public:
bool kill_section(char type, int level); bool kill_section(char type, int level);
int find_max_level(char type) const; int find_max_level(char type) const;
virtual bool on_link(const TReport_link& link);
const TReport_font& font() const { return _font; } const TReport_font& font() const { return _font; }
void set_font(const TReport_font& f) { _font = f; } void set_font(const TReport_font& f) { _font = f; }
void unmap_font(); void unmap_font();

View File

@ -16,6 +16,7 @@ class TPrint_preview_window : public TField_window
TPage_printer* _printer; TPage_printer* _printer;
word _page, _last; word _page, _last;
int _zoom; int _zoom;
static bool _locked;
protected: protected:
void page_select(); void page_select();
@ -26,12 +27,15 @@ protected:
public: public:
virtual PNT log2dev(long lx, long ly) const; virtual PNT log2dev(long lx, long ly) const;
static void lock_preview_update(bool yes) { _locked = yes; }
void set_printer(TPage_printer* printer) { _printer = printer; } void set_printer(TPage_printer* printer) { _printer = printer; }
TPrint_preview_window(int x, int y, int dx, int dy, WINDOW parent, TPrint_preview_window(int x, int y, int dx, int dy, WINDOW parent,
TWindowed_field* owner, TPage_printer* printer); TWindowed_field* owner, TPage_printer* printer);
}; };
bool TPrint_preview_window::_locked = false;
PNT TPrint_preview_window::log2dev(long lx, long ly) const PNT TPrint_preview_window::log2dev(long lx, long ly) const
{ {
PNT pnt; PNT pnt;
@ -47,7 +51,8 @@ PNT TPrint_preview_window::log2dev(long lx, long ly) const
void TPrint_preview_window::update() void TPrint_preview_window::update()
{ {
_printer->print_page(_page); if (!_locked)
_printer->print_page(_page);
} }
#define POPUP_FIRST 20883 #define POPUP_FIRST 20883
@ -96,8 +101,20 @@ void TPrint_preview_window::handler(WINDOW win, EVENT* ep)
{ {
switch (ep->type) switch (ep->type)
{ {
case E_MOUSE_MOVE:
if (_printer->find_link(ep->v.mouse.where) != NULL)
xvt_win_set_cursor(win, CURSOR_CROSS);
else
xvt_win_set_cursor(win, CURSOR_ARROW);
break;
case E_MOUSE_DOWN: case E_MOUSE_DOWN:
if (ep->v.mouse.button != 0) if (ep->v.mouse.button == 0)
{
const TReport_link* lnk = _printer->find_link(ep->v.mouse.where);
if (lnk != NULL)
_printer->on_link(*lnk);
}
else
popup_menu(ep); popup_menu(ep);
break; break;
case E_COMMAND: case E_COMMAND:
@ -154,7 +171,8 @@ bool TPrint_preview_window::on_key(KEY k)
TPrint_preview_window::TPrint_preview_window(int x, int y, int dx, int dy, WINDOW parent, TPrint_preview_window::TPrint_preview_window(int x, int y, int dx, int dy, WINDOW parent,
TWindowed_field* owner, TPage_printer* printer) TWindowed_field* owner, TPage_printer* printer)
: TField_window(x, y, dx, dy, parent, owner), _printer(printer), _page(1), _last(0), _zoom(100) : TField_window(x, y, dx, dy, parent, owner), _printer(printer),
_page(1), _last(0), _zoom(100)
{ {
RCT r; xvt_vobj_get_client_rect(win(), &r); RCT r; xvt_vobj_get_client_rect(win(), &r);
_zoom = 100 * r.right / 800; _zoom = 100 * r.right / 800;
@ -301,6 +319,8 @@ TPreview_mask::TPreview_mask(TPage_printer* printer)
// TPage_printer // TPage_printer
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
static bool _print_aborted = false;
const char* TPage_printer::form_name() const const char* TPage_printer::form_name() const
{ {
return printer().get_form_name(); return printer().get_form_name();
@ -368,6 +388,7 @@ bool TPage_printer::main_loop()
if (!ok) if (!ok)
return false; return false;
} }
_print_aborted = false;
for (word c = 0; c < _copies && ok; c++) for (word c = 0; c < _copies && ok; c++)
{ {
@ -411,7 +432,12 @@ bool TPage_printer::open_page()
if (print_mode()) if (print_mode())
_page_is_open = xvt_print_open_page(_rcd) != 0; _page_is_open = xvt_print_open_page(_rcd) != 0;
else else
{
_page_is_open = true; _page_is_open = true;
_links.destroy(); // Distrugge elenco dei links
_links_sorted = false;
}
} }
else else
_page_is_open = false; _page_is_open = false;
@ -432,6 +458,12 @@ bool TPage_printer::close_page()
return was_open; return was_open;
} }
void TPage_printer::add_link(TReport_link* link)
{
_links.add(link);
_links_sorted = false;
}
static BOOLEAN main_loop_callback(long jolly) static BOOLEAN main_loop_callback(long jolly)
{ {
TPage_printer* pp = (TPage_printer*)jolly; TPage_printer* pp = (TPage_printer*)jolly;
@ -440,6 +472,7 @@ static BOOLEAN main_loop_callback(long jolly)
bool TPage_printer::do_print() bool TPage_printer::do_print()
{ {
_print_aborted = true;
bool ok = ask_pages(); bool ok = ask_pages();
if (ok) if (ok)
ok = xvt_print_start_thread(main_loop_callback, long(this)) == FALSE; ok = xvt_print_start_thread(main_loop_callback, long(this)) == FALSE;
@ -455,6 +488,8 @@ void TPage_printer::print_page(word page)
bool TPage_printer::do_preview() bool TPage_printer::do_preview()
{ {
_print_aborted = true;
TPrinter& p = printer(); TPrinter& p = printer();
_rcd = p.get_printrcd(); _rcd = p.get_printrcd();
if (!xvt_print_is_valid(_rcd)) if (!xvt_print_is_valid(_rcd))
@ -470,6 +505,7 @@ bool TPage_printer::do_preview()
set_win(_preview_window->win()); set_win(_preview_window->win());
_pagefrom = _pageto = _page = 1; _pagefrom = _pageto = _page = 1;
_print_aborted = false;
const KEY key = _preview_mask->run(); const KEY key = _preview_mask->run();
set_win(NULL_WIN); set_win(NULL_WIN);
@ -482,6 +518,36 @@ bool TPage_printer::do_preview()
return true; return true;
} }
const TReport_link* TPage_printer::find_link(const PNT& pnt) const
{
if (!_links_sorted)
{
TPage_printer* myself = (TPage_printer*)this;
myself->_links.sort();
myself->_links_sorted = true;
}
int primo = 0, ultimo = _links.last();
while (primo <= ultimo)
{
const int in_mezzo = (primo+ultimo)/2;
const TReport_link* lnk = (const TReport_link*)_links.objptr(in_mezzo);
const int cmp = lnk->hit_test(pnt);
if (cmp == 0)
return lnk;
if (cmp < 0)
ultimo = in_mezzo-1;
else
primo = in_mezzo+1;
}
return NULL;
}
bool TPage_printer::on_link(const TReport_link& lnk)
{
return false;
}
bool TPage_printer::print(bool prev_mode) bool TPage_printer::print(bool prev_mode)
{ {
return prev_mode ? do_preview() : do_print(); return prev_mode ? do_preview() : do_print();
@ -611,8 +677,42 @@ bool TReport_printer::close_page()
return TPage_printer::close_page(); return TPage_printer::close_page();
} }
void TReport_printer::create_links(const TReport_section& rs)
{
TAssoc_array* links = NULL;
for (int i = 0; i < rs.items(); i++)
{
const TReport_field& rf = rs.field(i);
if (rf.link().not_empty())
{
if (links == NULL)
links = new TAssoc_array;
TToken_string tok(rf.link(), '.');
TString table, field;
tok.get(0, table); tok.get(1, field);
TReport_link* rl = (TReport_link*)links->objptr(table);
if (rl == NULL)
{
rl = new TReport_link(table);
links->add(table, rl);
}
RCT rct; TWindow::log2dev(rf.get_rect(), rct);
rl->add_rect(rct);
rl->set(field, rf.get());
}
}
if (links != NULL)
{
FOR_EACH_ASSOC_OBJECT((*links), h, key, l)
add_link((TReport_link*)l);
}
}
long TReport_printer::print_section(TReport_section& rs) long TReport_printer::print_section(TReport_section& rs)
{ {
if (_print_aborted)
return 0;
rs.load_fields(); rs.load_fields();
rs.execute_prescript(); rs.execute_prescript();
const long height = rs.compute_size().y; // Compute size after the initilization script! const long height = rs.compute_size().y; // Compute size after the initilization script!
@ -628,13 +728,16 @@ long TReport_printer::print_section(TReport_section& rs)
open_page(); open_page();
} }
if (_page_is_open) if (_page_is_open)
rs.draw(*this, rdm_print); rs.draw(*this, preview_mode() ? rdm_print_preview : rdm_print);
if (rs.level() > 0) // Ho stampa qualcosa che non sia lo sfondo! if (rs.level() > 0) // Ho stampa qualcosa che non sia lo sfondo!
_page_break_allowed = true; _page_break_allowed = true;
} }
rs.execute_postscript(); rs.execute_postscript();
if (_page_is_open && preview_mode())
create_links(rs);
return height; return height;
} }
@ -677,7 +780,7 @@ bool TReport_printer::print_loop()
bool aborted = false; bool aborted = false;
for (bool ok = rex.move_to(0); ok; ok = rex.move_next()) for (bool ok = rex.move_to(0); ok; ok = rex.move_next())
{ {
if (_pageto >= _pagefrom && _page > _pageto) // out of range if (_pageto >= _pagefrom && _page > _pageto || _print_aborted) // out of range
{ {
aborted = true; aborted = true;
break; break;
@ -691,7 +794,8 @@ bool TReport_printer::print_loop()
{ {
const TString& expr = _report.section('H', g).grouped_by(); const TString& expr = _report.section('H', g).grouped_by();
_report.evaluate(expr, var, _alfafld); _report.evaluate(expr, var, _alfafld);
newgroup.add(var.as_string(), g); const TString& grp = var.as_string();
newgroup.add(grp, g);
if (newgroup.row(g) != oldgroup.row(g) || rex.current_row() == 0) if (newgroup.row(g) != oldgroup.row(g) || rex.current_row() == 0)
changed = g; changed = g;
} }
@ -769,3 +873,19 @@ bool TReport_printer::print(bool preview_mode)
return ok; return ok;
} }
bool TReport_printer::on_link(const TReport_link& lnk)
{
return _report.on_link(lnk);
}
///////////////////////////////////////////////////////////
// Remote control interface
///////////////////////////////////////////////////////////
void lock_preview_update(bool yes)
{ TPrint_preview_window::lock_preview_update(yes); }
void abort_printing()
{ _print_aborted = true; }

View File

@ -9,6 +9,8 @@ class TPage_printer : public TWindow
{ {
PRINT_RCD* _rcd; PRINT_RCD* _rcd;
long _pw, _ph, _phr, _pvr; // Printer width, height, horizontal and vertical resolution long _pw, _ph, _phr, _pvr; // Printer width, height, horizontal and vertical resolution
TArray _links;
bool _links_sorted;
protected: protected:
word _copies, _pagefrom, _pageto, _page, _lastprinted; word _copies, _pagefrom, _pageto, _page, _lastprinted;
@ -54,6 +56,10 @@ public:
void toggle_preview_grid() { _draw_grid = !_draw_grid; } void toggle_preview_grid() { _draw_grid = !_draw_grid; }
bool show_preview_grid() const { return _draw_grid; } bool show_preview_grid() const { return _draw_grid; }
void add_link(TReport_link* link);
const TReport_link* find_link(const PNT& pnt) const;
virtual bool on_link(const TReport_link& lnk);
TPage_printer(); TPage_printer();
virtual ~TPage_printer(); virtual ~TPage_printer();
}; };
@ -79,15 +85,16 @@ protected:
virtual bool close_page(); virtual bool close_page();
long print_section(TReport_section& rs); long print_section(TReport_section& rs);
long print_section(char type, int level); long print_section(char type, int level);
void create_links(const TReport_section& rs);
public: public:
virtual bool print(bool preview = false); virtual bool print(bool preview = false);
virtual bool on_link(const TReport_link& lnk);
TReport_printer(TReport& r) : _report(r) { } TReport_printer(TReport& r) : _report(r) { }
}; };
void advanced_draw_rect(TWindow& win, const RCT& r, int border, COLOR fore, COLOR back); void lock_preview_update(bool yes);
void advanced_draw_text(TWindow& win, const char* text, const RCT& r, void abort_printing();
char halign, char valign);
#endif #endif

View File

@ -1,7 +1,10 @@
#include <ctype.h> #include <ctype.h>
#include <stdlib.h> #include <stdlib.h>
#include <automask.h>
#include <colors.h>
#include <prefix.h> #include <prefix.h>
#include "ba8303.h"
#include "ba8304.h" #include "ba8304.h"
TVariant& TVariant_stack::peek(int depth) TVariant& TVariant_stack::peek(int depth)
@ -59,15 +62,66 @@ bool TVariant_stack::push(const real& n)
return push(var); return push(var);
} }
bool TVariant_stack::push(const TString& str)
{
const TVariant var(str);
return push(var);
}
void TVariant_stack::reset()
{
_sp = 0;
}
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
// TAVM_op // TAVM_op
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
enum AVM_opcode { avm_nop, avm_add, avm_div, avm_dot, enum AVM_opcode
avm_cmp_eq, avm_cmp_gt, avm_cmp_gteq, avm_cmp_lt, avm_cmp_lteq, avm_cmp_noteq, {
avm_drop, avm_dup, avm_else, avm_nop,
avm_fetch, avm_if, avm_push, avm_rot, avm_store, avm_add, avm_and,
avm_sub, avm_swap, avm_then, avm_usrword }; avm_begin,
avm_call_word, avm_cold,
avm_cmp_eq, avm_cmp_gt, avm_cmp_gteq, avm_cmp_lt, avm_cmp_lteq, avm_cmp_noteq,
avm_div, avm_do, avm_dot, avm_drop, avm_dup,
avm_else, avm_execute,
avm_false, avm_fetch,
avm_if,
avm_loop,
avm_mon, avm_mul,
avm_or, avm_over,
avm_push,
avm_repeat, avm_rdrop, avm_rpeek, avm_rpush, avm_rot,
avm_store, avm_sub, avm_swap,
avm_then, avm_true,
avm_usrword,
avm_warm, avm_while,
avm_zzz
};
const char* AVM_TOKENS[avm_zzz+1] =
{
"$NOP$",
"+", "AND",
"BEGIN",
"$CALL_WORD$", "COLD",
"=", ">", ">=", "<", "<=", "<>",
"/", "DO", ".", "DROP", "DUP",
"ELSE", "EXECUTE",
"FALSE", "@",
"IF",
"LOOP",
"MON", "*",
"OR", "OVER",
"PUSH",
"REPEAT", "R>", "R@", ">R", "ROT",
"!", "-", "SWAP",
"THEN", "TRUE",
"#",
"WARM", "WHILE"
};
class TAVM_op : public TObject class TAVM_op : public TObject
{ {
@ -101,6 +155,186 @@ TAVM_op::TAVM_op(AVM_opcode o)
: _op(o) : _op(o)
{ } { }
///////////////////////////////////////////////////////////
// TAVM_monitor
///////////////////////////////////////////////////////////
class TAVM_list_window : public TField_window
{
const TBytecode* _bc;
int _ip;
protected:
virtual void update();
public:
void set_bytecode(const TBytecode* bc, int ip);
TAVM_list_window(int x, int y, int dx, int dy, WINDOW parent, TWindowed_field* owner);
};
void TAVM_list_window::update()
{
clear(NORMAL_BACK_COLOR);
if (_bc != NULL)
{
set_brush(DISABLED_BACK_COLOR);
bar(0, 0, 5, _bc->items());
set_brush(NORMAL_BACK_COLOR);
TString str;
int tab = 6;
const int first = origin().y;
const int last = min(_bc->items(), first+rows());
for (int i = first; i < last; i++)
{
if (_ip == i)
{
set_brush(FOCUS_BACK_COLOR);
bar(0, i, 80, i+1);
set_brush(NORMAL_BACK_COLOR);
}
printat(0, i, "%04d", i);
const TAVM_op& op = *(const TAVM_op*)_bc->objptr(i);
const AVM_opcode co = op.op();
const TVariant& var = op.var();
if (co == avm_else || co == avm_then)
tab -= 2;
if (co == avm_push)
{
if (var.type() == _alfafld && var.as_string()[0] != '#')
str.cut(0) << '"' << var.as_string() << '"';
else
str = var.as_string();
} else
if (co == avm_call_word)
{
str = var.as_string();
}
else
{
str = AVM_TOKENS[co];
if (!var.is_null())
str << " (" << var.as_string() << ')';
}
printat(tab, i, str);
if (co == avm_if || co == avm_else)
tab += 2;
}
}
}
void TAVM_list_window::set_bytecode(const TBytecode* bc, int ip)
{
_bc = bc;
_ip = ip;
set_scroll_max(80, _bc->items() - rows());
}
TAVM_list_window::TAVM_list_window(int x, int y, int dx, int dy, WINDOW parent, TWindowed_field* owner)
: TField_window(x, y, dx, dy, parent, owner), _bc(NULL)
{
autoscroll(true);
}
class TAVM_stack_window : public TField_window
{
TVariant_stack* _stack;
protected:
virtual void update();
public:
void set_stack(TVariant_stack& s);
TAVM_stack_window(int x, int y, int dx, int dy, WINDOW parent, TWindowed_field* owner);
};
void TAVM_stack_window::update()
{
clear(NORMAL_BACK_COLOR);
if (_stack != NULL)
{
for (int i = 0; i < _stack->items(); i++)
printat(0, i, _stack->peek(i).as_string());
}
}
void TAVM_stack_window::set_stack(TVariant_stack& s)
{
_stack = &s;
set_scroll_max(80, s.items() - rows());
}
TAVM_stack_window::TAVM_stack_window(int x, int y, int dx, int dy, WINDOW parent, TWindowed_field* owner)
: TField_window(x, y, dx, dy, parent, owner), _stack(NULL)
{
autoscroll(true);
}
class TAVM_list_field : public TWindowed_field
{
protected:
virtual TField_window* create_window(int x, int y, int dx, int dy, WINDOW parent);
public:
TAVM_list_field(TMask* m) : TWindowed_field(m) { }
virtual ~TAVM_list_field() { }
};
TField_window* TAVM_list_field::create_window(int x, int y, int dx, int dy, WINDOW parent)
{
return new TAVM_list_window(x, y, dx, dy, parent, this);
}
class TAVM_stack_field : public TWindowed_field
{
protected:
virtual TField_window* create_window(int x, int y, int dx, int dy, WINDOW parent);
public:
TAVM_stack_field(TMask* m) : TWindowed_field(m) { }
virtual ~TAVM_stack_field() { }
};
TField_window* TAVM_stack_field::create_window(int x, int y, int dx, int dy, WINDOW parent)
{
return new TAVM_stack_window(x, y, dx, dy, parent, this);
}
class TAVM_monitor : public TAutomask
{
protected:
TMask_field* parse_field(TScanner& scanner);
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
public:
TAVM_list_window& monitor() { return (TAVM_list_window&)((TAVM_list_field&)field(101)).win(); }
TAVM_stack_window& stacker() { return (TAVM_stack_window&)((TAVM_list_field&)field(102)).win(); }
TAVM_monitor();
};
bool TAVM_monitor::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
return true;
}
TMask_field* TAVM_monitor::parse_field(TScanner& scanner)
{
if (scanner.token().starts_with("LI"))
return new TAVM_list_field(this);
if (scanner.token().starts_with("ST"))
return new TAVM_stack_field(this);
return TAutomask::parse_field(scanner);
}
TAVM_monitor::TAVM_monitor()
{
read_mask("ba8304", 0, -1);
set_handlers();
}
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
// TAVM // TAVM
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
@ -109,21 +343,31 @@ class TAVM
{ {
TAlex_virtual_machine* _vm; TAlex_virtual_machine* _vm;
TString _last_error; TString _last_error;
TVariant_stack _stack; TVariant_stack _stack, _rstack;
const TBytecode* _bc; // Current word (or command line)
int _ip; // Current instruction pointer
TAssoc_array _words;
TAVM_monitor _mon;
protected: protected:
bool get_token(istream& instr, TString& str) const; bool get_token(istream& instr, TString& str) const;
AVM_opcode token2opcode(const TString& str) const; AVM_opcode token2opcode(const TString& str) const;
void log_error(const char* str); void log_error(const char* str);
int compare_tos_nos(); int compare_tos_nos();
int find_matching(const TBytecode& bytecode, AVM_opcode op1, AVM_opcode op2 = avm_nop) const;
void execute(const TAVM_op& op);
void do_call(const TString& func);
public: public:
const TString& get_last_error() const { return _last_error; } const TString& get_last_error() const { return _last_error; }
bool compile(istream& instr, TBytecode& bc); bool compile(istream& instr, TBytecode& bc);
bool execute(const TBytecode& bc, ostream& outstr); bool execute(const TBytecode& bc, ostream& outstr);
void restart(bool cold);
TAVM(TAlex_virtual_machine* vm) : _vm(vm) { } TAVM(TAlex_virtual_machine* vm);
virtual ~TAVM();
}; };
void TAVM::log_error(const char* str) void TAVM::log_error(const char* str)
@ -161,31 +405,39 @@ bool TAVM::get_token(istream& instr, TString& str) const
return *str > ' '; return *str > ' ';
} }
#define ALEX_TOKENS 24
AVM_opcode TAVM::token2opcode(const TString& str) const AVM_opcode TAVM::token2opcode(const TString& str) const
{ {
const char* AVM_TOKENS[20] = {
"+", "-", ".", "!", "@", "/",
"=", "<>", ">", "<", ">=", "<=",
"DROP", "DUP", "ELSE", "IF", "ROT",
"SWAP", "THEN",
NULL
};
AVM_opcode AVM_OPCODES[20] = {
avm_add, avm_sub, avm_dot, avm_store, avm_fetch, avm_div,
avm_cmp_eq, avm_cmp_noteq, avm_cmp_gt, avm_cmp_lt, avm_cmp_gteq, avm_cmp_lteq,
avm_drop, avm_dup, avm_else, avm_if, avm_rot, avm_swap, avm_then,
avm_nop
};
for (int i = 0; AVM_TOKENS[i] != NULL; i++) for (int i = 0; AVM_TOKENS[i] != NULL; i++)
{ {
if (str == AVM_TOKENS[i]) if (str == AVM_TOKENS[i])
return AVM_OPCODES[i]; return AVM_opcode(i);
} }
const TBytecode* bc =(const TBytecode*)_words.objptr(str);
if (bc != NULL)
return avm_call_word;
return avm_nop; return avm_nop;
} }
int TAVM::find_matching(const TBytecode& bytecode, AVM_opcode op1, AVM_opcode op2) const
{
int i;
for (i = bytecode.last(); i >= 0; i--)
{
TAVM_op& theop = (TAVM_op&)bytecode[i];
if ((theop.op() == op1 || theop.op() == op2) && theop.var().is_null())
{
theop.var() = bytecode.items();
break;
}
}
return i;
}
bool TAVM::compile(istream& instr, TBytecode& bytecode) bool TAVM::compile(istream& instr, TBytecode& bytecode)
{ {
TString str(256); TString str(256);
@ -199,7 +451,7 @@ bool TAVM::compile(istream& instr, TBytecode& bytecode)
str.rtrim(1); str.ltrim(1); str.rtrim(1); str.ltrim(1);
op = new TAVM_op(avm_push, str); op = new TAVM_op(avm_push, str);
} else } else
if (isdigit(str[0])) if (isdigit(str[0]) || (str[0]=='-' && isdigit(str[1])))
{ {
const real r(str); const real r(str);
op = new TAVM_op(avm_push, r); op = new TAVM_op(avm_push, r);
@ -207,7 +459,27 @@ bool TAVM::compile(istream& instr, TBytecode& bytecode)
if (str[0] == '#') // User variable if (str[0] == '#') // User variable
{ {
op = new TAVM_op(avm_push, str); op = new TAVM_op(avm_push, str);
} } else
if (str == ":") // User word
{
if (get_token(instr, str))
{
TBytecode* bc = new TBytecode;
bc->set_name(str);
_words.add(str, bc);
compile(instr, *bc);
}
else
{
_last_error = "Missing word after :";
log_error(_last_error);
return false;
}
} else
if (str == ";")
{
return true;
}
else else
{ {
const AVM_opcode oc = token2opcode(str); const AVM_opcode oc = token2opcode(str);
@ -216,44 +488,38 @@ bool TAVM::compile(istream& instr, TBytecode& bytecode)
switch (oc) switch (oc)
{ {
case avm_else: case avm_else:
if (find_matching(bytecode, avm_if) < 0)
{ {
for (int i = bytecode.last(); i >= 0; i--) _last_error = "ELSE without matching IF";
{ log_error(_last_error);
TAVM_op& ifop = (TAVM_op&)bytecode[i]; return false;
if (ifop.op() == avm_if && ifop.var().is_null())
{
ifop.var() = bytecode.items();
break;
}
}
if (i < 0)
{
_last_error = "ELSE without matching IF";
log_error(_last_error);
return false;
}
} }
op = new TAVM_op(oc); op = new TAVM_op(oc);
break; break;
case avm_then: case avm_then:
if (find_matching(bytecode, avm_if, avm_else) < 0)
{ {
for (int i = bytecode.last(); i >= 0; i--) _last_error = "THEN without matching IF";
log_error(_last_error);
return false;
}
op = new TAVM_op(oc);
break;
case avm_repeat:
{
const int begin_pos = find_matching(bytecode, avm_begin);
if (begin_pos < 0)
{ {
TAVM_op& ifop = (TAVM_op&)bytecode[i]; _last_error = "REPEAT without matching BEGIN";
if ((ifop.op() == avm_if || ifop.op() == avm_else) && ifop.var().is_null())
{
ifop.var() = bytecode.items();
break;
}
}
if (i < 0)
{
_last_error = "THEN without matching IF";
log_error(_last_error); log_error(_last_error);
return false; return false;
} }
find_matching(bytecode, avm_while);
op = new TAVM_op(oc, begin_pos);
} }
op = new TAVM_op(oc); break;
case avm_call_word:
op = new TAVM_op(oc, str);
break; break;
default: default:
op = new TAVM_op(oc); op = new TAVM_op(oc);
@ -283,111 +549,216 @@ int TAVM::compare_tos_nos()
{ {
const TVariant& v0 = _stack.pop(); const TVariant& v0 = _stack.pop();
const TVariant& v1 = _stack.pop(); const TVariant& v1 = _stack.pop();
return v0.compare(v1); return v1.compare(v0);
} }
bool TAVM::execute(const TBytecode& bc, ostream& outstr) void TAVM::do_call(const TString& func)
{ {
for (int ip = 0; ip < bc.items(); ip++) _rstack.push(_bc->name());
_rstack.push(_ip+1);
_ip = -1; // will be incremented!
_bc = (TBytecode*)_words.objptr(func);
}
void TAVM::execute(const TAVM_op& op)
{
switch(op.op())
{ {
const TAVM_op& op = *(const TAVM_op*)bc.objptr(ip); case avm_add :
switch(op.op())
{ {
case avm_add : const TVariant& v1 = _stack.pop();
{ TVariant& v0 = (TVariant&)_stack.peek();
const TVariant& v1 = _stack.pop(); v0.add(v1);
TVariant& v0 = (TVariant&)_stack.peek();
v0.add(v1);
}
break;
case avm_cmp_eq:
_stack.push(compare_tos_nos() == 0);
break;
case avm_cmp_gt:
_stack.push(compare_tos_nos() > 0);
break;
case avm_cmp_gteq:
_stack.push(compare_tos_nos() >= 0);
break;
case avm_cmp_lt:
_stack.push(compare_tos_nos() < 0);
break;
case avm_cmp_lteq:
_stack.push(compare_tos_nos() <= 0);
break;
case avm_cmp_noteq:
_stack.push(compare_tos_nos() != 0);
break;
case avm_div:
{
const real& r0 = _stack.pop().as_real();
const real& r1 = _stack.pop().as_real();
real n;
if (!r0.is_zero())
n = r1 / r0;
const TVariant var(n);
_stack.push(var);
}
break;
case avm_dot: outstr << _stack.pop().as_string(); break;
case avm_drop: _stack.drop(); break;
case avm_dup: _stack.push(_stack.peek()); break;
case avm_else:
ip = op.var().as_int();
break;
case avm_fetch:
{
const TString& name = _stack.pop().as_string();
TVariant var;
if (name[0] == '#')
_vm->get_usr_val(name, var);
else
{
// TBI: Get global var
}
_stack.push(var);
}
break;
case avm_if:
if (!_stack.pop().as_bool())
ip = op.var().as_int();
break;
case avm_push: _stack.push(op.var()); break;
case avm_rot: _stack.roll(2); break;
case avm_store:
{
const TString& name = _stack.pop().as_string();
const TVariant& var = _stack.pop();
if (name[0] == '#')
_vm->set_usr_val(name, var);
else
{
// TBI: Set global var
}
}
break;
case avm_sub :
{
const TVariant& v1 = _stack.pop();
TVariant& v0 = (TVariant&)_stack.peek();
v0.sub(v1);
}
break;
case avm_swap: _stack.roll(1); break;
case avm_then: break;
case avm_usrword:
{
const long usrword = op.var().as_int();
_vm->execute_usr_word(usrword, _stack);
}
break;
default:
_last_error << "Bad op code: " << op.op() << '\n';
log_error(_last_error);
return false;
} }
break;
case avm_and :
{
const TVariant& v1 = _stack.pop();
TVariant& v0 = (TVariant&)_stack.peek();
const long r = v0.as_int() & v1.as_int();
v0.set(r);
}
break;
case avm_call_word: do_call(op.var().as_string()); break;
case avm_cold: restart(true); _bc = NULL; break;
case avm_cmp_eq : _stack.push(compare_tos_nos() == 0); break;
case avm_cmp_gt : _stack.push(compare_tos_nos() > 0); break;
case avm_cmp_gteq : _stack.push(compare_tos_nos() >= 0); break;
case avm_cmp_lt : _stack.push(compare_tos_nos() < 0); break;
case avm_cmp_lteq : _stack.push(compare_tos_nos() <= 0); break;
case avm_cmp_noteq: _stack.push(compare_tos_nos() != 0); break;
case avm_div:
{
const real& r0 = _stack.pop().as_real();
const real& r1 = _stack.pop().as_real();
real n;
if (!r0.is_zero())
n = r1 / r0;
_stack.push(n);
}
break;
case avm_do: break;
case avm_dot: /* *_outstr << _stack.pop().as_string(); */ break;
case avm_drop: _stack.drop(); break;
case avm_dup: _stack.push(_stack.peek()); break;
case avm_else:
_ip = op.var().as_int();
break;
case avm_execute: do_call(_stack.pop().as_string()); break;
case avm_false: _stack.push(0L); break;
case avm_fetch:
{
const TString& name = _stack.pop().as_string();
TVariant var;
if (name[0] == '#')
_vm->get_usr_val(name, var);
else
{
// TBI: Get global var
}
_stack.push(var);
}
break;
case avm_if:
if (_stack.pop().is_zero())
_ip = op.var().as_int();
break;
case avm_loop: break;
case avm_mon:
{
lock_preview_update(true);
TAVM_list_window& monitor = _mon.monitor();
monitor.set_bytecode(_bc, _ip);
if (!_mon.is_open())
_mon.open();
}
break;
case avm_mul:
{
const TVariant& v1 = _stack.pop();
TVariant& v0 = (TVariant&)_stack.peek();
const real m = v0.as_real() * v1.as_real();
v0.set(m);
}
break;
case avm_or:
{
const TVariant& v1 = _stack.pop();
TVariant& v0 = (TVariant&)_stack.peek();
const long r = v0.as_int() | v1.as_int();
v0.set(r);
}
break;
case avm_over: _stack.push(_stack.peek(1)); break;
case avm_push: _stack.push(op.var()); break;
case avm_repeat: _ip = op.var().as_int(); break;
case avm_rdrop: _stack.push(_rstack.pop()); break;
case avm_rpeek: _stack.push(_rstack.peek()); break;
case avm_rpush: _rstack.push(_stack.pop()); break;
case avm_rot: _stack.roll(2); break;
case avm_store:
{
const TString& name = _stack.pop().as_string();
const TVariant& var = _stack.pop();
if (name[0] == '#')
_vm->set_usr_val(name, var);
else
{
// TBI: Set global var
}
}
break;
case avm_sub :
{
const TVariant& v1 = _stack.pop();
TVariant& v0 = (TVariant&)_stack.peek();
v0.sub(v1);
}
break;
case avm_swap: _stack.roll(1); break;
case avm_then: break;
case avm_true: _stack.push(1L); break;
case avm_usrword:
{
const long usrword = op.var().as_int();
_vm->execute_usr_word(usrword, _stack);
}
break;
case avm_warm: restart(false); _bc = NULL; break;
case avm_while: _ip = op.var().as_int(); break; // Jump to BEGIN
default:
_last_error << "Unimplemented op code: " << op.op() << '\n';
log_error(_last_error);
_bc = NULL; // force exit
break;
} }
return true; }
bool TAVM::execute(const TBytecode& cmdline, ostream& outstr)
{
_bc = &cmdline;
_ip = 0;
while (_bc != NULL)
{
if (_ip >= _bc->items()) // Fine funzione
{
if (_rstack.items() >= 2) // Controllo il return stack
{
_ip = _rstack.pop().as_int();
const TString& str = _rstack.pop().as_string();
if (str.blank())
_bc = &cmdline;
else
_bc = (const TBytecode*)_words.objptr(str);
}
else
break; // Fine esecuzione
}
if (_mon.is_open()) // Gestione debugger
{
lock_preview_update(true);
TAVM_list_window& monitor = _mon.monitor();
monitor.set_bytecode(_bc, _ip);
TAVM_stack_window& stacker = _mon.stacker();
stacker.set_stack(_stack);
const KEY k = _mon.run();
switch (k)
{
case K_NEXT: monitor.force_update(); stacker.force_update(); break;
case K_DEL : abort_printing();
case K_QUIT: _mon.close(); lock_preview_update(false); break;
default: break;
}
}
const TAVM_op& op = *(const TAVM_op*)_bc->objptr(_ip);
execute(op);
_ip++;
}
if (_mon.is_open()) // Chiudi debugger
{
_mon.close();
lock_preview_update(false);
}
return _bc != NULL;
}
void TAVM::restart(bool cold)
{
_stack.reset();
_rstack.reset();
}
TAVM::TAVM(TAlex_virtual_machine* vm)
: _vm(vm)
{ }
TAVM::~TAVM()
{
} }
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
@ -432,6 +803,16 @@ bool TAlex_virtual_machine::execute(const TBytecode& bc, TString& outs)
return execute(bc, outstr); return execute(bc, outstr);
} }
void TAlex_virtual_machine::warm_restart() // Ripartenza a caldo
{
avm().restart(false);
}
void TAlex_virtual_machine::cold_restart() // Ripartenza a freddo
{
avm().restart(true);
}
bool TAlex_virtual_machine::get_usr_val(const TString& name, TVariant& var) const bool TAlex_virtual_machine::get_usr_val(const TString& name, TVariant& var) const
{ {
if (name == "#TODAY") if (name == "#TODAY")

View File

@ -20,6 +20,8 @@ public:
bool push(const TVariant& var); bool push(const TVariant& var);
bool push(long n); bool push(long n);
bool push(const real& n); bool push(const real& n);
bool push(const TString& str);
void reset();
TVariant_stack() : _sp(0) { } TVariant_stack() : _sp(0) { }
}; };
@ -31,7 +33,7 @@ class TBytecode : public TArray
TString _name; TString _name;
public: public:
const set_name(const char* name) { _name = name; } void set_name(const char* name) { _name = name; }
const TString& name() const { return _name; } const TString& name() const { return _name; }
}; };
@ -57,6 +59,8 @@ public:
bool compile(const char* cmd, TBytecode& bc); bool compile(const char* cmd, TBytecode& bc);
bool execute(const TBytecode& bc, ostream& outstr); bool execute(const TBytecode& bc, ostream& outstr);
bool execute(const TBytecode& bc, TString& outstr); bool execute(const TBytecode& bc, TString& outstr);
void warm_restart();
void cold_restart();
TAlex_virtual_machine(); TAlex_virtual_machine();
virtual ~TAlex_virtual_machine(); virtual ~TAlex_virtual_machine();