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:
parent
912337c3e7
commit
5738d39723
@ -30,18 +30,10 @@ void TDir_sheet::add ()
|
||||
d.zero();
|
||||
d.put(nitems, _nordir, _sysdirop);
|
||||
_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)
|
||||
:TSheet(0, 0, 0, 0, title, colonne, buttons)
|
||||
: TSheet(0, 0, 0, 0, title, colonne, buttons)
|
||||
{
|
||||
_dir = new TDir;
|
||||
_rec = new TTrec;
|
||||
@ -55,7 +47,6 @@ TDir_sheet::~TDir_sheet()
|
||||
delete _rec;
|
||||
}
|
||||
|
||||
|
||||
void TDir_sheet::get_row(long n, TToken_string& l)
|
||||
{
|
||||
n++;
|
||||
@ -73,7 +64,6 @@ void TDir_sheet::get_row(long n, TToken_string& l)
|
||||
|
||||
TRec_sheet::TRec_sheet(int logicnum, const char * tab)
|
||||
: _descr(NULL), _tab(tab)
|
||||
|
||||
{
|
||||
_external = FALSE;
|
||||
_dir = new TDir;
|
||||
|
@ -139,7 +139,7 @@ public:
|
||||
~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 num = 0;
|
||||
@ -643,6 +643,13 @@ inline bool tok_get_bool(TToken_string& tok, int pos)
|
||||
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
|
||||
void TQuery_mask::sheet2sql()
|
||||
{
|
||||
@ -653,7 +660,7 @@ void TQuery_mask::sheet2sql()
|
||||
const bool multiple = _tree.has_son();
|
||||
|
||||
TToken_string from(50, ','), groupby(50, ','), orderby(50, ',');
|
||||
TString where;
|
||||
TString where, expr_from, expr_to;
|
||||
|
||||
TString field;
|
||||
FOR_EACH_SHEET_ROW(sheet, i, row)
|
||||
@ -672,7 +679,25 @@ void TQuery_mask::sheet2sql()
|
||||
orderby.add(field);
|
||||
if (tok_get_bool(*row, 4)) // Group
|
||||
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);
|
||||
@ -680,7 +705,8 @@ void TQuery_mask::sheet2sql()
|
||||
TString sql;
|
||||
sql << "SELECT " << select << '\n';
|
||||
sql << "FROM " << from << '\n';
|
||||
sql << "WHERE " << where << '\n';
|
||||
if (!where.blank())
|
||||
sql << "WHERE " << where << '\n';
|
||||
if (groupby.not_empty())
|
||||
sql << "GROUP BY " << groupby << '\n';
|
||||
if (orderby.not_empty())
|
||||
@ -833,7 +859,10 @@ bool TQuery_mask::save_fields_sheet(TXmlItem& xml)
|
||||
field.SetAttr("Group", tok_get_bool(*row,4));
|
||||
const char* str = row->get(5);
|
||||
if (str && *str > ' ')
|
||||
field.SetAttr("Expr", str);
|
||||
field.SetAttr("ExprFrom", str);
|
||||
str = row->get(6);
|
||||
if (str && *str > ' ')
|
||||
field.SetAttr("ExprTo", str);
|
||||
}
|
||||
}
|
||||
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("Sort") ? "X" : "",3);
|
||||
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();
|
||||
}
|
||||
@ -1072,7 +1102,7 @@ bool TQuery_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
|
||||
{
|
||||
next_page(1001);
|
||||
bool ok = true;
|
||||
if (_sql_dirty)
|
||||
if (_sql_dirty && !field(F_SQL).empty())
|
||||
ok = yesno_box(TR("Attenzione: la query verra' rigenerata\n"
|
||||
"annullando eventuali modifiche manuali.\n"
|
||||
"Si desidera proseguire?"));
|
||||
|
@ -98,11 +98,12 @@ SPREADSHEET F_SHEET -5
|
||||
BEGIN
|
||||
PROMPT 0 13 ""
|
||||
ITEM "Tabella@12F"
|
||||
ITEM "Colonna@32F"
|
||||
ITEM "Colonna@30F"
|
||||
ITEM "Nas.@3"
|
||||
ITEM "Ord.@3"
|
||||
ITEM "Grp.@3"
|
||||
ITEM "Condizione@50"
|
||||
ITEM "Da@30"
|
||||
ITEM "A@30"
|
||||
END
|
||||
|
||||
BUTTON F_MOVEUP 2 2
|
||||
@ -233,10 +234,14 @@ BEGIN
|
||||
PROMPT 35 2 "Raggruppa"
|
||||
END
|
||||
|
||||
MEMO 106 58 8
|
||||
STRING 106 70 50
|
||||
BEGIN
|
||||
PROMPT 1 3 "Condizione "
|
||||
FLAGS "D"
|
||||
PROMPT 1 3 "Da "
|
||||
END
|
||||
|
||||
STRING 107 70 50
|
||||
BEGIN
|
||||
PROMPT 1 4 "A "
|
||||
END
|
||||
|
||||
BUTTON DLG_CANCEL 10 2
|
||||
|
250
ba/ba8201.cpp
250
ba/ba8201.cpp
@ -81,7 +81,7 @@ bool TVariant::is_zero() const
|
||||
case _datefld: return !as_date().ok();
|
||||
case _longfld: return _ptr == NULL;
|
||||
case _realfld: return as_real().is_zero();
|
||||
case _alfafld: return as_string().blank();
|
||||
case _alfafld: return real::is_null(as_string());
|
||||
default: break;
|
||||
}
|
||||
return true;
|
||||
@ -248,6 +248,87 @@ TVariant& TVariant::sub(const TVariant& var)
|
||||
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
|
||||
@ -584,7 +665,6 @@ bool TRecordset::ask_variables(bool all)
|
||||
set_var(*name, var);
|
||||
}
|
||||
}
|
||||
move_to(-1);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
@ -654,12 +734,8 @@ class TSQLite : public TObject
|
||||
{
|
||||
sqlite* _handle;
|
||||
TFilename _currdb;
|
||||
TAssoc_array _names;
|
||||
|
||||
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;
|
||||
|
||||
void build_curr_path(TFilename& name) const;
|
||||
@ -763,7 +839,7 @@ bool TSQLite::create_dbf_times()
|
||||
if (!ok)
|
||||
{
|
||||
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);";
|
||||
ok = exec(sql);
|
||||
}
|
||||
@ -773,7 +849,6 @@ bool TSQLite::create_dbf_times()
|
||||
bool TSQLite::set_dbf_time(const TString& table, long last)
|
||||
{
|
||||
TString sql;
|
||||
// sql << "INSERT OR REPLACE INTO " << DBF_TIMES_TABLE << " VALUES("
|
||||
sql << "REPLACE INTO " << DBF_TIMES_TABLE << " VALUES("
|
||||
<< '\'' << table << "','" << last << "');";
|
||||
return exec(sql);
|
||||
@ -795,37 +870,6 @@ long TSQLite::get_dbf_time(const TString& table)
|
||||
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
|
||||
{
|
||||
switch (fd.TypeF)
|
||||
@ -836,8 +880,20 @@ TVariant& TSQLite::get_sql_value(const TRectype& curr, const RecFieldDes& fd, TV
|
||||
case _wordfld :
|
||||
case _intzerofld :
|
||||
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 _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;
|
||||
}
|
||||
return tmp;
|
||||
@ -866,13 +922,8 @@ bool TSQLite::esporta(const TRectype& rec, ostream& sql) const
|
||||
for (int i = 0; i < rd.NFields; i++)
|
||||
{
|
||||
if (i > 0) sql << '\t';
|
||||
if (rd.Fd[i].TypeF == _memofld)
|
||||
sql << "\\N";
|
||||
else
|
||||
{
|
||||
get_sql_value(rec, rd.Fd[i], tmp);
|
||||
sql << tmp.as_string();
|
||||
}
|
||||
get_sql_value(rec, rd.Fd[i], tmp);
|
||||
sql << tmp.as_string();
|
||||
}
|
||||
sql << '\n';
|
||||
return true;
|
||||
@ -880,7 +931,7 @@ bool TSQLite::esporta(const TRectype& rec, ostream& sql) const
|
||||
|
||||
bool TSQLite::import(int logicnum)
|
||||
{
|
||||
TString table; logicnum2name(logicnum, table);
|
||||
const TString& table = logic2table(logicnum);
|
||||
|
||||
long last = get_dbf_time(table);
|
||||
if (logicnum >= LF_USER) // Dummy test
|
||||
@ -905,26 +956,33 @@ bool TSQLite::import(int logicnum)
|
||||
for (int i = 0; i < rd.NFields; i++)
|
||||
{
|
||||
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 << ");";
|
||||
if (!exec(sql))
|
||||
return false;
|
||||
|
||||
// Create main index
|
||||
// sql.cut(0) << "CREATE UNIQUE INDEX " << table << "_1 ON "<< table << "\n(";
|
||||
sql.cut(0) << "CREATE INDEX " << table << "_1 ON "<< table << "\n(";
|
||||
const KeyDes& kd = rd.Ky[0];
|
||||
for (int k = 0; k < kd.NkFields; k++)
|
||||
// Creazione indici
|
||||
for (int index = 0; index < rd.NKeys; index++)
|
||||
{
|
||||
if (k > 0) sql << ',';
|
||||
const int ndx = kd.FieldSeq[k] % MaxFields;
|
||||
sql << rd.Fd[ndx].Name;
|
||||
sql.cut(0) << "CREATE INDEX " << table << '_' << (index+1) << " ON "<< table << "\n(";
|
||||
const KeyDes& kd = rd.Ky[index];
|
||||
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);
|
||||
TCursor cur(&rel);
|
||||
@ -995,7 +1053,7 @@ bool TSQLite::parse_select_from(const char* szSql)
|
||||
if (table[i] <= ' ' || table[i] == ';')
|
||||
{ table.cut(i); break; }
|
||||
}
|
||||
const int logicnum = name2logicnum(table);
|
||||
const int logicnum = table2logic(table);
|
||||
if (logicnum > 0)
|
||||
import(logicnum);
|
||||
}
|
||||
@ -1004,8 +1062,7 @@ bool TSQLite::parse_select_from(const char* szSql)
|
||||
}
|
||||
|
||||
TSQLite::TSQLite() : _handle(NULL)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
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;
|
||||
info->_name = columns[i];
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -1045,8 +1116,6 @@ int TSQL_recordset::on_get_items(int argc, char** values, char** columns)
|
||||
const int len = strlen(values[i]);
|
||||
if (len > info._width)
|
||||
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)
|
||||
{
|
||||
TSQL_recordset* q = (TSQL_recordset*)jolly;
|
||||
q->on_get_items(argc, values, columns);
|
||||
return SQLITE_OK;
|
||||
return q->on_get_items(argc, values, columns);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (_items == 0)
|
||||
{
|
||||
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("PRAGMA show_datatypes = OFF;", NULL, NULL);
|
||||
}
|
||||
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];
|
||||
}
|
||||
|
||||
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;
|
||||
for (int c = 0; c < argc; c++)
|
||||
{
|
||||
TVariant* var = new TVariant;
|
||||
if (is_numeric(values[c]))
|
||||
var->set(real(values[c]));
|
||||
else
|
||||
var->set(values[c]);
|
||||
switch (column_info(c)._type)
|
||||
{
|
||||
case _alfafld: var->set(values[c]); break;
|
||||
case _datefld: var->set(TDate(values[c])); break;
|
||||
default : var->set(real(values[c])); break;
|
||||
}
|
||||
a->add(var, c);
|
||||
}
|
||||
arr.add(a);
|
||||
_page.add(a);
|
||||
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)
|
||||
{
|
||||
_current_row = n;
|
||||
if (n < 0 || n >= items())
|
||||
{
|
||||
_page.destroy(); // Forza rilettura la prossiva volta
|
||||
_first_row = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (n < _firstrow || n >= _firstrow+_page.items())
|
||||
if (n < _first_row || n >= _first_row+_page.items())
|
||||
{
|
||||
TString sql; parsed_sql_text(sql);
|
||||
if (sql.find("LIMIT ") < 0)
|
||||
@ -1147,12 +1231,12 @@ bool TSQL_recordset::move_to(TRecnotype n)
|
||||
sql.trim();
|
||||
_page.destroy();
|
||||
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
|
||||
_firstrow = n;
|
||||
sql << "\nLIMIT " << _pagesize << " OFFSET " << _firstrow << ';';
|
||||
_first_row = n;
|
||||
sql << "\nLIMIT " << _pagesize << " OFFSET " << _first_row << ';';
|
||||
}
|
||||
_TheDataBase.exec(sql, query_get_rows, &_page);
|
||||
_TheDataBase.exec(sql, query_get_rows, this);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1162,13 +1246,13 @@ const TArray* TSQL_recordset::row(TRecnotype n)
|
||||
{
|
||||
const TArray* a = NULL;
|
||||
if (move_to(n))
|
||||
a = (const TArray*)_page.objptr(n-_firstrow);
|
||||
a = (const TArray*)_page.objptr(n-_first_row);
|
||||
return a;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
const TVariant* s = (const TVariant*)a->objptr(c);
|
||||
|
@ -113,7 +113,7 @@ public: // Absolutely needed methods
|
||||
virtual const TString_array& variables() const { return _varnames; }
|
||||
virtual const TVariant& get_var(const char* name) const;
|
||||
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 TVariant& get(const char* column_name) const;
|
||||
@ -130,7 +130,7 @@ class TSQL_recordset : public TRecordset
|
||||
{
|
||||
TString _sql;
|
||||
|
||||
TRecnotype _firstrow, _pagesize, _items, _current_row;
|
||||
TRecnotype _first_row, _pagesize, _items, _current_row;
|
||||
TArray _column;
|
||||
TArray _page;
|
||||
|
||||
@ -145,6 +145,7 @@ public: // TRecordset
|
||||
virtual unsigned int columns() const;
|
||||
virtual const TRecordset_column_info& column_info(unsigned int c) const;
|
||||
virtual const TVariant& get(unsigned int column) const;
|
||||
virtual bool ask_variables(bool all);
|
||||
const TString& query_text() const { return _sql; }
|
||||
|
||||
public:
|
||||
@ -152,6 +153,7 @@ public:
|
||||
|
||||
// Internal use only
|
||||
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);
|
||||
|
||||
TSQL_recordset(const char* sql);
|
||||
@ -179,7 +181,8 @@ public:
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
bool select_custom_file(TFilename& path, const char* ext);
|
||||
|
||||
const TString& logic2table(int logic_num);
|
||||
int table2logic(const TString& name);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -208,16 +208,28 @@ void TReport_field_mask::update()
|
||||
void TReport_field_mask::vedo_non_vedo()
|
||||
{
|
||||
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);
|
||||
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_TEXT, is_text);
|
||||
show(F_TEXT, is_text && !is_currency);
|
||||
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_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())
|
||||
force_update();
|
||||
@ -276,6 +288,8 @@ void TReport_field_mask::set_field(const TReport_field& rf)
|
||||
set(F_DISABLED, rf.deactivated() ? "X" : "");
|
||||
set(F_HIDE_ZEROES, rf.zeroes_hidden() ? "X" : "");
|
||||
set(F_GROUPS, rf.groups());
|
||||
set(F_CODVAL, rf.codval());
|
||||
set(F_LINK, rf.link());
|
||||
|
||||
str[0] = rf.horizontal_alignment();
|
||||
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.hide_zeroes(get_bool(F_HIDE_ZEROES));
|
||||
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_vertical_alignment(get(F_VALIGN)[0]);
|
||||
rf.set_border(get_int(F_BORDER));
|
||||
|
50
ba/ba8300.h
50
ba/ba8300.h
@ -9,31 +9,33 @@
|
||||
#define F_SEC_PROPERTIES 108
|
||||
#define F_REP_PROPERTIES 109
|
||||
|
||||
#define F_TYPE 109
|
||||
#define F_ID 110
|
||||
#define F_X 111
|
||||
#define F_Y 112
|
||||
#define F_DX 113
|
||||
#define F_DY 114
|
||||
#define F_TEXT 115
|
||||
#define F_SOURCE 116
|
||||
#define F_HALIGN 117
|
||||
#define F_VALIGN 118
|
||||
#define F_BORDER 119
|
||||
#define F_FGCOLOR 120
|
||||
#define F_BGCOLOR 121
|
||||
#define F_FONT_SELECT 122
|
||||
#define F_HIDDEN 123
|
||||
#define F_DISABLED 124
|
||||
#define F_HIDE_ZEROES 125
|
||||
#define F_PRESCRIPT 126
|
||||
#define F_POSTSCRIPT 127
|
||||
#define F_GROUPS 128
|
||||
#define F_TYPE 120
|
||||
#define F_ID 121
|
||||
#define F_X 122
|
||||
#define F_Y 123
|
||||
#define F_DX 124
|
||||
#define F_DY 125
|
||||
#define F_TEXT 126
|
||||
#define F_SOURCE 127
|
||||
#define F_HALIGN 128
|
||||
#define F_VALIGN 129
|
||||
#define F_BORDER 130
|
||||
#define F_FGCOLOR 131
|
||||
#define F_BGCOLOR 132
|
||||
#define F_FONT_SELECT 133
|
||||
#define F_HIDDEN 134
|
||||
#define F_DISABLED 135
|
||||
#define F_HIDE_ZEROES 136
|
||||
#define F_PRESCRIPT 137
|
||||
#define F_POSTSCRIPT 138
|
||||
#define F_GROUPS 139
|
||||
#define F_CODVAL 140
|
||||
#define F_LINK 141
|
||||
|
||||
#define F_LEVEL 130
|
||||
#define F_GROUP_BY 131
|
||||
#define F_HIDE_IF_NEEDED 132
|
||||
#define F_PAGE_BREAK 133
|
||||
#define F_LEVEL 160
|
||||
#define F_GROUP_BY 161
|
||||
#define F_HIDE_IF_NEEDED 162
|
||||
#define F_PAGE_BREAK 163
|
||||
|
||||
#define F_SQL 201
|
||||
#define F_IMPORT_QRY 202
|
||||
|
@ -67,6 +67,17 @@ BEGIN
|
||||
PROMPT 1 3 "Gruppi "
|
||||
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
|
||||
BEGIN
|
||||
PROMPT 1 5 "@bTesto"
|
||||
|
142
ba/ba8302.cpp
142
ba/ba8302.cpp
@ -962,14 +962,30 @@ void TReport_field::draw_rect(TWindow& win) const
|
||||
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();
|
||||
RCT r; win.log2dev(rct, r);
|
||||
advanced_draw_rect(win, r, border(), fore_color(), back_color());
|
||||
|
||||
xvt_dwin_set_font(win.win(), font().get_xvt_font(win));
|
||||
win.set_color(fore_color(), back_color());
|
||||
if (rdm == rdm_print_preview && link().not_empty())
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -991,7 +1007,7 @@ void TReport_field::draw_text(TWindow& win, const char* text) const
|
||||
for (int row = 0; row < rows; row++)
|
||||
{
|
||||
TRectangle rctline = rct;
|
||||
rctline.y = ybase+100*row;
|
||||
rctline.y = ybase + 100*row;
|
||||
rctline.set_height(100);
|
||||
win.log2dev(rctline, r);
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (_hide_zeroes && _var.is_zero())
|
||||
@ -1041,17 +1069,10 @@ const TString& TReport_field::formatted_text() const
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
{
|
||||
TString& tmp = get_tmp_string();
|
||||
TPrice cur(_var.as_real());
|
||||
tmp = cur.string(true);
|
||||
return tmp;
|
||||
}
|
||||
break;
|
||||
case 'V':
|
||||
{
|
||||
TString& tmp = get_tmp_string();
|
||||
TCurrency cur(_var.as_real());
|
||||
TCurrency cur; get_currency(cur);
|
||||
tmp = cur.string(true);
|
||||
return tmp;
|
||||
}
|
||||
@ -1136,12 +1157,7 @@ void TReport_field::draw(TWindow& win, TReport_draw_mode rdm) const
|
||||
}
|
||||
break;
|
||||
case 'R': draw_rect(win); break;
|
||||
case 'T': draw_text(win, _picture); break;
|
||||
case 'N':
|
||||
case 'P':
|
||||
case 'V':
|
||||
if (zeroes_hidden() && _var.as_real().is_zero())
|
||||
break;
|
||||
case 'T': draw_text(win, _picture, rdm); break;
|
||||
default :
|
||||
if (rdm == rdm_edit)
|
||||
{
|
||||
@ -1153,15 +1169,16 @@ void TReport_field::draw(TWindow& win, TReport_draw_mode rdm) const
|
||||
if (id() > 0)
|
||||
{
|
||||
TString16 str; str << id();
|
||||
draw_text(win, str);
|
||||
draw_text(win, str, rdm);
|
||||
}
|
||||
else
|
||||
draw_text(win, _field);
|
||||
draw_text(win, _field, rdm);
|
||||
}
|
||||
else
|
||||
else // Real printing
|
||||
{
|
||||
const TString& str = formatted_text();
|
||||
draw_text(win, str);
|
||||
if (!str.blank())
|
||||
draw_text(win, str, rdm);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1242,6 +1259,8 @@ void TReport_field::save(TXmlItem& root) const
|
||||
};
|
||||
fld.SetAttr("border", border());
|
||||
fld.SetAttr("text", picture());
|
||||
fld.SetAttr("codval", codval());
|
||||
fld.SetAttr("link", link());
|
||||
if (field().not_empty())
|
||||
fld.AddChild("source") << field();
|
||||
_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_vertical_alignment(get_chr_attr(fld, "valign", 'B'));
|
||||
set_picture(fld.GetAttr("text"));
|
||||
set_codval(fld.GetAttr("codval"));
|
||||
set_link(fld.GetAttr("link"));
|
||||
TXmlItem* src = fld.FindFirstChild("source");
|
||||
if (src != NULL)
|
||||
src->GetEnclosedText(_field);
|
||||
@ -1321,6 +1342,63 @@ TReport_field::~TReport_field()
|
||||
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
|
||||
///////////////////////////////////////////////////////////
|
||||
@ -1608,6 +1686,7 @@ bool TReport::execute_prescript()
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
warm_restart();
|
||||
if (_prescript.ok())
|
||||
{
|
||||
TString80 str;
|
||||
@ -1863,6 +1942,25 @@ bool TReport::execute_usr_word(unsigned int opcode, TVariant_stack& stack)
|
||||
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)
|
||||
{
|
||||
// Brutte inizializzazioni, ma inevitabili
|
||||
|
35
ba/ba8302.h
35
ba/ba8302.h
@ -218,7 +218,7 @@ class TReport_field : public TSortable
|
||||
short _border;
|
||||
char _halign, _valign;
|
||||
TBit_array _groups;
|
||||
TString _picture, _field;
|
||||
TString _picture, _field, _codval, _link;
|
||||
TVariant _var;
|
||||
TReport_script _prescript, _postscript;
|
||||
|
||||
@ -230,6 +230,7 @@ protected:
|
||||
void copy(const TReport_field& rf);
|
||||
TFieldtypes var_type() const;
|
||||
const TString& formatted_text() const;
|
||||
void get_currency(TCurrency& cur) const;
|
||||
|
||||
public:
|
||||
virtual TObject* dup() const { return new TReport_field(*this); }
|
||||
@ -284,11 +285,16 @@ public:
|
||||
void set_groups(const TString& groups);
|
||||
const TString& groups() 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; }
|
||||
COLOR fore_color() const { return _fgcolor; }
|
||||
void set_back_color(COLOR c) { _bgcolor = c; }
|
||||
COLOR back_color() const { return _bgcolor; }
|
||||
COLOR link_color() const;
|
||||
void set_border(short b) { _border = b; }
|
||||
short border() const { return _border; }
|
||||
void set_horizontal_alignment(char a) { _halign = a; }
|
||||
@ -306,7 +312,7 @@ public:
|
||||
void offset(const TPoint& pt);
|
||||
|
||||
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;
|
||||
|
||||
void save(TXmlItem& root) const;
|
||||
@ -317,6 +323,29 @@ public:
|
||||
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);
|
||||
|
||||
class TReport : public TAlex_virtual_machine
|
||||
@ -355,6 +384,8 @@ public:
|
||||
bool kill_section(char type, int level);
|
||||
int find_max_level(char type) const;
|
||||
|
||||
virtual bool on_link(const TReport_link& link);
|
||||
|
||||
const TReport_font& font() const { return _font; }
|
||||
void set_font(const TReport_font& f) { _font = f; }
|
||||
void unmap_font();
|
||||
|
132
ba/ba8303.cpp
132
ba/ba8303.cpp
@ -16,6 +16,7 @@ class TPrint_preview_window : public TField_window
|
||||
TPage_printer* _printer;
|
||||
word _page, _last;
|
||||
int _zoom;
|
||||
static bool _locked;
|
||||
|
||||
protected:
|
||||
void page_select();
|
||||
@ -26,12 +27,15 @@ protected:
|
||||
|
||||
public:
|
||||
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; }
|
||||
TPrint_preview_window(int x, int y, int dx, int dy, WINDOW parent,
|
||||
TWindowed_field* owner, TPage_printer* printer);
|
||||
};
|
||||
|
||||
bool TPrint_preview_window::_locked = false;
|
||||
|
||||
PNT TPrint_preview_window::log2dev(long lx, long ly) const
|
||||
{
|
||||
PNT pnt;
|
||||
@ -47,7 +51,8 @@ PNT TPrint_preview_window::log2dev(long lx, long ly) const
|
||||
|
||||
void TPrint_preview_window::update()
|
||||
{
|
||||
_printer->print_page(_page);
|
||||
if (!_locked)
|
||||
_printer->print_page(_page);
|
||||
}
|
||||
|
||||
#define POPUP_FIRST 20883
|
||||
@ -96,8 +101,20 @@ void TPrint_preview_window::handler(WINDOW win, EVENT* ep)
|
||||
{
|
||||
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:
|
||||
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);
|
||||
break;
|
||||
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,
|
||||
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);
|
||||
_zoom = 100 * r.right / 800;
|
||||
@ -301,6 +319,8 @@ TPreview_mask::TPreview_mask(TPage_printer* printer)
|
||||
// TPage_printer
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
static bool _print_aborted = false;
|
||||
|
||||
const char* TPage_printer::form_name() const
|
||||
{
|
||||
return printer().get_form_name();
|
||||
@ -368,6 +388,7 @@ bool TPage_printer::main_loop()
|
||||
if (!ok)
|
||||
return false;
|
||||
}
|
||||
_print_aborted = false;
|
||||
|
||||
for (word c = 0; c < _copies && ok; c++)
|
||||
{
|
||||
@ -411,7 +432,12 @@ bool TPage_printer::open_page()
|
||||
if (print_mode())
|
||||
_page_is_open = xvt_print_open_page(_rcd) != 0;
|
||||
else
|
||||
{
|
||||
_page_is_open = true;
|
||||
|
||||
_links.destroy(); // Distrugge elenco dei links
|
||||
_links_sorted = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
_page_is_open = false;
|
||||
@ -432,6 +458,12 @@ bool TPage_printer::close_page()
|
||||
return was_open;
|
||||
}
|
||||
|
||||
void TPage_printer::add_link(TReport_link* link)
|
||||
{
|
||||
_links.add(link);
|
||||
_links_sorted = false;
|
||||
}
|
||||
|
||||
static BOOLEAN main_loop_callback(long jolly)
|
||||
{
|
||||
TPage_printer* pp = (TPage_printer*)jolly;
|
||||
@ -440,6 +472,7 @@ static BOOLEAN main_loop_callback(long jolly)
|
||||
|
||||
bool TPage_printer::do_print()
|
||||
{
|
||||
_print_aborted = true;
|
||||
bool ok = ask_pages();
|
||||
if (ok)
|
||||
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()
|
||||
{
|
||||
_print_aborted = true;
|
||||
|
||||
TPrinter& p = printer();
|
||||
_rcd = p.get_printrcd();
|
||||
if (!xvt_print_is_valid(_rcd))
|
||||
@ -470,6 +505,7 @@ bool TPage_printer::do_preview()
|
||||
|
||||
set_win(_preview_window->win());
|
||||
_pagefrom = _pageto = _page = 1;
|
||||
_print_aborted = false;
|
||||
const KEY key = _preview_mask->run();
|
||||
set_win(NULL_WIN);
|
||||
|
||||
@ -482,6 +518,36 @@ bool TPage_printer::do_preview()
|
||||
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)
|
||||
{
|
||||
return prev_mode ? do_preview() : do_print();
|
||||
@ -611,8 +677,42 @@ bool TReport_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)
|
||||
{
|
||||
if (_print_aborted)
|
||||
return 0;
|
||||
|
||||
rs.load_fields();
|
||||
rs.execute_prescript();
|
||||
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();
|
||||
}
|
||||
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!
|
||||
_page_break_allowed = true;
|
||||
}
|
||||
|
||||
rs.execute_postscript();
|
||||
|
||||
if (_page_is_open && preview_mode())
|
||||
create_links(rs);
|
||||
|
||||
return height;
|
||||
}
|
||||
@ -677,7 +780,7 @@ bool TReport_printer::print_loop()
|
||||
bool aborted = false;
|
||||
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;
|
||||
break;
|
||||
@ -691,7 +794,8 @@ bool TReport_printer::print_loop()
|
||||
{
|
||||
const TString& expr = _report.section('H', g).grouped_by();
|
||||
_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)
|
||||
changed = g;
|
||||
}
|
||||
@ -769,3 +873,19 @@ bool TReport_printer::print(bool preview_mode)
|
||||
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; }
|
||||
|
||||
|
13
ba/ba8303.h
13
ba/ba8303.h
@ -9,6 +9,8 @@ class TPage_printer : public TWindow
|
||||
{
|
||||
PRINT_RCD* _rcd;
|
||||
long _pw, _ph, _phr, _pvr; // Printer width, height, horizontal and vertical resolution
|
||||
TArray _links;
|
||||
bool _links_sorted;
|
||||
|
||||
protected:
|
||||
word _copies, _pagefrom, _pageto, _page, _lastprinted;
|
||||
@ -54,6 +56,10 @@ public:
|
||||
void toggle_preview_grid() { _draw_grid = !_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();
|
||||
virtual ~TPage_printer();
|
||||
};
|
||||
@ -79,15 +85,16 @@ protected:
|
||||
virtual bool close_page();
|
||||
long print_section(TReport_section& rs);
|
||||
long print_section(char type, int level);
|
||||
void create_links(const TReport_section& rs);
|
||||
|
||||
public:
|
||||
virtual bool print(bool preview = false);
|
||||
virtual bool on_link(const TReport_link& lnk);
|
||||
|
||||
TReport_printer(TReport& r) : _report(r) { }
|
||||
};
|
||||
|
||||
void advanced_draw_rect(TWindow& win, const RCT& r, int border, COLOR fore, COLOR back);
|
||||
void advanced_draw_text(TWindow& win, const char* text, const RCT& r,
|
||||
char halign, char valign);
|
||||
void lock_preview_update(bool yes);
|
||||
void abort_printing();
|
||||
|
||||
#endif
|
||||
|
681
ba/ba8304.cpp
681
ba/ba8304.cpp
@ -1,7 +1,10 @@
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <automask.h>
|
||||
#include <colors.h>
|
||||
#include <prefix.h>
|
||||
#include "ba8303.h"
|
||||
#include "ba8304.h"
|
||||
|
||||
TVariant& TVariant_stack::peek(int depth)
|
||||
@ -59,15 +62,66 @@ bool TVariant_stack::push(const real& n)
|
||||
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
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
enum AVM_opcode { avm_nop, avm_add, avm_div, avm_dot,
|
||||
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_fetch, avm_if, avm_push, avm_rot, avm_store,
|
||||
avm_sub, avm_swap, avm_then, avm_usrword };
|
||||
enum AVM_opcode
|
||||
{
|
||||
avm_nop,
|
||||
avm_add, avm_and,
|
||||
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
|
||||
{
|
||||
@ -101,6 +155,186 @@ TAVM_op::TAVM_op(AVM_opcode 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
|
||||
///////////////////////////////////////////////////////////
|
||||
@ -109,21 +343,31 @@ class TAVM
|
||||
{
|
||||
TAlex_virtual_machine* _vm;
|
||||
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:
|
||||
bool get_token(istream& instr, TString& str) const;
|
||||
AVM_opcode token2opcode(const TString& str) const;
|
||||
void log_error(const char* str);
|
||||
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:
|
||||
const TString& get_last_error() const { return _last_error; }
|
||||
|
||||
bool compile(istream& instr, TBytecode& bc);
|
||||
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)
|
||||
@ -161,31 +405,39 @@ bool TAVM::get_token(istream& instr, TString& str) const
|
||||
return *str > ' ';
|
||||
}
|
||||
|
||||
#define ALEX_TOKENS 24
|
||||
|
||||
|
||||
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++)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
TString str(256);
|
||||
@ -199,7 +451,7 @@ bool TAVM::compile(istream& instr, TBytecode& bytecode)
|
||||
str.rtrim(1); str.ltrim(1);
|
||||
op = new TAVM_op(avm_push, str);
|
||||
} else
|
||||
if (isdigit(str[0]))
|
||||
if (isdigit(str[0]) || (str[0]=='-' && isdigit(str[1])))
|
||||
{
|
||||
const real r(str);
|
||||
op = new TAVM_op(avm_push, r);
|
||||
@ -207,7 +459,27 @@ bool TAVM::compile(istream& instr, TBytecode& bytecode)
|
||||
if (str[0] == '#') // User variable
|
||||
{
|
||||
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
|
||||
{
|
||||
const AVM_opcode oc = token2opcode(str);
|
||||
@ -216,44 +488,38 @@ bool TAVM::compile(istream& instr, TBytecode& bytecode)
|
||||
switch (oc)
|
||||
{
|
||||
case avm_else:
|
||||
if (find_matching(bytecode, avm_if) < 0)
|
||||
{
|
||||
for (int i = bytecode.last(); i >= 0; i--)
|
||||
{
|
||||
TAVM_op& ifop = (TAVM_op&)bytecode[i];
|
||||
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;
|
||||
}
|
||||
_last_error = "ELSE without matching IF";
|
||||
log_error(_last_error);
|
||||
return false;
|
||||
}
|
||||
op = new TAVM_op(oc);
|
||||
break;
|
||||
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];
|
||||
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";
|
||||
_last_error = "REPEAT without matching BEGIN";
|
||||
log_error(_last_error);
|
||||
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;
|
||||
default:
|
||||
op = new TAVM_op(oc);
|
||||
@ -283,111 +549,216 @@ int TAVM::compare_tos_nos()
|
||||
{
|
||||
const TVariant& v0 = _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);
|
||||
switch(op.op())
|
||||
case avm_add :
|
||||
{
|
||||
case avm_add :
|
||||
{
|
||||
const TVariant& v1 = _stack.pop();
|
||||
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;
|
||||
const TVariant& v1 = _stack.pop();
|
||||
TVariant& v0 = (TVariant&)_stack.peek();
|
||||
v0.add(v1);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (name == "#TODAY")
|
||||
|
@ -20,6 +20,8 @@ public:
|
||||
bool push(const TVariant& var);
|
||||
bool push(long n);
|
||||
bool push(const real& n);
|
||||
bool push(const TString& str);
|
||||
void reset();
|
||||
|
||||
TVariant_stack() : _sp(0) { }
|
||||
};
|
||||
@ -31,7 +33,7 @@ class TBytecode : public TArray
|
||||
TString _name;
|
||||
|
||||
public:
|
||||
const set_name(const char* name) { _name = name; }
|
||||
void set_name(const char* name) { _name = name; }
|
||||
const TString& name() const { return _name; }
|
||||
};
|
||||
|
||||
@ -57,6 +59,8 @@ public:
|
||||
bool compile(const char* cmd, TBytecode& bc);
|
||||
bool execute(const TBytecode& bc, ostream& outstr);
|
||||
bool execute(const TBytecode& bc, TString& outstr);
|
||||
void warm_restart();
|
||||
void cold_restart();
|
||||
|
||||
TAlex_virtual_machine();
|
||||
virtual ~TAlex_virtual_machine();
|
||||
|
Loading…
x
Reference in New Issue
Block a user