campo-sirio/ba/ba8200.cpp
guy 309d8b23fd Patch level : 10.0
Files correlati     : ba8300a.msk ba8300b.msk ba8300c.msk ba8.exe
Ricompilazione Demo : [ ]
Commento            :

Riassunto	 0001600: Dopo la stampa di un report in orizz ritorna in visual con il foglio in vert.
Faccio l'anteprima di un report creato con orientamento foglio orrizzontale fisso, dopo aver stampato ritorna in visualizzazione con l'orientamento del foglio impostato sulla stampante (normalmente in verticale)


git-svn-id: svn://10.65.10.50/trunk@20332 c028cbd2-c16b-5b4b-a496-9718f37d4682
2010-04-13 14:31:37 +00:00

1526 lines
35 KiB
C++
Executable File

#include <xinclude.h>
#include <applicat.h>
#include <automask.h>
#include <defmask.h>
#include <extcdecl.h>
#include <modaut.h>
#include <odbcrset.h>
#include <prefix.h>
#include <relation.h>
#include <sheet.h>
#include <tree.h>
#include <treectrl.h>
#include <utility.h>
#include <xml.h>
#include "ba8200.h"
///////////////////////////////////////////////////////////
// TRelation_node & TRelation_tree
///////////////////////////////////////////////////////////
// Informazioni relative ad un nodo della relazione:
class TRelation_node : public TObject
{
const TRelation_node* _father; // Puntatore all'eventuale padre
int _logicnum; // Numero logico
TString16 _name, _alias; // Nome ed Alias
TString_array _join_fields; // Elenco dei campi di join
public:
bool description(TString& str) const;
int num() const { return _logicnum; }
const TString& name() const { return _name; }
const TString& alias() const { return _alias; }
const TString& id() const { return _alias.not_empty() ? _alias : _name; }
const TRelation_node* father() const { return _father; }
void set_num(int num);
void set_alias(const char* alias) { _alias = alias; }
TString_array& join() { return _join_fields; }
TRelation_node(const TRelation_node* father, int ln, const char* alias);
virtual ~TRelation_node() {}
};
bool TRelation_node::description(TString& str) const
{
const bool ok = _logicnum >= LF_USER;
if (ok)
{
const FileDes& fd = prefix().get_filedes(_logicnum);
str = _name;
if (_alias.not_empty())
str << " ALIAS " << _alias;
str << " (" << fd.Des << ')';
}
return ok;
}
void TRelation_node::set_num(int num)
{
_logicnum = num;
const FileDes& fd = prefix().get_filedes(_logicnum);
_name = fd.SysName; _name.strip("$%"); _name.upper();
}
TRelation_node::TRelation_node(const TRelation_node* father, int ln, const char* alias)
: _father(father)
{
set_num(ln);
set_alias(alias);
}
// Albero di una relazione
class TRelation_tree : public TObject_tree
{
protected:
virtual bool get_description(TString& str) const;
public:
bool find_id(const TString& id);
};
bool TRelation_tree::get_description(TString& str) const
{
const TRelation_node* rn = (const TRelation_node*)curr_node();
if (rn != NULL)
return rn->description(str);
return false;
}
static bool find_id_callback(TTree& tree, void* jolly, word flags)
{
const TRelation_node* n = (const TRelation_node*)tree.curr_node();
if (n != NULL)
{
const TString& id = *(const TString*)jolly;
return n->id() == id;
}
return false;
}
bool TRelation_tree::find_id(const TString& id)
{
bool ok = goto_root();
if (ok)
{
scan_depth_first(find_id_callback, (void*)&id);
const TRelation_node* n = (const TRelation_node*)curr_node();
ok = n != NULL && n->id() == id;
}
return ok;
}
///////////////////////////////////////////////////////////
// TTable_mask
///////////////////////////////////////////////////////////
// Maschera per inserire/editare un nodo dell'albero
class TTable_mask : public TAutomask
{
protected:
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
protected:
int father_logicnum() const;
const char* find_linked_field(int logicnum, const RecFieldDes& fd) const;
public:
int son_logicnum() const;
void mask2node(TRelation_node& node);
TTable_mask();
~TTable_mask();
};
int TTable_mask::father_logicnum() const
{
return table2logic(get(F_FATHER));
}
int TTable_mask::son_logicnum() const
{
return table2logic(get(F_SON));
}
// Dato il numero logico di una tabella ed un campo (di un'altra tabella)
// cerca il campo piu' simile all'interno del tracciato record
const char* TTable_mask::find_linked_field(int logicnum, const RecFieldDes& fd) const
{
const RecDes& rd = prefix().get_recdes(logicnum);
int nBest = -1;
double dBest = 0.0;
for (int i = 0; i < rd.NFields; i++)
{
const RecFieldDes& field = rd.Fd[i];
if (field.TypeF == fd.TypeF && field.Len == fd.Len)
{
const double fuzzy = xvt_str_fuzzy_compare(field.Name, fd.Name);
if (fuzzy > dBest)
{
nBest = i;
dBest = fuzzy;
if (dBest == 1.0)
break;
}
}
}
return nBest >= 0 ? rd.Fd[nBest].Name : "";
}
bool TTable_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
switch (o.dlg())
{
case F_SON:
if (e == fe_modify)
{
const int logicnum = son_logicnum();
const int fathernum = father_logicnum();
TSheet_field& sheet = sfield(F_SHEET);
sheet.destroy();
if (logicnum >= LF_USER && fathernum >= LF_USER)
{
const RecDes& rd = prefix().get_recdes(logicnum);
const KeyDes& kd = rd.Ky[0];
TToken_string tok;
for (int j = 0; j < kd.NkFields; j++)
{
const int n = kd.FieldSeq[j] % MaxFields;
tok = rd.Fd[n].Name;
tok.add(find_linked_field(fathernum, rd.Fd[n]));
sheet.rows_array().add(tok);
}
}
sheet.force_update();
}
break;
case F_SHEET:
if (e == se_query_add || e == se_query_del)
return false;
break;
case F_FLD_TO:
if (e == fe_button)
{
const int logicnum = son_logicnum();
if (logicnum >= LF_USER)
{
TArray_sheet sheet(-1, -1, 24, 20, TR("Selezione"), HR("Nome@12|Lunghezza"));
const RecDes& rd = prefix().get_recdes(logicnum);
TToken_string row;
for (int i = 0; i < rd.NFields; i++)
{
row = rd.Fd[i].Name;
row.add(rd.Fd[i].Len);
sheet.add(row);
}
sheet.rows_array().sort();
if (sheet.run() == K_ENTER)
o.set(sheet.row(-1).get(0));
}
}
break;
default:
break;
}
return true;
}
// Trasferisce le informazioni dalla maschera ad un nodo della tabella
void TTable_mask::mask2node(TRelation_node& son)
{
son.set_num(son_logicnum());
son.set_alias(get(F_SON_ALIAS));
if (son.father() != NULL)
{
TString_array& join = son.join();
join.destroy();
TSheet_field& sheet = sfield(F_SHEET);
FOR_EACH_SHEET_ROW(sheet, i, row)
{
TToken_string* newrow = new TToken_string(50, '=');
newrow->add(row->get(0));
newrow->add(row->get());
join.add(newrow);
}
}
}
TTable_mask::TTable_mask() : TAutomask("ba8200b")
{
const TDir dir(LF_DIR);
const int nfiles = (int)dir.eod();
TList_sheet& sht = *efield(F_SON).sheet();
TToken_string tt(80);
for (int logic = LF_USER; logic < nfiles; logic++)
{
const FileDes& fd = prefix().get_filedes(logic);
tt = fd.SysName;
if (tt.full())
{
tt.strip("$%"); tt.upper();
tt.add(logic);
tt.add(fd.Des);
sht.rows_array().add(tt);
}
}
sht.rows_array().sort();
}
TTable_mask::~TTable_mask()
{ }
///////////////////////////////////////////////////////////
// TQuery_mask
///////////////////////////////////////////////////////////
// Maschera principale della costruzione della query
class TQuery_mask : public TAutomask
{
TRelation_tree _tree; // Albero della relazione
int _curr_num; // Numero del file corrente
bool _dragster; // Operazione di trascinamento in corso
TFilename _curr_query;// Nome completo della query in editazione
bool _is_dirty; // Maschera cambiata dall'ultimo caricamento
bool _sql_dirty; // Query modificata manualmente
protected:
virtual long handler(WINDOW win, EVENT* ep);
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
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 ask_vars(const char* maskname, TRecordset& recset) const;
TRecordset* new_recordset() const;
bool edit_file_in_tree();
static int sort_fields(const TObject** r1, const TObject** r2);
void fill_fields();
void enable_sql_button();
void enable_field_buttons();
void move_curr_field(int dir);
void tree2sql(TString& from, TString& where);
void tree2isam(TString_array& a);
void sheet2sql();
void sheet2isam();
bool select_query();
bool load_tables_tree(TXmlItem& tables);
bool load_fields_sheet(TXmlItem& fields);
void global_reset();
bool save_tables_tree(TXmlItem& xml);
bool save_fields_sheet(TXmlItem& xml);
public:
void edit_query();
void save_as(TRecordsetExportFormat fmt, const char* ext = NULL);
bool load_query();
bool save_query();
bool save_if_needed();
bool delete_query();
bool get_qry_path(TFilename& path) const;
TRelation_node* curr_node();
TQuery_mask();
};
// Nodo corrente dell'albero
TRelation_node* TQuery_mask::curr_node()
{
TTree_field& tf = tfield(F_TABLES);
tf.goto_selected();
TRelation_node* n = (TRelation_node*)_tree.curr_node();
return n;
}
// Aggiunge interattivamente un nodo all'albero
bool TQuery_mask::add_file_to_tree()
{
TTable_mask msk;
const TRelation_node* father = curr_node();
TString fatherid;
if (father != NULL)
{
_tree.curr_id(fatherid);
msk.set(F_FATHER, father->name());
msk.set(F_FATHER_ALIAS, father->alias());
}
msk.disable(DLG_DELREC);
bool ok = msk.run() == K_ENTER;
if (ok)
{
TRelation_node* son = new TRelation_node(father, msk.son_logicnum(), msk.get(F_SON_ALIAS));
msk.mask2node(*son);
if (fatherid.not_empty())
_tree.goto_node(fatherid);
_tree.add_son(son);
_tree.expand_all();
tfield(F_TABLES).win().force_update();
_curr_num = son->num();
fill_fields();
}
return ok;
}
// Modifica interattivamente il nodo corrente dell'albero
bool TQuery_mask::edit_file_in_tree()
{
TRelation_node* son = curr_node();
if (son == NULL)
return false;
TString sonid; _tree.curr_id(sonid);
const TRelation_node* father = NULL;
if (_tree.goto_father())
father = (const TRelation_node*)_tree.curr_node();
TTable_mask msk;
if (father != NULL)
{
msk.set(F_FATHER, father->name());
msk.set(F_FATHER_ALIAS, father->alias());
TString_array& arr = son->join();
FOR_EACH_ARRAY_ROW(arr, i, row)
{
TToken_string& newrow = msk.sfield(F_SHEET).row(-1);
FOR_EACH_TOKEN((*row), tok)
{
TToken_string str(tok, '.');
str.strip_spaces();
if (str.items() > 1)
newrow.add(str.get(1));
else
newrow.add(str);
}
}
}
msk.set(F_SON, son->name());
msk.set(F_SON_ALIAS, son->alias());
bool update = true;
switch (msk.run())
{
case K_ENTER:
msk.mask2node(*son);
break;
case K_DEL:
if (curr_node() != NULL)
{
if (yesno_box(TR("Eliminare anche le colonne associate della query?")))
{
TSheet_field& sheet = sfield(F_SHEET);
FOR_EACH_SHEET_ROW_BACK(sheet, r, row)
{
const TString& id = row->get(0);
if (id == son->id())
sheet.destroy(r);
}
}
_tree.goto_node(sonid);
_tree.kill_node();
_tree.goto_root();
}
break;
default:
update = false;
break;
}
if (update)
{
TTree_field& tf = tfield(F_TABLES);
tf.win().force_update();
_curr_num = 0;
if (tf.select_current())
{
const TRelation_node* curr = curr_node();
if (curr != NULL)
_curr_num = curr->num();
}
fill_fields();
}
return update; // ????
}
// Ordina per importanza i campi di un tracciato record
int TQuery_mask::sort_fields(const TObject** r1, const TObject** r2)
{
TToken_string& s1 = (TToken_string&)**r1;
TToken_string& s2 = (TToken_string&)**r2;
const int w1 = s1.get_int(4);
const int w2 = s2.get_int(4);
int cmp = w2-w1;
if (cmp == 0)
cmp = strcmp(s1.get(0), s2.get(0));
return cmp;
}
// Riempie la lista dei campi del file corrente
void TQuery_mask::fill_fields()
{
TSheet_field& sht = sfield(F_FIELDS);
sht.destroy();
if (_curr_num >= LF_USER)
{
TRelation rel(_curr_num);
TRelation_description reldes(rel);
const RecDes& rd = prefix().get_recdes(_curr_num);
for (int i = 0; i < rd.NFields; i++)
{
TToken_string& row = sht.row(-1);
const RecFieldDes& fd = rd.Fd[i];
row = fd.Name;
row.add(fd.Len);
int weight = 0;
for (int k = 0; k < rd.NKeys; k++)
{
const KeyDes& kd = rd.Ky[k];
for (int j = 0; j < kd.NkFields; j++)
{
const int n = kd.FieldSeq[j] % MaxFields;
if (n == i)
{
if (weight == 0)
{
weight = (rd.NKeys-k)*100 + kd.NkFields-j;
row.add(k+1);
}
else
row << ' ' << (k+1);
}
}
}
row.add(reldes.get_field_description(fd.Name), 3);
row.add(weight, 4);
}
sht.rows_array().TArray::sort(sort_fields);
}
sht.force_update();
enable_field_buttons();
}
// 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& ff = sfield(F_SHEET);
TToken_string& row = ff.row(-1);
row = n->id();
row.add(fld);
_is_dirty = true;
if (update)
{
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)
{
if (yesno_box("Si desisdera aggiungere tutti i campi singolarmente?"))
{
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);
}
else
add_field_to_sheet("*", true);
}
}
// Decide se attivare o meno il bottone SQL
void TQuery_mask::enable_sql_button()
{
const bool yes = sfield(F_SHEET).items() > 0;
enable(F_GENSQL, yes);
}
// Decide se attivare o meno i bottoni di aggiunta campi
void TQuery_mask::enable_field_buttons()
{
const TSheet_field& sf = sfield(F_FIELDS);
const bool ok = sf.items() > 0;
enable(-1, ok);
}
void TQuery_mask::move_curr_field(int dir)
{
TSheet_field& s = sfield(F_SHEET);
const int sel = s.selected();
if (sel >= 0 && sel < s.items())
{
const int des = sel+dir;
if (des >= 0 && des < s.items())
{
s.rows_array().swap(sel, des);
s.select(des);
s.force_update();
}
}
}
static bool sql_tree_handler(TTree& tree, void* jolly, word flags)
{
TRelation_node* rn = (TRelation_node*)tree.curr_node();
TPointer_array& arr = *(TPointer_array*)jolly;
TToken_string& from = *(TToken_string*)arr.objptr(0);
TString& where = *(TString*)arr.objptr(1);
TString_array& join = rn->join();
TString str;
if (from.get_pos(rn->id()) < 0)
{
from.add(rn->name());
if (rn->alias().not_empty())
from << " AS " << rn->alias();
FOR_EACH_ARRAY_ROW(join, i, row)
{
if (where.find(*row) < 0)
{
if (where.not_empty())
where << "AND";
where << '(' << rn->id() << '.' << row->get(0) << '=';
str = row->get();
if (isalpha(str[0]))
where << rn->father()->id() << '.';
where << str << ')';
}
}
}
return false; // Don't stop search
}
// Riempie una stringa SQL con la relazione tra le tabelle
void TQuery_mask::tree2sql(TString& from, TString& where)
{
if (_tree.goto_root())
{
TPointer_array a;
a.add(&from);
a.add(&where);
_tree.scan_depth_first(sql_tree_handler, &a);
}
}
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);
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()
{
const TSheet_field& sheet = sfield(F_SHEET);
TToken_string select(50, ',');
_tree.goto_root();
const bool multiple = _tree.has_son();
TToken_string from(50, ','), groupby(50, ','), orderby(50, ',');
TString where, expr_from, expr_to;
TString field;
FOR_EACH_SHEET_ROW(sheet, i, row)
{
field = row->get(1);
if (!field.blank() && !tok_get_bool(*row, 2)) // Campo valido e visibile
{
if (multiple)
{
const TString& tab = row->get(0);
if (!tab.blank())
{
field.insert(".");
field.insert(tab); // Table name
}
}
select.add(field); // Column name only
if (tok_get_bool(*row, 3)) // Sort
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.not_empty() && isalpha(expr_from[0]))
{
expr_from.insert("'");
expr_from << '\'';
}
if (expr_to.not_empty() && isalpha(expr_to[0]))
{
expr_to.insert("'");
expr_to << '\'';
}
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);
TString sql;
sql << "SELECT " << select << '\n';
sql << "FROM " << from << '\n';
if (!where.blank())
sql << "WHERE " << where << '\n';
if (groupby.not_empty())
sql << "GROUP BY " << groupby << '\n';
if (orderby.not_empty())
sql << "ORDER BY " << orderby << '\n';
sql << ";";
set(F_SQL, sql, true);
_sql_dirty = false;
TEdit_field& fs = efield(F_SQL);
fs.set_focusdirty(false); // Evita di scatenare eventi inutili
}
// Genera una query ISAM a partire dallo spreadsheet F_SHEET
void TQuery_mask::sheet2isam()
{
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
}
bool TQuery_mask::ask_vars(const char* maskname, TRecordset& recset) const
{
if (recset.variables().items() == 0)
return true;
TFilename fname = maskname; fname.ext("msk");
KEY key = K_QUIT;
if (!fname.custom_path())
return recset.ask_variables(true);
TMask m(maskname);
TVariant var;
for (int i = m.fields()-1; i >= 0; i--)
{
TMask_field& f = m.fld(i);
const TFieldref* ref = f.field();
if (ref != NULL)
{
TString name = ref->name();
if (name[0] != '#')
name.insert("#");
const TVariant& var = recset.get_var(name);
if (!var.is_null())
f.set(var.as_string());
}
}
key = m.run();
const bool ok = key != K_QUIT && key != K_ESC;
if (ok)
{
// Rendi visibili tutte le variabili utente al report
for (int i = m.fields()-1; i >= 0; i--)
{
TMask_field& f = m.fld(i);
const TFieldref* ref = f.field();
if (ref != NULL)
{
switch (f.class_id())
{
case CLASS_CURRENCY_FIELD:
case CLASS_REAL_FIELD:
var = real(f.get());
break;
case CLASS_DATE_FIELD:
var = TDate(f.get());
break;
default:
var = f.get();
break;
}
TString name = ref->name();
if (name[0] != '#')
name.insert("#");
recset.set_var(name, var, true);
}
}
}
return ok;
}
TRecordset* TQuery_mask::new_recordset() const
{
const TString& sql = get(F_SQL);
TRecordset* rex = create_recordset(sql);
if (rex != NULL)
{
if (!ask_vars(get(F_CODICE), *rex))
{
delete rex;
rex = NULL;
}
if (rex != NULL && rex->items() == 0)
{
warning_box(TR("Nessuna riga risultato"));
delete rex;
rex = NULL;
}
}
return rex;
}
void TQuery_mask::edit_query()
{
TRecordset* rex = new_recordset();
if (rex != NULL)
{
TRecordset_sheet sht(*rex);
sht.run();
delete rex;
}
}
void TQuery_mask::save_as(TRecordsetExportFormat fmt, const char* ext)
{
TRecordset* rex = new_recordset();
if (rex == NULL)
return;
if (fmt == fmt_dbf)
{
TTable_mask tm;
TList_sheet& sht = *tm.efield(F_SON).sheet();
if (sht.run() == K_ENTER)
{
const TString& table = tm.get(F_SON);
const KEY k = yesnocancel_box(FR("Si desidera azzerare il file %s prima dell'esportazione?"),
(const char*)table);
if (k != K_ESC)
rex->save_as(table, fmt_dbf, k == K_YES ? 0x5 : 0x3);
}
return;
}
xvt_fsys_save_dir();
TFilename path; path.tempdir();
if (ext == NULL || *ext == '\0')
{
switch (fmt)
{
case fmt_html: ext = "html"; break;
default : ext = "txt"; break;
}
}
if (field(F_CODICE).empty())
path.add("query");
else
path.add(get(F_CODICE));
path.ext(ext);
FILE_SPEC fs;
xvt_fsys_convert_str_to_fspec(path, &fs);
xvt_fsys_save_dir();
const bool good = xvt_dm_post_file_save(&fs, TR("Esportazione")) == FL_OK;
xvt_fsys_restore_dir();
if (good)
{
xvt_fsys_convert_fspec_to_str(&fs, path.get_buffer(), path.size());
if (rex->save_as(path, fmt))
xvt_sys_goto_url(path, "open");
}
delete rex;
}
bool TQuery_mask::get_qry_path(TFilename& path) const
{
const TString& name = get(F_CODICE);
const bool ok = name.full();
if (ok)
{
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;
}
bool TQuery_mask::select_query()
{
TFilename path;
const bool ok = select_custom_file(path, "qry");
if (ok)
{
path = path.name(); path.ext("");
set(F_CODICE, path);
}
return ok;
}
static bool xml_save_tree_handler(TTree& tree, void* jolly, word flags)
{
TXmlItem* rel = (TXmlItem*)jolly;
TRelation_node& node = (TRelation_node&)*tree.curr_node();
TXmlItem& son = rel->AddChild("table");
TString4 num; num << node.num();
son.SetAttr("Num", num);
son.SetAttr("Name", node.name());
if (node.alias().not_empty())
son.SetAttr("Alias", node.alias());
if (node.father() != NULL)
{
son.SetAttr("Father", node.father()->id());
FOR_EACH_ARRAY_ROW(node.join(), i, row)
{
if (i > 0)
son << "AND";
son << "(" << *row << ")";
}
}
return false;
}
bool TQuery_mask::save_tables_tree(TXmlItem& xml)
{
const bool ok = _tree.goto_root();
if (ok)
{
TXmlItem& rel = xml.AddChild("tables");
_tree.scan_depth_first(xml_save_tree_handler, &rel);
}
return ok;
}
bool TQuery_mask::save_fields_sheet(TXmlItem& xml)
{
TSheet_field& sf = sfield(F_SHEET);
const bool ok = sf.items() > 0;
if (ok)
{
TXmlItem& fields = xml.AddChild("fields");
FOR_EACH_SHEET_ROW(sf, i, row)
{
TXmlItem& field = fields.AddChild("field");
field.SetAttr("Table", row->get(0));
field.SetAttr("Name", row->get(1));
field.SetAttr("Hidden", tok_get_bool(*row,2));
field.SetAttr("Sort", tok_get_bool(*row,3));
field.SetAttr("Group", tok_get_bool(*row,4));
const char* str = row->get(5);
if (str && *str > ' ')
field.SetAttr("ExprFrom", str);
str = row->get(6);
if (str && *str > ' ')
field.SetAttr("ExprTo", str);
}
}
return ok;
}
bool TQuery_mask::save_query()
{
bool ok = _curr_query.not_empty();
if (!ok)
ok = get_qry_path(_curr_query);
if (!ok)
return field(F_CODICE).on_key(K_ENTER); // Segnala errore
char name[_MAX_FNAME];
xvt_fsys_parse_pathname (_curr_query, NULL, NULL, name, NULL, NULL);
ok = *name > ' ';
if (ok)
{
TXmlItem xml;
xml.SetTag("query");
xml.SetAttr("Name", name);
xml.AddChild("description") << get(F_DESCR);
save_tables_tree(xml);
save_fields_sheet(xml);
xml.AddChild("sql") << get(F_SQL);
xml.Save(_curr_query);
_is_dirty = false;
}
return ok;
}
bool TQuery_mask::save_if_needed()
{
if (!_is_dirty || !field(DLG_SAVEREC).active())
return true;
if (!yesno_box(TR("Si desidera registrare la query?")))
return false;
return save_query();
}
///////////////////////////////////////////////////////////
// Caricamento da file xml
///////////////////////////////////////////////////////////
// Carica l'albero della relazione
bool TQuery_mask::load_tables_tree(TXmlItem& tables)
{
for (int i = 0; i < tables.GetChildren(); i++)
{
const TXmlItem& table = *tables.GetChild(i);
const int num = atoi(table.GetAttr("Num"));
if (num >= LF_USER)
{
_tree.find_id(table.GetAttr("Father"));
const TRelation_node* father = (const TRelation_node*)_tree.curr_node();
TRelation_node* son = new TRelation_node(father, num, table.GetAttr("Alias"));
if (father != NULL)
{
TString expr; table.GetEnclosedText(expr);
int i = expr.find('(');
while (i >= 0)
{
const int j = expr.find(')', i+1);
TToken_string* eq = new TToken_string(expr.sub(i+1, j), '=');
son->join().add(eq);
i = expr.find('(', j+1);
}
}
_tree.add_son(son);
}
}
const bool ok = _tree.goto_root();
if (ok)
{
const TRelation_node* rn = (TRelation_node*)_tree.curr_node();
_curr_num = rn->num();
fill_fields();
_tree.expand_all();
tfield(F_TABLES).win().force_update();
}
enable_field_buttons();
return ok;
}
// Carica l'elenco dei campi (o colonne)
bool TQuery_mask::load_fields_sheet(TXmlItem& xml)
{
TSheet_field& sheet = sfield(F_SHEET);
TXmlItem* fields = xml.FindFirst("fields");
const bool ok = fields != NULL;
if (ok)
{
for (int i = 0; i < fields->GetChildren(); i++)
{
const TXmlItem& field = *fields->GetChild(i);
TToken_string& row = sheet.row(-1);
row.add(field.GetAttr("Table"),0);
row.add(field.GetAttr("Name"),1);
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("ExprFrom"),5);
row.add(field.GetAttr("ExprTo"),6);
}
sheet.force_update();
}
enable_sql_button();
return ok;
}
// Azzera tutto, ma proprio tutto
void TQuery_mask::global_reset()
{
if (_tree.goto_root())
{
_tree.kill_node();
TTree_field& tf = tfield(F_TABLES);
tf.select_current();
tf.win().force_update();
}
reset();
_is_dirty = _sql_dirty = false;
}
// Caica l'intera query
bool TQuery_mask::load_query()
{
TFilename path; get_qry_path(path);
bool ok = path.exist();
if (ok)
{
TXmlItem xml;
ok = xml.Load(path);
if (ok)
{
_curr_query = path;
global_reset();
path = path.name(); path.ext("");
set(F_CODICE, path);
const TXmlItem* desc = xml.FindFirst("description");
if (desc != NULL)
{
TString str; desc->GetEnclosedText(str);
set(F_DESCR, str);
}
TXmlItem* tables = xml.FindFirst("tables");
if (tables != NULL)
load_tables_tree(*tables);
load_fields_sheet(xml);
const TXmlItem* sql = xml.FindFirst("sql");
if (sql != NULL)
{
TString str; sql->GetEnclosedText(str);
set(F_SQL, str, true); // Aggiorna anche stato bottoni di esportazione
TEdit_field& sf = efield(F_SQL);
sf.set_dirty(false); // Evita falsi allarmi di registrazione
_sql_dirty = !sf.empty();
}
_is_dirty = false; // Resetta definitivamente il dirty
}
}
return ok;
}
bool TQuery_mask::delete_query()
{
TFilename path; get_qry_path(path);
const bool ok = yesno_box(FR("Si desidera eliminare il file %s"), (const char*)path);
if (ok)
{
::remove(path);
global_reset();
}
return ok;
}
// Gestione eventi standard
bool TQuery_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
switch (o.dlg())
{
case F_CODICE:
if (e == fe_button)
{
if (select_query())
e = fe_modify;
}
if (e == fe_init || e == fe_modify)
{
save_if_needed();
load_query();
}
break;
case F_TABLES:
if (e == fe_modify)
{
const TRelation_node* rn = (TRelation_node*)_tree.curr_node();
if (rn && rn->num() != _curr_num)
{
_curr_num = rn->num();
fill_fields();
}
}
break;
case F_FIELDS:
if (e == se_query_modify || e == se_query_add || e == se_query_del)
return false;
enable_field_buttons();
break;
case F_ADDFILE:
if (e == fe_button)
add_file_to_tree();
break;
case F_EDITFILE:
if (e == fe_button)
edit_file_in_tree();
break;
case DLG_USER:
if (e == fe_button)
add_field_to_sheet();
break;
case F_ASTERISK:
if (e == fe_button)
add_asterisk_to_sheet();
break;
case F_GENSQL:
case F_GENISAM:
if (e == fe_button)
{
next_page(1001);
bool ok = true;
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?"));
if (ok)
{
if (o.dlg() == F_GENSQL)
sheet2sql();
else
sheet2isam();
}
}
break;
case F_EDITQUERY:
if (e == fe_button)
edit_query();
break;
case F_SQL:
if (e == fe_init || e == fe_modify)
{
const bool on = !o.empty();
enable(F_EXPORT_DBF, on && is_power_station());
if (e == fe_modify)
{
_is_dirty = true;
_sql_dirty = !o.empty();
}
}
break;
case F_EXPORT_HTML:
if (e == fe_button)
save_as(fmt_html);
break;
case F_EXPORT_EXCEL:
if (e == fe_button)
save_as(fmt_html, "xls");
break;
case F_EXPORT_TXT:
if (e == fe_button)
save_as(fmt_text);
break;
case F_EXPORT_CAMPO:
if (e == fe_button)
save_as(fmt_campo);
break;
case F_EXPORT_DBF:
if (e == fe_button)
save_as(fmt_dbf);
break;
case F_SHEET:
enable_sql_button();
break;
case F_MOVEUP:
if (e == fe_button)
move_curr_field(-1);
break;
case F_MOVEDN:
if (e == fe_button)
move_curr_field(+1);
break;
case DLG_NEWREC:
if (e == fe_button)
{
save_if_needed();
global_reset();
next_page(1000);
}
break;
case DLG_FINDREC:
if (e == fe_button)
send_key(K_F9, F_CODICE);
case DLG_SAVEREC:
if (e == fe_button)
{
get_qry_path(_curr_query);
save_query();
next_page(1000);
}
break;
case DLG_DELREC:
if (e == fe_button && jolly == 0) // Elimina della Toolbar
{
delete_query();
next_page(1000);
return false; // Do not exit!
}
break;
case DLG_QUIT:
save_if_needed();
break;
default:
break;
}
return true;
}
// Gestione eventi di trascinamento
long TQuery_mask::handler(WINDOW wnd, EVENT* ep)
{
switch (ep->type)
{
case E_MOUSE_DOWN:
if (ep->v.mouse.button == 0 && wnd == page_win(0))
{
const TSheet_field& sf = sfield(F_FIELDS);
RCT rct; sf.get_rect(rct);
_dragster = xvt_rect_has_point(&rct, ep->v.mouse.where) != 0;
}
else
_dragster = false;
if (_dragster)
{
XinCursor hand = xi_get_pref(XI_PREF_HAND_CURSOR_RID);
xvt_win_set_cursor(wnd, (CURSOR)hand);
}
else
xvt_win_set_cursor(wnd, CURSOR_ARROW);
break;
case E_MOUSE_UP:
if (ep->v.mouse.button == 0 && _dragster)
{
TSheet_field& ff = sfield(F_SHEET);
RCT rct; ff.get_rect(rct);
if (xvt_rect_has_point(&rct, ep->v.mouse.where))
add_field_to_sheet();
xvt_win_set_cursor(wnd, CURSOR_ARROW);
}
_dragster = false;
break;
default:
break;
}
return TAutomask::handler(wnd, ep);
}
TQuery_mask::TQuery_mask() : TAutomask("ba8200a"), _curr_num(0), _is_dirty(false)
{
RCT rcts, rctf, rctt;
TSheet_field& sheet = sfield(F_SHEET);
sheet.get_rect(rcts);
// Allarga a dritta lo spreadsheet coi noi dei campi
TSheet_field& fields = sfield(F_FIELDS);
fields.get_rect(rctf);
rctf.right = rcts.right;
fields.set_rect(rctf);
// Allarga a mancina l'albero della relazione
TTree_field& trf = tfield(F_TABLES);
trf.get_rect(rctt);
rctt.top -= 4;
rctt.left = rcts.left+4;
rctt.right -= 32; // Toglie scrollbar
rctt.bottom = rctf.bottom - 32;
trf.set_rect(rctt);
trf.set_tree(&_tree); // Associa l'albero al campo della maschera
}
///////////////////////////////////////////////////////////
// TSQL_recordset_app
///////////////////////////////////////////////////////////
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()
{
if (!has_module(RSAUT))
return error_box(TR("Modulo non autorizzato"));
_msk = new TQuery_mask;
xvt_sys_sleep(500); // Lasciamo il tempo di leggere il titolo
if (argc() > 2)
{
_msk->set(F_CODICE, argv(2));
_msk->load_query();
if (argc() > 3)
{
switch (argv(3)[0])
{
case 'H':
_msk->save_as(fmt_html);
break;
case 'T':
_msk->save_as(fmt_text);
break;
case 'X':
_msk->save_as(fmt_html, "xls");
break;
case 'C':
_msk->save_as(fmt_campo);
break;
default :
_msk->save_as(fmt_html);
break;
}
}
else
_msk->edit_query();
return FALSE;
}
return TSkeleton_application::create();
}
void TSQL_recordset_app::main_loop()
{
if (argc() > 2)
{
_msk->set(F_CODICE, argv(2)); // Carico la query da riga di comando
_msk->disable(DLG_SAVEREC); // Non permetto modifiche di alcun genere
_msk->disable(DLG_NEWREC);
_msk->disable(DLG_DELREC);
_msk->disable(DLG_FINDREC);
}
_msk->run();
}
bool TSQL_recordset_app::destroy()
{
if (_msk != NULL)
{
delete _msk;
_msk = NULL;
}
return true;
}
int ba8200(int argc, char* argv[])
{
TSQL_recordset_app app;
app.run(argc, argv, TR("Query Generator"));
return 0;
}