package kerhoswing;
import java.awt.Color;
import java.awt.Desktop;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.io.PrintStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import kerho.Harrastus;
import kanta.Kentta;
import kanta.SailoException;
import kanta.Tietue;
import kerho.Jasen;
import kerho.Kerho;
import fi.jyu.mit.gui.AbstractChooser;
import fi.jyu.mit.gui.EditPanel;
import fi.jyu.mit.gui.IStringListChooser;
import fi.jyu.mit.gui.IStringTable;
import fi.jyu.mit.gui.SelectionChangeListener;
import fi.jyu.mit.gui.StringTable;
import fi.jyu.mit.gui.TableEditListener;
import fi.jyu.mit.gui.TableRendererListener;
import fi.jyu.mit.gui.TableSelectionListener;
import fi.jyu.mit.gui.TextAreaOutputStream;
/**
* Luokka joka käsittelee kerhoa Swing-komponenteilla.
* Luokan käyttö:
*
* 1) Tee jollakin tavalla lomake, jossa on tarvittavat komponentit
* 2) Laita lomakkeelle myös Lisää ja Talleta -napit niin halutessasi
* 3) Luo koodissa lomakkeella KerhoSwing-olio
*
* kerhoswing = new KerhoSwing();
* kerhoswing.setListJasenet(listJasenet);
* kerhoswing.setEditHaku(editHaku);
* kerhoswing.setCbKentat(cbKentat);
* kerhoswing.setTableHarrastukset(tableHarrastus);
* kerhoswing.setPanelJasen(boxJasen);
* kerhoswing.setLabelVirhe(labelVirhe);
*
* String virhe = kerhoswing.lueTiedosto("kelmit");
* if ( virhe != null ) JOptionPane.showMessageDialog(null, virhe);
*
* 4) Kutsu nappien tapahtumista mm. olion lisaa ja talleta -metodeja.
* kerhoswing.lisaa();
* kerhoswing.talleta();
* 5) Jotta kaikki tulee talletettua, kutsu ohjelmasta poistuvissa paikoissa
* kerhoswing.talleta();
*
* @author vesal
* @version 10.4.2009
* @version 30.1.2012 - gui-komponenteilla
* @version 16.2.2012 - lisätty jäsenien käsittely
* @version 28.2.2012 - lisätty harrastusten käsittely
* @version 17.3.2012 - harrastukset kenttien perusteella
* TODO rivin vaihtuminen taulukossa
*/
public class KerhoSwing {
/** Kun halutaan haussa nykyjäsen valituksi haun jälkeen */
public static final int NYKY = -1;
private static Color virheVari = new Color(255, 0, 0);
private static Color normaaliVari = new Color(255, 255, 255);
private final static Jasen apujasen = new Jasen();
/** Apuharrastus josta katsotaan kenttien määrää yms */
protected final static Tietue apuharrastus = new Harrastus();
private AbstractChooser cbKentat;
private JTextField editHaku;
private AbstractChooser listJasenet;
private StringTable tableHarrastukset;
private JComponent panelJasen;
private JLabel labelVirhe;
private final Kerho kerho;
private Jasen jasenKohdalla; // Kohdalla oleva jäsen, ÄLÄ muuta muuten kuin set-kautta!
private Jasen editJasen; // Kohdalla oleva jäsen jos tehty muutoksia
private EditPanel editJasenKentta[]; // Jäsenen kenttiä vastaavat edit-kentät
/**
* Alustaa luokan niin, että se voi käyttää Swing-komponentteja
*/
public KerhoSwing() {
kerho = new Kerho();
}
/**
* @return mihin näytetään virheteksti
*/
public JLabel getLabelVirhe() {
return labelVirhe;
}
/**
* @param labelVirhe mihin näytetään virheteksti
*/
public void setLabelVirhe(JLabel labelVirhe) {
this.labelVirhe = labelVirhe;
}
/**
* @return combobox jossa kenttälista
*/
public AbstractChooser getCbKentat() {
return cbKentat;
}
/**
* @param cbKentat comboboxkenttälistaa varten
*/
public void setCbKentat(AbstractChooser cbKentat) {
this.cbKentat = cbKentat;
}
/**
* @return edit jossa hakuehto
*/
public JTextField getEditHaku() {
return editHaku;
}
/**
* @param editHaku edit johon saa kirjoittaa hakuehdon
*/
public void setEditHaku(JTextField editHaku) {
this.editHaku = editHaku;
}
/**
* @return lista johon jäsenet laitetaan
*/
public AbstractChooser getListJasenet() {
return listJasenet;
}
/**
* @param listJasenet lista johon jäsenet laitetaan
*/
public void setListJasenet(AbstractChooser listJasenet) {
this.listJasenet = listJasenet;
}
/**
* @return taulukko johon tulee jäsenen harrastukset
*/
public StringTable getTableHarrastukset() {
return tableHarrastukset;
}
/**
* @param tableHarrastukset taulukko johon tulee jäsenen harrastukset
*/
public void setTableHarrastukset(StringTable tableHarrastukset) {
this.tableHarrastukset = tableHarrastukset;
}
/**
* @return alue johon lisätään jäsenen yksittäiset kentät.
*/
public JComponent getPanelJasen() {
return panelJasen;
}
/**
* @param panelJasen alue johon lisätään jäsenen tiedot. Mielellään joku johon tulevat alekkain
*/
public void setPanelJasen(JComponent panelJasen) {
this.panelJasen = panelJasen;
}
/**
* Taulukon malli, jossa jokainen solu on Kentta-tyyppiä
*/
public static class KenttaTableModel extends DefaultTableModel {
private static final long serialVersionUID = 1L;
/**
* @param otsikot millä otsikoille malli alustetaan
*/
public KenttaTableModel(String[] otsikot) {
super(otsikot, 0);
}
@Override
public Class> getColumnClass(int columnIndex) {
return Kentta.class; // Jotta lajittelu toimii
}
}
/**
* Tämä alustaa valitut alueet käyttökuntoon.
*/
public void alusta() {
if ( editJasenKentta != null ) return; // on jo alustettu
cbKentat.setKohteet(apujasen.getOtsikot());
editHaku.addKeyListener(new KeyAdapter() {
@Override public void keyReleased(KeyEvent e) { hae(NYKY); }
});
cbKentat.addSelectionChangeListener(new SelectionChangeListener() {
@Override
public void selectionChange(IStringListChooser sender) { hae(NYKY);}
});
listJasenet.addSelectionChangeListener(new SelectionChangeListener() {
@Override
public void selectionChange(IStringListChooser sender) { naytaJasen(); }
});
tableHarrastukset.addTableEditListener(new TableEditListener() {
@Override
public String tableEdit(IStringTable sender, int row, int column, Object s) {
return setHarrastus(sender,row,column,s);
}
});
tableHarrastukset.addTableRendererListener(new TableRendererListener() {
@Override // Jotta saadaan vasen/oikea reuna kentän mukaan
public DefaultTableCellRenderer tableRenderer(IStringTable sender, DefaultTableCellRenderer renderer, int row, int column) {
renderer.setHorizontalAlignment(apuharrastus.getKentta(column+apuharrastus.ekaKentta()).getSijainti());
return renderer;
}
});
tableHarrastukset.addTableSelectionListener(new TableSelectionListener() {
@Override // jotta mahdollinen virhe pyyhkiytyy pois kun solua vaihdetaan
public void selectionChanged(IStringTable sender, int row, int column) {
setVirhe(null);
}
});
tableHarrastukset.setEditorSetValues(false); // kun on suorat viitteet kenttiin
tableHarrastukset.getTable().setModel(new KenttaTableModel(apuharrastus.getOtsikot()));
luoNaytto();
}
/**
* Asetetaan editoitava jäsen
* @param j uusi viite editJasenelle
*/
private void setEditJasen(Jasen j) {
editJasen = j;
}
/**
* Asetetaan editoitava jäsen
* @param j uusi viite editJasenelle
*/
private void setJasenKohdalla(Jasen j) {
int jnro = NYKY;
if ( j != null ) jnro = j.getTunnusNro();
tarkistaMuutos(jnro);
jasenKohdalla = j;
setEditJasen(null);
}
/**
* Tutkii onko editoitavaan jäseneen tehty muutoksia, jotka kannattaa
* tallettaa.
* @return false jos ei muutoksia
*/
private boolean muuttunut() {
if (jasenKohdalla == null) return false;
if (editJasen == null) return false;
return !jasenKohdalla.equals(editJasen);
}
/**
* Tarkitetaan onko jäsenen tiedot muuttuneet ja jos on, kysytään halutaanko tallentaa
* @param jnro mikä jäsen aktiiviseksi muutoksne jälkeen
*/
public void tarkistaMuutos(int jnro) {
if (muuttunut()) {
int vastaus = JOptionPane.showConfirmDialog(null, "Talletetaanko?", "Jäsen muuttunut!", JOptionPane.YES_NO_OPTION);
if (vastaus == JOptionPane.YES_OPTION) talleta(jnro);
}
}
/**
* Luo uuden jäsenen jota aletaan editoimaan
*/
private void luoUusiJasen() {
Jasen uusi = new Jasen();
uusi.rekisteroi();
setJasenKohdalla(uusi);
}
private boolean uusiDialogilla = false;
/**
* @param dialogilla kysytäänkö uudet tietueet dialogilla
*/
public void setUusiDialogilla(boolean dialogilla) {
uusiDialogilla = dialogilla;
}
/**
* @return kysytäänkö uudet tietueet dialogilla
*/
public boolean isUusiDialogilla() {
return uusiDialogilla;
}
/**
* Tekee uuden tyhjän jäsenen editointia varten
*/
public void uusiJasen() {
if ( uusiDialogilla ) {
tarkistaMuutos(jasenKohdalla.getTunnusNro());
Jasen uusi = new Jasen();
if ( !TietueDialog.kysyTietue(uusi, "Anna uuden jäsenen tiedot", 150) ) return;
uusi.rekisteroi();
kerho.lisaa(uusi);
hae(uusi.getTunnusNro());
return;
}
luoUusiJasen();
laitaJasen();
listJasenet.clearSelection();
}
/**
* Tekee uuden tyhjän harrastuksen editointia varten
*/
public void uusiHarrastus() {
if ( jasenKohdalla == null ) return;
tarkistaMuutos(jasenKohdalla.getTunnusNro());
Harrastus harrastus = new Harrastus(jasenKohdalla.getTunnusNro());
if ( uusiDialogilla )
if ( !TietueDialog.kysyTietue(harrastus, "Anna uuden harrastuksen tiedot", 80) ) return;
harrastus.rekisteroi();
kerho.lisaa(harrastus);
naytaHarrastukset();
}
/**
* Näytetään harrastukset taulukkoon. Tyhjennetään ensin taulukko ja sitten
* lisätään siihen kaikki harrastukset
*/
protected void naytaHarrastukset() {
if ( jasenKohdalla == null ) return;
tableHarrastukset.clear();
tableHarrastukset.getTable().getColumnModel().getColumn(0).setMinWidth(100);
List harrastukset = kerho.annaHarrastukset(jasenKohdalla);
for (Tietue har : harrastukset) {
int r = tableHarrastukset.addRow();
tableHarrastukset.setObjectAt(har, r);
for (int i=0,k = har.ekaKentta(); k < har.getKenttia() && i < tableHarrastukset.getColumnCount(); i++,k++) {
tableHarrastukset.setValueAtModel(har.getKentta(k), r, i);
}
}
// tableHarrastukset.selectCell(tableHarrastukset.getRowCount()-1, 0);
}
/**
* Asetetaan harrastukseen uusi arvo
* @param sender mistä taulukosta pyyntö tuli
* @param row miltä riviltä
* @param column mistä sarakkeesta
* @param s mitä haluttiin laittaa
* @return null jos ok, muuten virhe
*/
public String setHarrastus(IStringTable sender, int row, int column, Object s) {
Tietue har = (Tietue)sender.getObjectAt(row);
if ( har == null ) return "Ei harrastusta";
String virhe = har.aseta(column+har.ekaKentta(), s.toString());
if ( virhe == null ) kerho.setHarrastusMuutos();
setVirhe(virhe);
return virhe;
}
/**
* Lukee kerhon tiedot tiedostosta. Tarkistetaan aluksi että kaikki
* kentät on asetettu paikalleen.
* @param s tiedoston nimi
* @return null jos onnistuu, muuten virheilmoitus
*/
public String lueTiedosto(String s) {
try {
if ( cbKentat == null ) return "cbKentat on alustamatta";
if ( editHaku == null ) return "editHaku on alustamatta";
if ( listJasenet == null ) return "listJasenet on alustamatta";
if ( tableHarrastukset == null ) return "tableHarrastukset on alustamatta";
if ( panelJasen == null ) return "panelJasen on alsutamatta";
alusta();
kerho.lueTiedostosta(s);
hae(0);
return null;
} catch (SailoException e) {
hae(0);
// uusiJasen();
return e.getMessage();
}
}
/**
* Tallettaa nykyisen mahdollisesti muutetun jäsenen ja sitten koko tiedoston
* @param jnro Mikä jäsen aktiiviseksi talletuksen jälkeen. -1 = nykyinen valittu jäsen.
* @return null jos menee hyvin, muuten virheteksti
*/
public String talleta(int jnro) {
int jn = jnro;
try {
if (muuttunut()) {
kerho.korvaaTaiLisaa(editJasen);
jasenKohdalla = editJasen;
if (jasenKohdalla != null && jnro < 0) {
jn = jasenKohdalla.getTunnusNro();
}
hae(jn);
}
setEditJasen(null);
kerho.talleta();
return null;
} catch (SailoException ex) {
JOptionPane.showMessageDialog(null, "Talletuksessa ongelmia! " + ex.getMessage());
return ex.getMessage();
}
}
/**
* Tallettaa nykyisen mahdollisesti muutetun jäsenen ja sitten koko tiedoston
* @return null jos menee hyvin, muuten virheteksti
*/
public String talleta() {
return talleta(NYKY);
}
/**
* Suorittaa niiden jäsenten hakemisen, joiden valittu kenttä täyttää hakuehdon
* @param jnro jäsenen numero, joka aktivoidaan haun jälkeen, -1 = aktivoidaan nykyinen jäsen
*/
protected void hae(int jnro) {
int jn = jnro;
if ( jn == NYKY && jasenKohdalla != null ) jn = jasenKohdalla.getTunnusNro();
int k = cbKentat.getSelectedIndex() + apujasen.ekaKentta();
String ehto = editHaku.getText();
if (ehto.indexOf('*') < 0) ehto = "*" + ehto + "*";
Collection haunTulos = kerho.etsi(ehto, k);
listJasenet.clear();
int index = 0, i = 0;
for (Jasen jasen : haunTulos ) {
if (jasen.getTunnusNro() == jn) index = i;
listJasenet.add(jasen.getNimi(),jasen);
i++;
}
listJasenet.setSelectedIndex(index);
}
/**
* Näyttää jäsenen tiedot jäsenen alueeseen
*/
private void laitaJasen() {
if (jasenKohdalla == null) return;
setVirhe(null);
for (int i = 0, k = jasenKohdalla.ekaKentta(); k < jasenKohdalla.getKenttia(); k++, i++) {
editJasenKentta[i].setText(jasenKohdalla.anna(k));
editJasenKentta[i].getEdit().setBackground(normaaliVari);
editJasenKentta[i].setToolTipText("");
}
naytaHarrastukset();
}
/**
* Näyttää listasta valitun jäsenen tiedot
*/
protected void naytaJasen() {
int ind = listJasenet.getSelectedIndex();
if (ind < 0) return;
setJasenKohdalla(listJasenet.getSelectedObject());
laitaJasen();
}
/**
* Käsittelee edit-kenttään tulleen muutoksen jäseneen.
* Mikäli jäsentä ei vielä ole editoitu, luodaan jäsenestä
* kopio editJasen-olioon ja muutokset kohdistetaan tähän
* jäseneen. Näin voidaan muutoksia verrata jasen-olioon
* ja tunnistetaan muutostarpeet. Jos muutosta ei voida
* sijoittaa jäseneen, muutetaan taustaväri punaiseksi.
* @param edit muuttunut kenttä
*/
protected void kasitteleMuutosJaseneen(JTextField edit) {
if (jasenKohdalla == null) luoUusiJasen();
if (editJasen == null)
try {
setEditJasen(jasenKohdalla.clone());
} catch (CloneNotSupportedException e) { // virhettä ei tule
}
String s = edit.getText();
int k = Integer.parseInt(edit.getName().substring(2));
String virhe = editJasen.aseta(k, s);
setVirhe(virhe);
if (virhe == null) {
edit.setToolTipText("");
edit.setBackground(normaaliVari);
} else {
edit.setToolTipText(virhe);
edit.setBackground(virheVari);
}
}
/**
* Laitetaan virheilmoitus näkyville jos labelVirhe on alustettu.
* Miksä virhettä ei ole, niin piilotetaan virheilmoitus.
* @param virhe virheteksti
*/
protected void setVirhe(String virhe) {
if ( labelVirhe == null ) return;
if ( virhe == null ) {
labelVirhe.setText("");
labelVirhe.setVisible(false);
return;
}
labelVirhe.setVisible(true);
labelVirhe.setText(virhe);
labelVirhe.setBackground(virheVari);
}
/**
* Käsittelijäluokka edit kentän näppäimen vapauttamiselle
*/
protected class EditKeyReleased extends KeyAdapter {
@Override public void keyReleased(KeyEvent e) {
kasitteleMuutosJaseneen((JTextField)e.getComponent());
}
}
private EditKeyReleased editKeyReleased = new EditKeyReleased();
/**
* Luo panelJasen:een paikat johon jäsenen tiedot voi laittaa
*/
private void luoNaytto() {
panelJasen.removeAll();
int n = apujasen.getKenttia() - apujasen.ekaKentta();
editJasenKentta = new EditPanel[n];
for (int i = 0, k = apujasen.ekaKentta(); k < apujasen.getKenttia(); k++, i++) {
EditPanel edit = new EditPanel();
edit.setCaption(apujasen.getKysymys(k));
editJasenKentta[i] = edit;
edit.setName("ej" + k);
edit.getEdit().setName("tj" + k);
panelJasen.add(edit);
edit.addKeyListener(editKeyReleased);
}
}
/**
* Poistetaan harrastustaulukosta valitulla kohdalla oleva harrastus.
*/
public void poistaHarrastus() {
int rivi = tableHarrastukset.getSelectedRow();
if ( rivi < 0 ) return;
Harrastus harrastus = (Harrastus)tableHarrastukset.getSelectedObject();
if ( harrastus == null ) return;
kerho.poistaHarrastus(harrastus);
naytaHarrastukset();
if ( rivi >= tableHarrastukset.getRowCount() ) rivi = tableHarrastukset.getRowCount() - 1;
tableHarrastukset.selectCell(rivi, 0);
}
/**
* Poistetaan listasta valittu jäsen.
*/
public void poistaJasen() {
if ( jasenKohdalla == null ) return;
int vastaus = JOptionPane.showConfirmDialog(null, "Poistetaanko jäsen: " + jasenKohdalla.getNimi(), "Poisto?", JOptionPane.YES_NO_OPTION);
if ( vastaus == JOptionPane.NO_OPTION ) return;
kerho.poista(jasenKohdalla.getTunnusNro());
int index = listJasenet.getSelectedIndex();
hae(0);
listJasenet.setSelectedIndex(index);
}
/**
* Avataan ulkoinen selain näyttämään avustustekstiä.
*/
public void avustus() {
Desktop desktop = Desktop.getDesktop();
try {
//URI uri = new URI("kerho.html");
URI uri = new URI("https://trac.cc.jyu.fi/projects/ohj2k12/wiki/suunnitelmat/vesal2");
desktop.browse(uri);
} catch (URISyntaxException e) {
return;
} catch (IOException e) {
return;
}
}
/**
* Tulostaa jäsenen tiedot
* @param os tietovirta johon tulostetaan
* @param jasen tulostettava jäsen
*/
public void tulosta(PrintStream os, final Jasen jasen) {
os.println("----------------------------------------------");
jasen.tulosta(os);
os.println("----------------------------------------------");
for (Tietue har:kerho.annaHarrastukset(jasen)) har.tulosta(os);
}
/**
* Tulostaa listassa olevat jäsenet tekstialueeseen
* @param text alue johon tulostetaan
*/
public void tulostaValitut(JTextArea text) {
PrintStream os = TextAreaOutputStream.getTextPrintStream(text);
os.println("Valitut jäsenet:");
for (Jasen jasen : listJasenet.getObjectList()) {
tulosta(os, jasen);
os.println("\n\n");
}
}
}