/*
* Copyright (c) 2012, Fromentin Xavier, Schnell Michaël, Dervin Cyrielle, Brabant Quentin
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * The names of its contributors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Fromentin Xavier, Schnell Michaël, Dervin Cyrielle OR Brabant Quentin
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package kameleon.gui.view;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;
import kameleon.exception.FileReadingException;
import kameleon.gui.exception.InvalidOutputFileException;
import kameleon.gui.exception.UnknownKeyException;
import kameleon.gui.language.SwitchLanguage;
import kameleon.gui.model.FileInfo;
import kameleon.gui.model.Model;
import kameleon.gui.model.Observer;
import kameleon.gui.util.FileConstants;
import kameleon.gui.util.ImageUtility;
import kameleon.gui.util.LanguageConstants;
import kameleon.plugin.PlugInInfo;
/**
* View showing the available output formats and the generation button.
* The available formats are displayed using the colored pictures for
* selected formats and grayed pictures for the others.
*
* @author Fromentin Xavier, Schnell Michaël
* @version 1.0
*/
public class GenerationView extends JPanel
implements Observer, FileConstants, LanguageConstants {
/**
* Needed to serialize this class.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 9147115868827007825L;
/**
* Model of this view.
*/
protected Model model ;
/**
* View displaying the available formats.
*/
protected OutputFormatView formatsView ;
/**
* "Generate" button. Launches the generation.
*/
protected JButton generate ;
/**
* Message displayed when there are no generators installed.
*/
protected JLabel emptyMessage ;
/**
* Component containing this view.
*/
protected Component container ;
/**
* Builds an instance with the given model and parent.
*
* @param model
* model for this view
*
* @param container
* parent {@code Component} for this view
*/
public GenerationView(Model model, Component container) {
super();
this.model = model ;
this.model.addObserver(this) ;
this.container = container ;
this.build() ;
}// GenerationView(Model, Component)
/**
* Builds the content of this view.
*/
protected void build() {
this.setBorder(BorderFactory.createTitledBorder("")) ; //$NON-NLS-1$
GridBagLayout gridbag = new GridBagLayout() ;
this.setLayout(gridbag) ;
GridBagConstraints constraints ;
// Display the available formats
constraints = new GridBagConstraints() ;
constraints.gridwidth = GridBagConstraints.REMAINDER ;
constraints.fill = GridBagConstraints.HORIZONTAL ;
this.formatsView = new OutputFormatView(this.model) ;
this.add(this.formatsView) ;
gridbag.setConstraints(this.formatsView, constraints) ;
// Generate button
constraints = new GridBagConstraints() ;
constraints.gridwidth = GridBagConstraints.REMAINDER ;
constraints.anchor = GridBagConstraints.CENTER ;
this.generate = new JButton() ;
this.generate.addActionListener(new GenerationListener()) ;
this.generate.setEnabled(false) ;
this.add(this.generate) ;
gridbag.setConstraints(this.generate, constraints) ;
}// build()
/**
* Updates the displayed output formats and enables/disables the
* generate button.
*
* @throws UnknownKeyException
* if an error occurred while updating the text of this view
*/
@Override
public void update() throws UnknownKeyException {
if (this.model.generatorAddedOrRemoved()) {
this.removeAll() ;
this.build() ;
this.reloadLanguage() ;
} else {
this.generate.setEnabled(this.model.generationIsPossible());
}// if
}// udpate()
/**
* Updates the text to match the currently selected language.
*
* @throws UnknownKeyException
* if an error occurred while updating the text of this view
*/
@Override
public void reloadLanguage() throws UnknownKeyException {
SwitchLanguage sl = SwitchLanguage.getInstance() ;
TitledBorder border = (TitledBorder) this.getBorder() ;
border.setTitle(sl.getText(GENERATION_TITLE_BORDER)) ;
this.generate.setText(sl.getText(GENERATE_BUTTON)) ;
if (this.emptyMessage != null) {
this.emptyMessage.setText(sl.getText(NO_GENERATORS)) ;
}// if
}// reloadLanguage()
/**
* View displaying the available output formats.
*
* <p>Each format is displayed using a coloured/grayed picture based
* on whether the output format is selected or not. Each picture
* uses the format name as tooltip.
*
* @author Fromentin Xavier, Schnell Michaël
* @version 1.0
*/
private class OutputFormatView extends JPanel {
/**
* Needed to serialize this class.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = -640280176195965001L ;
/**
* Buttons used to display the available output formats.
*/
protected JButton[] formats ;
/**
* Builds an instance with the given model.
*
* @param model
* model for this view
*/
public OutputFormatView(Model model) {
super() ;
this.build(model) ;
}// OutputFormatView(Model)
/**
* Builds the content of this view.
*
* @param sourceModel
* model used to retrieve the available formats
*/
protected void build(Model sourceModel) {
GridBagLayout gridbag = new GridBagLayout() ;
this.setLayout(gridbag) ;
GridBagConstraints c ;
List<PlugInInfo> generators =
sourceModel.getKnownGenerators() ;
if (generators.isEmpty()) {
JLabel info = new JLabel() ;
try {
SwitchLanguage sl = SwitchLanguage.getInstance() ;
info.setText(sl.getText(NO_GENERATORS)) ;
} catch (UnknownKeyException uke) {
//TODO Handle exception
sourceModel.displayDebugInformation(uke) ;
}// try
c = new GridBagConstraints() ;
c.gridwidth = 1 ;
c.weightx = 1.0 ;
this.add(info) ;
gridbag.setConstraints(info, c) ;
GenerationView.this.emptyMessage = info ;
} else {
GenerationView.this.emptyMessage = null ;
this.formats = new JButton[generators.size()] ;
int nGenerators = generators.size() ;
List<String> selectedGenerators =
GenerationView.this.model.getSelectedOutputFormats();
for(int g=0; g < nGenerators; ++g) {
try {
PlugInInfo generatorInfo = generators.get(g) ;
boolean selected =
selectedGenerators.contains(generatorInfo.getId());
String imagePath = String.format(selected ? COLOR_ICON : GRAY_ICON,
generatorInfo.getId()) ;
JButton button = new JButton(new ImageIcon(
ImageUtility.getImageBytes(imagePath))) ;
button.setContentAreaFilled(false) ;
button.setBorderPainted(false) ;
button.setCursor(
Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)) ;
button.setToolTipText(generatorInfo.getFormatName());
button.addActionListener(new FormatSelectionListener(
g,
generatorInfo.getId(),
button)) ;
button.setSelected(selected);
c = new GridBagConstraints() ;
c.gridwidth = 1 ;
c.weightx = 1.0 ;
this.add(button) ;
gridbag.setConstraints(button, c) ;
this.formats[g] = button ;
} catch(FileReadingException fre) {
//TODO Handle exception
sourceModel.displayDebugInformation(fre) ;
}// try
}// for
}// if
}// build(Model)
}// class OutputFormatView
/**
* Listener handling the clicks on the format pictures. Selects
* or "de-selects" the output format whose picture was clicked.
*
* @author Fromentin Xavier, Schnell Michaël
* @version 1.0
*/
private class FormatSelectionListener implements ActionListener {
/**
* Identifier of the handled output format.
*/
protected String formatId ;
/**
* Button attached to this listener.
*/
protected JButton button ;
/**
* Builds an instance with the given values.
*
* @param iconId
* identifier of the icon within the containing view
*
* @param formatId
* identifier of the handled output format
*
* @param button
* button attached to this listener
*/
public FormatSelectionListener(int iconId, String formatId,
JButton button) {
super() ;
this.formatId = formatId ;
this.button = button ;
}// FormatSelectionListener(int, String, String, JButton)
/**
* Selects or de-selects the handled format.
*
* @param e
* event which triggered this listener
*/
@Override
public void actionPerformed(ActionEvent e) {
GenerationView gv = GenerationView.this ;
try {
if (this.button.isSelected()) {
this.button.setIcon(new ImageIcon(ImageUtility.getImageBytes(
String.format(GRAY_ICON, this.formatId)))) ;
this.button.setSelected(false) ;
gv.model.removeSelectedFormat(this.formatId) ;
} else {
this.button.setIcon(new ImageIcon(ImageUtility.getImageBytes(
String.format(COLOR_ICON, this.formatId)))) ;
this.button.setSelected(true) ;
gv.model.addSelectedFormat(this.formatId) ;
}// if
} catch(FileReadingException fre) {
//TODO Handle Exception
gv.model.displayDebugInformation(fre) ;
}// try
}// actionPerformed(ActionEvent)
}// class FormatSelectionListener
/**
* Listener handling the clicks on the generate button. Launches
* the "output file selector" window before starting the generation.
*
* @author Fromentin Xavier, Schnell Michaël
* @version 1.0
*/
private class GenerationListener implements ActionListener {
/**
* File chooser used to determine output folder and the
* output file name.
*/
protected JFileChooser outputChooser ;
/**
* Sole constructor.
*/
public GenerationListener() {
super() ;
this.outputChooser = new JFileChooser() ;
}// GenerationListener()
/**
* Prompt the user to get the output folder and output file
* name before launching the generation.
*
* @param e
* event which triggered the listener
*/
@Override
public void actionPerformed(ActionEvent e) {
GenerationView gv = GenerationView.this ;
FileInfo selectedFile = gv.model.getSelectedFileInfo() ;
// Sets the output folder to the folder of the last
// generation
if (selectedFile.getLastGeneration() != null) {
String outputFile = selectedFile.getTargetPath()[0] ;
int fileNameStart =
outputFile.lastIndexOf(File.separatorChar) ;
String outputFolder =
outputFile.substring(0, fileNameStart) ;
this.outputChooser.setCurrentDirectory(
new File(outputFolder)) ;
}// if
int saveResult =
this.outputChooser.showSaveDialog(gv.container) ;
if (saveResult == JFileChooser.APPROVE_OPTION) {
try {
gv.model.setOutputFile(
this.outputChooser.getSelectedFile()) ;
gv.model.launchGeneration() ;
} catch (InvalidOutputFileException iofe) {
//TODO Handle exception
gv.model.displayDebugInformation(iofe) ;
}// try
}// if
}// actionPerformed(ActionEvent)
}// class GenerationListener
}// class GenerationView