Patch level : 2.1 nopatch
Files correlati : ba0 ba8 Ricompilazione Demo : [ ] Commento : ba0 aggiunto meccanismo di chiusura automatica in caso di installazione modulo sys ba8 aggiunto converitore di form primordiale git-svn-id: svn://10.65.10.50/trunk@12048 c028cbd2-c16b-5b4b-a496-9718f37d4682
This commit is contained in:
parent
5e9712217e
commit
2b0291afdb
@ -66,7 +66,6 @@ protected: // TApplication
|
||||
|
||||
protected:
|
||||
void deconnect_user();
|
||||
bool dll_changed() const;
|
||||
virtual void main_loop();
|
||||
|
||||
void test_temp();
|
||||
@ -1021,7 +1020,7 @@ bool TMenu_application::test_programs()
|
||||
user() = old_user; // Ripristino utente normale
|
||||
more = TRUE; // ricontrolla
|
||||
|
||||
if (dll_changed()) //costringe ad uscire dal programma se si e' installato il modulo SY
|
||||
if (sys_dll_changed()) //costringe ad uscire dal programma se si e' installato il modulo SY
|
||||
return false;
|
||||
}
|
||||
_menu.set_dangerous_modules(dangerous);
|
||||
@ -1092,19 +1091,11 @@ void TMenu_application::deconnect_user()
|
||||
}
|
||||
}
|
||||
|
||||
bool TMenu_application::dll_changed() const
|
||||
{
|
||||
TString_array list;
|
||||
list_files("*.ex_", list);
|
||||
list_files("*.dl_", list);
|
||||
return (list.items() > 0);
|
||||
}
|
||||
|
||||
bool TMenu_application::destroy()
|
||||
{
|
||||
deconnect_user();
|
||||
|
||||
if (dll_changed())
|
||||
if (sys_dll_changed())
|
||||
{
|
||||
TExternal_app ba0close("ba0close.exe");
|
||||
ba0close.run(TRUE,TRUE,TRUE); // run asynchronous...
|
||||
|
@ -12,6 +12,18 @@
|
||||
#include "ba0101.h"
|
||||
#include "ba0100.h"
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// Utility
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
bool sys_dll_changed()
|
||||
{
|
||||
TString_array list;
|
||||
list_files("*.ex_", list);
|
||||
list_files("*.dl_", list);
|
||||
return list.items() > 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// Menu management
|
||||
///////////////////////////////////////////////////////////
|
||||
@ -303,6 +315,10 @@ bool TMenuitem::perform_program() const
|
||||
}
|
||||
}
|
||||
prefix().set("DEF"); // Aggiorna prefix
|
||||
|
||||
const bool install_app = _action.starts_with("ba1 -6", TRUE) == 0;
|
||||
if (install_app && sys_dll_changed())
|
||||
main_app().stop_run();
|
||||
}
|
||||
|
||||
return ok;
|
||||
|
@ -168,5 +168,7 @@ public:
|
||||
virtual ~TMenu();
|
||||
};
|
||||
|
||||
bool sys_dll_changed();
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -8,6 +8,7 @@ int main(int argc, char** argv)
|
||||
{
|
||||
case 1: ba8200(argc, argv); break; // Query Generator
|
||||
case 2: ba8300(argc, argv); break; // Report Generator
|
||||
case 3: ba8400(argc, argv); break; // Form Converter
|
||||
default: ba8100(argc, argv); break; // Record Selector
|
||||
}
|
||||
return 0;
|
||||
|
1
ba/ba8.h
1
ba/ba8.h
@ -1,5 +1,6 @@
|
||||
int ba8100(int argc, char* argv[]);
|
||||
int ba8200(int argc, char* argv[]);
|
||||
int ba8300(int argc, char* argv[]);
|
||||
int ba8400(int argc, char* argv[]);
|
||||
|
||||
|
||||
|
177
ba/ba8200.cpp
177
ba/ba8200.cpp
@ -300,6 +300,7 @@ protected:
|
||||
|
||||
protected:
|
||||
bool add_file_to_tree();
|
||||
void add_field_to_sheet(const char* fld, bool update);
|
||||
void add_field_to_sheet(bool update = true);
|
||||
void add_asterisk_to_sheet();
|
||||
bool edit_file_in_tree();
|
||||
@ -311,7 +312,9 @@ protected:
|
||||
void move_curr_field(int dir);
|
||||
|
||||
void tree2sql(TString& from, TString& where);
|
||||
void tree2isam(TString_array& a);
|
||||
void sheet2sql();
|
||||
void sheet2isam();
|
||||
void edit_query();
|
||||
|
||||
bool select_query();
|
||||
@ -521,53 +524,64 @@ void TQuery_mask::fill_fields()
|
||||
enable_field_buttons();
|
||||
}
|
||||
|
||||
// Aggiunge il campo selezionato nello spredasheet F_FIELDS allo spreadsheet F_SHEET
|
||||
void TQuery_mask::add_field_to_sheet(bool update)
|
||||
// Aggiunge un cmapo allo spreadsheet F_SHEET
|
||||
void TQuery_mask::add_field_to_sheet(const char* fld, bool update)
|
||||
{
|
||||
const TRelation_node* n = curr_node();
|
||||
if (n != NULL)
|
||||
{
|
||||
TSheet_field& sf = sfield(F_FIELDS);
|
||||
const int r = sf.selected();
|
||||
if (r >= 0)
|
||||
TSheet_field& ff = sfield(F_SHEET);
|
||||
TToken_string& row = ff.row(-1);
|
||||
row = n->id();
|
||||
row.add(fld);
|
||||
_is_dirty = true;
|
||||
if (update)
|
||||
{
|
||||
TToken_string& rowsel = sf.row(r);
|
||||
TSheet_field& ff = sfield(F_SHEET);
|
||||
TToken_string& row = ff.row(-1);
|
||||
row = n->id();
|
||||
row.add(rowsel.get(0));
|
||||
_is_dirty = true;
|
||||
if (update)
|
||||
{
|
||||
ff.force_update();
|
||||
enable_sql_button();
|
||||
}
|
||||
ff.force_update();
|
||||
enable_sql_button();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Aggiunge il campo selezionato nello spredasheet F_FIELDS allo spreadsheet F_SHEET
|
||||
void TQuery_mask::add_field_to_sheet(bool update)
|
||||
{
|
||||
TSheet_field& sf = sfield(F_FIELDS);
|
||||
const int r = sf.selected();
|
||||
if (r >= 0)
|
||||
{
|
||||
TToken_string& rowsel = sf.row(r);
|
||||
add_field_to_sheet(rowsel.get(0), update);
|
||||
}
|
||||
}
|
||||
|
||||
// Aggiunge tutte le colonne allo sheet
|
||||
void TQuery_mask::add_asterisk_to_sheet()
|
||||
{
|
||||
const TRelation_node* n = curr_node();
|
||||
if (n != NULL)
|
||||
{
|
||||
TSheet_field& sf = sfield(F_FIELDS);
|
||||
const int nLast = sf.items()-1;
|
||||
for (int i = 0; i <= nLast; i++)
|
||||
if (yesno_box("Si desisdera aggiungere tutti i campi singolarmente?"))
|
||||
{
|
||||
sf.select(i);
|
||||
add_field_to_sheet(i == nLast);
|
||||
TSheet_field& sf = sfield(F_FIELDS);
|
||||
const int nLast = sf.items()-1;
|
||||
for (int i = 0; i <= nLast; i++)
|
||||
{
|
||||
sf.select(i);
|
||||
add_field_to_sheet(i == nLast);
|
||||
}
|
||||
sf.select(0);
|
||||
}
|
||||
sf.select(0);
|
||||
else
|
||||
add_field_to_sheet("*", true);
|
||||
}
|
||||
}
|
||||
|
||||
// Decide se attivare o meno il bottone SQL
|
||||
void TQuery_mask::enable_sql_button()
|
||||
{
|
||||
const TSheet_field& s = sfield(F_SHEET);
|
||||
enable(F_GENSQL, s.items() > 0);
|
||||
const bool yes = sfield(F_SHEET).items() > 0;
|
||||
enable(F_GENSQL, yes);
|
||||
}
|
||||
|
||||
// Decide se attivare o meno i bottoni di aggiunta campi
|
||||
@ -637,6 +651,37 @@ void TQuery_mask::tree2sql(TString& from, TString& where)
|
||||
}
|
||||
}
|
||||
|
||||
static bool isam_tree_handler(TTree& tree, void* jolly, word flags)
|
||||
{
|
||||
TRelation_node* rn = (TRelation_node*)tree.curr_node();
|
||||
TString_array* a = (TString_array*)jolly;
|
||||
TToken_string row;
|
||||
if (a->items() == 0)
|
||||
{
|
||||
row << "USE " << rn->name();
|
||||
}
|
||||
else
|
||||
{
|
||||
row << "JOIN " << rn->name();
|
||||
if (rn->father()->name() != a->row(0).mid(4))
|
||||
row << " TO " << rn->father()->name();
|
||||
if (!rn->alias().blank())
|
||||
row << " ALIAS " << rn->alias();
|
||||
row << " INTO ";
|
||||
FOR_EACH_ARRAY_ROW(rn->join(), i, r)
|
||||
row << *r << ' ';
|
||||
}
|
||||
a->add(row);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Riempie una stringa ISAM con la relazione tra le tabelle
|
||||
void TQuery_mask::tree2isam(TString_array& a)
|
||||
{
|
||||
if (_tree.goto_root())
|
||||
_tree.scan_depth_first(isam_tree_handler, &a);
|
||||
}
|
||||
|
||||
inline bool tok_get_bool(TToken_string& tok, int pos)
|
||||
{
|
||||
const char* str = tok.get(pos);
|
||||
@ -719,26 +764,43 @@ void TQuery_mask::sheet2sql()
|
||||
fs.set_focusdirty(false); // Evita di scatenare eventi inutili
|
||||
}
|
||||
|
||||
static int select_callback(void* jolly, int argc, char** value, char** field)
|
||||
// Genera una query ISAM a partire dallo spreadsheet F_SHEET
|
||||
void TQuery_mask::sheet2isam()
|
||||
{
|
||||
TArray_sheet* sht = (TArray_sheet*)jolly;
|
||||
TToken_string row;
|
||||
for (int i = 0; i < argc; i++)
|
||||
row.add(value[i], i);
|
||||
sht->add(row);
|
||||
return SQLITE_OK;
|
||||
TString_array rel;
|
||||
tree2isam(rel);
|
||||
|
||||
TString use;
|
||||
FOR_EACH_ARRAY_ROW(rel, i, row)
|
||||
{
|
||||
use << *row << '\n';
|
||||
}
|
||||
|
||||
set(F_SQL, use, true);
|
||||
_sql_dirty = false;
|
||||
TEdit_field& fs = efield(F_SQL);
|
||||
fs.set_focusdirty(false); // Evita di scatenare eventi inutili
|
||||
}
|
||||
|
||||
void TQuery_mask::edit_query()
|
||||
{
|
||||
TSQL_recordset qry(get(F_SQL));
|
||||
if (qry.columns() > 0)
|
||||
const TString& sql = get(F_SQL);
|
||||
TRecordset* rex = NULL;
|
||||
|
||||
if (sql.starts_with("SELECT "))
|
||||
rex = new TSQL_recordset(sql);
|
||||
else
|
||||
rex = new TISAM_recordset(sql);
|
||||
|
||||
if (rex->columns() > 0)
|
||||
{
|
||||
TRecordset_sheet sht(qry);
|
||||
TRecordset_sheet sht(*rex);
|
||||
sht.run();
|
||||
}
|
||||
else
|
||||
warning_box(TR("Nessuna riga risultato"));
|
||||
|
||||
delete rex;
|
||||
}
|
||||
|
||||
|
||||
@ -785,11 +847,15 @@ bool TQuery_mask::get_qry_path(TFilename& path) const
|
||||
const bool ok = name.not_empty();
|
||||
if (ok)
|
||||
{
|
||||
path = firm2dir(-1);
|
||||
path.add("custom");
|
||||
if (!path.exist())
|
||||
xvt_fsys_mkdir(path);
|
||||
path.add(name);
|
||||
path = name;
|
||||
if (!path.is_absolute_path())
|
||||
{
|
||||
path = firm2dir(-1);
|
||||
path.add("custom");
|
||||
if (!path.exist())
|
||||
xvt_fsys_mkdir(path);
|
||||
path.add(name);
|
||||
}
|
||||
path.ext("qry");
|
||||
}
|
||||
return ok;
|
||||
@ -1098,6 +1164,7 @@ bool TQuery_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
|
||||
add_asterisk_to_sheet();
|
||||
break;
|
||||
case F_GENSQL:
|
||||
case F_GENISAM:
|
||||
if (e == fe_button)
|
||||
{
|
||||
next_page(1001);
|
||||
@ -1107,7 +1174,12 @@ bool TQuery_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
|
||||
"annullando eventuali modifiche manuali.\n"
|
||||
"Si desidera proseguire?"));
|
||||
if (ok)
|
||||
sheet2sql();
|
||||
{
|
||||
if (o.dlg() == F_GENSQL)
|
||||
sheet2sql();
|
||||
else
|
||||
sheet2isam();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case F_EDITQUERY:
|
||||
@ -1258,15 +1330,34 @@ TQuery_mask::TQuery_mask() : TAutomask("ba8200a"), _curr_num(0), _is_dirty(false
|
||||
|
||||
class TSQL_recordset_app : public TSkeleton_application
|
||||
{
|
||||
TQuery_mask* _msk;
|
||||
|
||||
public:
|
||||
virtual bool create();
|
||||
virtual void main_loop();
|
||||
virtual bool destroy();
|
||||
};
|
||||
|
||||
bool TSQL_recordset_app::create()
|
||||
{
|
||||
_msk = new TQuery_mask;
|
||||
xvt_sys_sleep(500);
|
||||
return TSkeleton_application::create();
|
||||
}
|
||||
|
||||
void TSQL_recordset_app::main_loop()
|
||||
{
|
||||
TQuery_mask* msk = new TQuery_mask;
|
||||
msk->run();
|
||||
delete msk;
|
||||
_msk->run();
|
||||
}
|
||||
|
||||
bool TSQL_recordset_app::destroy()
|
||||
{
|
||||
if (_msk != NULL)
|
||||
{
|
||||
delete _msk;
|
||||
_msk = NULL;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int ba8200(int argc, char* argv[])
|
||||
|
11
ba/ba8200.h
11
ba/ba8200.h
@ -7,11 +7,12 @@
|
||||
#define F_EDITFILE 302
|
||||
#define F_ASTERISK 303
|
||||
#define F_GENSQL 304
|
||||
#define F_EDITQUERY 305
|
||||
#define F_EXPORT_HTML 306
|
||||
#define F_EXPORT_EXCEL 307
|
||||
#define F_EXPORT_TXT 308
|
||||
#define F_EXPORT_CAMPO 309
|
||||
#define F_GENISAM 305
|
||||
#define F_EDITQUERY 306
|
||||
#define F_EXPORT_HTML 307
|
||||
#define F_EXPORT_EXCEL 308
|
||||
#define F_EXPORT_TXT 309
|
||||
#define F_EXPORT_CAMPO 310
|
||||
#define F_SHEET 400
|
||||
#define F_MOVEUP 401
|
||||
#define F_MOVEDN 402
|
||||
|
@ -68,32 +68,38 @@ END
|
||||
|
||||
BUTTON F_ADDFILE 10 2
|
||||
BEGIN
|
||||
PROMPT -15 11 "~Tabella"
|
||||
PROMPT -16 11 "~Tabella"
|
||||
END
|
||||
|
||||
BUTTON F_EDITFILE 10 2
|
||||
BEGIN
|
||||
PROMPT -25 11 "~Edit"
|
||||
PROMPT -26 11 "~Edit"
|
||||
PICTURE BMP_EDIT
|
||||
END
|
||||
|
||||
BUTTON DLG_USER 10 2
|
||||
BEGIN
|
||||
PROMPT -35 11 "~Campo"
|
||||
PROMPT -36 11 "~Campo"
|
||||
GROUP 1
|
||||
END
|
||||
|
||||
BUTTON F_ASTERISK 10 2
|
||||
BEGIN
|
||||
PROMPT -45 11 "Campo ~*"
|
||||
PROMPT -46 11 "Campo ~*"
|
||||
GROUP 1
|
||||
END
|
||||
|
||||
BUTTON F_GENSQL 10 2
|
||||
BEGIN
|
||||
PROMPT -55 11 "~SQL"
|
||||
PROMPT -56 11 "~SQL"
|
||||
END
|
||||
|
||||
BUTTON F_GENISAM 10 2
|
||||
BEGIN
|
||||
PROMPT -66 11 "~ISAM"
|
||||
END
|
||||
|
||||
|
||||
SPREADSHEET F_SHEET -5
|
||||
BEGIN
|
||||
PROMPT 0 13 ""
|
||||
|
776
ba/ba8201.cpp
776
ba/ba8201.cpp
@ -11,6 +11,7 @@
|
||||
#include <utility.h>
|
||||
#include <xml.h>
|
||||
|
||||
#include <statbar.h>
|
||||
#include "ba8201.h"
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
@ -301,11 +302,19 @@ int TTable_names::logic_num(const TString& 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
|
||||
{
|
||||
if (name.right(1) == '@')
|
||||
add_file(-atoi(name), name);
|
||||
else
|
||||
add_file(atoi(name), name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (name[0] == '%')
|
||||
add_file(LF_TABCOM, name); else
|
||||
if (name.len() == 3)
|
||||
add_file(LF_TAB, name);
|
||||
}
|
||||
|
||||
str = (TString*)_names.objptr(name);
|
||||
}
|
||||
@ -364,7 +373,7 @@ const TString& TRecordset::query_text() const
|
||||
|
||||
const TToken_string& TRecordset::sheet_head() const
|
||||
{
|
||||
TToken_string& head = get_tmp_string();
|
||||
TToken_string head;
|
||||
TToken_string tablefield(32, '.');
|
||||
for (unsigned int c = 0; c < columns(); c++)
|
||||
{
|
||||
@ -382,10 +391,14 @@ const TToken_string& TRecordset::sheet_head() const
|
||||
maxlen = len;
|
||||
}
|
||||
head << '@' << max(ci._width, maxlen);
|
||||
if (ci._type == _longfld || ci._type == _realfld)
|
||||
if (ci._type == _wordfld || ci._type == _intfld || ci._type == _longfld || ci._type == _realfld)
|
||||
head << 'R';
|
||||
}
|
||||
return head;
|
||||
|
||||
// Creo la stringa temporanea solo ora, altrimenti puo' essere sovrascritta!
|
||||
TToken_string& h = get_tmp_string();
|
||||
h = head;
|
||||
return h;
|
||||
}
|
||||
|
||||
bool TRecordset::save_as_html(const char* path)
|
||||
@ -661,6 +674,65 @@ bool TRecordset::set_var(const char* name, const TVariant& var, bool create)
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool is_var_separator(char c)
|
||||
{
|
||||
if (isspace(c))
|
||||
return true;
|
||||
return strchr("<=>,", c) != NULL;
|
||||
}
|
||||
|
||||
// Cerca le variabili nel testo SQL:
|
||||
// Una variabile comincia per # ed e' composta da soli caratteri alfanumerici.
|
||||
// Prima del simbolo # e dopo il nome della variabile deve esserci un separatore o blank
|
||||
void TRecordset::find_and_reset_vars()
|
||||
{
|
||||
_var.destroy();
|
||||
_varnames.destroy();
|
||||
|
||||
const TString& sql = query_text();
|
||||
int diesis = sql.find('#'); // cerco il primo #
|
||||
for ( ; diesis > 0; diesis = sql.find('#', diesis+1)) // Cerco tutti i #
|
||||
{
|
||||
if (is_var_separator(sql[diesis-1])) // Controllo che ci sia un separatore prima del #
|
||||
{
|
||||
int i = diesis+1;
|
||||
for ( ; sql[i] && (isalnum(sql[i]) || sql[i] == '_'); i++);
|
||||
if (i > diesis+1)
|
||||
{
|
||||
const TString& name = sql.sub(diesis, i);
|
||||
set_var(name, NULL_VARIANT, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TRecordset::parsed_text(TString& sql) const
|
||||
{
|
||||
sql = query_text();
|
||||
const bool vars = ((TSQL_recordset*)this)->ask_variables(false);
|
||||
if (vars) // Se ci sono variabili faccio le sostituzioni
|
||||
{
|
||||
const TString_array& names = variables();
|
||||
FOR_EACH_ARRAY_ROW(names, i, name) // Scandisco tutte le variabili
|
||||
{
|
||||
TVariant var = get_var(*name);
|
||||
int pos = sql.find(*name);
|
||||
for ( ; pos > 0; pos = sql.find(*name, pos+1))
|
||||
{
|
||||
const TString& after = sql.mid(pos+name->len());
|
||||
sql.cut(pos);
|
||||
TString s = var.as_string();
|
||||
if ((var.is_string() && s[0] != '\'') || var.is_null())
|
||||
{
|
||||
s.insert("'");
|
||||
s << '\'';
|
||||
}
|
||||
sql << s << after;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ask_variable(const char* name, TVariant& var)
|
||||
{
|
||||
TMask m("Richiesta variabile", 1, 52, 4);
|
||||
@ -1054,13 +1126,6 @@ bool TSQLite::import(int logicnum)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_var_separator(char c)
|
||||
{
|
||||
if (isspace(c))
|
||||
return true;
|
||||
return strchr("<=>,", c) != NULL;
|
||||
}
|
||||
|
||||
bool TSQLite::parse_select_from(const char* szSql)
|
||||
{
|
||||
test_path();
|
||||
@ -1170,44 +1235,20 @@ static int query_get_items(void* jolly, int argc, char** values, char** columns)
|
||||
return q->on_get_items(argc, values, columns);
|
||||
}
|
||||
|
||||
void TSQL_recordset::parsed_sql_text(TString& sql) const
|
||||
{
|
||||
sql = _sql;
|
||||
const bool vars = ((TSQL_recordset*)this)->ask_variables(false);
|
||||
if (vars) // Se ci sono variabili faccio le sostituzioni
|
||||
{
|
||||
const TString_array& names = variables();
|
||||
FOR_EACH_ARRAY_ROW(names, i, name) // Scandisco tutte le variabili
|
||||
{
|
||||
TVariant var = get_var(*name);
|
||||
int pos = sql.find(*name);
|
||||
for ( ; pos > 0; pos = sql.find(*name, pos+1))
|
||||
{
|
||||
const TString& after = sql.mid(pos+name->len());
|
||||
sql.cut(pos);
|
||||
TString s = var.as_string();
|
||||
if ((var.is_string() && s[0] != '\'') || var.is_null())
|
||||
{
|
||||
s.insert("'");
|
||||
s << '\'';
|
||||
}
|
||||
sql << s << after;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TSQL_recordset::ask_variables(bool all)
|
||||
{
|
||||
_page.destroy();
|
||||
return TRecordset::ask_variables(all);
|
||||
const bool ok = TRecordset::ask_variables(all);
|
||||
if (ok)
|
||||
_page.destroy();
|
||||
return ok;
|
||||
}
|
||||
|
||||
TRecnotype TSQL_recordset::items() const
|
||||
{
|
||||
if (_items == 0)
|
||||
{
|
||||
TString sql; parsed_sql_text(sql);
|
||||
TString sql; parsed_text(sql);
|
||||
TProfiler prof("SQL query");
|
||||
_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);
|
||||
@ -1277,7 +1318,7 @@ bool TSQL_recordset::move_to(TRecnotype n)
|
||||
|
||||
if (n < _first_row || n >= _first_row+_page.items())
|
||||
{
|
||||
TString sql; parsed_sql_text(sql);
|
||||
TString sql; parsed_text(sql);
|
||||
if (sql.find("LIMIT ") < 0)
|
||||
{
|
||||
const int semicolon = sql.rfind(';');
|
||||
@ -1324,24 +1365,7 @@ void TSQL_recordset::set(const char* sql)
|
||||
if (_sql.find("SELECT") >= 0 || _sql.find("select") >= 0)
|
||||
{
|
||||
_TheDataBase.parse_select_from(_sql);
|
||||
|
||||
// Cerca le variabili nel testo SQL:
|
||||
// Una variabile comincia per # ed e' composta da soli caratteri alfanumerici.
|
||||
// Prima del simbolo # e dopo il nome della variabile deve esserci un separatore o blank
|
||||
int diesis = _sql.find('#'); // cerco il primo #
|
||||
for ( ; diesis > 0; diesis = _sql.find('#', diesis+1)) // Cerco tutti i #
|
||||
{
|
||||
if (is_var_separator(_sql[diesis-1])) // Controllo che ci sia un separatore prima del #
|
||||
{
|
||||
int i = diesis+1;
|
||||
for ( ; _sql[i] && (isalnum(_sql[i]) || _sql[i] == '_'); i++);
|
||||
if (i > diesis+1)
|
||||
{
|
||||
const TString& name = _sql.sub(diesis, i);
|
||||
set_var(name, NULL_VARIANT, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
find_and_reset_vars();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1350,6 +1374,573 @@ TSQL_recordset::TSQL_recordset(const char* sql)
|
||||
set(sql);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// TCursor_parser
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
class TCursor_parser
|
||||
{
|
||||
istream& _instr;
|
||||
TArray& _column;
|
||||
|
||||
TString _pushed;
|
||||
TString _token;
|
||||
|
||||
TRelation* _relation;
|
||||
TCursor* _cursor;
|
||||
|
||||
protected:
|
||||
const TString& pop();
|
||||
void push();
|
||||
void add_column_info(const char* table, const TRectype& rec);
|
||||
|
||||
void parse_sortexpr(TToken_string& se);
|
||||
void parse_filter(TToken_string& filter);
|
||||
void parse_region(TRectype& rec);
|
||||
void parse_join_param(TRelation* rel, const TString& j, int to);
|
||||
void parse_join();
|
||||
void parse_sortedjoin();
|
||||
|
||||
public:
|
||||
TRelation* get_relation() { return _relation; }
|
||||
TCursor* get_cursor() { return _cursor; }
|
||||
|
||||
TCursor_parser(istream& instr, TArray& column);
|
||||
};
|
||||
|
||||
const TString& TCursor_parser::pop()
|
||||
{
|
||||
if (_pushed.not_empty())
|
||||
{
|
||||
_token = _pushed;
|
||||
_pushed.cut(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
_token.cut(0);
|
||||
|
||||
_instr.eatwhite();
|
||||
if (_instr.eof())
|
||||
return _token;
|
||||
|
||||
char c;
|
||||
_instr.get(c);
|
||||
while (!isspace(c) && c != EOF)
|
||||
{
|
||||
_token << c;
|
||||
_instr.get(c);
|
||||
}
|
||||
}
|
||||
return _token;
|
||||
}
|
||||
|
||||
void TCursor_parser::push()
|
||||
{
|
||||
CHECK(_pushed.empty(), "Repushing?");
|
||||
_pushed = _token;
|
||||
}
|
||||
|
||||
void TCursor_parser::add_column_info(const char* table, const TRectype& rec)
|
||||
{
|
||||
for (int i = 0; i < rec.items(); i++)
|
||||
{
|
||||
TRecordset_column_info* info = new TRecordset_column_info;
|
||||
const char* name = rec.fieldname(i);
|
||||
info->_name << table << '.' << name;
|
||||
info->_type = rec.type(name);
|
||||
switch (info->_type)
|
||||
{
|
||||
case _datefld: info->_width = 10; break;
|
||||
case _memofld: info->_width = 50; break;
|
||||
default : info->_width = rec.length(name); break;
|
||||
}
|
||||
_column.add(info);
|
||||
}
|
||||
}
|
||||
|
||||
void TCursor_parser::parse_sortexpr(TToken_string& se)
|
||||
{
|
||||
const char sep = se.separator();
|
||||
se.separator(' ');
|
||||
_instr.getline(se.get_buffer(), se.size());
|
||||
se.strip_d_spaces();
|
||||
se.replace(' ', sep);
|
||||
se.separator(sep);
|
||||
}
|
||||
|
||||
void TCursor_parser::parse_filter(TToken_string& filter)
|
||||
{
|
||||
const TString& str = pop();
|
||||
while (str.find('=') > 0)
|
||||
{
|
||||
filter.add(str);
|
||||
pop();
|
||||
}
|
||||
push();
|
||||
}
|
||||
|
||||
void TCursor_parser::parse_region(TRectype& rec)
|
||||
{
|
||||
TString16 field;
|
||||
TString value;
|
||||
while (true)
|
||||
{
|
||||
const TString& ass = pop();
|
||||
const int equal = ass.find('=');
|
||||
if (equal > 0)
|
||||
{
|
||||
field = ass.left(equal);
|
||||
value = ass.mid(equal+1);
|
||||
if (value[0] == '"' || value[0] == '\'')
|
||||
{
|
||||
value.rtrim(1);
|
||||
value.ltrim(1);
|
||||
}
|
||||
rec.put(field, value);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
push();
|
||||
}
|
||||
|
||||
|
||||
void TCursor_parser::parse_join_param(TRelation* rel, const TString& j, int to)
|
||||
{
|
||||
int key = 1;
|
||||
const TString& tok = pop();
|
||||
if (tok.starts_with("KE"))
|
||||
{
|
||||
pop();
|
||||
key = atoi(tok);
|
||||
}
|
||||
else
|
||||
push();
|
||||
|
||||
int alias = 0;
|
||||
pop();
|
||||
if (tok.starts_with("AL"))
|
||||
{
|
||||
pop();
|
||||
alias = atoi(tok);
|
||||
}
|
||||
else
|
||||
push();
|
||||
|
||||
TToken_string exp(80);
|
||||
pop();
|
||||
if (tok == "INTO")
|
||||
{
|
||||
parse_filter(exp);
|
||||
}
|
||||
if (exp.empty())
|
||||
yesnofatal_box("JOIN senza espressioni INTO");
|
||||
|
||||
const int logicnum = table2logic(j);
|
||||
if (logicnum != LF_TAB && logicnum != LF_TABCOM)
|
||||
rel->add(logicnum, exp, key, to, alias); // join file
|
||||
else
|
||||
rel->add(j, exp, key, to, alias); // join table
|
||||
|
||||
TString16 tabname;
|
||||
if (alias > 0)
|
||||
tabname << alias << '@';
|
||||
else
|
||||
tabname = j;
|
||||
const TRectype& rec = rel->curr(logicnum);
|
||||
add_column_info(tabname, rec);
|
||||
}
|
||||
|
||||
void TCursor_parser::parse_join()
|
||||
{
|
||||
const TString j = pop(); // File or table
|
||||
|
||||
int to = 0;
|
||||
const TString& tok = pop();
|
||||
if (tok == "TO") // TO keyword
|
||||
{
|
||||
pop();
|
||||
to = table2logic(tok);
|
||||
}
|
||||
else
|
||||
push();
|
||||
|
||||
parse_join_param(_relation, j, to);
|
||||
}
|
||||
|
||||
void TCursor_parser::parse_sortedjoin()
|
||||
{
|
||||
TToken_string filter,sortexp;
|
||||
const TString j = pop(); // File or table
|
||||
const TString& tok = pop();
|
||||
if (tok == "BY" )
|
||||
{
|
||||
parse_sortexpr(sortexp);
|
||||
}
|
||||
else
|
||||
push();
|
||||
|
||||
pop();
|
||||
if (tok.starts_with("FI") || tok.starts_with("SE"))
|
||||
{
|
||||
parse_filter(filter);
|
||||
}
|
||||
else
|
||||
push();
|
||||
|
||||
TRelation* sortrel = new TRelation(table2logic(j));
|
||||
while (true)
|
||||
{
|
||||
pop();
|
||||
if (tok.empty() || tok.starts_with("JO"))
|
||||
{
|
||||
push();
|
||||
break;
|
||||
}
|
||||
|
||||
if (tok.starts_with("US")) // USING keyword
|
||||
{
|
||||
const TString subj = pop(); // File or table
|
||||
parse_join_param(sortrel, subj, table2logic(j));
|
||||
}
|
||||
}
|
||||
|
||||
int to = 0;
|
||||
pop();
|
||||
if (tok == "TO") // TO keyword
|
||||
{
|
||||
pop();
|
||||
to = table2logic(tok);
|
||||
}
|
||||
else
|
||||
push();
|
||||
|
||||
int key = 1;
|
||||
pop();
|
||||
if (tok.starts_with("KE"))
|
||||
{
|
||||
pop();
|
||||
key = atoi(tok);
|
||||
}
|
||||
else
|
||||
push();
|
||||
|
||||
int alias = 0;
|
||||
pop();
|
||||
if (tok.starts_with("AL"))
|
||||
{
|
||||
pop();
|
||||
alias = atoi(tok);
|
||||
}
|
||||
else
|
||||
push();
|
||||
|
||||
TToken_string exp(80);
|
||||
if (pop() == "INTO")
|
||||
{
|
||||
pop();
|
||||
while (tok.find('=') > 0)
|
||||
{
|
||||
exp.add(tok);
|
||||
pop();
|
||||
}
|
||||
}
|
||||
push();
|
||||
|
||||
TSortedfile *sf= new TSortedfile(atoi(j),sortrel,sortexp,filter,key);
|
||||
_relation->add((TLocalisamfile *)sf, exp, key, to, alias, false); // join table
|
||||
|
||||
TString16 tabname = j;
|
||||
if (alias > 0)
|
||||
tabname.cut(0) << alias << '@';
|
||||
add_column_info(tabname, sf->curr());
|
||||
}
|
||||
|
||||
TCursor_parser::TCursor_parser(istream& instr, TArray& col)
|
||||
: _instr(instr), _column(col), _relation(NULL), _cursor(NULL)
|
||||
{
|
||||
_column.destroy();
|
||||
const TString& tok = pop();
|
||||
if (!tok.starts_with("US"))
|
||||
push();
|
||||
|
||||
pop();
|
||||
if (tok.blank())
|
||||
return;
|
||||
|
||||
const int logicnum = table2logic(tok);
|
||||
const char* tab = NULL;
|
||||
|
||||
if (logicnum != LF_TAB && logicnum != LF_TABCOM)
|
||||
_relation = new TRelation(logicnum);
|
||||
else
|
||||
_relation = new TRelation(tok);
|
||||
add_column_info(tok, _relation->curr());
|
||||
|
||||
int key = 1; // key number
|
||||
pop();
|
||||
if (tok.starts_with("KE"))
|
||||
{
|
||||
pop();
|
||||
key = atoi(tok);
|
||||
}
|
||||
else
|
||||
push();
|
||||
|
||||
pop();
|
||||
if (tok.starts_with("BY")) // "sort BY": user-defined sort
|
||||
{
|
||||
TToken_string ordexpr(256);
|
||||
parse_sortexpr(ordexpr);
|
||||
_cursor = new TSorted_cursor(_relation, ordexpr,"", key);
|
||||
}
|
||||
else
|
||||
push();
|
||||
|
||||
pop();
|
||||
if (tok.starts_with("FI") || tok.starts_with("SE"))
|
||||
{
|
||||
TToken_string filter;
|
||||
parse_filter(filter);
|
||||
if (_cursor == NULL)
|
||||
_cursor = new TCursor(_relation, filter, key);
|
||||
else
|
||||
_cursor->setfilter(filter);
|
||||
}
|
||||
else
|
||||
push();
|
||||
|
||||
if (_cursor == NULL)
|
||||
_cursor = new TCursor(_relation, "", key);
|
||||
|
||||
TRectype rec_start(_relation->curr());
|
||||
TRectype rec_stop(_relation->curr());
|
||||
|
||||
pop();
|
||||
if (tok.starts_with("FR"))
|
||||
parse_region(rec_start);
|
||||
else
|
||||
push();
|
||||
pop();
|
||||
if (tok.starts_with("TO"))
|
||||
parse_region(rec_stop);
|
||||
else
|
||||
push();
|
||||
if (!rec_start.empty() || !rec_stop.empty())
|
||||
_cursor->setregion(rec_start, rec_stop, 0x2);
|
||||
|
||||
while (true)
|
||||
{
|
||||
pop();
|
||||
if (tok.starts_with("JO"))
|
||||
parse_join(); else
|
||||
if (tok.starts_with("SO"))
|
||||
parse_sortedjoin();
|
||||
else
|
||||
break;
|
||||
}
|
||||
push();
|
||||
|
||||
if (_relation->items() == 0) // Non ci sono anche tabelle collegate
|
||||
{
|
||||
FOR_EACH_ARRAY_ITEM(_column, i, obj)
|
||||
{
|
||||
TRecordset_column_info* info = (TRecordset_column_info*)obj;
|
||||
const int arrow = info->_name.find('.');
|
||||
if (arrow > 0)
|
||||
info->_name = info->_name.mid(arrow+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// TISAM_recordset
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
TVariant& TISAM_recordset::get_tmp_var() const
|
||||
{
|
||||
static TArray _page; // Variants to be returned by get
|
||||
static int _next_var = 0; // Index of next variant to be returned
|
||||
|
||||
if (_next_var >= 32)
|
||||
_next_var = 0;
|
||||
TVariant* var = (TVariant*)_page.objptr(_next_var);
|
||||
if (var == NULL)
|
||||
{
|
||||
var = new TVariant;
|
||||
_page.add(var, _next_var);
|
||||
}
|
||||
_next_var++;
|
||||
return *var;
|
||||
}
|
||||
|
||||
const TVariant& TISAM_recordset::get(int logic, const char* name) const
|
||||
{
|
||||
char* square = strchr(name, '[');
|
||||
if (square != NULL) *square = '\0'; // Per il momento tronco il nome
|
||||
|
||||
const TRectype& rec = _relation->curr(logic);
|
||||
const TFieldtypes ft = rec.type(name);
|
||||
|
||||
if (square != NULL) *square = '['; // Ripristino il nome
|
||||
|
||||
if (ft == _nullfld)
|
||||
return NULL_VARIANT;
|
||||
|
||||
TVariant& var = get_tmp_var();
|
||||
switch (ft)
|
||||
{
|
||||
case _datefld: var.set(rec.get_date(name)); break;
|
||||
case _realfld: var.set(rec.get_real(name)); break;
|
||||
case _intfld :
|
||||
case _longfld:
|
||||
case _wordfld: var.set(rec.get_long(name)); break;
|
||||
default : var.set(rec.get(name)); break;
|
||||
}
|
||||
|
||||
if (square != NULL)
|
||||
{
|
||||
int from = 0, to = -1;
|
||||
sscanf(square, "[%d,%d]", &from, &to);
|
||||
var.set(var.as_string().sub(from-1, to));
|
||||
}
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
const TVariant& TISAM_recordset::get(size_t c) const
|
||||
{
|
||||
const TRecordset_column_info* info = (const TRecordset_column_info*)_column.objptr(c);
|
||||
if (info != NULL)
|
||||
{
|
||||
int logic = 0;
|
||||
const char* field = info->_name;
|
||||
const int dot = info->_name.find('.');
|
||||
if (dot > 0)
|
||||
{
|
||||
logic = table2logic(info->_name.left(dot));
|
||||
field += dot+1;
|
||||
}
|
||||
return get(logic, field);
|
||||
}
|
||||
return NULL_VARIANT;
|
||||
}
|
||||
|
||||
const TVariant& TISAM_recordset::get(const char* name) const
|
||||
{
|
||||
const TFixed_string fldname(name);
|
||||
|
||||
int table_end = fldname.find('.');
|
||||
int field_start = table_end+1;
|
||||
if (table_end < 0)
|
||||
{
|
||||
table_end = fldname.find('-');
|
||||
if (table_end > 0)
|
||||
field_start++;
|
||||
}
|
||||
int logic = 0;
|
||||
const char* field = name;
|
||||
if (table_end > 0)
|
||||
{
|
||||
logic = table2logic(fldname.left(table_end));
|
||||
field += field_start;
|
||||
}
|
||||
return get(logic, field);
|
||||
}
|
||||
|
||||
const TRecordset_column_info& TISAM_recordset::column_info(size_t i) const
|
||||
{
|
||||
return (const TRecordset_column_info&)_column[i];
|
||||
}
|
||||
|
||||
TRecnotype TISAM_recordset::current_row() const
|
||||
{
|
||||
return _cursor != NULL ? _cursor->pos() : -1;
|
||||
}
|
||||
|
||||
bool TISAM_recordset::ask_variables(bool all)
|
||||
{
|
||||
bool ok = TRecordset::ask_variables(all);
|
||||
if (ok)
|
||||
reset();
|
||||
return ok;
|
||||
}
|
||||
|
||||
TRecnotype TISAM_recordset::items() const
|
||||
{
|
||||
if (_cursor == NULL)
|
||||
{
|
||||
TString use; parsed_text(use);
|
||||
TProfiler prof("ISAM query");
|
||||
TISAM_recordset* my = (TISAM_recordset*)this;
|
||||
istrstream instr(use.get_buffer(), use.len());
|
||||
TCursor_parser parser(instr, my->_column);
|
||||
|
||||
my->_relation = parser.get_relation();
|
||||
my->_cursor = parser.get_cursor();
|
||||
|
||||
if (_cursor != NULL)
|
||||
{
|
||||
_cursor->items();
|
||||
_cursor->freeze();
|
||||
}
|
||||
}
|
||||
|
||||
return _cursor != NULL ? _cursor->items() : 0;
|
||||
}
|
||||
|
||||
unsigned int TISAM_recordset::columns() const
|
||||
{
|
||||
if (_cursor == NULL)
|
||||
items();
|
||||
return _column.items();
|
||||
}
|
||||
|
||||
|
||||
bool TISAM_recordset::move_to(TRecnotype pos)
|
||||
{
|
||||
bool ok = _cursor != NULL;
|
||||
if (ok)
|
||||
{
|
||||
*_cursor = pos;
|
||||
ok = pos >= 0 && pos < items();
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
void TISAM_recordset::reset()
|
||||
{
|
||||
_column.destroy();
|
||||
if (_relation != NULL)
|
||||
{
|
||||
delete _relation;
|
||||
_relation = NULL;
|
||||
}
|
||||
if (_cursor != NULL)
|
||||
{
|
||||
delete _cursor;
|
||||
_cursor = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void TISAM_recordset::set(const char* use)
|
||||
{
|
||||
reset();
|
||||
_use = use;
|
||||
find_and_reset_vars();
|
||||
}
|
||||
|
||||
TISAM_recordset::TISAM_recordset(const char* use)
|
||||
: _relation(NULL), _cursor(NULL)
|
||||
{
|
||||
set(use);
|
||||
}
|
||||
|
||||
TISAM_recordset::~TISAM_recordset()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// TRecordset_sheet
|
||||
///////////////////////////////////////////////////////////
|
||||
@ -1378,3 +1969,60 @@ TRecordset_sheet::TRecordset_sheet(TRecordset& query)
|
||||
: TSheet(-1, -1, -2, -4, "Query", query.sheet_head()), _query(query)
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// TProfiler
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
TProfiler::TProfiler(const char* desc)
|
||||
: _desc(desc)
|
||||
{
|
||||
#ifdef DBG
|
||||
_start = clock();
|
||||
|
||||
TString80 msg;
|
||||
msg << "Profiling " << desc << "...";
|
||||
statbar_set_title(TASK_WIN, msg);
|
||||
|
||||
while (true)
|
||||
{
|
||||
const clock_t clk = clock();
|
||||
if (clk != _start)
|
||||
{
|
||||
_start = clk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void TProfiler::show() const
|
||||
{
|
||||
#ifdef DBG
|
||||
const double s = double(clock() - _start) / CLOCKS_PER_SEC;
|
||||
|
||||
int hour = 0, min = 0;
|
||||
int sec = int(s);
|
||||
const int cent = int((s - sec)*100);
|
||||
|
||||
if (sec >= 3600)
|
||||
{
|
||||
hour = sec / 3600;
|
||||
sec -= hour * 3600;
|
||||
}
|
||||
if (sec >= 60)
|
||||
{
|
||||
min = sec / 60;
|
||||
sec -= min * 60;
|
||||
}
|
||||
|
||||
TString80 msg = _desc;
|
||||
msg.format("%s %02d:%02d:%02d.%02d", (const char*)_desc, hour, min, sec, cent);
|
||||
statbar_set_title(TASK_WIN, msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
TProfiler::~TProfiler()
|
||||
{
|
||||
show();
|
||||
}
|
||||
|
51
ba/ba8201.h
51
ba/ba8201.h
@ -15,7 +15,7 @@
|
||||
|
||||
struct TRecordset_column_info : public TObject
|
||||
{
|
||||
TString _name;
|
||||
TString _name; // Table.Column
|
||||
int _width;
|
||||
TFieldtypes _type;
|
||||
};
|
||||
@ -93,6 +93,9 @@ protected:
|
||||
bool save_as_silk(const char* path);
|
||||
bool save_as_text(const char* path);
|
||||
bool save_as_campo(const char* path);
|
||||
|
||||
void find_and_reset_vars();
|
||||
void parsed_text(TString& sql) const;
|
||||
|
||||
public: // Absolutely needed methods
|
||||
virtual TRecnotype items() const pure;
|
||||
@ -161,6 +164,40 @@ public:
|
||||
virtual ~TSQL_recordset() { }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// TISAM_recordset
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
class TISAM_recordset : public TRecordset
|
||||
{
|
||||
TString _use;
|
||||
|
||||
TRelation* _relation;
|
||||
TCursor* _cursor;
|
||||
TArray _column; // Column infos
|
||||
|
||||
protected:
|
||||
void reset();
|
||||
TVariant& get_tmp_var() const;
|
||||
const TVariant& get(int logic, const char* field) const;
|
||||
|
||||
public:
|
||||
void set(const char* use);
|
||||
virtual TRecnotype items() const;
|
||||
virtual bool move_to(TRecnotype pos);
|
||||
virtual TRecnotype current_row() const;
|
||||
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 const TVariant& get(const char* column_name) const;
|
||||
virtual bool ask_variables(bool all);
|
||||
virtual const TString& query_text() const { return _use; }
|
||||
|
||||
|
||||
TISAM_recordset(const char* use);
|
||||
virtual ~TISAM_recordset();
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// TRecordset_sheet
|
||||
///////////////////////////////////////////////////////////
|
||||
@ -181,6 +218,18 @@ public:
|
||||
// Utility
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
class TProfiler : public TObject
|
||||
{
|
||||
TString _desc;
|
||||
clock_t _start;
|
||||
|
||||
public:
|
||||
void show() const;
|
||||
|
||||
TProfiler(const char* desc = "");
|
||||
~TProfiler();
|
||||
};
|
||||
|
||||
bool select_custom_file(TFilename& path, const char* ext);
|
||||
const TString& logic2table(int logic_num);
|
||||
int table2logic(const TString& name);
|
||||
|
@ -55,9 +55,9 @@ class TReport_base_mask : public TAutomask
|
||||
{
|
||||
TReport_font _font;
|
||||
bool _font_changed;
|
||||
TReport& _report;
|
||||
|
||||
protected:
|
||||
TReport& _report;
|
||||
char _halign, _valign;
|
||||
COLOR _fgcolor, _bgcolor;
|
||||
|
||||
@ -239,6 +239,7 @@ void TReport_field_mask::vedo_non_vedo()
|
||||
show(F_BGCOLOR, type != 'L');
|
||||
show(F_FONT_SELECT, is_text);
|
||||
show(F_SOURCE, (is_text || type == 'I') && type != 'T');
|
||||
show(DLG_FINDREC, field(F_SOURCE).active());
|
||||
show(F_CODVAL, is_currency); // Codice valuta di riferimento
|
||||
show(F_LINK, strchr("DNS", type) != NULL); // Chi puo' essere un link?
|
||||
show(F_PRESCRIPT, is_text);
|
||||
@ -295,6 +296,39 @@ bool TReport_field_mask::on_field_event(TOperable_field& o, TField_event e, long
|
||||
return error_box(TR("Specificare almeno due codici"));
|
||||
}
|
||||
break;
|
||||
case DLG_FINDREC:
|
||||
if (e == fe_button)
|
||||
{
|
||||
TRecordset* rex = _report.recordset();
|
||||
if (rex != NULL && rex->columns() > 0)
|
||||
{
|
||||
TArray_sheet sheet(-1, -1, -1, 20, "Colonne Query", "Nome@16|Tipo@8|Dimensoni@R");
|
||||
TToken_string row;
|
||||
for (size_t i = 0; i < rex->columns(); i++)
|
||||
{
|
||||
const TRecordset_column_info& info = rex->column_info(i);
|
||||
row = info._name;
|
||||
switch (info._type)
|
||||
{
|
||||
case _alfafld: row.add("Stringa"); break;
|
||||
case _boolfld: row.add("Logico"); break;
|
||||
case _datefld: row.add("Data"); break;
|
||||
case _memofld: row.add("Memo"); break;
|
||||
default : row.add("Numero"); break;
|
||||
}
|
||||
row.add(info._width);
|
||||
sheet.add(row);
|
||||
}
|
||||
if (sheet.run() == K_ENTER)
|
||||
{
|
||||
row = sheet.row(-1);
|
||||
set(F_SOURCE, row.get(0));
|
||||
}
|
||||
}
|
||||
else
|
||||
warning_box("Query non definita");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -716,11 +750,15 @@ bool TReport_mask::get_rep_path(TFilename& path) const
|
||||
const bool ok = name.not_empty();
|
||||
if (ok)
|
||||
{
|
||||
path = firm2dir(-1);
|
||||
path.add("custom");
|
||||
if (!path.exist())
|
||||
xvt_fsys_mkdir(path);
|
||||
path.add(name);
|
||||
path = name;
|
||||
if (!path.is_absolute_path())
|
||||
{
|
||||
path = firm2dir(-1);
|
||||
path.add("custom");
|
||||
if (!path.exist())
|
||||
xvt_fsys_mkdir(path);
|
||||
path.add(name);
|
||||
}
|
||||
path.ext("rep");
|
||||
}
|
||||
return ok;
|
||||
@ -826,6 +864,7 @@ void TReport_mask::add_field()
|
||||
{
|
||||
TReport_section& rs = curr_section();
|
||||
TReport_field* rf = new TReport_field(&rs);
|
||||
rf->set_pos(0, rs.compute_size().y);
|
||||
TReport_field_mask m(*rf);
|
||||
m.disable(DLG_DELREC);
|
||||
if (m.run() == K_ENTER)
|
||||
@ -1062,12 +1101,23 @@ bool TReport_mask::on_field_event(TOperable_field& o, TField_event e, long jolly
|
||||
case F_SHOW_QRY:
|
||||
if (e == fe_button)
|
||||
{
|
||||
TSQL_recordset qry(get(F_SQL));
|
||||
if (qry.columns() > 0)
|
||||
TRecordset* rex = NULL;
|
||||
|
||||
const TString& sql = get(F_SQL);
|
||||
if (sql.starts_with("SELECT "))
|
||||
rex = new TSQL_recordset(sql);
|
||||
else
|
||||
rex = new TISAM_recordset(sql);
|
||||
|
||||
if (rex->columns() > 0)
|
||||
{
|
||||
TRecordset_sheet sheet(qry);
|
||||
sheet.run();
|
||||
TRecordset_sheet sht(*rex);
|
||||
sht.run();
|
||||
}
|
||||
else
|
||||
warning_box(TR("Nessuna riga risultato"));
|
||||
|
||||
delete rex;
|
||||
}
|
||||
break;
|
||||
case DLG_PRINT:
|
||||
@ -1146,8 +1196,13 @@ class TReporter_app : public TSkeleton_application
|
||||
TReport_mask* _msk;
|
||||
|
||||
protected:
|
||||
virtual void print();
|
||||
virtual bool create();
|
||||
virtual void main_loop();
|
||||
virtual bool destroy();
|
||||
virtual void print();
|
||||
|
||||
public:
|
||||
TReporter_app() : _msk(NULL) { }
|
||||
};
|
||||
|
||||
void TReporter_app::print()
|
||||
@ -1156,12 +1211,26 @@ void TReporter_app::print()
|
||||
_msk->on_print();
|
||||
}
|
||||
|
||||
void TReporter_app::main_loop()
|
||||
bool TReporter_app::create()
|
||||
{
|
||||
_msk = new TReport_mask;
|
||||
xvt_sys_sleep(500);
|
||||
return TSkeleton_application::create();
|
||||
}
|
||||
|
||||
bool TReporter_app::destroy()
|
||||
{
|
||||
if (_msk != NULL)
|
||||
{
|
||||
delete _msk;
|
||||
_msk = NULL;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TReporter_app::main_loop()
|
||||
{
|
||||
_msk->run();
|
||||
delete _msk;
|
||||
_msk = NULL;
|
||||
}
|
||||
|
||||
int ba8300(int argc, char* argv[])
|
||||
|
@ -89,6 +89,12 @@ BEGIN
|
||||
PROMPT 1 10 "@bSorgente"
|
||||
END
|
||||
|
||||
BUTTON DLG_FINDREC 10 2
|
||||
BEGIN
|
||||
PROMPT -33, 9 ""
|
||||
PICTURE BMP_FINDREC
|
||||
END
|
||||
|
||||
BUTTON DLG_CANCEL 10 2
|
||||
BEGIN
|
||||
PROMPT -13 -1 ""
|
||||
|
@ -392,7 +392,7 @@ bool TReport_window::get_selection_rect(TRectangle& rct) const
|
||||
const TReport_field& f = *(const TReport_field*)o;
|
||||
if (f.selected())
|
||||
{
|
||||
const TRectangle& fr = f.get_rect();
|
||||
const TRectangle fr = f.get_draw_rect();
|
||||
if (!full)
|
||||
{
|
||||
rct = fr;
|
||||
|
152
ba/ba8302.cpp
152
ba/ba8302.cpp
@ -495,7 +495,7 @@ TPoint TReport_section::compute_size() const
|
||||
const TReport_field& rf = field(i);
|
||||
if (rf.shown())
|
||||
{
|
||||
const TRectangle& r = rf.get_rect();
|
||||
const TRectangle r = rf.get_draw_rect();
|
||||
if (_size.x <= 0 && r.right() > s.x) // Richiesto calcolo larghezza
|
||||
s.x = r.right();
|
||||
if (_size.y <= 0 && r.bottom() > s.y) // Richiesto calcolo altezza
|
||||
@ -677,7 +677,8 @@ TString& TReport_script::translate_message() const
|
||||
{
|
||||
TToken_string source(_src, '\n');
|
||||
TToken_string line(256, '|');
|
||||
TString cmd, arg, fld;
|
||||
TToken_string args(256, ',');
|
||||
TString cmd, fld;
|
||||
TString& alex = get_tmp_string();
|
||||
FOR_EACH_TOKEN(source, srcrow)
|
||||
{
|
||||
@ -699,26 +700,29 @@ TString& TReport_script::translate_message() const
|
||||
if (comma > 0)
|
||||
{
|
||||
cmd = msg.left(comma);
|
||||
arg = msg.mid(comma+1);
|
||||
fld = arg;
|
||||
args = msg.mid(comma+1);
|
||||
fld = args.get(0);
|
||||
if (fld[0] != '#')
|
||||
fld.insert("#", 0);
|
||||
fld.insert("REPORT.", 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd = msg;
|
||||
arg.cut(0);
|
||||
args.cut(0);
|
||||
fld.cut(0);
|
||||
}
|
||||
|
||||
if (cmd.starts_with("AL")) // ALIGN
|
||||
{
|
||||
alex << fld << " ALIGN_FIELD_" << args.get(1) << ' ';
|
||||
} else
|
||||
if (cmd.starts_with("CO")) // COPY
|
||||
{
|
||||
alex << "#REPORT.THIS @ " << fld << " ! ";
|
||||
alex << "#THIS @ " << fld << " ! ";
|
||||
} else
|
||||
if (cmd.starts_with("AD")) // ADD
|
||||
{
|
||||
alex << "#REPORT.THIS @ " << fld << " @ + "<< fld << " ! ";
|
||||
alex << "#THIS @ " << fld << " @ + "<< fld << " ! ";
|
||||
} else
|
||||
if (cmd.starts_with("IN")) // INC
|
||||
{
|
||||
@ -867,6 +871,51 @@ void TReport_field::offset(const TPoint& pt)
|
||||
_rct.y += pt.y;
|
||||
}
|
||||
|
||||
void TReport_field::set_draw_pos(long x, long y)
|
||||
{
|
||||
_rct_draw.x = x;
|
||||
_rct_draw.y = y;
|
||||
}
|
||||
|
||||
void TReport_field::set_draw_size(long w, long h)
|
||||
{
|
||||
_rct_draw.set_width(w);
|
||||
_rct_draw.set_height(h);
|
||||
}
|
||||
|
||||
void TReport_field::compute_draw_rect() const
|
||||
{
|
||||
TRectangle& rct = ((TReport_field*)this)->_rct_draw;
|
||||
rct = get_rect();
|
||||
if (type() == 'S')
|
||||
{
|
||||
if (rct.width() <= 0)
|
||||
{
|
||||
TString text = formatted_text(); text.rtrim();
|
||||
TToken_string str(text, '\n');
|
||||
int maxlen = 1;
|
||||
FOR_EACH_TOKEN(str, line)
|
||||
{
|
||||
const int len = strlen(line);
|
||||
if (len > maxlen)
|
||||
maxlen = len;
|
||||
}
|
||||
rct.set_width(maxlen * 100);
|
||||
}
|
||||
if (rct.height() <= 0)
|
||||
{
|
||||
if (rct.width() >= 100)
|
||||
{
|
||||
TString text = formatted_text(); text.rtrim();
|
||||
TParagraph_string str(text, rct.width()/100);
|
||||
rct.set_height(str.items() * 100);
|
||||
}
|
||||
if (rct.height() <= 0)
|
||||
rct.set_height(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const TReport_font& TReport_field::font() const
|
||||
{
|
||||
return _font != NULL ? *_font : _section->font();
|
||||
@ -1010,6 +1059,8 @@ bool TReport_field::load_field()
|
||||
else
|
||||
_var.set_null();
|
||||
}
|
||||
compute_draw_rect();
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
@ -1039,7 +1090,7 @@ COLOR TReport_field::link_color() const
|
||||
|
||||
void TReport_field::draw_text(TWindow& win, const char* text, TReport_draw_mode rdm) const
|
||||
{
|
||||
const TRectangle& rct = get_rect();
|
||||
const TRectangle& rct = get_draw_rect();
|
||||
RCT r; win.log2dev(rct, r);
|
||||
advanced_draw_rect(win, r, border(), fore_color(), back_color());
|
||||
|
||||
@ -1176,6 +1227,9 @@ void TReport_field::draw(TWindow& win, TReport_draw_mode rdm) const
|
||||
if (rdm != rdm_edit && hidden())
|
||||
return;
|
||||
|
||||
if (rdm == rdm_edit)
|
||||
compute_draw_rect();
|
||||
|
||||
PAT_STYLE back_pattern = PAT_HOLLOW;
|
||||
if (rdm == rdm_edit)
|
||||
{
|
||||
@ -1251,7 +1305,7 @@ void TReport_field::draw(TWindow& win, TReport_draw_mode rdm) const
|
||||
{
|
||||
if (border() <= 0) // Rendi piu' visibile il bordo dei campi che non ce l'hanno
|
||||
{
|
||||
RCT r; win.log2dev(get_rect(), r);
|
||||
RCT r; win.log2dev(get_draw_rect(), r);
|
||||
advanced_draw_rect(win, r, 1, COLOR_LTGRAY, COLOR_WHITE);
|
||||
}
|
||||
if (id() > 0)
|
||||
@ -1378,6 +1432,7 @@ bool TReport_field::load(const TXmlItem& fld)
|
||||
set_row(get_num_attr(fld, "y"));
|
||||
set_width(get_num_attr(fld, "width"));
|
||||
set_height(get_num_attr(fld, "height", 100));
|
||||
_rct_draw = _rct;
|
||||
show(!fld.GetBoolAttr("hidden"));
|
||||
activate(!fld.GetBoolAttr("deactivated"));
|
||||
hide_zeroes(fld.GetBoolAttr("zeroes_hidden"));
|
||||
@ -1461,6 +1516,7 @@ TReport_field::TReport_field(TReport_section* sec)
|
||||
{
|
||||
set_pos(0,0);
|
||||
set_size(1600,100);
|
||||
_rct_draw = _rct;
|
||||
}
|
||||
|
||||
TReport_field::TReport_field(const TReport_field& rf) : _font(NULL)
|
||||
@ -1592,8 +1648,10 @@ bool TReport::set_recordset(TRecordset* rs)
|
||||
bool TReport::set_recordset(const TString& sql)
|
||||
{
|
||||
bool ok = false;
|
||||
if (sql.compare("SELECT", 6, true) == 0)
|
||||
if (sql.compare("SELECT ", 7, true) == 0)
|
||||
ok = set_recordset(new TSQL_recordset(sql));
|
||||
else
|
||||
ok = set_recordset(new TISAM_recordset(sql));
|
||||
return ok;
|
||||
}
|
||||
|
||||
@ -1952,16 +2010,17 @@ bool TReport::set_usr_val(const TString& name, const TVariant& var)
|
||||
return TAlex_virtual_machine::set_usr_val(name, var);
|
||||
}
|
||||
|
||||
unsigned int TReport::compile_usr_word(const TString& name) const
|
||||
size_t TReport::get_usr_words(TString_array& words) const
|
||||
{
|
||||
const int words = 10;
|
||||
const char* const names[words] = { NULL, "DISABLE", "ENABLE", "GET_SIZE", "HIDE",
|
||||
"RUN_FORM", "SET_BACK_COLOR", "SET_FORE_COLOR",
|
||||
"SET_SIZE", "SHOW" };
|
||||
int i;
|
||||
for (i = words-1; i > 0; i--)
|
||||
if (name == names[i])
|
||||
break;
|
||||
const char* const name[] =
|
||||
{
|
||||
"***", "DISABLE", "ENABLE", "GET_POS",
|
||||
"GET_SIZE", "HIDE", "RUN_FORM", "SET_BACK_COLOR", "SET_FORE_COLOR",
|
||||
"SET_POS", "SET_SIZE", "SHOW", NULL
|
||||
};
|
||||
size_t i;
|
||||
for (i = 0; name[i] != NULL; i++)
|
||||
words.add(name[i]);
|
||||
return i;
|
||||
}
|
||||
|
||||
@ -1971,10 +2030,16 @@ static void do_show(TReport_field& rf, void* jolly)
|
||||
static void do_enable(TReport_field& rf, void* jolly)
|
||||
{ rf.activate(jolly != NULL); }
|
||||
|
||||
static void do_set_pos(TReport_field& rf, void* jolly)
|
||||
{
|
||||
const TPoint& pt = *(const TPoint*)jolly;
|
||||
rf.set_draw_pos(pt.x, pt.y);
|
||||
}
|
||||
|
||||
static void do_set_size(TReport_field& rf, void* jolly)
|
||||
{
|
||||
const TPoint& pt = *(const TPoint*)jolly;
|
||||
rf.set_size(pt.x, pt.y);
|
||||
rf.set_draw_size(pt.x, pt.y);
|
||||
}
|
||||
|
||||
static void do_set_back_color(TReport_field& rf, void* jolly)
|
||||
@ -2082,47 +2147,70 @@ bool TReport::execute_usr_word(unsigned int opcode, TVariant_stack& stack)
|
||||
{
|
||||
switch (opcode)
|
||||
{
|
||||
case 1: // DISABLE
|
||||
case 1: // Placeholder
|
||||
break;
|
||||
case 2: // DISABLE
|
||||
do_message(stack.pop(), do_enable, NULL);
|
||||
break;
|
||||
case 2: // ENABLE
|
||||
case 3: // ENABLE
|
||||
do_message(stack.pop(), do_enable, (void*)1);
|
||||
break;
|
||||
case 3: // GET_SIZE
|
||||
case 4: // GET_POS
|
||||
{
|
||||
const TReport_field* fld = field(stack.pop().as_string());
|
||||
real x, y;
|
||||
if (fld != NULL)
|
||||
{
|
||||
const TRectangle& r = fld->get_draw_rect();
|
||||
x = r.x / CENTO; y = r.y / CENTO;
|
||||
}
|
||||
stack.push(x); stack.push(y);
|
||||
}
|
||||
break;
|
||||
case 5: // GET_SIZE
|
||||
{
|
||||
const TReport_field* fld = field(stack.pop().as_string());
|
||||
real w, h;
|
||||
if (fld != NULL)
|
||||
{
|
||||
const TRectangle& r = fld->get_rect();
|
||||
const TRectangle& r = fld->get_draw_rect();
|
||||
w = r.width() / CENTO; h = r.height() / CENTO;
|
||||
}
|
||||
stack.push(w); stack.push(h);
|
||||
}
|
||||
break;
|
||||
case 4: // HIDE
|
||||
case 6: // HIDE
|
||||
do_message(stack.pop(), do_show, NULL);
|
||||
break;
|
||||
case 5: // RUN_FORM
|
||||
case 7: // RUN_FORM
|
||||
{
|
||||
const TString& msk = stack.pop().as_string();
|
||||
const KEY key = run_form(msk);
|
||||
stack.push(key);
|
||||
}
|
||||
break;
|
||||
case 6: // SET_BACK_COLOR
|
||||
case 8: // SET_BACK_COLOR
|
||||
{
|
||||
const COLOR rgb = stack.pop().as_color();
|
||||
do_message(stack.pop(), do_set_back_color, (void*)rgb);
|
||||
}
|
||||
break;
|
||||
case 7: // SET_FORE_COLOR
|
||||
case 9: // SET_FORE_COLOR
|
||||
{
|
||||
const COLOR rgb = stack.pop().as_color();
|
||||
do_message(stack.pop(), do_set_fore_color, (void*)rgb);
|
||||
}
|
||||
break;
|
||||
case 8: // SET_SIZE
|
||||
case 10: // SET_POS
|
||||
{
|
||||
const TVariant& fld = stack.pop();
|
||||
const real y = stack.pop().as_real() * CENTO;
|
||||
const real x = stack.pop().as_real() * CENTO;
|
||||
const TPoint pt(x.integer(), y.integer());
|
||||
do_message(fld, do_set_pos, (void*)&pt);
|
||||
}
|
||||
break;
|
||||
case 11: // SET_SIZE
|
||||
{
|
||||
const TVariant& fld = stack.pop();
|
||||
const real h = stack.pop().as_real() * CENTO;
|
||||
@ -2131,7 +2219,7 @@ bool TReport::execute_usr_word(unsigned int opcode, TVariant_stack& stack)
|
||||
do_message(fld, do_set_size, (void*)&sz);
|
||||
}
|
||||
break;
|
||||
case 9: // SHOW
|
||||
case 12: // SHOW
|
||||
do_message(stack.pop(), do_show, (void*)1);
|
||||
break;
|
||||
default:
|
||||
@ -2161,9 +2249,9 @@ bool TReport::on_link(const TReport_link& lnk)
|
||||
|
||||
TReport::TReport() : _lpi(6), _recordset(NULL), _curr_field(NULL)
|
||||
{
|
||||
// Brutte inizializzazioni, ma inevitabili
|
||||
_expressions.set_report(this);
|
||||
|
||||
fload("report.alx");
|
||||
_prescript.set_description("PRESCRIPT");
|
||||
_postscript.set_description("POSTSCRIPT");
|
||||
}
|
||||
|
@ -226,7 +226,7 @@ class TReport_field : public TSortable
|
||||
TReport_section* _section;
|
||||
int _id;
|
||||
char _type; // Text, String, Numeric, Price, Valuta, Date, Line, Rectangle, Image
|
||||
TRectangle _rct; // In centesimi
|
||||
TRectangle _rct, _rct_draw; // In centesimi
|
||||
COLOR _fgcolor, _bgcolor;
|
||||
short _border;
|
||||
char _halign, _valign;
|
||||
@ -246,6 +246,7 @@ protected:
|
||||
TFieldtypes var_type() const;
|
||||
const TString& formatted_text() const;
|
||||
void get_currency(TCurrency& cur) const;
|
||||
void compute_draw_rect() const;
|
||||
|
||||
public:
|
||||
virtual TObject* dup() const { return new TReport_field(*this); }
|
||||
@ -288,6 +289,10 @@ public:
|
||||
void set_width(long dx) { _rct.set_width(dx); }
|
||||
void set_height(long dy) { _rct.set_height(dy); }
|
||||
const TRectangle& get_rect() const { return _rct; }
|
||||
|
||||
void set_draw_pos(long x, long y);
|
||||
void set_draw_size(long x, long y);
|
||||
const TRectangle& get_draw_rect() const { return _rct_draw; }
|
||||
|
||||
bool hidden() const { return _hidden; }
|
||||
bool shown() const { return !hidden(); }
|
||||
@ -382,7 +387,7 @@ class TReport : public TAlex_virtual_machine
|
||||
|
||||
protected:
|
||||
virtual const char* class_name() const { return "Report"; }
|
||||
virtual unsigned int compile_usr_word(const TString& name) const;
|
||||
virtual size_t get_usr_words(TString_array& words) const;
|
||||
virtual bool execute_usr_word(unsigned int opcode, TVariant_stack& stack);
|
||||
virtual bool get_usr_val(const TString& name, TVariant& var) const;
|
||||
virtual bool set_usr_val(const TString& name, const TVariant& var);
|
||||
|
@ -515,6 +515,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);
|
||||
|
||||
|
142
ba/ba8304.cpp
142
ba/ba8304.cpp
@ -86,8 +86,8 @@ enum AVM_opcode
|
||||
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_div, avm_divide, avm_do, avm_dot, avm_drop, avm_dup,
|
||||
avm_else,
|
||||
avm_false, avm_fetch, avm_fload,
|
||||
avm_i, avm_if,
|
||||
avm_j,
|
||||
@ -95,8 +95,8 @@ enum AVM_opcode
|
||||
avm_mod, avm_mon, avm_mul,
|
||||
avm_negate,
|
||||
avm_or, avm_over,
|
||||
avm_pick, avm_plus_loop, avm_push,
|
||||
avm_repeat, avm_rdrop, avm_rpeek, avm_rpush, avm_rot,
|
||||
avm_perform, avm_pick, avm_plus_loop, avm_push,
|
||||
avm_repeat, avm_rdrop, avm_rpeek, avm_rpush, avm_roll, avm_rot,
|
||||
avm_store, avm_sub, avm_swap,
|
||||
avm_then, avm_true,
|
||||
avm_until, avm_usrword,
|
||||
@ -111,8 +111,8 @@ const char* AVM_TOKENS[avm_zzz+1] =
|
||||
"BEGIN",
|
||||
"$CALL_WORD$", "COLD",
|
||||
"=", ">", ">=", "<", "<=", "<>",
|
||||
"/", "DO", ".", "DROP", "DUP",
|
||||
"ELSE", "EXECUTE",
|
||||
"DIV", "/", "DO", ".", "DROP", "DUP",
|
||||
"ELSE",
|
||||
"FALSE", "@", "FLOAD",
|
||||
"I", "IF",
|
||||
"J",
|
||||
@ -120,8 +120,8 @@ const char* AVM_TOKENS[avm_zzz+1] =
|
||||
"MOD", "MON", "*",
|
||||
"NEGATE",
|
||||
"OR", "OVER",
|
||||
"PICK", "+LOOP", "PUSH",
|
||||
"REPEAT", "R>", "R@", ">R", "ROT",
|
||||
"PERFORM", "PICK", "+LOOP", "PUSH",
|
||||
"REPEAT", "R>", "R@", ">R", "ROLL", "ROT",
|
||||
"!", "-", "SWAP",
|
||||
"THEN", "TRUE",
|
||||
"UNTIL", "#",
|
||||
@ -189,13 +189,14 @@ class TAVM_list_window : public TField_window
|
||||
{
|
||||
TBytecode* _bc;
|
||||
int _ip;
|
||||
const TString_array* _user_words;
|
||||
|
||||
protected:
|
||||
virtual void update();
|
||||
virtual void handler(WINDOW win, EVENT* ep);
|
||||
|
||||
public:
|
||||
void set_bytecode(const TBytecode* bc, int ip);
|
||||
void set_bytecode(const TBytecode* bc, int ip, const TString_array& uw);
|
||||
TAVM_list_window(int x, int y, int dx, int dy, WINDOW parent, TWindowed_field* owner);
|
||||
};
|
||||
|
||||
@ -263,6 +264,11 @@ void TAVM_list_window::update()
|
||||
if (co == avm_call_word)
|
||||
{
|
||||
str = var.as_string();
|
||||
} else
|
||||
if (co == avm_usrword)
|
||||
{
|
||||
str = _user_words->row(var.as_int());
|
||||
str << " (#" << var.as_int() << ')';
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -278,10 +284,11 @@ void TAVM_list_window::update()
|
||||
}
|
||||
}
|
||||
|
||||
void TAVM_list_window::set_bytecode(const TBytecode* bc, int ip)
|
||||
void TAVM_list_window::set_bytecode(const TBytecode* bc, int ip, const TString_array& uw)
|
||||
{
|
||||
_bc = (TBytecode*)bc;
|
||||
_ip = ip;
|
||||
_user_words = &uw;
|
||||
set_scroll_max(80, _bc->items() - rows());
|
||||
}
|
||||
|
||||
@ -403,6 +410,7 @@ class TAVM
|
||||
ostream* _outstr;
|
||||
|
||||
TAssoc_array _words;
|
||||
TString_array _user_words;
|
||||
TAVM_monitor _mon;
|
||||
|
||||
protected:
|
||||
@ -413,7 +421,9 @@ protected:
|
||||
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);
|
||||
void do_fload(const char* fname);
|
||||
|
||||
const TString_array& get_user_words();
|
||||
int compile_user_word(const TString& n);
|
||||
|
||||
public:
|
||||
const TString& get_last_error() const { return _last_error; }
|
||||
@ -421,6 +431,7 @@ public:
|
||||
bool compile(istream& instr, TBytecode& bc);
|
||||
bool execute(const TBytecode& bc, ostream* outstr = NULL);
|
||||
void restart(bool cold);
|
||||
bool do_fload(const char* fname);
|
||||
|
||||
TAVM(TAlex_virtual_machine* vm);
|
||||
virtual ~TAVM();
|
||||
@ -494,6 +505,23 @@ int TAVM::find_matching(const TBytecode& bytecode, AVM_opcode op1, AVM_opcode op
|
||||
return i;
|
||||
}
|
||||
|
||||
const TString_array& TAVM::get_user_words()
|
||||
{
|
||||
if (_user_words.items() == 0)
|
||||
{
|
||||
_user_words.add("***");
|
||||
_vm->get_usr_words(_user_words);
|
||||
}
|
||||
return _user_words;
|
||||
}
|
||||
|
||||
int TAVM::compile_user_word(const TString& w)
|
||||
{
|
||||
const TString_array& uw = get_user_words();
|
||||
const int i = uw.find(w);
|
||||
return i > 0 ? i : 0;
|
||||
}
|
||||
|
||||
bool TAVM::compile(istream& instr, TBytecode& bytecode)
|
||||
{
|
||||
TString str(256);
|
||||
@ -610,7 +638,7 @@ bool TAVM::compile(istream& instr, TBytecode& bytecode)
|
||||
}
|
||||
else
|
||||
{
|
||||
const unsigned int oc = _vm->compile_usr_word(str);
|
||||
const int oc = compile_user_word(str);
|
||||
if (oc > 0)
|
||||
op = new TAVM_op(avm_usrword, oc);
|
||||
}
|
||||
@ -647,16 +675,18 @@ void TAVM::do_call(const TString& func)
|
||||
_bc = (TBytecode*)_words.objptr(func);
|
||||
}
|
||||
|
||||
void TAVM::do_fload(const char* fname)
|
||||
bool TAVM::do_fload(const char* fname)
|
||||
{
|
||||
TFilename name = fname;
|
||||
if (name.custom_path())
|
||||
bool ok = name.custom_path();
|
||||
if (ok)
|
||||
{
|
||||
TBytecode bc;
|
||||
ifstream inf(name);
|
||||
if (compile(inf, bc))
|
||||
execute(bc);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
void TAVM::execute(const TAVM_op& op)
|
||||
@ -687,14 +717,31 @@ void TAVM::execute(const TAVM_op& op)
|
||||
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:
|
||||
case avm_div:
|
||||
{
|
||||
const long r0 = _stack.pop().as_int();
|
||||
const long r1 = _stack.pop().as_int();
|
||||
if (r0 != 0)
|
||||
{
|
||||
const long n = r1 / r0;
|
||||
_stack.push(n);
|
||||
}
|
||||
else
|
||||
_stack.push(NULL_VARIANT);
|
||||
}
|
||||
|
||||
break;
|
||||
case avm_divide:
|
||||
{
|
||||
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);
|
||||
{
|
||||
const real n = r1 / r0;
|
||||
_stack.push(n);
|
||||
}
|
||||
else
|
||||
_stack.push(NULL_VARIANT);
|
||||
}
|
||||
break;
|
||||
case avm_do:
|
||||
@ -719,15 +766,6 @@ void TAVM::execute(const TAVM_op& op)
|
||||
case avm_else:
|
||||
_ip = op.var().as_int();
|
||||
break;
|
||||
case avm_execute:
|
||||
{
|
||||
const TString& cmd = _stack.pop().as_string();
|
||||
istrstream instr((char*)(const char*)cmd, cmd.len());
|
||||
TBytecode bc;
|
||||
if (compile(instr, bc))
|
||||
execute(bc);
|
||||
}
|
||||
break;
|
||||
case avm_false: _stack.push(0L); break;
|
||||
case avm_fetch:
|
||||
{
|
||||
@ -794,12 +832,16 @@ void TAVM::execute(const TAVM_op& op)
|
||||
}
|
||||
break;
|
||||
case avm_over: _stack.push(_stack.peek(1)); break;
|
||||
case avm_pick:
|
||||
case avm_perform:
|
||||
{
|
||||
const int depth = _stack.pop().as_int();
|
||||
_stack.push(_stack.peek(depth));
|
||||
const TString& cmd = _stack.pop().as_string();
|
||||
istrstream instr((char*)(const char*)cmd, cmd.len());
|
||||
TBytecode bc;
|
||||
if (compile(instr, bc))
|
||||
execute(bc);
|
||||
}
|
||||
break;
|
||||
case avm_pick: _stack.push(_stack.peek(_stack.pop().as_int())); break;
|
||||
case avm_plus_loop:
|
||||
{
|
||||
TVariant& start = _rstack.pop();
|
||||
@ -815,6 +857,7 @@ void TAVM::execute(const TAVM_op& op)
|
||||
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_roll: _stack.roll(_stack.pop().as_int()); break;
|
||||
case avm_rot: _stack.roll(2); break;
|
||||
case avm_store:
|
||||
{
|
||||
@ -869,7 +912,7 @@ bool TAVM::execute(const TBytecode& cmdline, ostream* outstr)
|
||||
_outstr = outstr;
|
||||
while (_bc != NULL)
|
||||
{
|
||||
if (_ip >= _bc->items()) // Fine funzione
|
||||
while (_ip >= _bc->items()) // Fine funzione
|
||||
{
|
||||
if (_rstack.items() >= 2) // Controllo il return stack
|
||||
{
|
||||
@ -881,10 +924,13 @@ bool TAVM::execute(const TBytecode& cmdline, ostream* outstr)
|
||||
_bc = (const TBytecode*)_words.objptr(str);
|
||||
}
|
||||
else
|
||||
{
|
||||
_bc = NULL;
|
||||
break; // Fine esecuzione
|
||||
if (_bc == NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_bc == NULL || _ip > _bc->items())
|
||||
break;
|
||||
|
||||
TAVM_op& op = *(TAVM_op*)_bc->objptr(_ip);
|
||||
if (op.has_break() && !_mon.is_open())
|
||||
@ -898,7 +944,7 @@ bool TAVM::execute(const TBytecode& cmdline, ostream* outstr)
|
||||
{
|
||||
lock_preview_update(true);
|
||||
TAVM_list_window& monitor = _mon.monitor();
|
||||
monitor.set_bytecode(_bc, _ip);
|
||||
monitor.set_bytecode(_bc, _ip, _user_words);
|
||||
TAVM_stack_window& stacker = _mon.stacker();
|
||||
stacker.set_stack(_stack);
|
||||
TAVM_stack_window& rstacker = _mon.rstacker();
|
||||
@ -915,8 +961,8 @@ bool TAVM::execute(const TBytecode& cmdline, ostream* outstr)
|
||||
op.set_auto_break(true);
|
||||
}
|
||||
break;
|
||||
case K_DEL : abort_printing();
|
||||
case K_QUIT: _mon.close_modal(); lock_preview_update(false); break;
|
||||
case K_QUIT: abort_printing();
|
||||
case K_F5 : _mon.close_modal(); lock_preview_update(false); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@ -932,23 +978,28 @@ bool TAVM::execute(const TBytecode& cmdline, ostream* outstr)
|
||||
lock_preview_update(false);
|
||||
}
|
||||
|
||||
const bool ok = _bc != NULL; // Not aborted
|
||||
//const bool ok = _bc != NULL; // Not aborted
|
||||
_bc = old_bc;
|
||||
_ip = old_ip;
|
||||
|
||||
return ok;
|
||||
return true;
|
||||
}
|
||||
|
||||
void TAVM::restart(bool cold)
|
||||
{
|
||||
_stack.reset();
|
||||
_rstack.reset();
|
||||
if (cold)
|
||||
{
|
||||
_words.destroy();
|
||||
do_fload("alex.alx");
|
||||
}
|
||||
}
|
||||
|
||||
TAVM::TAVM(TAlex_virtual_machine* vm)
|
||||
: _vm(vm), _outstr(NULL)
|
||||
{
|
||||
do_fload("alex.alx");
|
||||
restart(true);
|
||||
}
|
||||
|
||||
TAVM::~TAVM()
|
||||
@ -1017,6 +1068,12 @@ bool TAlex_virtual_machine::get_usr_val(const TString& name, TVariant& var) cons
|
||||
var.set(dongle().administrator());
|
||||
return true;
|
||||
}
|
||||
if (n == "CLOCK")
|
||||
{
|
||||
const long msec = clock() / (CLOCKS_PER_SEC / 1000);
|
||||
var.set(msec);
|
||||
return true;
|
||||
}
|
||||
if (n == "FIRM")
|
||||
{
|
||||
var.set(prefix().get_codditta());
|
||||
@ -1055,7 +1112,7 @@ bool TAlex_virtual_machine::set_usr_val(const TString& name, const TVariant& var
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int TAlex_virtual_machine::compile_usr_word(const TString& name) const
|
||||
unsigned int TAlex_virtual_machine::get_usr_words(TString_array&) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -1065,6 +1122,11 @@ bool TAlex_virtual_machine::execute_usr_word(unsigned int opcode, TVariant_stack
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TAlex_virtual_machine::fload(const char* fname)
|
||||
{
|
||||
return avm().do_fload(fname);
|
||||
}
|
||||
|
||||
TAlex_virtual_machine::TAlex_virtual_machine() : _avm(NULL)
|
||||
{
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ protected:
|
||||
TAVM& avm();
|
||||
|
||||
public:
|
||||
virtual unsigned int compile_usr_word(const TString& name) const;
|
||||
virtual size_t get_usr_words(TString_array& names) const;
|
||||
virtual bool execute_usr_word(unsigned int opcode, TVariant_stack& stack);
|
||||
virtual bool get_usr_val(const TString& name, TVariant& var) const;
|
||||
virtual bool set_usr_val(const TString& name, const TVariant& var);
|
||||
@ -59,6 +59,7 @@ public:
|
||||
bool compile(const char* cmd, TBytecode& bc);
|
||||
bool execute(const TBytecode& bc, ostream& outstr);
|
||||
bool execute(const TBytecode& bc, TString& outstr);
|
||||
bool fload(const char* fname);
|
||||
void warm_restart();
|
||||
void cold_restart();
|
||||
|
||||
|
@ -15,31 +15,31 @@ BEGIN
|
||||
PROMPT 27 11 ""
|
||||
END
|
||||
|
||||
BUTTON DLG_NEXTREC 10 2
|
||||
BUTTON DLG_NEXTREC 9 2
|
||||
BEGIN
|
||||
PROMPT -14 -1 ""
|
||||
PICTURE 124
|
||||
MESSAGE EXIT,K_F11
|
||||
END
|
||||
|
||||
BUTTON DLG_LASTREC 10 2
|
||||
BUTTON DLG_LASTREC 9 2
|
||||
BEGIN
|
||||
PROMPT -24 -1 ""
|
||||
PICTURE 1671
|
||||
MESSAGE EXIT,K_F10
|
||||
END
|
||||
|
||||
BUTTON DLG_ELABORA 10 2
|
||||
BUTTON DLG_ELABORA 9 2
|
||||
BEGIN
|
||||
PROMPT -34 -1 ""
|
||||
PICTURE BMP_LASTREC
|
||||
MESSAGE EXIT,K_QUIT
|
||||
MESSAGE EXIT,K_F5
|
||||
END
|
||||
|
||||
BUTTON DLG_DELREC 10 2
|
||||
BUTTON DLG_QUIT 9 2
|
||||
BEGIN
|
||||
PROMPT -44 -1 "Abort"
|
||||
MESSAGE EXIT,K_DEL
|
||||
PROMPT -44 -1 ""
|
||||
MESSAGE EXIT,K_QUIT
|
||||
END
|
||||
|
||||
|
||||
|
168
ba/ba8400.cpp
Executable file
168
ba/ba8400.cpp
Executable file
@ -0,0 +1,168 @@
|
||||
#include <applicat.h>
|
||||
#include <automask.h>
|
||||
#include <defmask.h>
|
||||
#include <execp.h>
|
||||
#include <form.h>
|
||||
#include <prefix.h>
|
||||
#include <scanner.h>
|
||||
|
||||
#include "ba8302.h"
|
||||
#include "ba8400.h"
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// TFormer_mask
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
class TFormer_mask : public TAutomask
|
||||
{
|
||||
protected:
|
||||
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
|
||||
|
||||
void import();
|
||||
|
||||
public:
|
||||
TFormer_mask();
|
||||
};
|
||||
|
||||
void TFormer_mask::import_use()
|
||||
{
|
||||
}
|
||||
|
||||
void TFormer_mask::import_use(TReport& rep) const
|
||||
{
|
||||
TScanner scan(get(F_FORM));
|
||||
|
||||
TString use;
|
||||
int parse_use = 0;
|
||||
while (scan.ok())
|
||||
{
|
||||
const TString& line = scan.line();
|
||||
if (line.empty())
|
||||
break;
|
||||
|
||||
if (parse_use == 0 && line.starts_with("US"))
|
||||
parse_use = 1;
|
||||
|
||||
if (parse_use == 1)
|
||||
{
|
||||
if (line.starts_with("EN"))
|
||||
{
|
||||
parse_use = 2;
|
||||
break;
|
||||
}
|
||||
else
|
||||
use << line << '\n';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!use.blank())
|
||||
rep.set_recordset(use);
|
||||
}
|
||||
|
||||
void TFormer_mask::import_sections(TReport& rep) const
|
||||
{
|
||||
TExportable_form frm(get(F_FORM));
|
||||
frm.export_section('G', odd_page, rep, 'B', 0);
|
||||
frm.export_section('B', odd_page, rep, 'B', 2);
|
||||
}
|
||||
|
||||
void TFormer_mask::import()
|
||||
{
|
||||
TReport rep;
|
||||
import_use(rep);
|
||||
import_sections(rep);
|
||||
rep.save(get(F_REPORT));
|
||||
}
|
||||
|
||||
bool TFormer_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
|
||||
{
|
||||
switch (o.dlg())
|
||||
{
|
||||
case F_FORM:
|
||||
if (e == fe_modify)
|
||||
{
|
||||
TFilename output = get(F_REPORT);
|
||||
TFilename path = output.path();
|
||||
if (path.empty())
|
||||
{
|
||||
path = firm2dir(-1);
|
||||
path.add("custom");
|
||||
}
|
||||
const TFilename input = o.get();
|
||||
output = path;
|
||||
output.add(input.name());
|
||||
output.ext("rep");
|
||||
output.lower();
|
||||
set(F_REPORT, output);
|
||||
enable(DLG_ELABORA, input.exist());
|
||||
}
|
||||
break;
|
||||
case F_REPORT:
|
||||
if (e == fe_modify)
|
||||
{
|
||||
const TFilename output = get(F_REPORT);
|
||||
enable(DLG_PRINT, output.exist());
|
||||
}
|
||||
break;
|
||||
case DLG_ELABORA:
|
||||
if (e == fe_button)
|
||||
{
|
||||
const TFilename output = get(F_REPORT);
|
||||
if (output.exist())
|
||||
{
|
||||
if (!yesno_box(TR("Il file %s esiste gia':\nSi desidera sovrascriverlo?"), (const char*)output))
|
||||
return false;
|
||||
}
|
||||
import();
|
||||
enable(DLG_PRINT, output.exist());
|
||||
}
|
||||
break;
|
||||
case DLG_PRINT:
|
||||
if (e == fe_button)
|
||||
{
|
||||
const TFilename output = get(F_REPORT);
|
||||
if (output.exist())
|
||||
{
|
||||
TString cmd;
|
||||
cmd << "ba8 -2 " << output;
|
||||
TExternal_app app(cmd);
|
||||
app.run();
|
||||
return false; // Altrimenti esce dalla maschera
|
||||
}
|
||||
else
|
||||
return error_box(TR("Il file %s non esiste"), (const char*)output);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TFormer_mask::TFormer_mask() : TAutomask("ba8400a")
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// TFormer_app
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
class TFormer_app : public TSkeleton_application
|
||||
{
|
||||
protected:
|
||||
virtual void main_loop();
|
||||
};
|
||||
|
||||
void TFormer_app::main_loop()
|
||||
{
|
||||
TFormer_mask m;
|
||||
m.run();
|
||||
}
|
||||
|
||||
int ba8400(int argc, char* argv[])
|
||||
{
|
||||
TFormer_app app;
|
||||
app.run(argc, argv, TR("Form Converter"));
|
||||
return 0;
|
||||
}
|
2
ba/ba8400.h
Executable file
2
ba/ba8400.h
Executable file
@ -0,0 +1,2 @@
|
||||
#define F_FORM 101
|
||||
#define F_REPORT 102
|
37
ba/ba8400a.uml
Executable file
37
ba/ba8400a.uml
Executable file
@ -0,0 +1,37 @@
|
||||
#include "ba8400.h"
|
||||
|
||||
PAGE "Conversione Form in Report" -1 -1 62 6
|
||||
|
||||
STRINGA F_FORM 256 50
|
||||
BEGIN
|
||||
PROMPT 1 1 "Form "
|
||||
FSELECT "*.frm"
|
||||
END
|
||||
|
||||
STRINGA F_REPORT 256 50
|
||||
BEGIN
|
||||
PROMPT 1 2 "Report "
|
||||
END
|
||||
|
||||
BUTTON DLG_ELABORA 10 2
|
||||
BEGIN
|
||||
PROMPT -13 -1 "~Elabora"
|
||||
PICTURE BMP_ELABORA
|
||||
FLAGS "D"
|
||||
END
|
||||
|
||||
BUTTON DLG_PRINT 10 2
|
||||
BEGIN
|
||||
PROMPT -23 -1 "~Stampa"
|
||||
PICTURE BMP_PRINT
|
||||
FLAGS "D"
|
||||
END
|
||||
|
||||
BUTTON DLG_QUIT 10 2
|
||||
BEGIN
|
||||
PROMPT -33 -1 ""
|
||||
END
|
||||
|
||||
ENDPAGE
|
||||
|
||||
ENDMASK
|
Loading…
x
Reference in New Issue
Block a user