Archive for the ‘Java’ Category.

Realizzare un Parser XML con ANDROID

Ciao,
vi riporto questo utilissimo tutorial ANDROID relativo al parsing XML con android. E' utilissimo anche nel caso in cui vogliate realizzare un vostro RSS reader personalizzato.


Fonte: http://www.anddev.it/index.php?topic=180.0

Salve a tutti,
vorrei mostrarvi come è possibile fare il parsing di un documento XML tramite il Document Object Model.

A differenza del parsing tramite SAX, che legge il documento e fa scattare degli eventi (metodi dell'handler) ad ogni tag incontrato, il parsing tramite DOM legge la struttura ad albero di un XML. A discrezione dell'utente (programmatore) la struttura letta potrà essere direttamente interrogata (nel codice si capisce meglio di cosa si tratta).

Per documenti XML relativamente semplici, questo tipo di parsing risulta sicuramente più immediato e semplice da implementare. 
Tuttavia, per strutture con albero xml troppo profondo, questo metodo potrebbe risultare scomodo, e sarebbe quindi meglio optare per il sax parsing.

Vorrei osservare, che queste operazioni (DOM e SAX parsing) sono inerenti a Java più che ad android, ma visto che molte persone si avvicinano a questo fantastico linguaggio grazie ad android, ritengo giusto condividere questo tipo di informazioni su questa board.

Vediamo il documento che vogliamo analizzare:
 

Codice (XML): [Seleziona]

<?xml version="1.0" encoding="utf-8"?>
<messages>
        <note id="p501">
          <to>Carlo</to>
          <from>Luca</from>
          <heading>Promemoria</heading>
          <body>Ricordati gli appunti!</body>
        </note>
        
        <note id="p502">
          <to>Luca</to>
          <from>Carlo</from>
          <heading>Re: Promemoria</heading>
          <body>Ok, mi ricorderò!</body>
        </note>
</messages>


Creiamo una classe che rappresenta una nota:
 

Codice (Java): [Seleziona]

public class MyNote {
        private String body;
        private String heading;
        private String from;
        private String to;
        private String id;
        
        public String getId() {
                return id;
        }

        public void setId(String id) {
                this.id = id;
        }

        public String getFrom() {
                return from;
        }

        public void setFrom(String from) {
                this.from = from;
        }

        public String getTo() {
                return to;
        }

        public void setTo(String to) {
                this.to = to;
        }

        public String getHeading() {
                return heading;
        }

        public void setHeading(String heading) {
                this.heading = heading;
        }

        public String getBody() {
                return body;
        }

        public void setBody(String body) {
                this.body = body;
        }

        @Override
        public String toString() {
                return "MyNote [id=" + id  + ", from=" + from + ", to=" + to +", heading="
                                + heading + ",body=" + body+ "]";
        }
}


Creiamo una classe che gestisce il parsing: (potremmo utilizzare un metodo, ma in questo modo rendiamo più pulito e riutilizzabile il tutto)
Se eliminate i metodi di debug e le chiamate a questi metodi, vi accorgerete della semplicità di questo tipo di parsing(nel caso vi sembrasse troppo lungo :P).

 

Codice (Java): [Seleziona]

public class MyParser {
        static void vDebug(String debugString){         //metodi di convenienza
                Log.v("DomParsing", debugString+"\n");
        }
        static void eDebug(String debugString){
                Log.e("DomParsing", debugString+"\n");
        }
        
        ArrayList<MyNote> parsedData=new ArrayList<MyNote>(); //struttura dati che immagazzinerà i dati letti
        public ArrayList<MyNote> getParsedData() {  //metodo di accesso alla struttura dati
                return parsedData;
        }

    public void parseXml(String xmlUrl){
                
                Document doc;
                try {
                                                
                        doc=DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new URL(xmlUrl).openStream());
                        //Costruiamo il nostro documento a partire dallo stream dati fornito dall'URL
                        Element root=doc.getDocumentElement();
                        //Elemento(nodo) radice del documento
                        
                        vDebug("Root element :" + root.getNodeName());
                        vDebug("");
                        
                        //NodeList notes=root.getElementsByTagName("note"); //potremmo direttamente prendere gli elementi note
                        NodeList notes=root.getChildNodes(); 
                        //ma prediamo tutti i "figli" diretti di root. Utile se non avessimo solo "note" come figli di root
                        
                        for(int i=0;i<notes.getLength();i++){//per ogni
                                Node c= notes.item(i);//nodo
                                
                                
                                
                                if(c.getNodeType()==Node.ELEMENT_NODE){//controlliamo se questo è un nodo elemento (un tag)
                                        //se avessimo usato root.getElementsByTagName("note") questo controllo
                                        //non sarebbe stato necessario
                                        
                                        MyNote newNote=new MyNote(); //costruiamo un oggetto MyNote dove andremo a salvare i dati
                                        
                                        Element note=(Element)c; //cast da nodo a Elemento
                                        
                                        //non controlliamo if(note.getNodeName().equals("note"))  in quanto sappiamo di avere solo "note" come childs
                                        
                                        String id=note.getAttribute("id"); // lettura attributo
                                        vDebug("_Attributo note id:"+id);
                                        vDebug("");
                                        
                                        newNote.setId(id); // settiamo l'id del nostro oggetto MyNote
                                        
                                        NodeList noteDetails=c.getChildNodes();  //per ogni nota abbiamo i vari dettagli 
                                        for(int j=0;j<noteDetails.getLength();j++){
                                                Node c1=noteDetails.item(j);
                                                
                                                        if(c1.getNodeType()==Node.ELEMENT_NODE){ //anche in questo caso controlliamo se si tratta di tag
                                                                Element detail=(Element)c1; //cast
                                                                String nodeName=detail.getNodeName(); //leggo il nome del tag
                                                                String nodeValue=detail.getFirstChild().getNodeValue();//leggo il testo in esso contenuto
                                                                vDebug("______Dettaglio:"+nodeName);
                                                                vDebug("______Contenuto Dettaglio:"+nodeValue);
                                                                vDebug("");
                                                                
                                                                //a dipendenza del nome del nodo (del dettaglio) settiamo il relativo valore nell'oggetto
                                                                if(nodeName.equals("from"))
                                                                        newNote.setFrom(nodeValue);
                                                                
                                                                if(nodeName.equals("to"))
                                                                        newNote.setTo(nodeValue);
                                                                
                                                                if(nodeName.equals("heading"))
                                                                        newNote.setHeading(nodeValue);
                                                                
                                                                if(nodeName.equals("body"))
                                                                        newNote.setBody(nodeValue);
                                                                
                                                                
                                                        }
                                                
                                        }
                                        vDebug("");
                                
                                        parsedData.add(newNote); //aggiungiamo il nostro oggetto all'arraylist
                                }
                                                                                                
                        }                       
                //gestione eccezioni
                } catch (SAXException e) {
                        eDebug(e.toString());
                } catch (IOException e) {
                        eDebug(e.toString());
                } catch (ParserConfigurationException e) {
                        eDebug(e.toString());
                } catch (FactoryConfigurationError e) {
                        eDebug(e.toString());
                } 
                
        }
    
}


