JList - Visualizzazione aleatoria dei model associati.

di il
15 risposte

JList - Visualizzazione aleatoria dei model associati.

Salve a tutti del forum,
Ho un problema assurdo su due oggetti JList.

In particolare: Ho un Frame->Panel dove ho inserito due JScrollPane e ad ognuno di essi ho inserito un'oggetto JList<String> a cui è associato un ListModel (la dichiarazione degli oggetti sono definiti al livello di classe come private).

Di seguito una parte del metodo initialize()

	Oggetti vari del frame panel
	......
	......
	listModelGUI = new DefaultListModel<String>();
        scrollPane_ToProcessing = new JScrollPane();
	scrollPane_ToProcessing.setBounds(230, 297, 329, 160);
	frmPanel.add(scrollPane_ToProcessing);		
		
	list_ToProcessing = new JList<String>(listModelGUI);
	scrollPane_ToProcessing.setViewportView(list_ToProcessing);

	listModelPreadvising = new DefaultListModel<String>();
	scrollPane_ToPreadvising = new JScrollPane();
        scrollPane_ToPreadvising.setBounds(569, 297, 320, 160);
        frmPanel.add(scrollPane_ToPreadvising);
        
        list_ToPreadvising = new JList<String>(listModelPreadvising);
        scrollPane_ToPreadvising.setViewportView(list_ToPreadvising);
	.......
	.......
	Oggetti vari del frame/panel
Successivamente, nel costruttore della classe, viene richiamato prima l'inizializzazione di cui sopra, poi viene lanciato un thread che ha lo scopo di effettuare una elaborazione di dati e aggiornare le listModelPreadvising e listModelGUI valorizzandoli. Il Thread serve per sganciare il frame per non tenerlo bloccato durante l'elaborazione anche se tutti i controlli sono vuoti.

Il problema è che in runtime, i valori nei ListModel sono presenti.
Ma la visualizzazione a video delle JList:
- a volte ci sono i dati
- a volte no
- a volte solo una o entrambe le List hanno solo una parte dei dati rispetto ai contenuti della ListModel.
- a volte solo la JList di sinistra visualizza i dati e a destra no.
- a volte solo la JList di destra visualizza i dati e quella di sinistra no

Praticamente ho tutte le combinazioni e in modo aleatorio.

Il fatto è che eseguo il thread per liberare la GUI dal processo di elaborazione dati.

Gli altri controlli (TextBox e etc.) funzionano perfettamente, le ComboBox funzionano perfettamente ma le JList danno i numeri.

In VB6, anni fa, esisteva il me.refresh, in Java con swing?

Esiste una soluzione?

Grazie a tutti per aver letto ancor di più se mi rispondete.

