/**
* Copyright (C) 2008-2011 Daniel Senff
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package de.danielsenff.imageflow.models.unit;
import ij.IJ;
import ij.ImagePlus;
import ij.io.OpenDialog;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.ImageObserver;
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import de.danielsenff.imageflow.ImageFlow;
import de.danielsenff.imageflow.models.MacroElement;
import de.danielsenff.imageflow.models.connection.Output;
import de.danielsenff.imageflow.models.datatype.ImageDataType;
import de.danielsenff.imageflow.models.parameter.Parameter;
import de.danielsenff.imageflow.models.parameter.StringParameter;
import de.danielsenff.imageflow.utils.ImageJHelper;
import de.danielsenff.imageflow.utils.UrlCheck;
/**
* Specialized {@link UnitElement} for loading image files.
* This supports the file formats ImageJ does natively.
* @author danielsenff
*
*/
public class SourceUnitElement extends UnitElement implements ImageSourceUnit {
private boolean exists = false;
private static final int FILE_PARAMETER_INDEX = 0;
/**
* @param origin
* @param unitName
* @param macroElement
*/
public SourceUnitElement(final Point origin,
final String unitName,
final MacroElement macroElement)
{
super(origin, unitName, macroElement);
}
/**
* @param origin
* @param unitName
* @param macroString
*/
public SourceUnitElement(final Point origin,
final String unitName,
final String macroString)
{
super(origin, unitName, macroString);
}
@Override
public void showProperties(Point point) {
// display file dialog
if(!existsFile())
showOpenFileChooser();
super.showProperties(point);
updateImageType();
notifyModelListeners();
}
/**
* The current ImageType is determined by the currently selected file.
* The unit-icon and labels will be updated as well.
* If no file is selected or the file doesn't exist, a message is displayed.
*/
public void updateImageType() {
int imageType = -1;
setExistsFile(getFilePath());
if(existsFile()) {
imageType = getImageType();
setIconScaled(getImagePlus().getImage());
} else {
this.setIcon(null);
JOptionPane.showMessageDialog(ImageFlow.getApplication().getMainFrame(),
"The file " +getFile()+ " you selected does not exist."+
'\n'+"An image type can not be determined, which can invalidate the current graph.",
"File doesn't exist",
JOptionPane.WARNING_MESSAGE);
}
// change bit depth for all outputs
setOutputImageType(imageType);
}
/**
* Display the default file chooser.
*/
protected void showOpenFileChooser() {
showOpenJFileChooser();
// showIJOpenDialog();
}
/**
* Opens a {@link JFileChooser} to select a new file.
*/
protected void showOpenJFileChooser() {
final JFileChooser fc = new JFileChooser();
String filepath = getFilePath();
fc.setSelectedFile(new File(filepath));
final int option = fc.showOpenDialog(null);
if (option == JFileChooser.APPROVE_OPTION) {
filepath = fc.getSelectedFile().getAbsolutePath();
// backslashes need to be escaped
//filepath = filepath.replace("\\", "\\\\"); // \ to \\
setFilePath(filepath);
}
}
/**
* Opens an ImageJ {@link OpenDialog} for selecting an image file.
*/
private void showIJOpenDialog() {
OpenDialog openDialog;
if(hasFilePath())
openDialog = new OpenDialog("Select image", getFilePath());
else
openDialog = new OpenDialog("Select image", "");
String filepath = openDialog.getDirectory() + openDialog.getFileName();
if(openDialog.getFileName() != null) {
// backslashes need to be escaped
filepath = filepath.replace("\\", "\\\\"); // \ to \\
setFilePath(filepath);
}
}
/**
* The ImageType on the output depends on the current image.
* This function updates all {@link Output}s to the specified imageType.
* @param imageType
*/
public void setOutputImageType(final int imageType) {
for (final Output output : outputs) {
if(output.getDataType() instanceof ImageDataType)
((ImageDataType)output.getDataType()).setImageBitDepth(imageType);
}
}
/**
* Bit depth of the file behind the specified FilePath
* @return
*/
public int getBitDepth() {
ImagePlus imp = getImagePlus();
int bitDepth = 0;
if(imp != null) {
imp.close();
bitDepth = imp.getBitDepth();
}
return bitDepth;
}
/**
* Returns the ImageType of the file specified in the FilePath.
* @return
*/
public int getImageType() {
return ImageJHelper.getImageType(getImagePlus());
}
/**
* {@link ImagePlus} based on the path saved in the first parameter of this UnitElement.
* @return
*/
public ImagePlus getImagePlus() {
if(existsFile()) {
return IJ.openImage(getFilePath());
}
return null;
}
@Override
public SourceUnitElement clone() {
// clone the object
String imageJSyntax;
try {
imageJSyntax = (String) cloneNonClonableObject(this.obj);
} catch (CloneNotSupportedException e) {
imageJSyntax = ((MacroElement)this.obj).getImageJSyntax();
}
SourceUnitElement clone = new SourceUnitElement(new Point(origin.x+15, origin.y+15),
this.label, imageJSyntax);
for (int j = 0; j < getInputsCount(); j++) {
cloneInput(clone, j);
}
for (int i = 0; i < getOutputsCount(); i++) {
cloneOutput(clone, i);
}
for (Parameter parameter : parameters) {
cloneParameter(clone, parameter);
}
// set filepath
clone.setFilePath(this.getFilePath());
clone.setOriginalUnit(this);
clone.setDisplay(isDisplay());
clone.setDisplaySilent(isDisplaySilent());
clone.setColor(this.color);
clone.setIcon(this.preview);
clone.setHelpString(this.infoText);
clone.setCompontentSize(this.getCompontentSize());
return clone;
}
/*
* Handling File
*/
/**
* Returns true if the first parameter has a path.
* This doesn't check if the path is valid.
* @return
*/
public boolean hasFilePath() {
return (getFilePath().length() > 0);
}
/**
* Returns the path of the file from the first parameter.
* @return
*/
public String getFilePath() {
return ((StringParameter)getParameter(FILE_PARAMETER_INDEX)).getValue();
}
/**
* The path of the current file.
* This is taken from the first parameter of the {@link UnitElement}.
* @return
*/
public File getFile() {
return new File(getFilePath());
}
/**
* Set the file connected with the file path.
* @param filepath
*/
public void setFilePath(String filepath) {
((StringParameter)getParameter(FILE_PARAMETER_INDEX)).setValue(filepath);
setLabel(filepath.substring(filepath.lastIndexOf(File.separator)+1));
setExistsFile(filepath);
}
/**
* Returns true if the File exists.
* @return
*/
public boolean existsFile() {
return this.exists;
}
private void setExistsFile(String path) {
if (path.indexOf("://")>0) // is url
this.exists = UrlCheck.existsFile(path);
else // is file
this.exists = this.getFile().exists();
}
/*
* painting
*/
/*
* (non-Javadoc)
* @see de.danielsenff.imageflow.models.unit.UnitElement#paint(java.awt.Graphics, java.awt.image.ImageObserver)
*/
@Override
public Rectangle paint(final Graphics g, final ImageObserver io) {
if(!existsFile() && !selected) {
g.setColor(new Color(255,0,0,80));
g.fillRoundRect(origin.x, origin.y, getDimension().width, getDimension().height,
unitComponentIcon.arc, unitComponentIcon.arc);
}
final Rectangle paint = super.paint(g, io);
return paint;
}
}