git-svn-id: svn://10.65.10.50/branches/R_10_00@23050 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			1530 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1530 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);
 | ||
|   TString title; m.get_caption(title);
 | ||
|   if (title.full())
 | ||
|     main_app().set_title(title);
 | ||
| 
 | ||
|   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;
 | ||
|   }
 | ||
| 
 | ||
|   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;
 | ||
| }
 | ||
| 
 | ||
| // Carica 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);
 | ||
|         if (str.blank())
 | ||
|           str = path.name_only();
 | ||
|         set(F_DESCR, str);
 | ||
|         main_app().set_title(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 verr<72> 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;
 | ||
| } |