Aggiungiamo questa permission al manifest:
 

Codice (XML): [Seleziona]

<uses-permission android:name="android.permission.INTERNET"></uses-permission>
Usiamo ciò che abbiamo creato:

Codice (Java): [Seleziona]

public class DomParsing extends Activity {
   
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        String xmlUrl="http://www.xxxx.xx/myfiles/messages.xml";
        MyParser parser=new MyParser(); //otteniamo un istanza del nostro parser 
        parser.parseXml(xmlUrl);//usiamo il parser
        ((TextView)findViewById(R.id.result)).setText(parser.getParsedData().toString()); 
        //per semplicità stampiamo il toString (che richiamerà i toString di MyNote) dell'arraylist risultato dal parsing
    }   
}

Concatenare due files ( anche mp3 ) su ANDROID

A seguire una utile funzione in grado di concatenare due files ( presenti preferibilmente nella vostra /mnt/sdcard ).

La concatenazione ha effetto anche se utilizzata con files MP3.
 

 

public void concatFiles(String file1,String file2,String out){
    	FileInputStream fistream1;
		try {
			fistream1 = new FileInputStream(file1);
			FileInputStream fistream2 = new FileInputStream(file2);//second source file
	        SequenceInputStream sistream = new SequenceInputStream(fistream1, fistream2);
 
	        FileOutputStream fostream = new FileOutputStream(out);//destinationfile
 
	        int temp;
 
	        while( ( temp = sistream.read() ) != -1)
	        {
	            // System.out.print( (char) temp ); // to print at DOS prompt
	            fostream.write(temp);   // to write to file
	        }
	        fostream.close();
	        sistream.close();
	        fistream1.close();
	        fistream2.close();
		}catch(Exception e){
 
		}
}

