#include #include #include #include #include #include #include #include #include #include #include #include "../../sqlite/sources/sqlite.h" #include "ba8200.h" #include "ba8201.h" /////////////////////////////////////////////////////////// // Utility /////////////////////////////////////////////////////////// // Ritorna l'indice di somiglianza tra due stringhe: // va da 0.0 (assolutamente diverse) a 1.0 (veramente identiche) // Inventata sul momento: in letteratura si dovrebbe trovare di meglio double fuzzy_strcmp(const char* s1, const char* s2) { if (xvt_str_compare_ignoring_case(s1, s2) == 0) return 1.0; TString p1(s1), p2(s2); if (p1.len() > p2.len()) { p1 = s2; p2 = s1; } p1.upper(); p2.upper(); const int l1 = p1.len(), l2 = p2.len(); double idx = 0.0; if (p2.find(p1) < 0) { if (l1 >= 3) { for (int i = l1-3; i >= 0; i--) if (p2.find(p1.mid(i, 3), i) >= i) idx++; idx /= l1-2; } } else idx = 1.0; if (idx >= 1.0) { idx = (double)l1 / (double)l2; if (idx >= 1.0) idx = 0.99; } return idx; } /////////////////////////////////////////////////////////// // 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); const TFilename name = fd.SysName; _name = name.name(); _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 name2num(const TString& name) const; 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(); }; // Converte un nome di tabella nel suo numero loigico int TTable_mask::name2num(const TString& name) const { int num = 0; if (name.not_empty()) { TList_sheet& sht = *efield(F_SON).sheet(); TString_array& arr = sht.rows_array(); FOR_EACH_ARRAY_ROW(arr, i, row) { if (name == row->get(0)) { num = row->get_int(1); break; } } } return num; } int TTable_mask::father_logicnum() const { return name2num(get(F_FATHER)); } int TTable_mask::son_logicnum() const { return name2num(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 = fuzzy_strcmp(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; 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") { FileDes dir; CGetFile(LF_DIR, &dir, _nolock, NORDIR); const int nfiles = (int)dir.EOD; TList_sheet& sht = *efield(F_SON).sheet(); TToken_string tt(80); TFilename n; for (int logic = LF_USER; logic < nfiles; logic++) { const FileDes& fd = prefix().get_filedes(logic); n = fd.SysName; n = n.name(); n.upper(); tt = n; 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 protected: virtual void 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(bool update = true); void add_asterisk_to_sheet(); 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 sheet2sql(); void edit_query(); 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); void export(TQueryExportFormat fmt); public: 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(); if (father != NULL) { 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); _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; 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, '.'); newrow.add(str.get(1)); } } } 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) { _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 ok; } // 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 il campo selezionato nello spredasheet F_FIELDS allo spreadsheet F_SHEET void TQuery_mask::add_field_to_sheet(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) { 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(); } } } } // 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++) { sf.select(i); add_field_to_sheet(i == nLast); } sf.select(0); } } // 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); } // 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(DLG_USER, ok); enable(F_ASTERISK, 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.find(rn->id()) < 0) { from.add(rn->id()); 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); } } inline bool tok_get_bool(TToken_string& tok, int pos) { const char* str = tok.get(pos); return str && *str > ' '; } // 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; 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) { field.insert("."); field.insert(row->get(0)); // 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); } } tree2sql(from, where); TString sql; sql << "SELECT " << select << '\n'; sql << "FROM " << from << '\n'; 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); } static int select_callback(void* jolly, int argc, char** value, char** field) { 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; } void TQuery_mask::edit_query() { TSQL_query qry(get(F_SQL)); if (qry.columns() > 0) { TQuery_sheet sht(qry); sht.run(); } else warning_box(TR("Nessuna riga risultato")); } void TQuery_mask::export(TQueryExportFormat fmt) { xvt_fsys_save_dir(); TFilename path; path.tempdir(); const char* ext = "txt"; switch (fmt) { case fmt_html: ext = "html"; break; case fmt_slk : ext = "xls"; break; default: break; } FILE_SPEC fs; xvt_fsys_convert_str_to_dir(path, &fs.dir); strcpy(fs.type, ext); strcpy(fs.name, get(F_CODICE)); strcpy(fs.creator, "AGA"); const bool good = xvt_dm_post_file_save(&fs, TR("Esportazione")) == FL_OK; xvt_fsys_restore_dir(); if (good) { xvt_fsys_convert_dir_to_str(&fs.dir, path.get_buffer(), path.size()); path.add(fs.name); TSQL_query qry(get(F_SQL)); if (qry.save_as(path, fmt)) xvt_sys_goto_url(path, "open"); } } bool TQuery_mask::get_qry_path(TFilename& path) const { const TString& name = get(F_CODICE); const bool ok = name.not_empty(); if (ok) { get_sql_directory(path); path.add(name); path.ext("qry"); } return ok; } bool TQuery_mask::select_query() { TEdit_field& fld = efield(F_CODICE); TFilename dirname; get_sql_directory(dirname); xvt_fsys_save_dir(); FILE_SPEC fs; xvt_fsys_convert_str_to_dir(dirname, &fs.dir); strcpy(fs.type, "qry"); strcpy(fs.name, "*"); strcpy(fs.creator, "AGA"); const bool good = xvt_dm_post_file_open(&fs, (char*)fld.prompt()) == FL_OK; xvt_fsys_restore_dir(); if (good) { char name[_MAX_FNAME]; xvt_fsys_parse_pathname (fs.name, NULL, NULL, name, NULL, NULL); fld.set(name); } return good; } 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("Expr", str); } } return ok; } bool TQuery_mask::save_query() { if (_curr_query.empty() && !field(F_CODICE).empty()) get_qry_path(_curr_query); if (_curr_query.empty()) 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); const bool ok = *name > ' '; if (ok) { TXmlItem xml; xml.SetTag("query"); xml.SetAttr("Name", name); xml.SetAttr("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) 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("Expr"),5); } 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(); tfield(F_TABLES).win().force_update(); } reset(); } // 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(); set(F_CODICE, xml.GetAttr("Name")); set(F_DESCR, xml.GetAttr("Description")); 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); } _is_dirty = false; } } 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_modify) { save_if_needed(); load_query(); get_qry_path(_curr_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: if (e == fe_button) { sheet2sql(); next_page(1001); } break; case F_EDITQUERY: if (e == fe_button) edit_query(); break; case F_SQL: if (e == fe_modify) _is_dirty = true; break; case F_EXPORT_HTML: if (e == fe_button) export(fmt_html); break; case F_EXPORT_EXCEL: if (e == fe_button) export(fmt_slk); break; case F_EXPORT_TXT: if (e == fe_button) export(fmt_txt); break; case F_EXPORT_CAMPO: if (e == fe_button) export(fmt_campo); 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(); } break; case DLG_FINDREC: if (e == fe_button) send_key(K_F9, F_CODICE); case DLG_SAVEREC: if (e == fe_button) save_query(); break; case DLG_DELREC: if (e == fe_button && jolly == 0) // Elimina della Toolbar { delete_query(); return false; // Do not exit! } break; case DLG_QUIT: save_if_needed(); break; default: break; } return true; } // Gestione eventi di trascinamento void TQuery_mask::handler(WINDOW wnd, EVENT* ep) { switch (ep->type) { case E_MOUSE_DOWN: if (ep->v.mouse.button == 0 && wnd == 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; } } 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_query_app /////////////////////////////////////////////////////////// class TSQL_query_app : public TSkeleton_application { public: virtual void main_loop(); }; void TSQL_query_app::main_loop() { TQuery_mask* msk = new TQuery_mask; msk->run(); delete msk; } int ba8200(int argc, char* argv[]) { TSQL_query_app app; app.run(argc, argv, TR("Query Generator")); return 0; }