15 Risposte

  • Re: JList - Visualizzazione aleatoria dei model associati.

    Aggiornamento:
    E' uscita una nuova combinazione ossia:
    In una delle JList, viene aggiornato in:
    - riga 1 normale
    - riga 2 normale
    - riga 3 vuota composta da più righe come blocco unico
    - riga 4 normale

    Premetto che i dati che inserisco nei model, li visualizzo anche in runtime con Syste.out.println() proprio per sapere cosa ho inserito, questo perchè non mi trovavo con i conti.
  • Re: JList - Visualizzazione aleatoria dei model associati.

    Ho eliminato il richiamo del thread dal costruttore della classe. Ho spostato le operazioni che eseguivo nel thread nel costruttore.

    Così facendo funziona tutto correttamente ma quando lancio l'applicazione, prima che viene visualizzato l'interfaccia, ne passa di tempo poichè l'elaborazione è lunga (2 minuti circa).

    Infatti il thread mi serviva per far terminare il costruttore in modo che venisse visualizzata l'interfaccia.
    Il thread (unico) continuava con una elaborazione (durante il quale aggiornava una textbox usata come status program) e successivamente abilitava i controlli e etc. per le operazioni utente.

    In origine il form aveva diversi componenti e solo una JList e con il thread tutto andava a meraviglia.
    E' bastato aggiungere un'altra JList + DefaultModel + JScrollpane per avere l'effetto aleatorio di cui sopra.

    Qualche idea?

    Può essere che devo tenere legato l'interfaccia con una preelaborazione dati?

    Grazie a tutti per la pazienza.
  • Re: JList - Visualizzazione aleatoria dei model associati.

    cnesan ha scritto:


    poi viene lanciato un thread che ha lo scopo di effettuare una elaborazione di dati e aggiornare le listModelPreadvising e listModelGUI valorizzandoli. Il Thread serve per sganciare il frame per non tenerlo bloccato durante l'elaborazione anche se tutti i controlli sono vuoti.

    Il fatto è che eseguo il thread per liberare la GUI dal processo di elaborazione dati.
    E questo È buono e giusto MA Swing di base e in generale NON è "thread-safe". L'accesso alla interfaccia utente (ai componenti/layout) e anche ai model va fatto (detto in generale) sempre e solo nel contesto del Event Dispatch Thread ... non in un altro tuo thread.
    Ci sono davvero poche operazioni (documentate) che sono thread-safe e si possono invocare da qualunque thread, anche non il EDT.

    DefaultListModel usa internamente un Vector, che di per sé è synchronized e thread-safe ma non è tanto questo il punto. Quando ad esempio su DefaultListModel fai un add/addElement essi invocano il fireIntervalAdded (fornito da AbstractListModel) che va a notificare tutti i listener registrati.
    Se add/addElement li invochi in un tuo thread, i listener vengono notificati nel contesto del TUO thread e questo è inappropriato (e può causare problemi).

    In sostanza, per concludere, se vuoi usare il multi-threading in Swing, DEVI essere consapevole e accorto su tutti questi aspetti. Ed agire di conseguenza.
  • Re: JList - Visualizzazione aleatoria dei model associati.

    Andbin,
    grazie per aver risposto.

    Ok, inizialmente avevo tolto il thread da mezzo (commentandolo) e quindi quello che richiamavo nel trhead (ossia i metodi della classe che lavorano sulle istanze dei DefaultListModel) li ho spostati dopo la chiamata del metodo initialize() nel costruttore.

    L'applicazione funziona nel senso che il form, quando esce (circa 2 minuti dal lancio), visualizza le 2 JList e la ComboBox con una valorizzazione corretta e l'applicazione è stata lanciata 10 volte senza problemi a parte la visualizzazione del form in ritardo.

    Quindi, quanto sopra mette a riparo l'applicazione dal problema ma, si ritorna al problema che un utente che avvia tale applicazione, potrebbe pensare che questa non si è avviata riprovando.

    Ora, ho fatto il backup del sorgente e sono andato avanti più per capire che per altro.

    Vediamo cosa ho fatto!!

    Sulla base di quanto hai scritto, in effetti non mi aspettavo che un DefaultListModel potesse avere/avviare degli eventi anche se a pensarci bene, per logica, è anche ovvio poichè, nel caso di un'aggiunta/rimozione di item, come farebbe poi la JList (o quello che è agganciato all'istanza del DefaultListModel) a sapere quando rifare il rendering ?

    Sulla sponda di ciò, ho pensato di non associare in initialize() le due istanze del DefaultListModel alle JListBox ma solo di generarle.
    Rammento che la dichiarazione del tipo delle due istanze sono al livello di classe.
    Successivamente ho ripristinato il mio thread il quale viene lanciato dopo Initialize().

    Il thread, come prima attività, lancia una sequenza di metodi (le quali ognuna lavora con una sola istanza del DefaultListModel inserendo degli item) ma, rispetto a prima, associano l'istanza del componente Swing JListBox o JComboBox alla rispettiva istanze del DefaultListModel mediante JList.setModel().

    Alla prova, ho lanciato l'applicazione 10 volte senza più avere il problema di item non visualizzati o parzialmente visualizzati.

    Francamente non so se sia giusto quello che ho fatto. Che ne pensi?

    Grazie di tutto.
  • Re: JList - Visualizzazione aleatoria dei model associati.

    Spero di non scrivere una cosa che sai già, ma un modo comodo per eseguire procedure lunghe in background quando si lavora con swing è utilizzare la classe SwingWorker.
    Ci sono molti esempi online di programmi che devono svolgere task molto lunghi e contemporaneamente aggiornare una progress bar che mostri l'avanzamento del processo, senza bloccare l'interfaccia.

    Io personalmente l'ho usato solo in questo modo, ad esempio se dovevo leggere migliaia di file di testo per riempire una JTable, facevo fare tutto il lavoro in background e solo quando il task era completato popolavo la tabella e la mostravo all'utente.

    Ma penso che sia del tutto fattibile il mostrare subito le JList, anche vuote, avviare la tua elaborazione in background, e aggiornare man mano l'interfaccia ogni tot tempo oppure ogni tot operazioni eseguite.
    Il tutto eseguito nel contesto giusto, senza preoccuparti di gestire tu esplicitamente cosa far fare all'EDT e ad altri thread, e senza il rischio di congelare la tua interfaccia.

    Personalmente mi sono perso un po' nella tua spiegazione, probabilmente andbin o altri ti potranno dare indicazioni più dettagliate e adatte al tuo caso, ma se non conoscevi già SwingWorker può comunque esserti utile cercare qualche esempio, magari partendo dal tutorial ufficiale.

    Ciao
  • Re: JList - Visualizzazione aleatoria dei model associati.

    cnesan ha scritto:


    Sulla base di quanto hai scritto, in effetti non mi aspettavo che un DefaultListModel potesse avere/avviare degli eventi anche se a pensarci bene, per logica, è anche ovvio poichè, nel caso di un'aggiunta/rimozione di item, come farebbe poi la JList (o quello che è agganciato all'istanza del DefaultListModel) a sapere quando rifare il rendering ?
    Allora devi prima comprendere come funziona Swing in generale! Swing è modellato sul noto Design pattern MVC (Model-View-Controller). In questo pattern, quando "qualcosa" cambia nel model, la view deve essere notificata affinché possa aggiornarsi. E in Swing questo avviene proprio tramite eventi, dispacciati tramite i listener registrati sui componenti.
    Swing è TUTTO fatto così. Tutti i componenti che hanno un model associato funzionano in questo modo. Salvo alcuni componenti basilari/"stupidi" come JLabel, che non ha un model poiché è soltanto una etichetta di testo non modificabile dall'utente.

    cnesan ha scritto:


    Il thread, come prima attività, lancia una sequenza di metodi (le quali ognuna lavora con una sola istanza del DefaultListModel inserendo degli item) ma, rispetto a prima, associano l'istanza del componente Swing JListBox o JComboBox alla rispettiva istanze del DefaultListModel mediante JList.setModel().
    Il setModel va comunque sempre fatto nel contesto del EDT. Quando sei in un thread che non è il EDT, se vuoi settare qualcosa sui componenti, aggiungere/togliere componenti, ecc... devi fare passare quel pezzetto di codice nel EDT e questo lo si può fare con il "solito" SwingUtilities.invokeLater() che prende un Runnable il cui run() verrà poi eseguito nel EDT.

    Se devi aggiornare continuamente la UI da un thread di background e devi farlo più volte in contesti o per operazioni differenti, puoi anche usare lo SwingWorker (javax.swing.SwingWorker) che è stato introdotto ufficialmente in Java 6. SwingWorker permette di eseguire un lavoro in un thread di background facilitando però l'aggiornamento della UI poiché offre una infrastruttura che "nasconde" i noiosi dettagli che servono per la interazione tra il thread e il EDT.
  • Re: JList - Visualizzazione aleatoria dei model associati.

    Ok, mi sto leggendo un ebook su Swing visto che sui manuali Java 7 e 8 è riportato come usare i componenti JText e etc. e solo un piccolo paragrafo su questo MVC, EDT e la classe astratta SwingWorker
  • Re: JList - Visualizzazione aleatoria dei model associati.

    Ok per la classe astratta SwingWorker: "doInBackground()" e "done()", proprio quello che ci voleva!!!!

    Non ho potuto fare a meno di notare un esempio che utilizza publish() che mi consente di aggiornare quello che volevo già mettere in passato ossia una JProgressBar per indicare l'avanzamento del processo di elaborazione.

    L'attuale JProgressBar è aggiornata tramite publish() quando si passa da un'istanza all'altra.

    Alla luce di tutto ciò, l'appetito vien studiando (nel mio caso), sto pensando di fare qualcosa simile allo spoiler delle stampanti ossia qualcosa che, in tempo reale, mi dia indicazioni delle istanze lanciate e il relativo stato di avanzamento del processo del costruttore.

    Una mezza idea ce l'avrei in modo orientativo ossia quello di creare due classi:
    - Una classe di tipo single-tone che fa da manager o spoiler registrando le istanze di un'altra classe mytask
    - Una classe di tipo normale e leggera molto semplice per inserire solo dati identificativi e status "min(int)"-"max(int)"-"current(int)" e dotato di un metodo upgrade() per aggiornare solo il current(int).

    Nel costruttore della classe, viene generata una istanza myTask dove vengono registrati il nome della classe e i tre valori (inoltre viene aggiunto al managertask mediante un metodo della classe manager) e successivamente viene invocato il metodo update di mytask per dare il valore di avanzamento di volta in volta.
    Il managertask aggiornerebbe la JProgressBar associata al task per dare visibilità dello stato di avanzamento.

    Sono sicuro che altri prima di me hanno affrontato questo problema, ma io non amo copiare a dispetto dei miei colleghi!!!! ma amo capire quindi sono accettate consigli su cosa andare a leggere.

    Grazie a tutti (in particolare andbin)
  • Re: JList - Visualizzazione aleatoria dei model associati.

    cnesan ha scritto:


    sto pensando di fare qualcosa simile allo spoiler delle stampanti ossia qualcosa che, in tempo reale, mi dia indicazioni delle istanze lanciate e il relativo stato di avanzamento del processo del costruttore.
    Sì .. credo di aver capito cosa intendi qui. Quindi puoi avere più task differenti che possono durare anche tempi abbastanza lunghi da poter/dover essere monitorati, giusto?

    A livello grafico, sarebbe utile e interessante avere un frame che contiene una tabella (JTable) in cui ogni riga rappresenta un task (proprio in modo similare alla finestra in MS Windows che mostra le stampe in corso per una stampante). Magari nella riga della tabella si può anche mettere una progress-bar per mostrare il progresso.
    Il punto è che per fare una cosa così ... non bastano "due classi" in croce come dici. Serve ben di più e serve una piccola infrastruttura che permetta di gestire il tutto in maniera corretta (dal punto di vista del threading) e in modo che il task debba "sapere" il minimo indispensabile su come aggiornare lo stato.

    Si fa ma serve un buon design.
  • Re: JList - Visualizzazione aleatoria dei model associati.

    Si,
    hai perfettamente colto nel segno.
  • Re: JList - Visualizzazione aleatoria dei model associati.

    Ok,
    l'implementazione non è stata semplice. C'è una prima stesura, qualcosa da rivedere e etc.

    Domanda: mettiamo che ci troviamo ad eseguire un codice di un metodo appartenente ad una classe.
    1) Posso identificare, in modo univoco, il metodo mediante qualche metodo di java? (A me servirebbe un'identificativo univoco dell'esecuzione del metodo).
    2) La classe la identifico con i metodi presenti quali getClassID() e getClassName(), dovrebbero andar bene?

    Facendo una classe di verifica e lanciando una decina di task con nomi diversi e in tempi diversi (emulando alla buona più thread di classi uguali e diverse e per ogni thread più task con add/set/remove). Il tutto funziona.

    MA, ce sempre il ma che lo sto al momento verificando.
    Quando viene effettuato l'update alla JTable (presente in TaskView()) mediante al dataModel con il metodo fire....(), tutto funziona ma perdo la selezione della riga. Si può fare qualcosa?

    Per il discorso thread-safe non l'ho valutato ma penso che tutti i task, essendo generati individualmente e gestiti individualmente non credo che dovrebbero avere problemi, sbaglio?

    Grazie per aver letto ancor di più se ho qualche risposta

    P.S.:
    Fino ad ora ho implementato:
    - class Task() (per memorizzare i dati e si autoregistra nell'unica istanza di TaskManager), accetta listener conformi IActionTaskListener
    - class TaskManager (tipo singletone) accetta listener conformi a IActionManagerTaskListener, per eventi di update fatti a loro volta dai task.
    Ogni volta che un task si registra nel task manager, il taskmanager si registra come ascoltatore di eventi del task stesso.
    - class TaskView per visualizzare lo stato dei singoli task attraverso una tabella e visualizzare su click il dettaglio nel panel sottostante.
    - interface IActionTaskListener utilizzata da TaskManager ma anche da chi genera il task (si rivolge ad entrambi) definisce evento new/set/delTask.
    - interface IActionManagerTaskListener (Utilizzato dal TaskView per essere messo al corrente di cosa cambia. L'evento passa l'istanza del task che ha fatto un update).

    La classe Task ha:
    Costruttore(parametri ClassID, ClassName, MethodName, MinProgress, MaxProgress)
    Metodo setTask(parametri CurrentProgress, Status, Comment)
    Metodo getxxxx() dove per xxxx sono i singoli campi di un task (per fare l'aggiornamento si deve usare setTask(...)
    Metodo addTaskListener(IActionTaskListener obj)
    Generazione eventi per i listener che si sono registrati sopra e che hanno implementano la mia interfaccia IActionTaskListener definendo:
    public void actionNewTask(Task task); //Nuovo task
    public void actionSetTask(Task task); //Cambio dati status/comment/progressValue
    public void actionRemoveTask(Task task); //Quando il task termina.
    Metodo privato runEventTaskxxx (3 casi Add/Set/Del) il quale scandaglia i listener registrati lanciando uno dei tre metodi.


    In effetti, al momento, memorizzo nelle istanze di tipo task i seguenti parametri:
    - ClassID
    -- ottenuto da getClassID()
    -- definito nei parametri del costruttore
    - ClassName
    -- ottenuto da getClassName()
    --definito nei parametri del costruttore
    - MethodName
    -- inserito manualmente?!?!!? vorrei che fosse definito da Java per rendere più sicuro e anche meno oneroso
    -- definito nei parametri del costruttore
    - MinProgressValue
    -- inserito manualmente e definisce il valore minimo
    -- corrisponde al minimo di partenza del progressBar
    --definito nei parametri del costruttore
    - MaxProgressValue
    -- inserito manualmente e definisce il valore masimo
    -- corrisponde al valore finale della progressBar
    --definito nei parametri del costruttore
    - Status
    -- inserito manualmente il quale da un'indicazione dell'operazione in corso
    -- definito nei parametri del metodo setTask()
    - Comment
    -- inserito manualmente che definisce il dettaglio di status
    -- definito nei parametri del metodo setTask()
    - CurrentProgressValue
    -- inserito manualmente e definisce il valore masimo
    -- corrisponde al valore corrente della progressBar
    -- definito nei parametri del metodo setTask()

    La classe TaskManager di tipo singleton pensa solo a memorizzare e ad ascoltare eventi delle istanze Task. Nel momento che c'è un'evento Add/Mod/Rem del task, viene generato un evento identico ma passando il riferimento del task (istanza). In genere è destinato al TaskView.

    La classe TaskView si preoccupa solo della GUI, Implementa l'intarfaccia IActionManagerTaskListener per poter rispondere agli eventi (come se si trattasse di un componente "orientativamente") ed è indipendente nel senso che bisogna lanciarlo inizialmente e legarlo all'unica istanza TaskManager.

    Grazie per aver letto.
  • Re: JList - Visualizzazione aleatoria dei model associati.

    Ok, tutto risolto o almeno sembra.

    Ora ho un package che mette a disposizione:
    - Una classe chiamata Task() che consente di inserire alcune informazioni che saranno gestite autonomamente da un'altra classe (protected).
    - Una classe GUI per visualizzare i task generati e visualizzare lo stato durante il funzionamento dell'applicazione che li ha generati.

    Le istanze generate dalla classe Task consentono di memorizzare, mediante costruttore, il nome della Classe che ha generato l'istanza e il relativo ID fornito da hashID, nome del metodo (opzionale), valore minimo e massimo di completezza del task (in genere 0% e 100%). Inoltre vi è un secondo metodo che consente di effettuare un'update di stato del task inserendo le seguenti info: StatusTask, Comment, CurrentValue (%completato).
    Inoltre il task, ha un gestore di listener perchè emette i seguenti eventi: ActionNewTask - ActionSetTask - ActionDelTask (quando vengono emessi è semplice a capirli, ma in realtà sono destinati ad una classe Singletone che gestisce i task o meglio i task si vanno a registrare e la classe singletone si autoregistra come listener.

    Inoltre vi è un'altra classe che ha una GUI per:
    - Visualizzare tutti i task registrati nella classe singletone
    - Visualizzare il dettaglio del task quando si clicca sulla JTable della GUI.

    Tuttavia, sebbene tutto funziona, è rimasto un problema quale: La gui, che visualizza i task, e la GUI che gestisce l'applicazione che a sua volta dichiara dei task, sono legati nell'esecuzione ossia al lancio di uno c'è il lancio a sua volta dell'altro creando un legame non voluto.

    Sulla base di quanto scritto, è possibile far comunicare due applicazioni Java lanciate in esecuzione distintamente?

    Quello che sto tentando di fare e produrre uno spooler di task come se si trattasse dello spooler di stampa. Quest'ultimo però è indipendente mentre il mio è comunque legato all'applicazione che lo richiama.

    Esistono soluzioni?

    A proposito se interessa a qualcuno basta chiedere!!

    Saluti a tutti e grazie per aver letto, ancor di più se mi rispondete!!
  • Re: JList - Visualizzazione aleatoria dei model associati.

    cnesan ha scritto:


    Tuttavia, sebbene tutto funziona, è rimasto un problema quale: La gui, che visualizza i task, e la GUI che gestisce l'applicazione che a sua volta dichiara dei task, sono legati nell'esecuzione ossia al lancio di uno c'è il lancio a sua volta dell'altro creando un legame non voluto.
    Ovvio .. hai fatto una architettura che è specifica per la tua applicazione.

    cnesan ha scritto:


    Sulla base di quanto scritto, è possibile far comunicare due applicazioni Java lanciate in esecuzione distintamente?

    Quello che sto tentando di fare e produrre uno spooler di task come se si trattasse dello spooler di stampa. Quest'ultimo però è indipendente mentre il mio è comunque legato all'applicazione che lo richiama.
    Cioè ... tu vorresti creare un "task monitor" che vada bene per qualunque applicazione Java? Ma che sia a conoscenza della TUA infrastruttura di monitor e la usi ... o del tutto ignara?

    Il punto è che il concetto di "task" non è qualcosa di esattamente e univocamente definito. Cosa è un task? Solo un Runnable? O anche un Callable? Uno SwingWorker? O che altro?
    Ci sono i thread, questi sono ben identificati ciascuno da un oggetto java.lang.Thread. Ma un singolo thread non è necessariamente un singolo task. Un thread può gestire più "task" in sequenza (è il caso dei thread-pool).

    Quindi?
  • Re: JList - Visualizzazione aleatoria dei model associati.

    Ciao andbin,
    credo che mi sono spiegato male, anzi mi sono reso conto di aver usato un termine "Task" che è fuorviante rispetto a quello che realmente è.

    Il termine corretto sarebbe TaskInfo e ManagerTask diventerebbe ManagerTaskInfo e la GUI, GUITaskInfo.

    Per classe Task non intendo task gestiti a loro volta dai thread ma si tratta di una classe che gestisce le informazioni di un istanza x.
    Nel costruttore definisco come parametri: Nome della classe di appartenenza, metodo in esecuzione, percentuale di completamento e etc.

    Ovviamente una classe che si vuole avvalere di questo monitoring, deve dichiarare un'istanza dalla classe Task e passare i parametri precedentemente detti. Successivamente richiamerà solo il comando set() dell'istanza Task passando due stringe (Stato,Commento) e un valore percentuale di completamento.

    Alla classe Task, si aggiunge nel package, anche un'altra classe chiamata TaskManager.
    TaskManager ha il solo compito di:
    - memorizzare, in un arraylist, le istanze della classe Task
    - eseguire delle attività se ci sono cambiamenti in una qualsiasi istanza di tipo Task.

    Poi c'è anche un'altra classe che in realtà è una applicazione GUI. Questa applicazione prende il riferimento del TaskManager e esegue le operazioni di visualizzazione.

    Ora spiegare i dettagli è molto difficile, per questo avevo detto se ci volevi dare un'occhio al package.

    La classe Task ha un gestore dei listener che li cambia in caso di cambiamenti (nel caso viene chiamato il metodo set(), mentre a sua volta il TaskManager implementa un'interfaccia (della classe Task) per la gestione dei possibili eventi. La cosa si ripete quando è in funzione la classe GUI poichè l'evento parte dalla istanza del Task -> Passa al TaskManager -> per approdare in TaskGUI (visualizzatore).

    La cosa funziona se richiamo la classe TaskGUI dalla GUI dell'applicazione, che utilizza le classi monitorate.

    Il monitoraggio è solo sulle classi utilizzate dalla applicazione.

    Ciao.
Devi accedere o registrarti per scrivere nel forum
15 risposte