Poichè è stato utilizzato solo JAVA la funzione è utilizzabile anche in software non ANDROID ( ma semplicemente JAVA ).

Copiare i propri assets ANDROID nella sdcard

A seguire vi allego una utilissima funzione in grado di spostare gli assets della vostra applicazione ANDROID verso la cartella relativa alla card sd ( anche se non avete sul vostro dispositivo una SD ricordate che la cartella /mnt/sdcard – o simile – sarà presente comunque ).

Questa operazione è essenziale nel caso in cui voleste modificare / rendere disponibili all'utilizzatore della vostra app i file sonori / grafici della stessa.

La stessa funzione potrebbe essere utilizzata per creare un dump del proprio db locale, leggibile poi mediante un semplice accesso alla /mnt/sdcard.

private void copyAssets() {
		File folder = new File(Environment.getExternalStorageDirectory() + &quot;/DIRTEMP&quot;);
		boolean success = true;
		if (!folder.exists()) {
		    success = folder.mkdir();
		}
		if (success) {
			AssetManager assetManager = getAssets();
		    String[] files = null;
		    try {
		        files = assetManager.list(&quot;&quot;);
		    } catch (IOException e) {
		        String err=&quot;&quot;;
		    }
		    for(String filename : files) {
		        InputStream in = null;
		        OutputStream out = null;
		        try {
		          in = assetManager.open(filename);
		          out = new FileOutputStream(Environment.getExternalStorageDirectory() + "/DIRTEMP/" + filename);
		          copyFile(in, out);
		          in.close();
		          in = null;
		          out.flush();
		          out.close();
		          out = null;
		        } catch(IOException e) {
 
		        }       
		    }
		} else {
		    // Do something else on failure 
		}
 
	}

Fatene buon uso!


Connettere una APP Android ad un database mysql remoto

Una delle soluzioni più semplici ed utilizzate e quelle di costruire un "service in the middle". In pratica un servizio che si ponga nel mezzo e si occupi di serializzare/deserializzare i dati sa caricare/scaricare.

Ipotizziamo di avere sul server MYSQL remoto la seguente tabella:


CREATE TABLE `people` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`name` VARCHAR( 100 ) NOT NULL ,
`sex` BOOL NOT NULL DEFAULT '1',
`birthyear` INT NOT NULL
)

In PHP potremmo serializzare i risultati di una query nel formato JSON in questo modo:


  1. <?php
  2. mysql_connect("host","username","password");
  3. mysql_select_db("PeopleData");

  4. $q=mysql_query("SELECT * FROM people WHERE birthyear>'".$_REQUEST['year']."'");
  5. while($e=mysql_fetch_assoc($q))
  6.         $output[]=$e;

  7. print(json_encode($output));

  8. mysql_close();
  9. ?>

Maggiori informazioni sul formato JSON qui: http://it.wikipedia.org/wiki/JSON

