Rileggendo il precedente post, mi sono accorto di acer omesso di descrivere cosa avviene sulla GUI chiamante quando viene trasmesso l'indirizzo e porta di ascolto da utilizzarsi tramite il metodo pubblico "
setAddress(String ind, int porta)", vengono semplicemente valorizzate due variabili globali alla classe GUI, emesso il messaggio relativo al posizionamento di ascolto e ricalibrati i controlli della form con il metodo "
resetComandi()" già anticipato.
il codice è semplicissimo ed auto-esplicativo, una sua lettura ritengo sia più che sufficiente
CODICE
/**Reimposta l'indirizzo IP su cui ascoltare le richieste di connessione
* per l'invio del file da scambiarsi.
*
* @param ind l'indirizzo IP su cui ascoltare, se nullo l'ascolto è generalizzato
* @param porta la porta di ascolto.
*/
public void setAddress(String ind, int porta) {
this.indirizzo = ind;
this.porta = porta;
if(!ind.equals("")) {
tMsg.append("Indirizzo di ascolto : " + ind + " sulla porta " + porta +"\n");
} else {
tMsg.append("Ascolto sulla porta : " + porta +"\n");
}
resetComandi();
}
PARTE 2 di 3 : Il server - selezione file, il "Worker"
Una volta valorizzata la porta di ascolto, il metodo privato, del JFrame GUI, "
resetComandi()" abiliterà il pulsante
btApri, individuabile dall'etichetta "
Apri" in figura nel precedente post, il cui lister di eventi rende disponibile una finestra di dialogo per la selezione, nel filesystem del server, del file da inviare, anche qui credo che la lettura dello stralcio di codice interessato sia esaustiva
CODICE
btApri.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
/* Richiama una finestra per la selezione del file da inviare, il
* path del file verrà memorizzato nella variabile locale "nomeFile" e
* ridisegnati i controlli
*/
javax.swing.JFileChooser dialogo = new javax.swing.JFileChooser();
// si imposta alla home la directory di inizio ricerca
dialogo.setCurrentDirectory(new java.io.File(System.getProperties().getProperty("user.home")));
// impostazione titolo finestra di dialogo
dialogo.setDialogTitle("Selezione file da trasmettere");
// attiva la finestra di dialogo e ne ottiene la condizione di uscita
int res = dialogo.showOpenDialog(Gui.this);
if (res == javax.swing.JFileChooser.APPROVE_OPTION) {
try {
nomeFile = dialogo.getSelectedFile().getCanonicalPath();
lblFile.setText(dialogo.getSelectedFile().getName());
tMsg.append("File da trasmettere : " + nomeFile + "\n");
} catch (IOException e) {
tMsg.append("Errore nella selezione del file : " + e.getMessage() + "\n");
nomeFile = "";
}
resetComandi();
}
}
});
Come si evince facilmente dal codice, non viene fatto altro che istanziare un oggetto "
JFileChooser()", usare i metodi propri dell'oggetto per definirne il titolo e la direttrice da cui partire, puntata alla home dell'utente letta dalle proprietà di sistema (istruzione "
System.getProperties().getProperty("user.home")") e quindi aprirlo col metodo "
showOpenDialog(Jframe Frame)".
Ovviamente, si procede a verificare che l'utente abbia effettivamente selezionato un file prima di incamerarne il nome "completo" nel sistema server ("
.getCanonicalPath()") assegnandolo alla variabile dedicata, informare della selezione effettuata e procedere a resettare i comadi.
Da notare, che la modalità di apertura adottata (più o meno quella di default)
NON permette la selezione di una directory, cosa che vedremo alla stesura del client, ma esclusivamente di files veri e propri ... al momento la cosa va benissimo, perché la trasmissione di un singolo file è il target di questo post, magari in una futura variante si studieranno le strategie per la trasmissione di interi pacchetti di files e direttrici.
Comunque, fatto salvo il verificarsi di errori, il nome file selezionato valorizzerà la variabile specifica ("nomeFile"), la qual cosa permetterà a resetComandi() (ultima istruzione nel listener) di abilitare le funzionalità del pulsante dedicato alla trasmissione del file, "
btInvia", riconoscibile dalla scritta "
Invia" nella finestra del precedente post ... qui le cose sono un attimino più complicate, rispetto a quanto visto sin ora.
Come già anticipato nella parte iniziale del primo post, qui si vuole realizzare una interfaccia utente che sia in grado di reagire anche in presenza di processi pesanti (pensate un po' alla trasmissione della ISO di un DVD), ciò malgrado l'univocità del Thread EDT (Event Dispatcher Thread), quello in cui gira swing per capirci, tale univocità, in presenza di elaborazioni che richiedono un certo tempo, causerebbe il congelamento della finestra fino al termine della elaborazione avviata.
Trasmissione del file : il worker
Detta scomodissima caratteristica, non presente in AWT, ha costretto i poveri programmatori a salti mortali sino al JDK 6, ove è stata introdotta la classe "
SwingWorker", tale classe permette di avviare dei thread paralleli allo EDT di swing, superando così il congelamento della interfaccia utente, con un certo grado di comunicazione con quest'ultimo, cosa che rende possibile l'aggiornamento della finestra in relazione allo stato della elaborazione "pesante" in corso ... è una specie di coordinatore tra thread, in sostanza.
Vi invito caldamente a consultare la documentazione (e i tutorial) di Oracle in merito, SwingWorker è una classe complicatuccia che, oltre tutto, ho affrontato per la prima volta nello esempio in post, qui vi dirò come mi è riuscito di implementare, sulla base di quanto ho capito, un oggetto SwingWorker funzionante che gestisce il ServerSocket per la trasmissione del file aggiornando la finestra principale con l'avanzamento delle operazioni.
In primo luogo Vi invito a guardare la definizione della classe nella docs :
Class SwingWorker<t,V>la classe possiede due parametri indeterminati come tipo dei quali il primo,
T, indica il tipo di valore che sarà restituito alla conclusione del processo parallelo allo EDT avviato, il secondo
V indica un eventuale valore parziale che sarà emesso nel corso della elaborazione.
Volendo trasmettere il file scelto dall'utente ed informarlo sulla trasmissione in corso, senza bloccare la finestra durante la trasmissione, ne consegue in primo luogo che voglio sapere l'esito della trasmissione e, secondariamente, lo stato di avanzamento della trasmissione stessa, cosa che può essere fatta comodamente con una progress bar ... in entrambi i casi, dei valori interi vanno benissimo per lo scopo, chiamando
SendWorker la nostra classe la sua dichiarazione sarà :
CODICE
public class SendWorker extends SwingWorker<Integer, Integer> {
Ovviamente il nostro worker dovrà conoscere l'indirizzo di rete e la porta di ascolto scelti dall'utente, oltre che il file da inviare, poi, dato che ci piace essere precisi, potremmo anche voler informare dello stato delle operazioni nelle varie fasi, oltre che dello avanzamento, potremo facilmente farlo in una text area. Dovremo, quindi prevedere nel nostro worker delle variabili
non modificabili da valorizzarsi con i parametri passati al costruttore, come nello stralcio di codice seguente :
CODICE
private final String file;
private final JTextArea inf;
private final int porta;
private final String indirizzo;
private ServerSocket ss = null;
private Socket s = null;
/**Costruisce il server per invio di un file
*
* @param ind - indirizzo di rete
* @param porta - porta di ascolto
* @param file - canonical name del file da inviare
* @param text - area di testo per messaggi
* @throws Exception - in caso di errori o interruzioni
*/
public SendWorker(String ind, int porta, String file, JTextArea text) throws Exception {
this.indirizzo = ind;
this.file = file;
this.inf = text;
this.porta = porta;
}
Da notarsi come nel costruttore del nostro SendWorker sia stata prevista la clausola "
throws", ciò è motivato dal fatto che un thread SwingWorker può venire interrotto, pur se qui non è implementata interruzione a livello software è comunque bene prevedere tale circostanza.
Dal punto di vista funzionale del nostro worker adotteremo la metodologia già visitata
in questo post, che Vi invito a leggere, dato che non ritratterò qui i concetti già espressi, ovviamente adattandola al contesto ed alle scelte effettuate dall'utente.
In primo luogo dovremo agire diversamente nei casi in cui l'utente abbia scelto di agire su di una specifica rete ovvero indipendentemente da specifiche interfacce, utilizzando un diversificato avvio del ServerSocket che, nel primo caso avrà necessariamente bisogno dello specifico InetAddress associato all'indirizzo di rete scelto dall'utente, è mia abitudine atomizzare le unità funzionali di attività secondo compiti specifici, per questioni di manutenzione e riciclo del codice, pertanto ho previsto un metodo privato,
getInetA(), che adotta tecniche analoghe a quelle viste per l'esposizione dei dati di rete e restituisce lo InetAddres trovato:
CODICE
private InetAddress getInetA() {
try {
Enumeration<NetworkInterface> schede = NetworkInterface.getNetworkInterfaces();
if (schede != null) {
for (NetworkInterface scheda : Collections.list(schede)) {
Enumeration<InetAddress> inAddrs = scheda.getInetAddresses();
for (InetAddress addr : Collections.list(inAddrs)) {
if(indirizzo.equals(addr.getHostAddress())) {
return addr;
}
}
}
}
} catch (SocketException ex) {
String errore = ex.getMessage();
javax.swing.JOptionPane.showMessageDialog(null, errore, "Errore nel rilevamento rete", javax.swing.JOptionPane.ERROR_MESSAGE);
}
return null;
}
Metodo che con qualche leggera modifica potrebbe anche essere inserito in una propria libreria di utilità.
Analogamente, ho preferito isolare anche le operazioni ascolto e connessione del ServerSocket, in un apposito metodo, che restituisce il Socket per la avvenuta connessione, al fine di poter gestire adeguatamente eventuali condizioni di errore :
CODICE
private Socket connetti() {
Socket sock;
try {
if (indirizzo.equals("")) {
ss = new ServerSocket(porta);
} else {
ss = new ServerSocket(porta, 0, getInetA());
}
inf.append("* Attendo un client\n");
sock = ss.accept();
} catch (UnknownHostException e) {
inf.append("Errore : " + e.getMessage() + "\n");
return null;
} catch (IOException e) {
inf.append("Errore : " + e.getMessage() + "\n");
return null;
}
return sock;
}
Si noti come entrambi i metodi utilizzino la text area ricevuta in parametro (
inf) per aggiungerci i loro messaggi, anche in caso di errore, tali messaggi saranno aggiunti dallo ETD anche in pendenza di processi del worker, aggiornando l'interfaccia utente.
Si noti, altresì come viene definito diversamente il ServerSocket a seconda se sia stato definito o meno un indirizzo IP di ascolto da parte dell'utente, in particolare, l'istruzione
CODICE
ss = new ServerSocket(porta, 0, getInetA());
richiama il metodo getInetA() prima definito direttamente nella costruzione del ServerSocket e potrebbe causare un errore che verrebbe intercettato causando la restutuzione di un Socket nullo.
la classe SwingWorker ha un metodo particolare che deve essere obbligatoriamente sovrascritto nella implementazione di un oggetto SwingWorker, tale metodo è "
doInBackground()" e rappresenta il metodo di avvio del thread parallelo allo EDT; esso deve restituire un valore analogo al parametro "
T" impostato nella definizione della classe, tale valore, nel caso implementato, viene utilizzato per comunicare lo stato di uscita del processo, vediamo un po' il codice relativo :
CODICE
@Override
protected Integer doInBackground() {
s = connetti();
if (s == null) {
return -1;
}
inf.append("** Connesso ad host " + s.getInetAddress().getHostAddress() + "\n");
File f = new File(file);
String nome = f.getName();
long dim = f.length();
try {
send_file(file, nome, dim);
} catch (Exception e) {
inf.append("Errore trasmissione : " + e.getMessage());
return -2;
}
return 0;
}
Come è evidente dal codice, il Thread del nostro worker utilizza immediatamente il metodo "connetti()" precedentemente visto per mettersi in ascolto, ottenendo il Socket per la comunicazione ad avvenuta richiesta di connessione, in caso di fallimento della connessione, connetti() restituisce un valore nullo ed in tale circostanza il thread viene immediatamente chiuso con restituzione di valore "
-1", indicante la condizione di errore.
Ottenuto un canale di comunicazione valido (il Socket) il processo provvede ad aprire il file da trasmettere estraendone il nome e la dimensione in byte per poi dare il tutto in pasto al metodo privato "
send_file(String path_file, String nome, long dim_file)" che in maniera del tutto analoga a quella già vista nel post prima indicato esegue l'effettiva trasmissione del file alla cui conclusione chiude restituendo "
0" se tutto è andato bene o "
-2" se si sono avuti errori nella trasmissione.
Il processo chiamante, analizzando il valore restituito da doInBackground() potrà, volendo, eseguire azioni conseguenziali all'esito avuto.
Naturalmente, sarà il metodo "send_file(...)" a provvedere ad informale sullo stato di avanzamento del trasferimento dati, lo fa utilizzando il metodo "
setProgress(int progress)" della classe SwingWorker; il frammento di codice relativo :
CODICE
while((read = fis.read(buff)) != -1) {
tot += read;
oos.write(buff, 0, read);
oos.flush();
progr = (int) (tot * 100 / dim);
setProgress(progr);
}
Come si evince dal codice, nel ciclo di trasmissione dati viene calcolata la percentuale intera dei dati trasmessi fornendola a setProcess().
L'invocazione di setProcess() causa una notifica allo EDT di variazione delle proprietà intercettabile nella finestra chiamante il worker, vedremo tra poco come, del tutto analoga a quella che sarebbe data dal metodo "
publish()" di SwingWorker, qui non utilizzato.
Per quanto riguarda il nostro oggetto
SendWorker, di classe SwingWorker, l'essenziale per la sua costruzione è stato detto, il resto sono ammenicoli di contorno la cui essenza è già trattata nel post prima citato (se non l'avete già fatto
leggetevelo!), vi sono ancora da fare delle codifiche a livello di processo chiamante che vedremo appresso.
Poco fa abbiamo detto che l'utilizzo del metodo setProcess() notifica un cambio di proprietà (ovviamente dell'oggetto SendWorker) allo EDT che può essere intercettato, l'intercettazzione può effettuarsi tramite un "
PropertyChandeListener()", da applicarsi ad una istanza di SendWorker, vedremo in seguito come, c'è ancora da chiarire in qual modo si possa intercettare il valore di uscita (
T) di doInBackground(), esso può essere fatto in vari modi, ciclado con i metodi get() di SwingWorker p.e.,
oppure intercettandolo nel metodo "
done()" che viene immediatamente eseguito nello EDT alla uscita di doInBackground(), possiamo, quindi, sovrascrivere tale metodo "
done()" intercettando detto valore di uscita.
Per questioni di comodità (disponibilità di variabili e controlli) tale implementazione può essere fatta già all'interno del lister del pulsante di comando relativo all'avvio ... ciò che ho fatto
:
CODICE
btInvia = new JButton("Invia");
btInvia.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
btInvia.setEnabled(false);
SendWorker worker = null;
PropertyChangeListener listener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent event) {
if("progress".equals(event.getPropertyName())) {
jpbComFile.setValue((int) event.getNewValue());
}
}
};
try {
worker = new SendWorker(indirizzo, porta, nomeFile, tMsg) {
@Override
protected void done() {
try {
int uscita = get();
if (uscita != 0) {
tMsg.append("Trasmissione file fallita\n");
} else {
indirizzo = "";
porta = 0;
nomeFile = "";
lblFile.setText("");
resetComandi();
}
} catch(InterruptedException | ExecutionException e) {
javax.swing.JOptionPane.showMessageDialog(null, e.getMessage(),
"Errore", javax.swing.JOptionPane.ERROR_MESSAGE);
}
}
};
worker.addPropertyChangeListener(listener);
} catch (Exception ex) {
javax.swing.JOptionPane.showMessageDialog(Gui.this, ex.getMessage(),
"Errore", javax.swing.JOptionPane.ERROR_MESSAGE);
}
worker.execute();
}
});
come potete leggere dal codice, il
PropertyChangeListener() valuta la proprietà che è stata modificata e, se essa è "
progress" provvede ad assegnare ad una JProgressBar (jpbComFile) il nuovo valore della proprietà; da notare il cast "
(int)", necessario perche un oggetto "
Integer" NON è un int (che è un tipo primitivo)
Per quanto riguarda il metodo "
done()" prima detto, esso viene sovrascritto direttamente durante la fase di definizione del nuovo oggetto SendWorker, qui la valutazione del codice di uscita si limita a segnalare una eventuale uscita con errore, senza dettagliare, oppure a reinizializzare variabili e GUI in modo da predisporre ad un eventuale nuovo invio.
Si noti come si sia incapsulata la definizione del nuovo oggetto SendWorker in un blocco "
try-catch", il motivo è dato dal fatto che un processo SwingWorker può essere interrotto, come qualsiasi altro thread, e tale interruzione andrebbe gestita ... certo, qui non l'ho fatto, puntando alla verifica della funzionalità di quanto ho fatto, magari si vedrà più in la, se e quando deciderò di affrontare il trasferimento di files multipli o direttrici.
Si noti altresì l'invocazione del metodo "
execute()" del nostro oggetto SwingWorker al di fuori di ogni altro blocco di codice, a parte quello di evento del bottone, esso è il punto in cui il thread viene effettivamente avviato, in precedenza il pulsante stesso è stato disabilitato, ad evitare l'avvio contemporaneo di più oggetti in ascolto sulla stessa porta, quindi in conflitto ... sai mai qualche crampo al ditino
Ok, quello che c'era da dire sull'aspetto "server" credo di averlo detto, segue il codice completo di SendWorker e della finestra chiamante, assieme a quello nel post della finestra di selezione della rete avete il codice completo.
Nel prossimo post tratterò in manierà più succinta il client, basantesi sui concetti già trattati, ciao
Codice di SendWorker
CODICE
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.Enumeration;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
public class SendWorker extends SwingWorker<Integer, Integer> {
private final String file;
private final JTextArea inf;
private final int porta;
private final String indirizzo;
private ServerSocket ss = null;
private Socket s = null;
/**Costruisce il server per invio di un file
*
* @param ind - indirizzo di rete
* @param porta - porta di ascolto
* @param file - canonical name del file da inviare
* @param text - area di testo per messaggi
* @throws Exception - in caso di errori o interruzioni
*/
public SendWorker(String ind, int porta, String file, JTextArea text) throws Exception {
this.indirizzo = ind;
this.file = file;
this.inf = text;
this.porta = porta;
}
@Override
protected Integer doInBackground() {
s = connetti();
if (s == null) {
return -1;
}
inf.append("** Connesso ad host " + s.getInetAddress().getHostAddress() + "\n");
File f = new File(file);
String nome = f.getName();
long dim = f.length();
try {
send_file(file, nome, dim);
} catch (Exception e) {
inf.append("Errore trasmissione : " + e.getMessage());
return -2;
}
return 0;
}
private InetAddress getInetA() {
try {
Enumeration<NetworkInterface> schede = NetworkInterface.getNetworkInterfaces();
if (schede != null) {
for (NetworkInterface scheda : Collections.list(schede)) {
Enumeration<InetAddress> inAddrs = scheda.getInetAddresses();
for (InetAddress addr : Collections.list(inAddrs)) {
if(indirizzo.equals(addr.getHostAddress())) {
return addr;
}
}
}
}
} catch (SocketException ex) {
String errore = ex.getMessage();
javax.swing.JOptionPane.showMessageDialog(null, errore, "Errore nel rilevamento rete", javax.swing.JOptionPane.ERROR_MESSAGE);
}
return null;
}
private Socket connetti() {
Socket sock;
try {
if (indirizzo.equals("")) {
ss = new ServerSocket(porta);
} else {
ss = new ServerSocket(porta, 0, getInetA());
}
inf.append("* Attendo un client\n");
sock = ss.accept();
} catch (UnknownHostException e) {
inf.append("Errore : " + e.getMessage() + "\n");
return null;
} catch (IOException e) {
inf.append("Errore : " + e.getMessage() + "\n");
return null;
}
return sock;
}
private void inviaParametri(String nome, long dimensione, ObjectOutputStream oos) {
String param = nome + "," + dimensione;
try {
oos.flush();
oos.writeObject(param);
inf.append("Parametri file inviati con successo\n");
} catch (IOException e) {
inf.append("Errore : " + e.getMessage() + "\n");
}
}
private void send_file(String path_file, String nome, long dim_file) throws IOException {
inf.append("* Inizio processo di invio file" + "\n");
String path = path_file;
long dim = dim_file;
FileInputStream fis = null;
ObjectOutputStream oos;
try {
fis = new FileInputStream(path);
oos = new ObjectOutputStream(s.getOutputStream());
byte[] buff = new byte[1024];
int read;
long tot = 0;
int progr;
// invio i dati del file al client
inviaParametri(nome, dim, oos);
// inizio fase di lettura
inf.append("* Inizio invio file di " + dim + " byte\n");
oos.flush();
while((read = fis.read(buff)) != -1) {
tot += read;
oos.write(buff, 0, read);
oos.flush();
progr = (int) (tot * 100 / dim);
setProgress(progr);
}
inf.append("\n");
inf.append("** File inviato con successo\n");
oos.close();
} catch (FileNotFoundException e) {
inf.append("Errore file" + e.getMessage() + "\n");
} finally {
if (fis!= null) {
fis.close();
}
if (s!= null) {
s.close();
}
if (ss != null) {
ss.close();
}
}
}
}
Codice della GUI principale
CODICE
import java.awt.EventQueue;
import javax.swing.JFrame;
import net.miginfocom.swing.MigLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.border.BevelBorder;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JProgressBar;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
@SuppressWarnings("serial")
public class Gui extends JFrame {
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Gui window = new Gui();
window.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Gui() {
initialize();
resetComandi();
}
// controlli che devono essere visibili dai processi
private JTextArea tMsg;
private JLabel lblFile;
private JProgressBar jpbComFile;
private JButton btApri;
private JButton btInvia;
/**
* Initialize the contents of the frame.
*/
private void initialize() {
setTitle("Server scambio file");
setBounds(100, 100, 376, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new MigLayout("", "[][grow][][][]", "[grow][][][]"));
JScrollPane scrollPane = new JScrollPane();
getContentPane().add(scrollPane, "cell 0 0 5 0,grow");
tMsg = new JTextArea();
tMsg.setLineWrap(true);
scrollPane.setViewportView(tMsg);
btApri = new JButton("Apri");
btApri.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
/* Richiama una finestra per la selezione del file da inviare, il
* path del file verrà memorizzato nella variabile locale "nomeFile" e
* ridisegnati i controlli
*/
javax.swing.JFileChooser dialogo = new javax.swing.JFileChooser();
// si imposta alla home la directory di inizio ricerca
dialogo.setCurrentDirectory(new java.io.File(System.getProperties().getProperty("user.home")));
// impostazione titolo finestra di dialogo
dialogo.setDialogTitle("Selezione file da trasmettere");
// attiva la finestra di dialogo e ne ottiene la condizione di uscita
int res = dialogo.showOpenDialog(Gui.this);
if (res == javax.swing.JFileChooser.APPROVE_OPTION) {
try {
nomeFile = dialogo.getSelectedFile().getCanonicalPath();
lblFile.setText(dialogo.getSelectedFile().getName());
tMsg.append("File da trasmettere : " + nomeFile + "\n");
} catch (IOException e) {
tMsg.append("Errore nella selezione del file : " + e.getMessage() + "\n");
nomeFile = "";
}
resetComandi();
}
}
});
getContentPane().add(btApri, "cell 0 1,alignx left");
lblFile = new JLabel("Nessun file selezionato");
lblFile.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null));
getContentPane().add(lblFile, "cell 1 1 3 1,growx");
btInvia = new JButton("Invia");
btInvia.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
btInvia.setEnabled(false);
SendWorker worker = null;
PropertyChangeListener listener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent event) {
if("progress".equals(event.getPropertyName())) {
jpbComFile.setValue((int) event.getNewValue());
}
}
};
try {
worker = new SendWorker(indirizzo, porta, nomeFile, tMsg) {
@Override
protected void done() {
try {
int uscita = get();
if (uscita != 0) {
tMsg.append("Trasmissione file fallita\n");
} else {
indirizzo = "";
porta = 0;
nomeFile = "";
lblFile.setText("");
resetComandi();
}
} catch(InterruptedException | ExecutionException e) {
javax.swing.JOptionPane.showMessageDialog(null, e.getMessage(),
"Errore", javax.swing.JOptionPane.ERROR_MESSAGE);
}
}
};
worker.addPropertyChangeListener(listener);
} catch (Exception ex) {
javax.swing.JOptionPane.showMessageDialog(Gui.this, ex.getMessage(),
"Errore", javax.swing.JOptionPane.ERROR_MESSAGE);
}
worker.execute();
}
});
getContentPane().add(btInvia, "cell 4 1,alignx right");
jpbComFile = new JProgressBar();
getContentPane().add(jpbComFile, "cell 0 2 5 1,growx");
JButton btRete = new JButton("Rete ...");
btRete.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
SelRete frame = new SelRete(Gui.this);
frame.setVisible(true);
}
});
getContentPane().add(btRete, "cell 0 3,alignx left");
JButton btChiudi = new JButton("Chiudi Finestra");
btChiudi.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Gui.this.dispose();
System.exit(0);
}
});
getContentPane().add(btChiudi, "cell 3 3 4 3,alignx right");
}
private void resetComandi() {
if (porta <= 0) {
btApri.setEnabled(false);
} else {
btApri.setEnabled(true);
}
if (porta == 0 || nomeFile.equals("")) {
btInvia.setEnabled(false);
} else {
btInvia.setEnabled(true);
}
}
/**Reimposta l'indirizzo IP su cui ascoltare le richieste di connessione
* per l'invio del file da scambiarsi.
*
* @param ind l'indirizzo IP su cui ascoltare, se nullo l'ascolto è generalizzato
* @param porta la porta di ascolto.
*/
public void setAddress(String ind, int porta) {
this.indirizzo = ind;
this.porta = porta;
if(!ind.equals("")) {
tMsg.append("Indirizzo di ascolto : " + ind + " sulla porta " + porta +"\n");
} else {
tMsg.append("Ascolto sulla porta : " + porta +"\n");
}
resetComandi();
}
private String indirizzo = "";
private int porta = 0;
private String nomeFile = "";
}