Il passo successivo sarà quello di lavorare ( ad esempio ) con i dati "serializzati" JSON nel modo seguente:

  1. String result = "";
  2. //the year data to send
  3. ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
  4. nameValuePairs.add(new BasicNameValuePair("year","1980"));

  5. //http post
  6. try{
  7.         HttpClient httpclient = new DefaultHttpClient();
  8.         HttpPost httppost = new HttpPost("http://example.com/getAllPeopleBornAfter.php");
  9.         httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
  10.         HttpResponse response = httpclient.execute(httppost);
  11.         HttpEntity entity = response.getEntity();
  12.         InputStream is = entity.getContent();
  13. }catch(Exception e){
  14.         Log.e("log_tag""Error in http connection "+e.toString());
  15. }
  16. //convert response to string
  17. try{
  18.         BufferedReader reader = new BufferedReader(newInputStreamReader(is,"iso-8859-1"),8);
  19.         StringBuilder sb = new StringBuilder();
  20.         String line = null;
  21.         while ((line = reader.readLine()) != null) {
  22.                 sb.append(line + "\n");
  23.         }
  24.         is.close();

  25.         result=sb.toString();
  26. }catch(Exception e){
  27.         Log.e("log_tag""Error converting result "+e.toString());
  28. }

  29. //parse json data
  30. try{
  31.         JSONArray jArray = new JSONArray(result);
  32.         for(int i=0;i<jArray.length();i++){
  33.                 JSONObject json_data = jArray.getJSONObject(i);
  34.                 Log.i("log_tag","id: "+json_data.getInt("id")+
  35.                         ", name: "+json_data.getString("name")+
  36.                         ", sex: "+json_data.getInt("sex")+
  37.                         ", birthyear: "+json_data.getInt("birthyear")
  38.                 );
  39.         }
  40. }
  41. }catch(JSONException e){
  42.         Log.e("log_tag""Error parsing data "+e.toString());
  43. }


Ovviamente se si vuole gestire la connessione in HTTPS la cosa è fattibile.

 

 

Gestire l’update della GUI di un APP Android mediante un Handler

Un problema molto ricorrente con cui si scontrano i novelli sviluppatori ANDROID è quello di dover gestire l'update della propria User Interface da una Activity in maniera asincrona ( senza cioè l'intervento di un evento da parte dell'utente ).

Per risolvere problematiche del genere io consiglierei l'utilizzo di un Handler.

Android ci mette a disposizione un meccanismo particolare per scambiare messaggi tra thread diversi a prescindere del tipo di thread, cioè worker o main thread.

Il modello prevede un insieme di classi definite nel package android.os che implementa un meccanismo che comprende una coda di messaggi condivisa dal main e worker thread. Il worker thread in questo caso 'produce' i messaggi e il main thread li 'consuma'. Questi messaggi possono tradursi in azioni, cioè il worker thread invia un messaggio che indica di settare un valore ad un controllo grafico ed il main thread lo esegue. 

Questo potrebbe essere un esempio di Handler:


private Handler textChangeHandler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
         time++;
         TextView secondi= (TextView) findViewById(R.id.secondi);
                secondi.setText("Secondi: " + time);
        }
    };

E questo potrebbe essere un modo di richiamarlo ( dalla funzione onCreate della propria Activity ):

    @Override
    public void onCreate(Bundle savedInstanceState) { 
       
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_new_game);
        
        
        task = new TimerTask() {
            public void run() {
            textChangeHandler.sendEmptyMessage(0);
            }
        };
        timer.scheduleAtFixedRate(task,0,1000);
        …
    }

Come è possibile vedere il timer è stato schedulato per partire ogni secondo.

Molto semplice direi.

Alla prossima!

 

Sviluppare una APP Android con Eclipse Juno è davvero divertente

Devo ricredermi: programmare ANDROID con Eclipse non è mai stato così facile e piacevole.

A patto però di avere a disposizione un terminale fisico su cui fare il debug della propria APP. Questo è sicuro ( l'emulatore infatti risulta davvero ancora troppo lento per consentire un debug agevole ).

Nel mio caso ho utilizzato il mio Samsung Galaxy S2 e devo dire che il risultato è stato davvero piacevole: tempi di upload e debug brevissimi.

E' stato sufficiente installare i driver del telefono ( nel mio caso ho installato direttamente KIES ), mettere il cellulare in modalità DEBUG ( menù sviluppo -> Modalità DEBUG ) e subito è stato riconosciuto da ECLIPSE come dispositivo disponibile.

Come non parlare della nuova versione di Eclipse ( JUNO )?

La stessa è scaricabile qui: http://www.eclipse.org/downloads/

Davvero fenomenale. Tutti gli aspetti più noiosi sono ora programmabili in maniera visuale e con la massima comodità ( ovvio che per fare qualcosa di una seppur minima complessità serve avere una buona infarinatura dell'ANDROID SDK, ma ciò è normalissimo ).





Ritengo che gli appassionati di JAVA possano davvero divertirsi con strumenti tanto potenti quanto versatili.

Nel mio caso mi sono dilettato a creare il gioco seguente (se vi capita dategli un'occhiata e magari dategli un voto):



Considerando che per lo sviluppo dello stesso ho impiegato qualche ora, devo dire che i risultati sono davvero entusiasmanti.   

Spring e l’inversione di controllo

Spring è un framework creato per costruire applicazioni J2EE robuste, basato su una  architettura a strati  composta da sette differenti moduli. 

  • lo strato Core è la sua parte più importante e contiene le funzioni essenziali del framework. In questo layer vengono esposte la implementazione di Spring del principio della inversione del controllo.
  • lo strato DAO è  un layer di persistenza.    
  • lo strato AOP integra all’interno del framework le funzionalità tipiche della programmazione orientata agli aspetti.
  • lo strato ORM consente di integrare all’interno delle applicazioni alcuni tra i più popolari tool per l’accesso ai database relazionali, come ad esempio Hibernate, iBatis ed altri ancora.
  • lo strato WEB fornisce una implementazione del paradigma Model – View – Controller per le applicazioni web.

Ci si potrebbe chiedere  cosa si intende in concreto quando si parla di inversion of control e qual'è la differenza tra IoC e Dependency Injection ?  

Spesso infatti questi due termini sono usati indifferentemente, come se fossero sinonimi, in realtà indicano  concetti sottilmente distinti. 


Per Inversion of Control (IOC - inversione di controllo) si intende un pattern di programmazione, secondo il quale si tende a tener disaccoppiati i singoli componenti di un sistema, in cui le eventuali dipendenze non vengono scritte all'interno del componente stesso, ma gli vengono iniettate dall'esterno: non si segue il normale flusso di controllo dei linguaggi imperativi, in cui, nel momento del bisogno, si richiamano funzioni di classi o librerie esterne, gli oggetti quindi non istanziano e richiamano gli oggetti dal quale il loro lavoro dipende, ma queste funzionalità vengono fornite da un ambiente esterno tramite dei contratti definiti da entrambe le entità.

La Dependency injection è una delle tecniche con le quali si può attuare l'IOC. Essa prende il controllo su tutti gli aspetti di creazione degli oggetti e delle loro dipendenze. Spring usa molto diffusamente la Dependency Injection con il risultato, tra le altre cose, di eliminare dal codice applicativo ogni logica di inizializzazione. Normalmente, senza l'utilizzo di questa tecnica, se un oggetto necessita di accedere ad un particolare servizio, l'oggetto stesso si prende la responsabilità di gestirlo, o avendo un diretto riferimento al servizio, o individuandolo con un "Service Locator" che gli restituisce un riferimento ad una specifica implementazione del servizio. Con l'utilizzo della dependency injection, l'oggetto ha in sé solamente una proprietà che può ospitare un riferimento a quel servizio, e quando l'oggetto viene istanziato, un riferimento ad una implementazione di questo servizio gli viene iniettata dal framework esterno, senza che il programmatore che crea l'oggetto sappia nulla sul suo posizionamento del servizio o altri dettagli sullo stesso.

Android 4.0 e Galaxy S II: disponibile una prima ROM beta

Samsung sta lavorando alacremente per poter portare Android 4 Ice Cream Sandwich sullo smartphone che ha fatto furore nel 2011, ovvero il Galaxy S II. Di tanto in tanto trapela qualche informazione o, come in questo caso, qualche ROM in versione beta…

La ROM che è possibile scaricare adesso da questo indirizzo è una beta, che lascia però vedere come sarà la versione definitiva di Ice Cream Sandwich per il Galaxy S II, per il cui rilascio non sono state ancora fornite date ufficiali.


La ROM è stata aggiornata il 31 gennaio, quindi è piuttosto recente, ed è basata sulla versione 4.0.3 di Android. Diverse modifiche sono state apportate rispetto alle precedenti: adesso quando si effettua lo scrolling c’è un effetto simil-3D, la stabilità è stata migliorata e l’aspetto e le funzioni pare siano molto simili a quelle della release attesa al debutto ufficiale. Migliorate anche le prestazioni, il riconoscimento facciale per lo sblocco del telefono e la gestione dei task.

Il miglioramento più gradito è però sicuramente quello relativo all’autonomia del telefono: la durata della batteria adesso è notevolmente superiore e questo, unito alla buona stabilità della ROM ne permette l’utilizzo anche se il Galaxy S II fosse il nostro unico telefono. 

Tutte le informazioni presenti su questo articolo sono protette dalla licenza CC Attribution-ShareAlike. 

Linux 3.3: presto Android anche su desktop e notebook

A quanto pare, Android e Linux sono destinati a riunirsi in fraterno abbraccio con il rilascio dei prossimi kernel 3.3 e 3.4, con i quali sarà possibile eseguire senza problemi Android sui comuni notebook o desktop. Parola di Greg-KH!


Greg-KH, una delle personalità di spicco del mondo Linux ha affermato, in una recente intervista, che “Il kernel 3.3 permetterà di avviare Android senza modifiche, ma non avrà una gestione del risparmio energetico ottimale. Il kernel 3.4 invece avrà la gestione dell’alimentazione che Android merita e verranno anche aggiunte alcuni pezzi dell’infrastruttura che non saranno invece disponibili nella release 3.3 del kernel”.

Di recente Torvalds aveva avuto occasione di dire che ogni volta che c’è un nuovo ramo di sviluppo in Linux, è una cosa positiva, perché c’è qualcuno che vede un motivo tecnico per fare qualcosa di diverso rispetto al kernel Linux standard. Molti di questi esperimenti finiscono per rivelarsi dei fallimenti e quindi l’alternativa finisce per auto-estinguersi. Altre volte, invece, queste alternative hanno successo, e Google può ben dire di aver costruito una storia di successo con Android. Adesso, però, è il momento di riunire Android al kernel “padre”, prendendo le cose buone di entrambi i progetti e fondendole assieme.

La fusione non sarà immediata, ma già con la versione 3.3 del kernel saremo in grado di eseguire Android su una serie di hardware supportati, e questo vuol dire che presto avremo anche notebook e desktop in grado di eseguire il sistema operativo “inventato” da Google. Vista la crescita dell’ecosistema mobile Android, è lecito supporre che anche le settore desktop questo possa avere un suo importante seguito, anche se il mercato desktop è più complicato di quello mobile. Sul computer le persone fanno molte più cose di quante non se ne facciano sullo smartphone o sul tablet, e questo potrebbe complicare le cose per Android.

Fonte: http://www.hwjournal.net/articoli/linux-3-3-presto-android-anche-su-desktop-e-notebook-9580

Tutte le informazioni presenti su questo articolo sono protette dalla licenza CC Attribution-ShareAlike. 

Come creare una nuova entità base – Detail Form e Detail List su NotaSoftware

Il tutorial è applicabile alle versioni di NotaSoftware maggiori o uguali alla 0.3

Di seguito è indicata la configurazione delle nuove funzionalità di dettaglio del Form e del List.

La modalità di realizzazione di tali funzionalità su Nota si basa sul popolamento delle seguenti tabelle "di sistema":

_forms_details
_form_columns_details

_lists_details
_list_columns_details
 
Gli step da seguire sono quelli a seguire ( tutte le operazioni possono essere eseguite in maniera visuale mediante un qualsiasi tool per mysql ).
 
Per la creazione di un DETAIL FORM con funzioni di visualizzazione/inserimento/modifica:
 
1) Realizzazione della tabella fisica "dettaglio_documenti" nel proprio db ( è la tabella dove risiederanno i dati )
 
Allego script sql per la creazione di una semplice tabella:
 
CREATE TABLE `dettaglio_documenti` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `id_documento` INT(11) NOT NULL DEFAULT '0',
    `qta` INT(11) NOT NULL DEFAULT '0',
    `prezzo_unitario` FLOAT(10,2) NOT NULL DEFAULT '0.00',
    `id_articolo` INT(11) UNSIGNED NULL DEFAULT '0',
    `totale` FLOAT(10,2) NULL DEFAULT NULL,
    `totale_iva` FLOAT(10,2) NULL DEFAULT NULL,
    `totale_iva_esclusa` FLOAT(10,2) NULL DEFAULT NULL,
    `id_codice_iva` INT(11) NULL DEFAULT NULL,
    PRIMARY KEY (`id`)
)
 
2) Configurazione di un record nella tabella _forms_details del proprio db:
 
La tabella _forms_details è composta dai seguenti campi:
 
id_form ( rappresenta l'id del form padre – tabella _forms )
name ( rappresenta il nome del detail form da creare. Il nome deve avere lo stesso nome indicato nel file jsp )
table ( rappresenta il nome della tabella fisica su cui si appoggia il detail form )
foreign_table ( rappresenta il nome della tabella fisica su cui si appoggia la form padre)
primary_key ( rappresenta la chiave della tabella fisica su cui si appoggia la form padre )
foreign_key ( rappresenta la chiave della tabella fisica su cui si appoggia il detail form )
auto_format_string ( è un flag Y/N che indica se le label del detail form devono essere formattate automaticamente )
detail_label ( rappresenta il nome della label del pulsante che porta alla form di dettaglio )
detail_form_pre_save ( rappresenta il metodo javascript da invocare prima del salvataggio )
detail_form_post_save ( rappresenta il metodo javascript da invocare dopo del salvataggio )
 
Allego script sql:
 
INSERT INTO `_forms_details` (`id`, `id_form`, `name`, `table`, `foreign_table`, `primary_key`, `foreign_key`, `auto_format_string`, `detail_label`, `detail_form_pre_save`, `detail_form_post_save`) VALUES (1, 1, 'documenti/dettaglio_documenti', 'dettaglio_documenti', 'documenti', 'id', 'id_documento', 'Y', 'Visualizza Dettaglio', NULL, 'viewForm()')
 
3) Configurazione di un record per ogni campo ( ad eccezione della primary_key ) da mappare nella tabella _form_columns_details del proprio db:
 
id_form_detail ( id della form detail a cui il record fa riferimento )
name ( nome descrittivo del campo che stiamo inserendo )
id_field_type ( il tipo che si vuole associare al campo )
field ( nome del campo fisico )
foreign_table ( nome tabella fisica esterna se il campo è in join )
foreign_key ( chiave delle tabella fisica in join se il campo è in join )
foreign_description ( valore da recuperare dalla tabella in join per il campo in join )
label ( valore a video per il campo )
read_only ( flag Y/N che identifica se il campo è di sola lettura )
sequence ( numero di sequenza a video per il campo )
foreign_long_description ( valore da recuperare dalla tabella in join per il campo in join )
foreign_sub_table ( nome tabella fisica esterna se il campo è un sub value)
foreign_sub_key ( chiave delle tabella fisica se il campo è un sub value )
sub_more_info ( info aggiungive per un campo di tipo sub value )
foreign_long_key ( chiave verso il valore di default dei campi di tipo long combo box )
foreign_long_default ( valore di default dei campi di tipo long combo box )
 
Allego script sql:
 
INSERT INTO `_form_columns_details` (`id`, `id_form_detail`, `name`, `id_field_type`, `field`, `foreign_table`, `foreign_key`, `foreign_description`, `foreign_code`, `label`, `read_only`, `sequence`, `foreign_long_description`, `foreign_sub_table`, `foreign_sub_key`, `sub_more_info`, `foreign_long_key`, `foreign_long_default`) VALUES
(1, 1, 'id_articolo', 3, 'id_articolo', 'articoli', 'id', 'descrizione', NULL, 'ARTICOLO', '', 1, 'descrizione', 'articoli', 'id', '', '2', '- Nessun Articolo -')
INSERT INTO `_form_columns_details` (`id`, `id_form_detail`, `name`, `id_field_type`, `field`, `foreign_table`, `foreign_key`, `foreign_description`, `foreign_code`, `label`, `read_only`, `sequence`, `foreign_long_description`, `foreign_sub_table`, `foreign_sub_key`, `sub_more_info`, `foreign_long_key`, `foreign_long_default`) VALUES
(2, 1, 'descrizione_articolo', 1, 'descrizione_articolo', '', NULL, NULL, NULL, NULL, '', 2, NULL, NULL, NULL, NULL, NULL, NULL);
 
 
Per la creazione di un DETAIL LIST con funzioni di visualizzazione/ricerca:
 
1) Configurazione di un record nella tabella _lists_details del proprio db:
 
La tabella _lists_details è composta dai seguenti campi:
 
id_list ( rappresenta l'id del list padre – tabella _lists )
name ( rappresenta il nome del list detail da creare. Il nome deve avere lo stesso nome indicato nel file jsp )
table ( rappresenta il nome della tabella fisica su cui si appoggia il detail form)
foreign_table ( rappresenta il nome della tabella fisica su cui si appoggia il list padre)
primary_key ( rappresenta la chiave della tabella fisica su cui si appoggia il list padre )
foreign_key ( rappresenta la chiave della tabella fisica su cui si appoggia il detail list )
auto_format_string ( è un flag Y/N che indica se le label del detail list devono essere formattate automaticamente )
paginate ( rappresenta il numero di record visualizzati per pagina )
options ( rappresenta le opzioni attive per la lista: e = edit; d = delete; s = search )
 
Allego script sql:
 
INSERT INTO `_lists_details` (`id`, `id_list`, `name`, `table`, `foreign_table`, `primary_key`, `foreign_key`, `paginate`, `options`, `auto_format_string`) VALUES
(1, 1, 'documenti/dettaglio_documenti', 'dettaglio_documenti', 'documenti', 'id', 'id_documento', 30, 'e/d/s', 'Y')

 
2)  Configurazione di un record per ogni campo ( ad eccezione della primary_key ) da mappare nella tabella _list_columns_details del proprio db:
 
La tabella _list_columns_details è composta dai seguenti campi:
 
id_list_detail  ( id del list detail a cui il record fa riferimento )
name ( nome descrittivo del campo che stiamo inserendo )
id_field_type ( il tipo che si vuole associare al campo )
field ( nome del campo fisico )
foreign_table ( nome tabella fisica esterna se il campo è in join )
foreign_key ( chiave delle tabella fisica in join se il campo è in join )
foreign_description ( valore da recuperare dalla tabella in join per il campo in join )
label ( valore a video per il campo )
search ( flag Y/N che indica se sul campo è possibile eseguire ricerche )
sequence ( numero di sequenza a video per il campo )
 
Allego script sql:
 
INSERT INTO `_list_columns_details` (`id`, `id_list_detail`, `name`, `id_field_type`, `field`, `foreign_table`, `foreign_key`, `foreign_description`, `label`, `read_only`, `search`, `sequence`) VALUES
(1, 1, 'descrizione_articolo', 1, 'descrizione_articolo', '', NULL, NULL, 'Articolo', '', '', 1)

INSERT INTO `_list_columns_details` (`id`, `id_list_detail`, `name`, `id_field_type`, `field`, `foreign_table`, `foreign_key`, `foreign_description`, `label`, `read_only`, `search`, `sequence`) VALUES
(2, 1, 'prezzo_unitario', 1, 'prezzo_unitario', '', NULL, NULL, 'Prezo Unitario', '', '', 2)
 
In uno dei seguenti tutorial affronteremo nel dettaglio la creazione di dettagli multipli.